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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (282) hide show
  1. data/.gitignore +14 -8
  2. data/.travis.yml +40 -31
  3. data/.yardopts +4 -0
  4. data/Appraisals +2 -5
  5. data/CONTRIBUTING.md +46 -0
  6. data/Gemfile +21 -4
  7. data/Gemfile.lock +42 -17
  8. data/{History.txt → History.md} +142 -75
  9. data/README.md +102 -104
  10. data/RUNNING_TESTS.md +76 -0
  11. data/Rakefile.jdbc +20 -0
  12. data/activerecord-jdbc-adapter.gemspec +35 -18
  13. data/gemfiles/rails23.gemfile +4 -3
  14. data/gemfiles/rails23.gemfile.lock +9 -6
  15. data/gemfiles/rails30.gemfile +4 -3
  16. data/gemfiles/rails30.gemfile.lock +9 -6
  17. data/gemfiles/rails31.gemfile +4 -3
  18. data/gemfiles/rails31.gemfile.lock +9 -6
  19. data/gemfiles/rails32.gemfile +4 -3
  20. data/gemfiles/rails32.gemfile.lock +17 -14
  21. data/gemfiles/rails40.gemfile +5 -5
  22. data/gemfiles/rails40.gemfile.lock +17 -69
  23. data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
  24. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  25. data/lib/arel/visitors/compat.rb +22 -3
  26. data/lib/arel/visitors/db2.rb +8 -4
  27. data/lib/arel/visitors/derby.rb +14 -13
  28. data/lib/arel/visitors/firebird.rb +5 -4
  29. data/lib/arel/visitors/hsqldb.rb +11 -9
  30. data/lib/arel/visitors/sql_server.rb +89 -61
  31. data/lib/arjdbc.rb +1 -1
  32. data/lib/arjdbc/db2/adapter.rb +181 -212
  33. data/lib/arjdbc/db2/as400.rb +31 -18
  34. data/lib/arjdbc/db2/column.rb +167 -0
  35. data/lib/arjdbc/db2/connection_methods.rb +2 -0
  36. data/lib/arjdbc/derby/adapter.rb +206 -107
  37. data/lib/arjdbc/derby/connection_methods.rb +4 -9
  38. data/lib/arjdbc/firebird.rb +1 -0
  39. data/lib/arjdbc/firebird/adapter.rb +202 -64
  40. data/lib/arjdbc/firebird/connection_methods.rb +20 -0
  41. data/lib/arjdbc/h2/adapter.rb +56 -36
  42. data/lib/arjdbc/hsqldb/adapter.rb +99 -68
  43. data/lib/arjdbc/jdbc/adapter.rb +474 -265
  44. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  45. data/lib/arjdbc/jdbc/adapter_require.rb +8 -7
  46. data/lib/arjdbc/jdbc/arel_support.rb +132 -0
  47. data/lib/arjdbc/jdbc/base_ext.rb +8 -7
  48. data/lib/arjdbc/jdbc/callbacks.rb +16 -10
  49. data/lib/arjdbc/jdbc/column.rb +25 -3
  50. data/lib/arjdbc/jdbc/connection.rb +28 -55
  51. data/lib/arjdbc/jdbc/extension.rb +14 -14
  52. data/lib/arjdbc/jdbc/java.rb +6 -3
  53. data/lib/arjdbc/jdbc/jdbc.rake +1 -1
  54. data/lib/arjdbc/jdbc/quoted_primary_key.rb +2 -2
  55. data/lib/arjdbc/jdbc/rake_tasks.rb +1 -1
  56. data/lib/arjdbc/jdbc/type_converter.rb +5 -2
  57. data/lib/arjdbc/mssql/adapter.rb +160 -280
  58. data/lib/arjdbc/mssql/column.rb +182 -0
  59. data/lib/arjdbc/mssql/connection_methods.rb +37 -4
  60. data/lib/arjdbc/mssql/explain_support.rb +13 -21
  61. data/lib/arjdbc/mssql/limit_helpers.rb +79 -42
  62. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  63. data/lib/arjdbc/mssql/utils.rb +11 -11
  64. data/lib/arjdbc/mysql/adapter.rb +165 -247
  65. data/lib/arjdbc/mysql/column.rb +123 -0
  66. data/lib/arjdbc/mysql/connection_methods.rb +3 -6
  67. data/lib/arjdbc/oracle/adapter.rb +282 -288
  68. data/lib/arjdbc/oracle/column.rb +122 -0
  69. data/lib/arjdbc/oracle/connection_methods.rb +3 -0
  70. data/lib/arjdbc/postgresql/adapter.rb +336 -574
  71. data/lib/arjdbc/postgresql/column.rb +458 -0
  72. data/lib/arjdbc/postgresql/connection_methods.rb +1 -2
  73. data/lib/arjdbc/postgresql/schema_creation.rb +38 -0
  74. data/lib/arjdbc/sqlite3/adapter.rb +189 -145
  75. data/lib/arjdbc/sqlite3/explain_support.rb +1 -1
  76. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +8 -8
  77. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  78. data/lib/arjdbc/util/table_copier.rb +110 -0
  79. data/lib/arjdbc/version.rb +6 -7
  80. data/pom.xml +56 -2
  81. data/rakelib/02-test.rake +72 -83
  82. data/rakelib/db.rake +29 -17
  83. data/src/java/arjdbc/ArJdbcModule.java +21 -18
  84. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +84 -12
  85. data/src/java/arjdbc/derby/DerbyModule.java +140 -143
  86. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +58 -7
  87. data/src/java/arjdbc/h2/H2Module.java +43 -0
  88. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +7 -6
  89. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1223 -648
  90. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +24 -23
  91. data/src/java/arjdbc/mysql/MySQLModule.java +33 -32
  92. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +147 -30
  93. data/src/java/arjdbc/oracle/OracleModule.java +13 -13
  94. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +114 -6
  95. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +166 -36
  96. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +101 -19
  97. data/src/java/arjdbc/util/QuotingUtils.java +19 -19
  98. metadata +240 -394
  99. data/bench/bench_attributes.rb +0 -13
  100. data/bench/bench_attributes_new.rb +0 -14
  101. data/bench/bench_create.rb +0 -12
  102. data/bench/bench_find_all.rb +0 -12
  103. data/bench/bench_find_all_mt.rb +0 -25
  104. data/bench/bench_model.rb +0 -85
  105. data/bench/bench_new.rb +0 -12
  106. data/bench/bench_new_valid.rb +0 -12
  107. data/bench/bench_valid.rb +0 -13
  108. data/lib/arel/engines/sql/compilers/db2_compiler.rb +0 -9
  109. data/lib/arel/engines/sql/compilers/derby_compiler.rb +0 -6
  110. data/lib/arel/engines/sql/compilers/h2_compiler.rb +0 -6
  111. data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +0 -15
  112. data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +0 -6
  113. data/lib/arel/engines/sql/compilers/mssql_compiler.rb +0 -46
  114. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +0 -98
  115. data/lib/arjdbc/mssql/lock_helpers.rb +0 -76
  116. data/lib/arjdbc/mssql/tsql_methods.rb +0 -58
  117. data/lib/arjdbc/postgresql/column_cast.rb +0 -134
  118. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +0 -25
  119. data/test/activerecord/jall.sh +0 -7
  120. data/test/activerecord/jtest.sh +0 -3
  121. data/test/assets/flowers.jpg +0 -0
  122. data/test/binary.rb +0 -67
  123. data/test/db/db2.rb +0 -43
  124. data/test/db/db2/binary_test.rb +0 -6
  125. data/test/db/db2/has_many_through_test.rb +0 -6
  126. data/test/db/db2/rake_test.rb +0 -82
  127. data/test/db/db2/rake_test_data.sql +0 -35
  128. data/test/db/db2/reset_column_information_test.rb +0 -5
  129. data/test/db/db2/serialize_test.rb +0 -6
  130. data/test/db/db2/simple_test.rb +0 -81
  131. data/test/db/db2/test_helper.rb +0 -6
  132. data/test/db/db2/unit_test.rb +0 -73
  133. data/test/db/derby.rb +0 -12
  134. data/test/db/derby/binary_test.rb +0 -6
  135. data/test/db/derby/migration_test.rb +0 -74
  136. data/test/db/derby/rake_test.rb +0 -96
  137. data/test/db/derby/reset_column_information_test.rb +0 -6
  138. data/test/db/derby/row_locking_test.rb +0 -20
  139. data/test/db/derby/schema_dump_test.rb +0 -5
  140. data/test/db/derby/serialize_test.rb +0 -6
  141. data/test/db/derby/simple_test.rb +0 -173
  142. data/test/db/derby/test_helper.rb +0 -6
  143. data/test/db/derby/unit_test.rb +0 -32
  144. data/test/db/derby/xml_column_test.rb +0 -17
  145. data/test/db/h2.rb +0 -11
  146. data/test/db/h2/binary_test.rb +0 -6
  147. data/test/db/h2/change_column_test.rb +0 -68
  148. data/test/db/h2/identity_column_test.rb +0 -35
  149. data/test/db/h2/offset_test.rb +0 -49
  150. data/test/db/h2/rake_test.rb +0 -98
  151. data/test/db/h2/schema_dump_test.rb +0 -29
  152. data/test/db/h2/serialize_test.rb +0 -6
  153. data/test/db/h2/simple_test.rb +0 -56
  154. data/test/db/hsqldb.rb +0 -11
  155. data/test/db/hsqldb/binary_test.rb +0 -6
  156. data/test/db/hsqldb/rake_test.rb +0 -101
  157. data/test/db/hsqldb/schema_dump_test.rb +0 -19
  158. data/test/db/hsqldb/serialize_test.rb +0 -6
  159. data/test/db/hsqldb/simple_test.rb +0 -17
  160. data/test/db/informix.rb +0 -13
  161. data/test/db/jdbc.rb +0 -16
  162. data/test/db/jdbc_derby.rb +0 -14
  163. data/test/db/jdbc_h2.rb +0 -17
  164. data/test/db/jdbc_mysql.rb +0 -13
  165. data/test/db/jdbc_postgres.rb +0 -23
  166. data/test/db/jndi_config.rb +0 -32
  167. data/test/db/jndi_pooled_config.rb +0 -32
  168. data/test/db/mssql.rb +0 -11
  169. data/test/db/mssql/binary_test.rb +0 -6
  170. data/test/db/mssql/exec_proc_test.rb +0 -46
  171. data/test/db/mssql/identity_insert_test.rb +0 -18
  172. data/test/db/mssql/ignore_system_views_test.rb +0 -40
  173. data/test/db/mssql/limit_offset_test.rb +0 -190
  174. data/test/db/mssql/multibyte_test.rb +0 -16
  175. data/test/db/mssql/multiple_connections_test.rb +0 -71
  176. data/test/db/mssql/rake_test.rb +0 -143
  177. data/test/db/mssql/reset_column_information_test.rb +0 -6
  178. data/test/db/mssql/row_locking_test.rb +0 -7
  179. data/test/db/mssql/serialize_test.rb +0 -6
  180. data/test/db/mssql/simple_test.rb +0 -140
  181. data/test/db/mssql/transaction_test.rb +0 -6
  182. data/test/db/mssql/types_test.rb +0 -205
  183. data/test/db/mssql/unit_test.rb +0 -249
  184. data/test/db/mysql.rb +0 -4
  185. data/test/db/mysql/_rails_test_mysql.32.out +0 -6585
  186. data/test/db/mysql/binary_test.rb +0 -6
  187. data/test/db/mysql/connection_test.rb +0 -51
  188. data/test/db/mysql/index_length_test.rb +0 -58
  189. data/test/db/mysql/multibyte_test.rb +0 -10
  190. data/test/db/mysql/nonstandard_primary_key_test.rb +0 -39
  191. data/test/db/mysql/rake_test.rb +0 -97
  192. data/test/db/mysql/reset_column_information_test.rb +0 -6
  193. data/test/db/mysql/schema_dump_test.rb +0 -228
  194. data/test/db/mysql/serialize_test.rb +0 -6
  195. data/test/db/mysql/simple_test.rb +0 -187
  196. data/test/db/mysql/statement_escaping_test.rb +0 -46
  197. data/test/db/mysql/transaction_test.rb +0 -6
  198. data/test/db/mysql/types_test.rb +0 -30
  199. data/test/db/mysql/unit_test.rb +0 -93
  200. data/test/db/mysql_config.rb +0 -7
  201. data/test/db/oracle.rb +0 -27
  202. data/test/db/oracle/binary_test.rb +0 -6
  203. data/test/db/oracle/limit_test.rb +0 -24
  204. data/test/db/oracle/multibyte_test.rb +0 -22
  205. data/test/db/oracle/rake_test.rb +0 -100
  206. data/test/db/oracle/reset_column_information_test.rb +0 -6
  207. data/test/db/oracle/serialize_test.rb +0 -6
  208. data/test/db/oracle/simple_test.rb +0 -140
  209. data/test/db/oracle/specific_test.rb +0 -180
  210. data/test/db/oracle/transaction_test.rb +0 -31
  211. data/test/db/oracle/unit_test.rb +0 -31
  212. data/test/db/postgres.rb +0 -11
  213. data/test/db/postgres/_rails_test_postgres.32.out +0 -6405
  214. data/test/db/postgres/a_custom_primary_key_test.rb +0 -50
  215. data/test/db/postgres/active_schema_unit_test.rb +0 -68
  216. data/test/db/postgres/array_type_test.rb +0 -101
  217. data/test/db/postgres/binary_test.rb +0 -6
  218. data/test/db/postgres/connection_test.rb +0 -63
  219. data/test/db/postgres/data_types_test.rb +0 -703
  220. data/test/db/postgres/hstore_test.rb +0 -200
  221. data/test/db/postgres/information_schema_leak_test.rb +0 -30
  222. data/test/db/postgres/json_test.rb +0 -86
  223. data/test/db/postgres/ltree_test.rb +0 -51
  224. data/test/db/postgres/mixed_case_test.rb +0 -29
  225. data/test/db/postgres/native_types_test.rb +0 -124
  226. data/test/db/postgres/rake_test.rb +0 -117
  227. data/test/db/postgres/reserved_test.rb +0 -22
  228. data/test/db/postgres/reset_column_information_test.rb +0 -6
  229. data/test/db/postgres/row_locking_test.rb +0 -21
  230. data/test/db/postgres/schema_dump_test.rb +0 -95
  231. data/test/db/postgres/schema_test.rb +0 -115
  232. data/test/db/postgres/simple_test.rb +0 -260
  233. data/test/db/postgres/table_alias_length_test.rb +0 -16
  234. data/test/db/postgres/transaction_test.rb +0 -6
  235. data/test/db/postgres/unit_test.rb +0 -31
  236. data/test/db/postgres_config.rb +0 -10
  237. data/test/db/sqlite3.rb +0 -6
  238. data/test/db/sqlite3/_rails_test_sqlite3.32.out +0 -6274
  239. data/test/db/sqlite3/has_many_though_test.rb +0 -6
  240. data/test/db/sqlite3/rake_test.rb +0 -71
  241. data/test/db/sqlite3/reset_column_information_test.rb +0 -6
  242. data/test/db/sqlite3/schema_dump_test.rb +0 -6
  243. data/test/db/sqlite3/serialize_test.rb +0 -6
  244. data/test/db/sqlite3/simple_test.rb +0 -268
  245. data/test/db/sqlite3/transaction_test.rb +0 -32
  246. data/test/db/sqlite3/type_conversion_test.rb +0 -104
  247. data/test/has_many_through.rb +0 -61
  248. data/test/informix_simple_test.rb +0 -48
  249. data/test/jdbc/db2.rb +0 -36
  250. data/test/jdbc/oracle.rb +0 -34
  251. data/test/jdbc_column_test.rb +0 -23
  252. data/test/jdbc_common.rb +0 -16
  253. data/test/jdbc_connection_test.rb +0 -196
  254. data/test/jndi_callbacks_test.rb +0 -33
  255. data/test/jndi_test.rb +0 -55
  256. data/test/manualTestDatabase.rb +0 -191
  257. data/test/models/add_not_null_column_to_table.rb +0 -9
  258. data/test/models/auto_id.rb +0 -15
  259. data/test/models/binary.rb +0 -18
  260. data/test/models/custom_pk_name.rb +0 -15
  261. data/test/models/data_types.rb +0 -40
  262. data/test/models/entry.rb +0 -41
  263. data/test/models/mixed_case.rb +0 -22
  264. data/test/models/reserved_word.rb +0 -15
  265. data/test/models/rights_and_roles.rb +0 -57
  266. data/test/models/string_id.rb +0 -17
  267. data/test/models/thing.rb +0 -17
  268. data/test/models/topic.rb +0 -32
  269. data/test/models/validates_uniqueness_of_string.rb +0 -19
  270. data/test/rails/mysql.rb +0 -13
  271. data/test/rails/sqlite3/version.rb +0 -6
  272. data/test/rails_stub.rb +0 -31
  273. data/test/rake_test_support.rb +0 -298
  274. data/test/row_locking.rb +0 -102
  275. data/test/schema_dump.rb +0 -182
  276. data/test/serialize.rb +0 -275
  277. data/test/shared_helper.rb +0 -35
  278. data/test/simple.rb +0 -1317
  279. data/test/sybase_jtds_simple_test.rb +0 -28
  280. data/test/sybase_reset_column_information_test.rb +0 -6
  281. data/test/test_helper.rb +0 -304
  282. data/test/transaction.rb +0 -109
@@ -0,0 +1,182 @@
1
+ module ArJdbc
2
+ module MSSQL
3
+
4
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
5
+ def self.column_selector
6
+ [ /sqlserver|tds|Microsoft SQL/i, lambda { |config, column| column.extend(Column) } ]
7
+ end
8
+
9
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn
10
+ module Column
11
+
12
+ def self.included(base)
13
+ # NOTE: assumes a standalone MSSQLColumn class
14
+ class << base; include Cast; end
15
+ end
16
+
17
+ include LockMethods
18
+
19
+ attr_accessor :identity, :special
20
+ # @deprecated
21
+ alias_method :is_special, :special
22
+
23
+ # @override
24
+ def simplified_type(field_type)
25
+ case field_type
26
+ when /int|bigint|smallint|tinyint/i then :integer
27
+ when /numeric/i then (@scale.nil? || @scale == 0) ? :integer : :decimal
28
+ when /float|double|money|real|smallmoney/i then :decimal
29
+ when /datetime|smalldatetime/i then :datetime
30
+ when /timestamp/i then :timestamp
31
+ when /time/i then :time
32
+ when /date/i then :date
33
+ when /text|ntext|xml/i then :text
34
+ when /binary|image|varbinary/i then :binary
35
+ when /char|nchar|nvarchar|string|varchar/i then (@limit == 1073741823 ? (@limit = nil; :text) : :string)
36
+ when /bit/i then :boolean
37
+ when /uniqueidentifier/i then :string
38
+ else
39
+ super
40
+ end
41
+ end
42
+
43
+ # @override
44
+ def default_value(value)
45
+ return $1 if value =~ /^\(N?'(.*)'\)$/
46
+ value
47
+ end
48
+
49
+ # @override
50
+ def type_cast(value)
51
+ return nil if value.nil?
52
+ case type
53
+ when :integer then value.delete('()').to_i rescue unquote(value).to_i rescue value ? 1 : 0
54
+ when :primary_key then value == true || value == false ? value == true ? 1 : 0 : value.to_i
55
+ when :decimal then self.class.value_to_decimal(unquote(value))
56
+ when :date then self.class.string_to_date(value)
57
+ when :datetime then self.class.string_to_time(value)
58
+ when :timestamp then self.class.string_to_time(value)
59
+ when :time then self.class.string_to_dummy_time(value)
60
+ when :boolean then value == true || (value =~ /^t(rue)?$/i) == 0 || unquote(value) == '1'
61
+ when :binary then unquote value
62
+ else value
63
+ end
64
+ end
65
+
66
+ # @override
67
+ def extract_limit(sql_type)
68
+ case sql_type
69
+ when /^smallint/i
70
+ 2
71
+ when /^int/i
72
+ 4
73
+ when /^bigint/i
74
+ 8
75
+ when /\(max\)/, /decimal/, /numeric/
76
+ nil
77
+ when /text|ntext|xml|binary|image|varbinary|bit/
78
+ nil
79
+ else
80
+ super
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def is_utf8?
87
+ !!( sql_type =~ /nvarchar|ntext|nchar/i )
88
+ end
89
+
90
+ def unquote(value)
91
+ value.to_s.sub(/\A\([\(\']?/, "").sub(/[\'\)]?\)\Z/, "")
92
+ end
93
+
94
+ # @deprecated no longer used
95
+ def cast_to_time(value)
96
+ return value if value.is_a?(Time)
97
+ DateTime.parse(value).to_time rescue nil
98
+ end
99
+
100
+ # @deprecated no longer used
101
+ def cast_to_date(value)
102
+ return value if value.is_a?(Date)
103
+ return Date.parse(value) rescue nil
104
+ end
105
+
106
+ # @deprecated no longer used
107
+ def cast_to_datetime(value)
108
+ if value.is_a?(Time)
109
+ if value.year != 0 and value.month != 0 and value.day != 0
110
+ return value
111
+ else
112
+ return Time.mktime(2000, 1, 1, value.hour, value.min, value.sec) rescue nil
113
+ end
114
+ end
115
+ if value.is_a?(DateTime)
116
+ begin
117
+ # Attempt to convert back to a Time, but it could fail for dates significantly in the past/future.
118
+ return Time.mktime(value.year, value.mon, value.day, value.hour, value.min, value.sec)
119
+ rescue ArgumentError
120
+ return value
121
+ end
122
+ end
123
+
124
+ return cast_to_time(value) if value.is_a?(Date) or value.is_a?(String) rescue nil
125
+
126
+ return value.is_a?(Date) ? value : nil
127
+ end
128
+
129
+ module Cast
130
+
131
+ def string_to_date(value)
132
+ return value unless value.is_a?(String)
133
+ return nil if value.empty?
134
+
135
+ date = fast_string_to_date(value)
136
+ date ? date : Date.parse(value) rescue nil
137
+ end
138
+
139
+ def string_to_time(value)
140
+ return value unless value.is_a?(String)
141
+ return nil if value.empty?
142
+
143
+ fast_string_to_time(value) ||
144
+ begin
145
+ DateTime.parse(value).to_time
146
+ rescue nil
147
+ end
148
+ end
149
+
150
+ ISO_TIME = /\A(\d\d)\:(\d\d)\:(\d\d)(\.\d+)?\z/
151
+
152
+ def string_to_dummy_time(value)
153
+ return value unless value.is_a?(String)
154
+ return nil if value.empty?
155
+
156
+ if value =~ ISO_TIME # "12:34:56.1234560"
157
+ microsec = ($4.to_f * 1_000_000).round.to_i
158
+ new_time 2000, 1, 1, $1.to_i, $2.to_i, $3.to_i, microsec
159
+ else
160
+ super(value)
161
+ end
162
+ end
163
+
164
+ # @private
165
+ def string_to_binary(value)
166
+ # this will only allow the adapter to insert binary data with a length
167
+ # of 7K or less because of a SQL Server statement length policy ...
168
+ '' # "0x#{value.unpack("H*")[0]}"
169
+ end
170
+
171
+ def binary_to_string(value)
172
+ if value.respond_to?(:force_encoding) && value.encoding != Encoding::ASCII_8BIT
173
+ value = value.force_encoding(Encoding::ASCII_8BIT)
174
+ end
175
+ value =~ /[^[:xdigit:]]/ ? value : [value].pack('H*')
176
+ end
177
+
178
+ end
179
+
180
+ end
181
+ end
182
+ end
@@ -1,5 +1,14 @@
1
1
  ArJdbc::ConnectionMethods.module_eval do
2
+
3
+ # Default connection method for MS-SQL adapter (`adapter: mssql`),
4
+ # uses the (open-source) jTDS driver.
5
+ # If you'd like to use the "official" MS's SQL-JDBC driver, it's preferable
6
+ # to use the {#sqlserver_connection} method (set `adapter: sqlserver`).
2
7
  def mssql_connection(config)
8
+ if config[:driver] =~ /SQLServerDriver$/ || config[:url] =~ /^jdbc:sqlserver:/
9
+ return sqlserver_connection(config)
10
+ end
11
+
3
12
  begin
4
13
  require 'jdbc/jtds'
5
14
  # NOTE: the adapter has only support for working with the
@@ -9,7 +18,7 @@ ArJdbc::ConnectionMethods.module_eval do
9
18
  raise e unless e.message.to_s.index('no such file to load')
10
19
  end
11
20
 
12
- config[:host] ||= "localhost"
21
+ config[:host] ||= 'localhost'
13
22
  config[:port] ||= 1433
14
23
  config[:driver] ||= defined?(::Jdbc::JTDS.driver_name) ? ::Jdbc::JTDS.driver_name : 'net.sourceforge.jtds.jdbc.Driver'
15
24
  config[:adapter_spec] ||= ::ArJdbc::MSSQL
@@ -29,10 +38,34 @@ ArJdbc::ConnectionMethods.module_eval do
29
38
  end
30
39
 
31
40
  unless config[:domain]
32
- config[:username] ||= "sa"
33
- config[:password] ||= ""
41
+ config[:username] ||= 'sa'
42
+ config[:password] ||= ''
34
43
  end
35
44
  jdbc_connection(config)
36
45
  end
37
46
  alias_method :jdbcmssql_connection, :mssql_connection
38
- end
47
+
48
+ # @note Assumes SQLServer SQL-JDBC driver on the class-path.
49
+ def sqlserver_connection(config)
50
+ config[:host] ||= 'localhost'
51
+ config[:driver] ||= 'com.microsoft.sqlserver.jdbc.SQLServerDriver'
52
+ config[:adapter_spec] ||= ::ArJdbc::MSSQL
53
+ config[:adapter_class] = ActiveRecord::ConnectionAdapters::MSSQLAdapter unless config.key?(:adapter_class)
54
+ config[:connection_alive_sql] ||= 'SELECT 1'
55
+
56
+ config[:url] ||= begin
57
+ url = "jdbc:sqlserver://#{config[:host]}"
58
+ url << ( config[:port] ? ":#{config[:port]};" : ';' )
59
+ url << "databaseName=#{config[:database]};" if config[:database]
60
+ url << "instanceName=#{config[:instance]};" if config[:instance]
61
+ app = config[:appname] || config[:application]
62
+ url << "applicationName=#{app};" if app
63
+ isc = config[:integrated_security] # Win only - needs sqljdbc_auth.dll
64
+ url << "integratedSecurity=#{isc};" unless isc.nil?
65
+ url
66
+ end
67
+ jdbc_connection(config)
68
+ end
69
+ alias_method :jdbcsqlserver_connection, :sqlserver_connection
70
+
71
+ end
@@ -3,24 +3,15 @@ require 'active_support/core_ext/string'
3
3
  module ArJdbc
4
4
  module MSSQL
5
5
  module ExplainSupport
6
-
6
+
7
7
  DISABLED = Java::JavaLang::Boolean.getBoolean('arjdbc.mssql.explain_support.disabled')
8
-
9
- def supports_explain?
10
- ! DISABLED
11
- end
8
+
9
+ def supports_explain?; ! DISABLED; end
12
10
 
13
11
  def explain(arel, binds = [])
14
12
  return if DISABLED
15
13
  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
14
+ result = with_showplan_on { exec_query(sql, 'EXPLAIN', binds) }
24
15
  PrinterTable.new(result).pp
25
16
  end
26
17
 
@@ -37,12 +28,13 @@ module ArJdbc
37
28
  option = 'SHOWPLAN_TEXT'
38
29
  execute "SET #{option} #{enable ? 'ON' : 'OFF'}"
39
30
  rescue Exception => e
40
- raise ActiveRecord::ActiveRecordError, "#{option} could not be turned" +
31
+ raise ActiveRecord::ActiveRecordError, "#{option} could not be turned" +
41
32
  " #{enable ? 'ON' : 'OFF'} (check SHOWPLAN permissions) due : #{e.inspect}"
42
33
  end
43
-
44
- class PrinterTable # :nodoc:
45
-
34
+
35
+ # @private
36
+ class PrinterTable
37
+
46
38
  cattr_accessor :max_column_width, :cell_padding
47
39
  self.max_column_width = 50
48
40
  self.cell_padding = 1
@@ -64,7 +56,7 @@ module ArJdbc
64
56
  pp << build_cells(row)
65
57
  end
66
58
  pp << @separator
67
- pp.join("\n") + "\n"
59
+ pp.join("\n") << "\n"
68
60
  end
69
61
 
70
62
  private
@@ -81,7 +73,7 @@ module ArJdbc
81
73
  end
82
74
 
83
75
  def build_separator
84
- '+' + @widths.map {|w| '-' * (w + (cell_padding * 2))}.join('+') + '+'
76
+ '+' << @widths.map {|w| '-' * (w + (cell_padding * 2))}.join('+') << '+'
85
77
  end
86
78
 
87
79
  def build_cells(items)
@@ -99,9 +91,9 @@ module ArJdbc
99
91
  else item.to_s.truncate(max_column_width)
100
92
  end
101
93
  end
102
-
94
+
103
95
  end
104
-
96
+
105
97
  end
106
98
  end
107
99
  end
@@ -1,70 +1,71 @@
1
1
  module ArJdbc
2
2
  module MSSQL
3
3
  module LimitHelpers
4
-
5
- FIND_SELECT = /\b(SELECT(?:\s+DISTINCT)?)\b(.*)/im # :nodoc:
6
-
4
+
5
+ # @private
6
+ FIND_SELECT = /\b(SELECT(\s+DISTINCT)?)\b(.*)/mi
7
+
7
8
  module SqlServerReplaceLimitOffset
8
-
9
+
9
10
  module_function
10
-
11
+
11
12
  def replace_limit_offset!(sql, limit, offset, order)
12
13
  if limit
13
14
  offset ||= 0
14
- start_row = offset + 1
15
- end_row = offset + limit.to_i
16
- _, select, rest_of_query = FIND_SELECT.match(sql).to_a
17
- rest_of_query.strip!
18
- if rest_of_query[0...1] == "1" && rest_of_query !~ /1 AS/i
19
- rest_of_query[0] = "*"
15
+ start_row, end_row = offset + 1, offset + limit.to_i
16
+
17
+ if match = FIND_SELECT.match(sql)
18
+ select, distinct, rest_of_query = match[1], match[2], match[3]
19
+ rest_of_query.strip!
20
20
  end
21
- if rest_of_query[0...1] == "*"
21
+ rest_of_query[0] = '*' if rest_of_query[0...1] == '1' && rest_of_query !~ /1 AS/i
22
+ if rest_of_query[0...1] == '*'
22
23
  from_table = Utils.get_table_name(rest_of_query, true)
23
- rest_of_query = from_table + '.' + rest_of_query
24
+ rest_of_query = "#{from_table}.#{rest_of_query}"
24
25
  end
25
- new_sql = "#{select} t.* FROM (SELECT ROW_NUMBER() OVER(#{order}) AS _row_num, #{rest_of_query}"
26
- new_sql << ") AS t WHERE t._row_num BETWEEN #{start_row} AND #{end_row}"
26
+
27
+ if distinct # select =~ /DISTINCT/i
28
+ order = order.gsub(/([a-z0-9_])+\./, 't.')
29
+ new_sql = "SELECT t.* FROM "
30
+ new_sql << "( SELECT ROW_NUMBER() OVER(#{order}) AS _row_num, t.* FROM (#{select} #{rest_of_query}) AS t ) AS t"
31
+ new_sql << " WHERE t._row_num BETWEEN #{start_row} AND #{end_row}"
32
+ else
33
+ new_sql = "#{select} t.* FROM "
34
+ new_sql << "( SELECT ROW_NUMBER() OVER(#{order}) AS _row_num, #{rest_of_query} ) AS t"
35
+ new_sql << " WHERE t._row_num BETWEEN #{start_row} AND #{end_row}"
36
+ end
37
+
27
38
  sql.replace(new_sql)
28
39
  end
29
40
  sql
30
41
  end
31
-
32
- end
33
42
 
34
- module SqlServerAddLimitOffset
35
-
36
- def add_limit_offset!(sql, options)
37
- if options[:limit]
38
- order = "ORDER BY #{options[:order] || determine_order_clause(sql)}"
39
- sql.sub!(/ ORDER BY.*$/i, '')
40
- SqlServerReplaceLimitOffset.replace_limit_offset!(sql, options[:limit], options[:offset], order)
41
- end
42
- end
43
-
44
43
  end
45
-
44
+
46
45
  module SqlServer2000ReplaceLimitOffset
47
-
46
+
48
47
  module_function
49
-
48
+
50
49
  def replace_limit_offset!(sql, limit, offset, order)
51
50
  if limit
52
51
  offset ||= 0
53
52
  start_row = offset + 1
54
53
  end_row = offset + limit.to_i
55
- _, select, rest_of_query = FIND_SELECT.match(sql).to_a
56
-
54
+
55
+ if match = FIND_SELECT.match(sql)
56
+ select, distinct, rest_of_query = match[1], match[2], match[3]
57
+ end
57
58
  #need the table name for avoiding amiguity
58
59
  table_name = Utils.get_table_name(sql, true)
59
60
  primary_key = get_primary_key(order, table_name)
60
-
61
+
61
62
  #I am not sure this will cover all bases. but all the tests pass
62
63
  if order[/ORDER/].nil?
63
64
  new_order = "ORDER BY #{order}, [#{table_name}].[#{primary_key}]" if order.index("#{table_name}.#{primary_key}").nil?
64
65
  else
65
66
  new_order ||= order
66
67
  end
67
-
68
+
68
69
  if (start_row == 1) && (end_row ==1)
69
70
  new_sql = "#{select} TOP 1 #{rest_of_query} #{new_order}"
70
71
  sql.replace(new_sql)
@@ -94,7 +95,7 @@ module ArJdbc
94
95
 
95
96
  # Split the rest_of_query into chunks based on regexs (applied from end of string to the beginning)
96
97
  # The result is an array of regexs.size+1 elements (the last one being the remaining once everything was chopped away)
97
- def split_sql rest_of_query, *regexs
98
+ def split_sql(rest_of_query, *regexs)
98
99
  results = Array.new
99
100
 
100
101
  regexs.each do |regex|
@@ -112,7 +113,7 @@ module ArJdbc
112
113
 
113
114
  results
114
115
  end
115
-
116
+
116
117
  def get_primary_key(order, table_name) # table_name might be quoted
117
118
  if order =~ /(\w*id\w*)/i
118
119
  $1
@@ -124,17 +125,53 @@ module ArJdbc
124
125
  end
125
126
 
126
127
  private
127
-
128
+
128
129
  if ActiveRecord::VERSION::MAJOR >= 3
129
130
  def descendants; ::ActiveRecord::Base.descendants; end
130
131
  else
131
132
  def descendants; ::ActiveRecord::Base.send(:subclasses) end
132
133
  end
133
-
134
+
135
+ end
136
+
137
+ private
138
+
139
+ if ::ActiveRecord::VERSION::MAJOR < 3
140
+
141
+ def setup_limit_offset!(version = nil)
142
+ if version.to_s == '2000' || sqlserver_2000?
143
+ extend SqlServer2000AddLimitOffset
144
+ else
145
+ extend SqlServerAddLimitOffset
146
+ end
147
+ end
148
+
149
+ else
150
+
151
+ def setup_limit_offset!(version = nil); end
152
+
134
153
  end
135
154
 
155
+ # @private
156
+ module SqlServerAddLimitOffset
157
+
158
+ # @note Only needed with (non-AREL) ActiveRecord **2.3**.
159
+ # @see Arel::Visitors::SQLServer
160
+ def add_limit_offset!(sql, options)
161
+ if options[:limit]
162
+ order = "ORDER BY #{options[:order] || determine_order_clause(sql)}"
163
+ sql.sub!(/ ORDER BY.*$/i, '')
164
+ SqlServerReplaceLimitOffset.replace_limit_offset!(sql, options[:limit], options[:offset], order)
165
+ end
166
+ end
167
+
168
+ end if ::ActiveRecord::VERSION::MAJOR < 3
169
+
170
+ # @private
136
171
  module SqlServer2000AddLimitOffset
137
-
172
+
173
+ # @note Only needed with (non-AREL) ActiveRecord **2.3**.
174
+ # @see Arel::Visitors::SQLServer
138
175
  def add_limit_offset!(sql, options)
139
176
  if options[:limit]
140
177
  order = "ORDER BY #{options[:order] || determine_order_clause(sql)}"
@@ -142,9 +179,9 @@ module ArJdbc
142
179
  SqlServer2000ReplaceLimitOffset.replace_limit_offset!(sql, options[:limit], options[:offset], order)
143
180
  end
144
181
  end
145
-
146
- end
147
-
182
+
183
+ end if ::ActiveRecord::VERSION::MAJOR < 3
184
+
148
185
  end
149
186
  end
150
187
  end