activerecord-jdbc-adapter 1.2.9.1 → 1.3.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (231) hide show
  1. data/.travis.yml +3 -0
  2. data/Appraisals +12 -4
  3. data/Gemfile +3 -3
  4. data/Gemfile.lock +19 -19
  5. data/History.txt +90 -16
  6. data/LICENSE.txt +2 -1
  7. data/README.md +14 -1
  8. data/activerecord-jdbc-adapter.gemspec +2 -2
  9. data/gemfiles/rails23.gemfile +5 -5
  10. data/gemfiles/rails23.gemfile.lock +27 -27
  11. data/gemfiles/rails30.gemfile +3 -3
  12. data/gemfiles/rails30.gemfile.lock +8 -8
  13. data/gemfiles/rails31.gemfile +4 -4
  14. data/gemfiles/rails31.gemfile.lock +18 -18
  15. data/gemfiles/rails32.gemfile +4 -4
  16. data/gemfiles/rails32.gemfile.lock +17 -17
  17. data/gemfiles/rails40.gemfile +17 -0
  18. data/gemfiles/rails40.gemfile.lock +126 -0
  19. data/lib/activerecord-jdbc-adapter.rb +0 -7
  20. data/lib/arjdbc.rb +6 -5
  21. data/lib/arjdbc/db2.rb +1 -1
  22. data/lib/arjdbc/db2/adapter.rb +52 -29
  23. data/lib/arjdbc/db2/connection_methods.rb +13 -14
  24. data/lib/arjdbc/derby.rb +1 -1
  25. data/lib/arjdbc/derby/adapter.rb +29 -9
  26. data/lib/arjdbc/derby/connection_methods.rb +17 -20
  27. data/lib/arjdbc/firebird.rb +1 -1
  28. data/lib/arjdbc/h2.rb +2 -2
  29. data/lib/arjdbc/h2/adapter.rb +1 -1
  30. data/lib/arjdbc/h2/connection_methods.rb +12 -16
  31. data/lib/arjdbc/hsqldb.rb +1 -1
  32. data/lib/arjdbc/hsqldb/connection_methods.rb +13 -16
  33. data/lib/arjdbc/informix.rb +1 -1
  34. data/lib/arjdbc/informix/connection_methods.rb +8 -10
  35. data/lib/arjdbc/jdbc.rb +1 -1
  36. data/lib/arjdbc/jdbc/adapter.rb +125 -53
  37. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  38. data/lib/arjdbc/jdbc/base_ext.rb +34 -9
  39. data/lib/arjdbc/jdbc/column.rb +15 -2
  40. data/lib/arjdbc/jdbc/connection.rb +0 -2
  41. data/lib/arjdbc/jdbc/connection_methods.rb +10 -3
  42. data/lib/arjdbc/jdbc/driver.rb +2 -2
  43. data/lib/arjdbc/jdbc/extension.rb +35 -21
  44. data/lib/arjdbc/jdbc/java.rb +0 -2
  45. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +35 -25
  46. data/lib/arjdbc/jdbc/railtie.rb +2 -9
  47. data/lib/arjdbc/mimer.rb +1 -1
  48. data/lib/arjdbc/mssql.rb +2 -2
  49. data/lib/arjdbc/mssql/adapter.rb +271 -92
  50. data/lib/arjdbc/mssql/connection_methods.rb +30 -32
  51. data/lib/arjdbc/mssql/explain_support.rb +107 -0
  52. data/lib/arjdbc/mssql/limit_helpers.rb +48 -18
  53. data/lib/arjdbc/mysql.rb +1 -1
  54. data/lib/arjdbc/mysql/adapter.rb +63 -14
  55. data/lib/arjdbc/mysql/connection_methods.rb +22 -24
  56. data/lib/arjdbc/mysql/explain_support.rb +2 -5
  57. data/lib/arjdbc/oracle.rb +1 -1
  58. data/lib/arjdbc/oracle/adapter.rb +78 -38
  59. data/lib/arjdbc/oracle/connection_methods.rb +9 -10
  60. data/lib/arjdbc/postgresql.rb +1 -1
  61. data/lib/arjdbc/postgresql/adapter.rb +964 -380
  62. data/lib/arjdbc/postgresql/column_cast.rb +136 -0
  63. data/lib/arjdbc/postgresql/connection_methods.rb +19 -21
  64. data/lib/arjdbc/postgresql/explain_support.rb +3 -6
  65. data/lib/arjdbc/railtie.rb +9 -0
  66. data/lib/arjdbc/sqlite3.rb +1 -1
  67. data/lib/arjdbc/sqlite3/adapter.rb +73 -26
  68. data/lib/arjdbc/sqlite3/connection_methods.rb +27 -28
  69. data/lib/arjdbc/sqlite3/explain_support.rb +2 -5
  70. data/lib/arjdbc/sybase.rb +1 -1
  71. data/lib/arjdbc/version.rb +5 -4
  72. data/pom.xml +8 -0
  73. data/rakelib/02-test.rake +57 -51
  74. data/rakelib/compile.rake +17 -5
  75. data/rakelib/rails.rake +42 -31
  76. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +4 -3
  77. data/src/java/arjdbc/derby/DerbyModule.java +98 -85
  78. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +70 -0
  79. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +0 -4
  80. data/src/java/arjdbc/jdbc/AdapterJavaService.java +26 -15
  81. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  82. data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +10 -2
  83. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1675 -834
  84. data/src/java/arjdbc/jdbc/SQLBlock.java +9 -3
  85. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +73 -36
  86. data/src/java/arjdbc/mysql/MySQLModule.java +11 -10
  87. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +86 -80
  88. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +27 -7
  89. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +214 -0
  90. data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +25 -67
  91. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +52 -49
  92. data/src/java/arjdbc/util/QuotingUtils.java +6 -6
  93. data/test/abstract_db_create.rb +11 -11
  94. data/test/activerecord/connection_adapters/type_conversion_test.rb +18 -12
  95. data/test/db/db2.rb +1 -1
  96. data/test/{db2_binary_test.rb → db/db2/binary_test.rb} +0 -0
  97. data/test/db/db2/has_many_through_test.rb +6 -0
  98. data/test/{db2_reset_column_information_test.rb → db/db2/reset_column_information_test.rb} +1 -2
  99. data/test/{db2_serialize_test.rb → db/db2/serialize_test.rb} +0 -0
  100. data/test/{db2_simple_test.rb → db/db2/simple_test.rb} +1 -8
  101. data/test/db/db2/test_helper.rb +6 -0
  102. data/test/{db2_test.rb → db/db2/unit_test.rb} +1 -1
  103. data/test/db/derby.rb +1 -1
  104. data/test/{derby_binary_test.rb → db/derby/binary_test.rb} +0 -0
  105. data/test/{derby_migration_test.rb → db/derby/migration_test.rb} +0 -0
  106. data/test/{derby_reset_column_information_test.rb → db/derby/reset_column_information_test.rb} +0 -0
  107. data/test/{derby_row_locking_test.rb → db/derby/row_locking_test.rb} +1 -4
  108. data/test/db/derby/schema_dump_test.rb +5 -0
  109. data/test/{derby_serialize_test.rb → db/derby/serialize_test.rb} +0 -0
  110. data/test/{derby_simple_test.rb → db/derby/simple_test.rb} +23 -38
  111. data/test/db/derby/test_helper.rb +6 -0
  112. data/test/db/derby/unit_test.rb +32 -0
  113. data/test/db/derby/xml_column_test.rb +17 -0
  114. data/test/db/h2.rb +1 -1
  115. data/test/{h2_binary_test.rb → db/h2/binary_test.rb} +0 -0
  116. data/test/{h2_change_column_test.rb → db/h2/change_column_test.rb} +1 -0
  117. data/test/{h2_schema_dump_test.rb → db/h2/schema_dump_test.rb} +0 -0
  118. data/test/{h2_serialize_test.rb → db/h2/serialize_test.rb} +0 -0
  119. data/test/{h2_simple_test.rb → db/h2/simple_test.rb} +3 -1
  120. data/test/db/hsqldb.rb +1 -1
  121. data/test/{hsqldb_binary_test.rb → db/hsqldb/binary_test.rb} +0 -0
  122. data/test/{hsqldb_schema_dump_test.rb → db/hsqldb/schema_dump_test.rb} +0 -0
  123. data/test/{hsqldb_serialize_test.rb → db/hsqldb/serialize_test.rb} +0 -0
  124. data/test/{hsqldb_simple_test.rb → db/hsqldb/simple_test.rb} +3 -1
  125. data/test/db/informix.rb +1 -1
  126. data/test/db/jdbc.rb +3 -2
  127. data/test/db/jdbc_derby.rb +1 -1
  128. data/test/db/jdbc_h2.rb +1 -1
  129. data/test/db/jdbc_mysql.rb +1 -1
  130. data/test/db/jdbc_postgres.rb +1 -1
  131. data/test/db/jndi_config.rb +1 -2
  132. data/test/db/jndi_pooled_config.rb +2 -3
  133. data/test/db/mssql.rb +2 -2
  134. data/test/{mssql_binary_test.rb → db/mssql/binary_test.rb} +0 -0
  135. data/test/{mssql_db_create_test.rb → db/mssql/db_create_test.rb} +1 -1
  136. data/test/db/mssql/exec_proc_test.rb +46 -0
  137. data/test/{mssql_identity_insert_test.rb → db/mssql/identity_insert_test.rb} +0 -0
  138. data/test/db/mssql/ignore_system_views_test.rb +40 -0
  139. data/test/{mssql_limit_offset_test.rb → db/mssql/limit_offset_test.rb} +10 -1
  140. data/test/{mssql_multibyte_test.rb → db/mssql/multibyte_test.rb} +0 -0
  141. data/test/db/mssql/multiple_connections_test.rb +71 -0
  142. data/test/{mssql_reset_column_information_test.rb → db/mssql/reset_column_information_test.rb} +0 -0
  143. data/test/{mssql_row_locking_test.rb → db/mssql/row_locking_test.rb} +0 -0
  144. data/test/{mssql_serialize_test.rb → db/mssql/serialize_test.rb} +1 -1
  145. data/test/db/mssql/simple_test.rb +140 -0
  146. data/test/db/mssql/transaction_test.rb +6 -0
  147. data/test/db/mssql/types_test.rb +205 -0
  148. data/test/{mssql_test.rb → db/mssql/unit_test.rb} +2 -2
  149. data/test/db/mysql.rb +1 -2
  150. data/test/db/mysql/_rails_test_mysql.32.out +6768 -0
  151. data/test/{mysql_binary_test.rb → db/mysql/binary_test.rb} +0 -0
  152. data/test/db/mysql/connection_test.rb +51 -0
  153. data/test/{mysql_db_create_test.rb → db/mysql/db_create_test.rb} +0 -0
  154. data/test/{mysql_index_length_test.rb → db/mysql/index_length_test.rb} +0 -0
  155. data/test/{mysql_multibyte_test.rb → db/mysql/multibyte_test.rb} +0 -0
  156. data/test/{mysql_nonstandard_primary_key_test.rb → db/mysql/nonstandard_primary_key_test.rb} +0 -0
  157. data/test/{mysql_reset_column_information_test.rb → db/mysql/reset_column_information_test.rb} +0 -0
  158. data/test/{mysql_schema_dump_test.rb → db/mysql/schema_dump_test.rb} +9 -1
  159. data/test/{mysql_serialize_test.rb → db/mysql/serialize_test.rb} +0 -0
  160. data/test/{mysql_simple_test.rb → db/mysql/simple_test.rb} +16 -8
  161. data/test/db/mysql/transaction_test.rb +6 -0
  162. data/test/db/mysql/types_test.rb +30 -0
  163. data/test/{mysql_test.rb → db/mysql/unit_test.rb} +1 -1
  164. data/test/db/mysql_config.rb +1 -1
  165. data/test/db/oracle.rb +1 -1
  166. data/test/{oracle_binary_test.rb → db/oracle/binary_test.rb} +0 -0
  167. data/test/{oracle_limit_test.rb → db/oracle/limit_test.rb} +0 -0
  168. data/test/db/oracle/multibyte_test.rb +22 -0
  169. data/test/{oracle_reset_column_information_test.rb → db/oracle/reset_column_information_test.rb} +0 -0
  170. data/test/{oracle_serialize_test.rb → db/oracle/serialize_test.rb} +0 -0
  171. data/test/{oracle_simple_test.rb → db/oracle/simple_test.rb} +14 -19
  172. data/test/{oracle_specific_test.rb → db/oracle/specific_test.rb} +62 -16
  173. data/test/db/oracle/transaction_test.rb +31 -0
  174. data/test/db/oracle/unit_test.rb +31 -0
  175. data/test/db/postgres.rb +1 -1
  176. data/test/db/postgres/_rails_test_postgres.32.out +6777 -0
  177. data/test/db/postgres/a_custom_primary_key_test.rb +50 -0
  178. data/test/db/postgres/array_type_test.rb +101 -0
  179. data/test/{postgres_binary_test.rb → db/postgres/binary_test.rb} +0 -0
  180. data/test/db/postgres/connection_test.rb +55 -0
  181. data/test/db/postgres/data_types_test.rb +703 -0
  182. data/test/{postgres_db_create_test.rb → db/postgres/db_create_test.rb} +1 -1
  183. data/test/{postgres_drop_db_test.rb → db/postgres/db_drop_test.rb} +2 -0
  184. data/test/db/postgres/hstore_test.rb +200 -0
  185. data/test/db/postgres/information_schema_leak_test.rb +30 -0
  186. data/test/db/postgres/json_test.rb +86 -0
  187. data/test/db/postgres/ltree_test.rb +50 -0
  188. data/test/{postgres_mixed_case_test.rb → db/postgres/mixed_case_test.rb} +0 -0
  189. data/test/db/postgres/native_types_test.rb +128 -0
  190. data/test/{postgres_reserved_test.rb → db/postgres/reserved_test.rb} +0 -0
  191. data/test/{postgres_reset_column_information_test.rb → db/postgres/reset_column_information_test.rb} +0 -0
  192. data/test/{postgres_row_locking_test.rb → db/postgres/row_locking_test.rb} +0 -0
  193. data/test/{postgres_schema_dump_test.rb → db/postgres/schema_dump_test.rb} +4 -4
  194. data/test/db/postgres/schema_test.rb +113 -0
  195. data/test/{postgres_simple_test.rb → db/postgres/simple_test.rb} +48 -8
  196. data/test/{postgres_table_alias_length_test.rb → db/postgres/table_alias_length_test.rb} +2 -1
  197. data/test/db/postgres/transaction_test.rb +6 -0
  198. data/test/{postgres_test.rb → db/postgres/unit_test.rb} +3 -3
  199. data/test/db/sqlite3.rb +1 -1
  200. data/test/db/sqlite3/_rails_test_sqlite3.32.out +6502 -0
  201. data/test/db/sqlite3/has_many_though_test.rb +6 -0
  202. data/test/{sqlite3_reset_column_information_test.rb → db/sqlite3/reset_column_information_test.rb} +0 -0
  203. data/test/{sqlite3_schema_dump_test.rb → db/sqlite3/schema_dump_test.rb} +0 -0
  204. data/test/{sqlite3_serialize_test.rb → db/sqlite3/serialize_test.rb} +0 -0
  205. data/test/{sqlite3_simple_test.rb → db/sqlite3/simple_test.rb} +63 -63
  206. data/test/db/sqlite3/transaction_test.rb +32 -0
  207. data/test/{sqlite3_type_conversion_test.rb → db/sqlite3/type_conversion_test.rb} +0 -0
  208. data/test/has_many_through.rb +29 -64
  209. data/test/jdbc/oracle.rb +11 -0
  210. data/test/jndi_test.rb +16 -4
  211. data/test/models/auto_id.rb +1 -1
  212. data/test/models/rights_and_roles.rb +57 -0
  213. data/test/row_locking.rb +3 -0
  214. data/test/schema_dump.rb +24 -10
  215. data/test/simple.rb +359 -104
  216. data/test/test_helper.rb +4 -2
  217. data/test/transaction.rb +109 -0
  218. metadata +119 -86
  219. data/lib/arjdbc/jdbc/compatibility.rb +0 -51
  220. data/lib/arjdbc/jdbc/core_ext.rb +0 -24
  221. data/lib/arjdbc/jdbc/discover.rb +0 -18
  222. data/test/derby_schema_dump_test.rb +0 -9
  223. data/test/mssql_ignore_system_views_test.rb +0 -30
  224. data/test/mssql_legacy_types_test.rb +0 -58
  225. data/test/mssql_null_test.rb +0 -14
  226. data/test/mssql_simple_test.rb +0 -51
  227. data/test/postgres_information_schema_leak_test.rb +0 -28
  228. data/test/postgres_native_type_mapping_test.rb +0 -93
  229. data/test/postgres_nonseq_pkey_test.rb +0 -38
  230. data/test/postgres_schema_search_path_test.rb +0 -48
  231. data/test/postgres_type_conversion_test.rb +0 -33
@@ -1,38 +1,36 @@
1
- class ActiveRecord::Base
2
- class << self
3
- def mssql_connection(config)
4
- begin
5
- require 'jdbc/jtds'
6
- # NOTE: the adapter has only support for working with the
7
- # open-source jTDS driver (won't work with MS's driver) !
8
- ::Jdbc::JTDS.load_driver(:require) if defined?(::Jdbc::JTDS.load_driver)
9
- rescue LoadError => e # assuming driver.jar is on the class-path
10
- raise e unless e.message.to_s.index('no such file to load')
11
- end
1
+ ArJdbc::ConnectionMethods.module_eval do
2
+ def mssql_connection(config)
3
+ begin
4
+ require 'jdbc/jtds'
5
+ # NOTE: the adapter has only support for working with the
6
+ # open-source jTDS driver (won't work with MS's driver) !
7
+ ::Jdbc::JTDS.load_driver(:require) if defined?(::Jdbc::JTDS.load_driver)
8
+ rescue LoadError => e # assuming driver.jar is on the class-path
9
+ raise e unless e.message.to_s.index('no such file to load')
10
+ end
12
11
 
13
- config[:host] ||= "localhost"
14
- config[:port] ||= 1433
15
- config[:driver] ||= defined?(::Jdbc::JTDS.driver_name) ? ::Jdbc::JTDS.driver_name : 'net.sourceforge.jtds.jdbc.Driver'
16
- config[:adapter_spec] = ::ArJdbc::MSSQL
12
+ config[:host] ||= "localhost"
13
+ config[:port] ||= 1433
14
+ config[:driver] ||= defined?(::Jdbc::JTDS.driver_name) ? ::Jdbc::JTDS.driver_name : 'net.sourceforge.jtds.jdbc.Driver'
15
+ config[:adapter_spec] = ::ArJdbc::MSSQL
17
16
 
18
- config[:url] ||= begin
19
- url = "jdbc:jtds:sqlserver://#{config[:host]}:#{config[:port]}/#{config[:database]}"
20
- # Instance is often a preferrable alternative to port when dynamic ports are used.
21
- # If instance is specified then port is essentially ignored.
22
- url << ";instance=#{config[:instance]}" if config[:instance]
23
- # This will enable windows domain-based authentication and will require the JTDS native libraries be available.
24
- url << ";domain=#{config[:domain]}" if config[:domain]
25
- # AppName is shown in sql server as additional information against the connection.
26
- url << ";appname=#{config[:appname]}" if config[:appname]
27
- url
28
- end
17
+ config[:url] ||= begin
18
+ url = "jdbc:jtds:sqlserver://#{config[:host]}:#{config[:port]}/#{config[:database]}"
19
+ # Instance is often a preferrable alternative to port when dynamic ports are used.
20
+ # If instance is specified then port is essentially ignored.
21
+ url << ";instance=#{config[:instance]}" if config[:instance]
22
+ # This will enable windows domain-based authentication and will require the JTDS native libraries be available.
23
+ url << ";domain=#{config[:domain]}" if config[:domain]
24
+ # AppName is shown in sql server as additional information against the connection.
25
+ url << ";appname=#{config[:appname]}" if config[:appname]
26
+ url
27
+ end
29
28
 
30
- unless config[:domain]
31
- config[:username] ||= "sa"
32
- config[:password] ||= ""
33
- end
34
- jdbc_connection(config)
29
+ unless config[:domain]
30
+ config[:username] ||= "sa"
31
+ config[:password] ||= ""
35
32
  end
36
- alias_method :jdbcmssql_connection, :mssql_connection
33
+ jdbc_connection(config)
37
34
  end
35
+ alias_method :jdbcmssql_connection, :mssql_connection
38
36
  end
@@ -0,0 +1,107 @@
1
+ require 'active_support/core_ext/string'
2
+
3
+ module ArJdbc
4
+ module MSSQL
5
+ module ExplainSupport
6
+
7
+ DISABLED = Java::JavaLang::Boolean.getBoolean('arjdbc.mssql.explain_support.disabled')
8
+
9
+ def supports_explain?
10
+ ! DISABLED
11
+ end
12
+
13
+ def explain(arel, binds = [])
14
+ return if DISABLED
15
+ sql = to_sql(arel)
16
+ result = with_showplan_on do
17
+ # exec_query(sql, 'EXPLAIN', binds)
18
+ raw_result = execute(sql, 'EXPLAIN', binds)
19
+ # TODO we should refactor to exec_query once it returns Result :
20
+ keys = raw_result[0] ? raw_result[0].keys : {}
21
+ rows = raw_result.map { |hash| hash.values }
22
+ ActiveRecord::Result.new(keys, rows)
23
+ end
24
+ PrinterTable.new(result).pp
25
+ end
26
+
27
+ protected
28
+
29
+ def with_showplan_on
30
+ set_showplan_option(true)
31
+ yield
32
+ ensure
33
+ set_showplan_option(false)
34
+ end
35
+
36
+ def set_showplan_option(enable = true)
37
+ option = 'SHOWPLAN_TEXT'
38
+ execute "SET #{option} #{enable ? 'ON' : 'OFF'}"
39
+ rescue Exception => e
40
+ raise ActiveRecord::ActiveRecordError, "#{option} could not be turned" +
41
+ " #{enable ? 'ON' : 'OFF'} (check SHOWPLAN permissions) due : #{e.inspect}"
42
+ end
43
+
44
+ class PrinterTable # :nodoc:
45
+
46
+ cattr_accessor :max_column_width, :cell_padding
47
+ self.max_column_width = 50
48
+ self.cell_padding = 1
49
+
50
+ attr_reader :result
51
+
52
+ def initialize(result)
53
+ @result = result
54
+ end
55
+
56
+ def pp
57
+ @widths = compute_column_widths
58
+ @separator = build_separator
59
+ pp = []
60
+ pp << @separator
61
+ pp << build_cells(result.columns)
62
+ pp << @separator
63
+ result.rows.each do |row|
64
+ pp << build_cells(row)
65
+ end
66
+ pp << @separator
67
+ pp.join("\n") + "\n"
68
+ end
69
+
70
+ private
71
+
72
+ def compute_column_widths
73
+ [].tap do |computed_widths|
74
+ result.columns.each_with_index do |column, i|
75
+ cells_in_column = [column] + result.rows.map { |r| cast_item(r[i]) }
76
+ computed_width = cells_in_column.map(&:length).max
77
+ final_width = computed_width > max_column_width ? max_column_width : computed_width
78
+ computed_widths << final_width
79
+ end
80
+ end
81
+ end
82
+
83
+ def build_separator
84
+ '+' + @widths.map {|w| '-' * (w + (cell_padding * 2))}.join('+') + '+'
85
+ end
86
+
87
+ def build_cells(items)
88
+ cells = []
89
+ items.each_with_index do |item, i|
90
+ cells << cast_item(item).ljust(@widths[i])
91
+ end
92
+ "| #{cells.join(' | ')} |"
93
+ end
94
+
95
+ def cast_item(item)
96
+ case item
97
+ when NilClass then 'NULL'
98
+ when Float then item.to_s.to(9)
99
+ else item.to_s.truncate(max_column_width)
100
+ end
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+ end
107
+ end
@@ -52,35 +52,65 @@ module ArJdbc
52
52
  start_row = offset + 1
53
53
  end_row = offset + limit.to_i
54
54
  _, select, rest_of_query = FIND_SELECT.match(sql).to_a
55
+
56
+ #need the table name for avoiding amiguity
57
+ table_name = Utils.get_table_name(sql, true)
58
+ primary_key = get_primary_key(order, table_name)
59
+
60
+ #I am not sure this will cover all bases. but all the tests pass
61
+ if order[/ORDER/].nil?
62
+ new_order = "ORDER BY #{order}, [#{table_name}].[#{primary_key}]" if order.index("#{table_name}.#{primary_key}").nil?
63
+ else
64
+ new_order ||= order
65
+ end
66
+
55
67
  if (start_row == 1) && (end_row ==1)
56
- new_sql = "#{select} TOP 1 #{rest_of_query}"
68
+ new_sql = "#{select} TOP 1 #{rest_of_query} #{new_order}"
57
69
  sql.replace(new_sql)
58
70
  else
59
- #UGLY
60
- #KLUDGY?
61
- #removing out stuff before the FROM...
62
- rest = rest_of_query[/FROM/i=~ rest_of_query.. -1]
63
- #need the table name for avoiding amiguity
64
- table_name = Utils.get_table_name(sql, true)
65
- primary_key = get_primary_key(order, table_name)
66
- #I am not sure this will cover all bases. but all the tests pass
67
- if order[/ORDER/].nil?
68
- new_order = "ORDER BY #{order}, #{table_name}.#{primary_key}" if order.index("#{table_name}.#{primary_key}").nil?
69
- else
70
- new_order ||= order
71
- end
71
+ # We are in deep trouble here. SQL Server does not have any kind of OFFSET build in.
72
+ # Only remaining solution is adding a where condition to be sure that the ID is not in SELECT TOP OFFSET FROM SAME_QUERY.
73
+ # To do so we need to extract each part of the query to insert our additional condition in the right place.
74
+ query_without_select = rest_of_query[/FROM/i=~ rest_of_query.. -1]
75
+ additional_condition = "#{table_name}.#{primary_key} NOT IN (#{select} TOP #{offset} #{table_name}.#{primary_key} #{query_without_select} #{new_order})"
72
76
 
73
- if (rest_of_query.match(/WHERE/).nil?)
74
- new_sql = "#{select} TOP #{limit} #{rest_of_query} WHERE #{table_name}.#{primary_key} NOT IN (#{select} TOP #{offset} #{table_name}.#{primary_key} #{rest} #{new_order}) #{order} "
77
+ # Extract the different parts of the query
78
+ having, group_by, where, from, selection = split_sql(rest_of_query, /having/i, /group by/i, /where/i, /from/i)
79
+
80
+ # Update the where part to add our additional condition
81
+ if where.blank?
82
+ where = "WHERE #{additional_condition}"
75
83
  else
76
- new_sql = "#{select} TOP #{limit} #{rest_of_query} AND #{table_name}.#{primary_key} NOT IN (#{select} TOP #{offset} #{table_name}.#{primary_key} #{rest} #{new_order}) #{order} "
84
+ where = "#{where} AND #{additional_condition}"
77
85
  end
78
86
 
79
- sql.replace(new_sql)
87
+ # Replace the query to be our new customized query
88
+ sql.replace("#{select} TOP #{limit} #{selection} #{from} #{where} #{group_by} #{having} #{new_order}")
80
89
  end
81
90
  end
82
91
  sql
83
92
  end
93
+
94
+ # Split the rest_of_query into chunks based on regexs (applied from end of string to the beginning)
95
+ # The result is an array of regexs.size+1 elements (the last one being the remaining once everything was chopped away)
96
+ def split_sql rest_of_query, *regexs
97
+ results = Array.new
98
+
99
+ regexs.each do |regex|
100
+ if position = (regex =~ rest_of_query)
101
+ # Extract the matched string and chop the rest_of_query
102
+ matched = rest_of_query[position..-1]
103
+ rest_of_query = rest_of_query[0...position]
104
+ else
105
+ matched = nil
106
+ end
107
+
108
+ results << matched
109
+ end
110
+ results << rest_of_query
111
+
112
+ results
113
+ end
84
114
 
85
115
  def get_primary_key(order, table_name) # table_name might be quoted
86
116
  if order =~ /(\w*id\w*)/i
data/lib/arjdbc/mysql.rb CHANGED
@@ -1,3 +1,3 @@
1
- require 'arjdbc/jdbc'
1
+ require 'arjdbc'
2
2
  require 'arjdbc/mysql/adapter'
3
3
  require 'arjdbc/mysql/connection_methods'
@@ -10,9 +10,41 @@ module ArJdbc
10
10
  end
11
11
 
12
12
  def configure_connection
13
- execute("SET SQL_AUTO_IS_NULL=0")
14
- end
13
+ variables = config[:variables] || {}
14
+ # By default, MySQL 'where id is null' selects the last inserted id. Turn this off.
15
+ variables[:sql_auto_is_null] = 0 # execute "SET SQL_AUTO_IS_NULL=0"
16
+
17
+ # Increase timeout so the server doesn't disconnect us.
18
+ wait_timeout = config[:wait_timeout]
19
+ wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum)
20
+ variables[:wait_timeout] = wait_timeout
21
+
22
+ # Make MySQL reject illegal values rather than truncating or blanking them, see
23
+ # http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_strict_all_tables
24
+ # If the user has provided another value for sql_mode, don't replace it.
25
+ if strict_mode? && ! variables.has_key?(:sql_mode)
26
+ variables[:sql_mode] = 'STRICT_ALL_TABLES' # SET SQL_MODE='STRICT_ALL_TABLES'
27
+ end
28
+
29
+ # NAMES does not have an equals sign, see
30
+ # http://dev.mysql.com/doc/refman/5.0/en/set-statement.html#id944430
31
+ # (trailing comma because variable_assignments will always have content)
32
+ encoding = "NAMES #{config[:encoding]}, " if config[:encoding]
33
+
34
+ # Gather up all of the SET variables...
35
+ variable_assignments = variables.map do |k, v|
36
+ if v == ':default' || v == :default
37
+ "@@SESSION.#{k.to_s} = DEFAULT" # Sets the value to the global or compile default
38
+ elsif ! v.nil?
39
+ "@@SESSION.#{k.to_s} = #{quote(v)}"
40
+ end
41
+ # or else nil; compact to clear nils out
42
+ end.compact.join(', ')
15
43
 
44
+ # ...and send them all in one query
45
+ execute("SET #{encoding} #{variable_assignments}", :skip_logging)
46
+ end
47
+
16
48
  def self.column_selector
17
49
  [ /mysql/i, lambda { |_,column| column.extend(::ArJdbc::MySQL::Column) } ]
18
50
  end
@@ -21,6 +53,10 @@ module ArJdbc
21
53
  ::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
22
54
  end
23
55
 
56
+ def strict_mode? # strict_mode is default since AR 4.0
57
+ config.key?(:strict) ? config[:strict] : ::ActiveRecord::VERSION::MAJOR > 3
58
+ end
59
+
24
60
  module Column
25
61
 
26
62
  def extract_default(default)
@@ -206,6 +242,10 @@ module ArJdbc
206
242
  true
207
243
  end
208
244
 
245
+ def supports_transaction_isolation?(level = nil)
246
+ version[0] >= 5 # MySQL 5+
247
+ end
248
+
209
249
  def create_savepoint
210
250
  execute("SAVEPOINT #{current_savepoint_name}")
211
251
  end
@@ -230,11 +270,17 @@ module ArJdbc
230
270
 
231
271
  # DATABASE STATEMENTS ======================================
232
272
 
233
- def exec_insert(sql, name, binds)
273
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) # :nodoc:
274
+ execute sql, name, binds
275
+ end
276
+
277
+ def exec_update(sql, name, binds) # :nodoc:
278
+ execute sql, name, binds
279
+ end
280
+
281
+ def exec_delete(sql, name, binds) # :nodoc:
234
282
  execute sql, name, binds
235
283
  end
236
- alias :exec_update :exec_insert
237
- alias :exec_delete :exec_insert
238
284
 
239
285
  # Make it public just like native MySQL adapter does.
240
286
  def update_sql(sql, name = nil) # :nodoc:
@@ -336,10 +382,11 @@ module ArJdbc
336
382
  super(name, {:options => "ENGINE=InnoDB DEFAULT CHARSET=utf8"}.merge(options))
337
383
  end
338
384
 
339
- def rename_table(name, new_name)
340
- execute "RENAME TABLE #{quote_table_name(name)} TO #{quote_table_name(new_name)}"
385
+ def rename_table(table_name, new_name)
386
+ execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
387
+ rename_table_indexes(table_name, new_name) if respond_to?(:rename_table_indexes) # AR-4.0 SchemaStatements
341
388
  end
342
-
389
+
343
390
  def remove_index!(table_name, index_name) #:nodoc:
344
391
  # missing table_name quoting in AR-2.3
345
392
  execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
@@ -387,8 +434,7 @@ module ArJdbc
387
434
  def rename_column(table_name, column_name, new_column_name) #:nodoc:
388
435
  options = {}
389
436
  if column = columns(table_name).find { |c| c.name == column_name.to_s }
390
- options[:default] = column.default
391
- options[:null] = column.null
437
+ options[:default] = column.default; options[:null] = column.null
392
438
  else
393
439
  raise ActiveRecord::ActiveRecordError, "No such column: #{table_name}.#{column_name}"
394
440
  end
@@ -396,8 +442,9 @@ module ArJdbc
396
442
  rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
397
443
  add_column_options!(rename_column_sql, options)
398
444
  execute(rename_column_sql)
445
+ rename_column_indexes(table_name, column_name, new_column_name) if respond_to?(:rename_column_indexes) # AR-4.0 SchemaStatements
399
446
  end
400
-
447
+
401
448
  def add_limit_offset!(sql, options) #:nodoc:
402
449
  limit, offset = options[:limit], options[:offset]
403
450
  if limit && offset
@@ -486,6 +533,10 @@ module ArJdbc
486
533
  end
487
534
  end
488
535
 
536
+ def empty_insert_statement_value
537
+ "VALUES ()"
538
+ end
539
+
489
540
  protected
490
541
  def quoted_columns_for_index(column_names, options = {})
491
542
  length = options[:length] if options.is_a?(Hash)
@@ -560,9 +611,7 @@ module ActiveRecord
560
611
  super(nil, name, *args)
561
612
  end
562
613
  end
563
-
564
- def call_discovered_column_callbacks(*)
565
- end
614
+
566
615
  end
567
616
 
568
617
  class MysqlAdapter < JdbcAdapter
@@ -1,27 +1,25 @@
1
- class ActiveRecord::Base
2
- class << self
3
- def mysql_connection(config)
4
- begin
5
- require 'jdbc/mysql'
6
- ::Jdbc::MySQL.load_driver(:require) if defined?(::Jdbc::MySQL.load_driver)
7
- rescue LoadError # assuming driver.jar is on the class-path
8
- end
9
-
10
- config[:port] ||= 3306
11
- config[:url] ||= "jdbc:mysql://#{config[:host]}:#{config[:port]}/#{config[:database]}"
12
- config[:driver] ||= defined?(::Jdbc::MySQL.driver_name) ? ::Jdbc::MySQL.driver_name : 'com.mysql.jdbc.Driver'
13
- config[:adapter_class] = ActiveRecord::ConnectionAdapters::MysqlAdapter
14
- config[:adapter_spec] = ::ArJdbc::MySQL
15
- options = (config[:options] ||= {})
16
- options['zeroDateTimeBehavior'] ||= 'convertToNull'
17
- options['jdbcCompliantTruncation'] ||= 'false'
18
- options['useUnicode'] ||= 'true'
19
- options['characterEncoding'] = config[:encoding] || 'utf8'
20
- connection = jdbc_connection(config)
21
- ::ArJdbc::MySQL.kill_cancel_timer(connection.raw_connection)
22
- connection
1
+ ArJdbc::ConnectionMethods.module_eval do
2
+ def mysql_connection(config)
3
+ begin
4
+ require 'jdbc/mysql'
5
+ ::Jdbc::MySQL.load_driver(:require) if defined?(::Jdbc::MySQL.load_driver)
6
+ rescue LoadError # assuming driver.jar is on the class-path
23
7
  end
24
- alias_method :jdbcmysql_connection, :mysql_connection
25
- alias_method :mysql2_connection, :mysql_connection
8
+
9
+ config[:port] ||= 3306
10
+ config[:url] ||= "jdbc:mysql://#{config[:host]}:#{config[:port]}/#{config[:database]}"
11
+ config[:driver] ||= defined?(::Jdbc::MySQL.driver_name) ? ::Jdbc::MySQL.driver_name : 'com.mysql.jdbc.Driver'
12
+ config[:adapter_class] = ActiveRecord::ConnectionAdapters::MysqlAdapter
13
+ config[:adapter_spec] = ::ArJdbc::MySQL
14
+ options = (config[:options] ||= {})
15
+ options['zeroDateTimeBehavior'] ||= 'convertToNull'
16
+ options['jdbcCompliantTruncation'] ||= 'false'
17
+ options['useUnicode'] ||= 'true'
18
+ options['characterEncoding'] = config[:encoding] || 'utf8'
19
+ connection = jdbc_connection(config)
20
+ ::ArJdbc::MySQL.kill_cancel_timer(connection.raw_connection)
21
+ connection
26
22
  end
23
+ alias_method :jdbcmysql_connection, :mysql_connection
24
+ alias_method :mysql2_connection, :mysql_connection
27
25
  end