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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (268) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.travis.yml +79 -0
  4. data/.yardopts +4 -0
  5. data/CONTRIBUTING.md +50 -0
  6. data/Gemfile +91 -0
  7. data/History.md +1191 -0
  8. data/LICENSE.txt +22 -17
  9. data/README.md +169 -0
  10. data/RUNNING_TESTS.md +127 -0
  11. data/Rakefile +294 -5
  12. data/Rakefile.jdbc +20 -0
  13. data/activerecord-jdbc-adapter.gemspec +55 -0
  14. data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
  15. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
  16. data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
  17. data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
  18. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  19. data/lib/activerecord-jdbc-adapter.rb +0 -5
  20. data/lib/arel/visitors/compat.rb +60 -0
  21. data/lib/arel/visitors/db2.rb +128 -6
  22. data/lib/arel/visitors/derby.rb +103 -10
  23. data/lib/arel/visitors/firebird.rb +79 -0
  24. data/lib/arel/visitors/h2.rb +25 -0
  25. data/lib/arel/visitors/hsqldb.rb +18 -10
  26. data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
  27. data/lib/arel/visitors/sql_server.rb +225 -0
  28. data/lib/arel/visitors/sql_server/ng42.rb +293 -0
  29. data/lib/arjdbc.rb +11 -21
  30. data/lib/arjdbc/abstract/connection_management.rb +35 -0
  31. data/lib/arjdbc/abstract/core.rb +64 -0
  32. data/lib/arjdbc/abstract/database_statements.rb +64 -0
  33. data/lib/arjdbc/abstract/statement_cache.rb +58 -0
  34. data/lib/arjdbc/abstract/transaction_support.rb +86 -0
  35. data/lib/arjdbc/db2.rb +3 -1
  36. data/lib/arjdbc/db2/adapter.rb +630 -250
  37. data/lib/arjdbc/db2/as400.rb +130 -0
  38. data/lib/arjdbc/db2/column.rb +167 -0
  39. data/lib/arjdbc/db2/connection_methods.rb +44 -0
  40. data/lib/arjdbc/derby.rb +1 -5
  41. data/lib/arjdbc/derby/active_record_patch.rb +13 -0
  42. data/lib/arjdbc/derby/adapter.rb +409 -217
  43. data/lib/arjdbc/derby/connection_methods.rb +16 -14
  44. data/lib/arjdbc/derby/schema_creation.rb +15 -0
  45. data/lib/arjdbc/discover.rb +62 -50
  46. data/lib/arjdbc/firebird.rb +3 -1
  47. data/lib/arjdbc/firebird/adapter.rb +365 -62
  48. data/lib/arjdbc/firebird/connection_methods.rb +23 -0
  49. data/lib/arjdbc/h2.rb +2 -3
  50. data/lib/arjdbc/h2/adapter.rb +273 -6
  51. data/lib/arjdbc/h2/connection_methods.rb +23 -8
  52. data/lib/arjdbc/hsqldb.rb +2 -3
  53. data/lib/arjdbc/hsqldb/adapter.rb +204 -77
  54. data/lib/arjdbc/hsqldb/connection_methods.rb +24 -10
  55. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  56. data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
  57. data/lib/arjdbc/informix.rb +4 -2
  58. data/lib/arjdbc/informix/adapter.rb +78 -54
  59. data/lib/arjdbc/informix/connection_methods.rb +8 -9
  60. data/lib/arjdbc/jdbc.rb +59 -2
  61. data/lib/arjdbc/jdbc/adapter.rb +356 -166
  62. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  63. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  64. data/lib/arjdbc/jdbc/base_ext.rb +15 -0
  65. data/lib/arjdbc/jdbc/callbacks.rb +27 -18
  66. data/lib/arjdbc/jdbc/column.rb +79 -20
  67. data/lib/arjdbc/jdbc/connection.rb +5 -119
  68. data/lib/arjdbc/jdbc/connection_methods.rb +32 -4
  69. data/lib/arjdbc/jdbc/error.rb +65 -0
  70. data/lib/arjdbc/jdbc/extension.rb +41 -29
  71. data/lib/arjdbc/jdbc/java.rb +5 -6
  72. data/lib/arjdbc/jdbc/jdbc.rake +3 -126
  73. data/lib/arjdbc/jdbc/railtie.rb +2 -9
  74. data/lib/arjdbc/jdbc/rake_tasks.rb +3 -10
  75. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -0
  76. data/lib/arjdbc/jdbc/type_cast.rb +166 -0
  77. data/lib/arjdbc/jdbc/type_converter.rb +35 -19
  78. data/lib/arjdbc/mssql.rb +6 -3
  79. data/lib/arjdbc/mssql/adapter.rb +630 -298
  80. data/lib/arjdbc/mssql/column.rb +200 -0
  81. data/lib/arjdbc/mssql/connection_methods.rb +66 -17
  82. data/lib/arjdbc/mssql/explain_support.rb +99 -0
  83. data/lib/arjdbc/mssql/limit_helpers.rb +189 -50
  84. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  85. data/lib/arjdbc/mssql/types.rb +343 -0
  86. data/lib/arjdbc/mssql/utils.rb +82 -0
  87. data/lib/arjdbc/mysql.rb +2 -3
  88. data/lib/arjdbc/mysql/adapter.rb +86 -356
  89. data/lib/arjdbc/mysql/connection_methods.rb +159 -23
  90. data/lib/arjdbc/oracle/adapter.rb +714 -263
  91. data/lib/arjdbc/postgresql.rb +2 -3
  92. data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +24 -0
  93. data/lib/arjdbc/postgresql/adapter.rb +570 -400
  94. data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
  95. data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
  96. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  97. data/lib/arjdbc/postgresql/base/pgconn.rb +11 -0
  98. data/lib/arjdbc/postgresql/column.rb +51 -0
  99. data/lib/arjdbc/postgresql/connection_methods.rb +57 -18
  100. data/lib/arjdbc/postgresql/name.rb +24 -0
  101. data/lib/arjdbc/postgresql/oid_types.rb +192 -0
  102. data/lib/arjdbc/railtie.rb +11 -0
  103. data/lib/arjdbc/sqlite3.rb +2 -3
  104. data/lib/arjdbc/sqlite3/adapter.rb +518 -198
  105. data/lib/arjdbc/sqlite3/connection_methods.rb +49 -24
  106. data/lib/arjdbc/sybase.rb +2 -2
  107. data/lib/arjdbc/sybase/adapter.rb +7 -6
  108. data/lib/arjdbc/tasks.rb +13 -0
  109. data/lib/arjdbc/tasks/database_tasks.rb +52 -0
  110. data/lib/arjdbc/tasks/databases.rake +91 -0
  111. data/lib/arjdbc/tasks/databases3.rake +215 -0
  112. data/lib/arjdbc/tasks/databases4.rake +39 -0
  113. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  114. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  115. data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
  116. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  117. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
  118. data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
  119. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  120. data/lib/arjdbc/util/serialized_attributes.rb +98 -0
  121. data/lib/arjdbc/util/table_copier.rb +110 -0
  122. data/lib/arjdbc/version.rb +1 -6
  123. data/lib/generators/jdbc/USAGE +9 -0
  124. data/lib/generators/jdbc/jdbc_generator.rb +8 -0
  125. data/lib/jdbc_adapter.rb +1 -1
  126. data/lib/jdbc_adapter/rake_tasks.rb +3 -2
  127. data/lib/jdbc_adapter/version.rb +2 -1
  128. data/pom.xml +114 -0
  129. data/rails_generators/jdbc_generator.rb +1 -1
  130. data/rails_generators/templates/config/initializers/jdbc.rb +8 -5
  131. data/rails_generators/templates/lib/tasks/jdbc.rake +7 -4
  132. data/rakelib/01-tomcat.rake +51 -0
  133. data/rakelib/02-test.rake +132 -0
  134. data/rakelib/bundler_ext.rb +11 -0
  135. data/rakelib/compile.rake +67 -22
  136. data/rakelib/db.rake +61 -0
  137. data/rakelib/rails.rake +204 -29
  138. data/src/java/arjdbc/ArJdbcModule.java +286 -0
  139. data/src/java/arjdbc/db2/DB2Module.java +76 -0
  140. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +126 -0
  141. data/src/java/arjdbc/derby/DerbyModule.java +99 -243
  142. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +152 -0
  143. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +174 -0
  144. data/src/java/arjdbc/{jdbc/JdbcConnectionFactory.java → h2/H2Module.java} +20 -6
  145. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +27 -12
  146. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +73 -0
  147. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +7 -6
  148. data/src/java/arjdbc/jdbc/AdapterJavaService.java +7 -29
  149. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  150. data/src/java/arjdbc/jdbc/ConnectionFactory.java +132 -0
  151. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +157 -0
  152. data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
  153. data/src/java/arjdbc/jdbc/DriverWrapper.java +119 -0
  154. data/src/java/arjdbc/jdbc/JdbcResult.java +130 -0
  155. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +3622 -948
  156. data/src/java/arjdbc/mssql/MSSQLModule.java +90 -0
  157. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +181 -0
  158. data/src/java/arjdbc/mysql/MySQLModule.java +99 -81
  159. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +294 -0
  160. data/src/java/arjdbc/oracle/OracleModule.java +80 -0
  161. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +387 -17
  162. data/src/java/arjdbc/postgresql/ByteaUtils.java +157 -0
  163. data/src/java/arjdbc/postgresql/PgResultSetMetaDataWrapper.java +23 -0
  164. data/src/java/arjdbc/postgresql/PostgreSQLModule.java +77 -0
  165. data/src/java/arjdbc/postgresql/PostgreSQLResult.java +184 -0
  166. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +952 -0
  167. data/src/java/arjdbc/sqlite3/SQLite3Module.java +73 -0
  168. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +525 -0
  169. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  170. data/src/java/arjdbc/util/DateTimeUtils.java +580 -0
  171. data/src/java/arjdbc/util/ObjectSupport.java +65 -0
  172. data/src/java/arjdbc/util/QuotingUtils.java +138 -0
  173. data/src/java/arjdbc/util/StringCache.java +63 -0
  174. data/src/java/arjdbc/util/StringHelper.java +159 -0
  175. metadata +245 -268
  176. data/History.txt +0 -369
  177. data/Manifest.txt +0 -180
  178. data/README.txt +0 -181
  179. data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
  180. data/lib/arel/engines/sql/compilers/db2_compiler.rb +0 -9
  181. data/lib/arel/engines/sql/compilers/derby_compiler.rb +0 -6
  182. data/lib/arel/engines/sql/compilers/h2_compiler.rb +0 -6
  183. data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +0 -15
  184. data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +0 -6
  185. data/lib/arel/engines/sql/compilers/mssql_compiler.rb +0 -46
  186. data/lib/arel/visitors/mssql.rb +0 -44
  187. data/lib/arjdbc/jdbc/compatibility.rb +0 -51
  188. data/lib/arjdbc/jdbc/core_ext.rb +0 -24
  189. data/lib/arjdbc/jdbc/discover.rb +0 -18
  190. data/lib/arjdbc/jdbc/driver.rb +0 -44
  191. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +0 -87
  192. data/lib/arjdbc/jdbc/quoted_primary_key.rb +0 -28
  193. data/lib/arjdbc/jdbc/require_driver.rb +0 -16
  194. data/lib/arjdbc/mimer.rb +0 -2
  195. data/lib/arjdbc/mimer/adapter.rb +0 -142
  196. data/lib/arjdbc/mssql/tsql_helper.rb +0 -61
  197. data/lib/arjdbc/oracle.rb +0 -3
  198. data/lib/arjdbc/oracle/connection_methods.rb +0 -11
  199. data/lib/pg.rb +0 -4
  200. data/rakelib/package.rake +0 -92
  201. data/rakelib/test.rake +0 -81
  202. data/src/java/arjdbc/jdbc/SQLBlock.java +0 -48
  203. data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +0 -127
  204. data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +0 -57
  205. data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +0 -64
  206. data/test/abstract_db_create.rb +0 -117
  207. data/test/activerecord/connection_adapters/type_conversion_test.rb +0 -31
  208. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +0 -25
  209. data/test/db/db2.rb +0 -11
  210. data/test/db/derby.rb +0 -12
  211. data/test/db/h2.rb +0 -11
  212. data/test/db/hsqldb.rb +0 -13
  213. data/test/db/informix.rb +0 -11
  214. data/test/db/jdbc.rb +0 -11
  215. data/test/db/jndi_config.rb +0 -40
  216. data/test/db/logger.rb +0 -3
  217. data/test/db/mssql.rb +0 -9
  218. data/test/db/mysql.rb +0 -10
  219. data/test/db/oracle.rb +0 -34
  220. data/test/db/postgres.rb +0 -9
  221. data/test/db/sqlite3.rb +0 -11
  222. data/test/db2_simple_test.rb +0 -66
  223. data/test/derby_migration_test.rb +0 -68
  224. data/test/derby_multibyte_test.rb +0 -12
  225. data/test/derby_simple_test.rb +0 -99
  226. data/test/generic_jdbc_connection_test.rb +0 -29
  227. data/test/h2_simple_test.rb +0 -41
  228. data/test/has_many_through.rb +0 -79
  229. data/test/helper.rb +0 -5
  230. data/test/hsqldb_simple_test.rb +0 -6
  231. data/test/informix_simple_test.rb +0 -48
  232. data/test/jdbc_common.rb +0 -25
  233. data/test/jndi_callbacks_test.rb +0 -40
  234. data/test/jndi_test.rb +0 -25
  235. data/test/manualTestDatabase.rb +0 -191
  236. data/test/models/add_not_null_column_to_table.rb +0 -12
  237. data/test/models/auto_id.rb +0 -18
  238. data/test/models/data_types.rb +0 -28
  239. data/test/models/entry.rb +0 -43
  240. data/test/models/mixed_case.rb +0 -25
  241. data/test/models/reserved_word.rb +0 -18
  242. data/test/models/string_id.rb +0 -18
  243. data/test/models/validates_uniqueness_of_string.rb +0 -19
  244. data/test/mssql_db_create_test.rb +0 -26
  245. data/test/mssql_identity_insert_test.rb +0 -19
  246. data/test/mssql_legacy_types_test.rb +0 -58
  247. data/test/mssql_limit_offset_test.rb +0 -136
  248. data/test/mssql_multibyte_test.rb +0 -18
  249. data/test/mssql_simple_test.rb +0 -55
  250. data/test/mysql_db_create_test.rb +0 -27
  251. data/test/mysql_info_test.rb +0 -113
  252. data/test/mysql_multibyte_test.rb +0 -10
  253. data/test/mysql_nonstandard_primary_key_test.rb +0 -42
  254. data/test/mysql_simple_test.rb +0 -49
  255. data/test/oracle_simple_test.rb +0 -18
  256. data/test/oracle_specific_test.rb +0 -83
  257. data/test/pick_rails_version.rb +0 -3
  258. data/test/postgres_db_create_test.rb +0 -32
  259. data/test/postgres_drop_db_test.rb +0 -16
  260. data/test/postgres_mixed_case_test.rb +0 -29
  261. data/test/postgres_nonseq_pkey_test.rb +0 -38
  262. data/test/postgres_reserved_test.rb +0 -22
  263. data/test/postgres_schema_search_path_test.rb +0 -44
  264. data/test/postgres_simple_test.rb +0 -51
  265. data/test/postgres_table_alias_length_test.rb +0 -15
  266. data/test/simple.rb +0 -546
  267. data/test/sqlite3_simple_test.rb +0 -233
  268. data/test/sybase_jtds_simple_test.rb +0 -28
@@ -0,0 +1,25 @@
1
+ require 'arel/visitors/compat'
2
+ require 'arel/visitors/hsqldb'
3
+
4
+ module Arel
5
+ module Visitors
6
+ class H2 < Arel::Visitors::HSQLDB
7
+ def visit_Arel_Nodes_SelectStatement(o, *)
8
+ o.limit ||= Arel::Nodes::Limit.new(-1) if o.offset
9
+ super
10
+ end if ArJdbc::AR42
11
+
12
+ def limit_offset sql, o
13
+ offset = o.offset || 0
14
+ offset = offset.expr unless (offset.nil? || offset == 0)
15
+ if limit = o.limit
16
+ "SELECT LIMIT #{offset} #{limit_for(limit)} #{sql[7..-1]}"
17
+ elsif offset > 0
18
+ "SELECT LIMIT #{offset} -1 #{sql[7..-1]}" # removes "SELECT "
19
+ else
20
+ sql
21
+ end
22
+ end unless ArJdbc::AR42
23
+ end
24
+ end
25
+ end
@@ -1,24 +1,32 @@
1
+ require 'arel/visitors/compat'
2
+
1
3
  module Arel
2
4
  module Visitors
3
5
  class HSQLDB < Arel::Visitors::ToSql
4
- def visit_Arel_Nodes_SelectStatement o
5
- [
6
- limit_offset(o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, o),
7
- ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
8
- ].compact.join ' '
9
- end
6
+ def visit_Arel_Nodes_SelectStatement(o, *)
7
+ o.limit ||= Arel::Nodes::Limit.new(0) if o.offset
8
+ super
9
+ end if ArJdbc::AR42
10
+
11
+ def visit_Arel_Nodes_SelectStatement o, a = nil
12
+ sql = limit_offset(o.cores.map { |x| do_visit_select_core x, a }.join, o)
13
+ sql << " ORDER BY #{o.orders.map { |x| do_visit x, a }.join(', ')}" unless o.orders.empty?
14
+ sql
15
+ end unless ArJdbc::AR42
16
+
17
+ private
10
18
 
11
19
  def limit_offset sql, o
12
20
  offset = o.offset || 0
13
- bef = sql[7..-1]
21
+ offset = offset.expr unless (offset.nil? || offset == 0)
14
22
  if limit = o.limit
15
- "SELECT LIMIT #{offset} #{limit} #{bef}"
23
+ "SELECT LIMIT #{offset} #{limit_for(limit)} #{sql[7..-1]}"
16
24
  elsif offset > 0
17
- "SELECT LIMIT #{offset} 0 #{bef}"
25
+ "SELECT LIMIT #{offset} 0 #{sql[7..-1]}" # removes "SELECT "
18
26
  else
19
27
  sql
20
28
  end
21
- end
29
+ end unless ArJdbc::AR42
22
30
  end
23
31
  end
24
32
  end
@@ -0,0 +1,6 @@
1
+ require 'arel/visitors/compat'
2
+
3
+ class Arel::Visitors::PostgreSQL
4
+ # AREL converts bind argument markers "?" to "$n" for PG, but JDBC wants "?".
5
+ remove_method :visit_Arel_Nodes_BindParam if ArJdbc::AR42
6
+ end
@@ -0,0 +1,225 @@
1
+ require 'arel/visitors/compat'
2
+
3
+ module Arel
4
+ module Visitors
5
+ ToSql.class_eval do
6
+ alias_method :_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement
7
+ end
8
+ # @note AREL set's up `Arel::Visitors::MSSQL` but its not usable as is ...
9
+ # @private
10
+ class SQLServer < const_defined?(:MSSQL) ? MSSQL : ToSql
11
+
12
+ private
13
+
14
+ def visit_Arel_Nodes_SelectStatement(*args) # [o] AR <= 4.0 [o, a] on 4.1
15
+ o, a = args.first, args.last
16
+
17
+ return _visit_Arel_Nodes_SelectStatement(*args) if ! o.limit && ! o.offset
18
+
19
+ unless o.orders.empty?
20
+ select_order_by = do_visit_columns o.orders, a, 'ORDER BY '
21
+ end
22
+
23
+ select_count = false; sql = ''
24
+ o.cores.each do |x|
25
+ x = x.dup
26
+ core_order_by = select_order_by || determine_order_by(x, a)
27
+ if select_count? x
28
+ x.projections = [
29
+ Arel::Nodes::SqlLiteral.new(core_order_by ? over_row_num(core_order_by) : '*')
30
+ ]
31
+ select_count = true
32
+ else
33
+ # NOTE: this should really be added here and we should built the
34
+ # wrapping SQL but than #replace_limit_offset! assumes it does that
35
+ # ... MS-SQL adapter code seems to be 'hacked' by a lot of people
36
+ #x.projections << Arel::Nodes::SqlLiteral.new over_row_num(order_by)
37
+ end
38
+ sql << do_visit_select_core(x, a)
39
+ end
40
+
41
+ #sql = "SELECT _t.* FROM (#{sql}) as _t WHERE #{get_offset_limit_clause(o)}"
42
+ select_order_by ||= "ORDER BY #{@connection.determine_order_clause(sql)}"
43
+ replace_limit_offset!(sql, limit_for(o.limit), o.offset && o.offset.value.to_i, select_order_by)
44
+
45
+ sql = "SELECT COUNT(*) AS count_id FROM (#{sql}) AS subquery" if select_count
46
+
47
+ add_lock!(sql, :lock => o.lock && true)
48
+
49
+ sql
50
+ end unless ArJdbc::AR42
51
+
52
+ # @private
53
+ MAX_LIMIT_VALUE = 9_223_372_036_854_775_807
54
+
55
+ def visit_Arel_Nodes_UpdateStatement(*args) # [o] AR <= 4.0 [o, a] on 4.1
56
+ o = args.first
57
+ if o.orders.any? && o.limit.nil?
58
+ o.limit = Nodes::Limit.new(MAX_LIMIT_VALUE)
59
+ end
60
+ super
61
+ end
62
+
63
+ def visit_Arel_Nodes_Lock o, a = nil
64
+ # MS-SQL doesn't support "SELECT...FOR UPDATE". Instead, it needs
65
+ # WITH(ROWLOCK,UPDLOCK) specified after each table in the FROM clause.
66
+ #
67
+ # we return nothing here and add the appropriate stuff with #add_lock!
68
+ #do_visit o.expr, a
69
+ end unless ArJdbc::AR42
70
+
71
+ def visit_Arel_Nodes_Top o, a = nil
72
+ # `top` wouldn't really work here:
73
+ # User.select("distinct first_name").limit(10)
74
+ # would generate "select top 10 distinct first_name from users",
75
+ # which is invalid should be "select distinct top 10 first_name ..."
76
+ a || ''
77
+ end
78
+
79
+ def visit_Arel_Nodes_Limit o, a = nil
80
+ "TOP (#{do_visit o.expr, a})"
81
+ end unless ArJdbc::AR42
82
+
83
+ def visit_Arel_Nodes_Ordering o, a = nil
84
+ expr = do_visit o.expr, a
85
+ if o.respond_to?(:direction)
86
+ "#{expr} #{o.ascending? ? 'ASC' : 'DESC'}"
87
+ else
88
+ expr
89
+ end
90
+ end unless ArJdbc::AR42
91
+
92
+ def visit_Arel_Nodes_Bin o, a = nil
93
+ expr = o.expr; sql = do_visit expr, a
94
+ if expr.respond_to?(:val) && expr.val.is_a?(Numeric)
95
+ sql
96
+ else
97
+ sql << " #{::ArJdbc::MSSQL.cs_equality_operator} "
98
+ sql
99
+ end
100
+ end unless ArJdbc::AR42
101
+
102
+ private
103
+
104
+ def self.possibly_private_method_defined?(name)
105
+ private_method_defined?(name) || method_defined?(name)
106
+ end
107
+
108
+ def select_count? x
109
+ x.projections.length == 1 && Arel::Nodes::Count === x.projections.first
110
+ end unless possibly_private_method_defined? :select_count?
111
+
112
+ def determine_order_by x, a
113
+ unless x.groups.empty?
114
+ do_visit_columns x.groups, a, 'ORDER BY '
115
+ else
116
+ table_pk = find_left_table_pk(x)
117
+ table_pk && "ORDER BY #{table_pk}"
118
+ end
119
+ end
120
+
121
+ def find_left_table_pk o
122
+ primary_key_from_table table_from_select_core(o)
123
+ end
124
+
125
+ def do_visit_columns(colls, a, sql)
126
+ last = colls.size - 1
127
+ colls.each_with_index do |x, i|
128
+ sql << do_visit(x, a); sql << ', ' unless i == last
129
+ end
130
+ sql
131
+ end
132
+
133
+ def do_visit_columns(colls, a, sql)
134
+ prefix = sql
135
+ sql = Arel::Collectors::PlainString.new
136
+ sql << prefix if prefix
137
+
138
+ last = colls.size - 1
139
+ colls.each_with_index do |x, i|
140
+ visit(x, sql); sql << ', ' unless i == last
141
+ end
142
+ sql.value
143
+ end if ArJdbc::AR42
144
+
145
+ def do_visit_columns(colls, a, sql)
146
+ non_simple_order = /\sASC|\sDESC|\sCASE|\sCOLLATE|[\.,\[\(]/i # MIN(width)
147
+
148
+ last = colls.size - 1
149
+ colls.each_with_index do |x, i|
150
+ coll = do_visit(x, a)
151
+
152
+ if coll !~ non_simple_order && coll.to_i == 0
153
+ sql << @connection.quote_column_name(coll)
154
+ else
155
+ sql << coll
156
+ end
157
+
158
+ sql << ', ' unless i == last
159
+ end
160
+ sql
161
+ end if Arel::VERSION < '4.0.0'
162
+
163
+ def over_row_num order_by
164
+ "ROW_NUMBER() OVER (#{order_by}) as _row_num"
165
+ end # unless possibly_private_method_defined? :row_num_literal
166
+
167
+ def table_from_select_core core
168
+ if Arel::Table === core.from
169
+ core.from
170
+ elsif Arel::Nodes::SqlLiteral === core.from
171
+ Arel::Table.new(core.from, @engine)
172
+ elsif Arel::Nodes::JoinSource === core.source
173
+ Arel::Nodes::SqlLiteral === core.source.left ? Arel::Table.new(core.source.left, @engine) : core.source.left
174
+ end
175
+ end
176
+
177
+ def table_from_select_core core
178
+ table_finder = lambda do |x|
179
+ case x
180
+ when Arel::Table
181
+ x
182
+ when Arel::Nodes::SqlLiteral
183
+ Arel::Table.new(x, @engine)
184
+ when Arel::Nodes::Join
185
+ table_finder.call(x.left)
186
+ end
187
+ end
188
+ table_finder.call(core.froms)
189
+ end if ActiveRecord::VERSION::STRING < '3.2'
190
+
191
+ def primary_key_from_table t
192
+ return unless t
193
+ return t.primary_key if t.primary_key
194
+
195
+ engine = t.engine
196
+ if engine_pk = engine.primary_key
197
+ pk = engine.arel_table[engine_pk]
198
+ return pk if pk
199
+ end
200
+
201
+ pk = (@primary_keys ||= {}).fetch(table_name = engine.table_name) do
202
+ pk_name = @connection.primary_key(table_name)
203
+ # some tables might be without primary key
204
+ @primary_keys[table_name] = pk_name && t[pk_name]
205
+ end
206
+ return pk if pk
207
+
208
+ column_name = engine.columns.first.try(:name)
209
+ column_name && t[column_name]
210
+ end
211
+
212
+ include ArJdbc::MSSQL::LockMethods
213
+
214
+ include ArJdbc::MSSQL::LimitHelpers::SqlServerReplaceLimitOffset
215
+
216
+ end
217
+
218
+ class SQLServer2000 < SQLServer
219
+ include ArJdbc::MSSQL::LimitHelpers::SqlServer2000ReplaceLimitOffset
220
+ end
221
+
222
+ load 'arel/visitors/sql_server/ng42.rb' if ArJdbc::AR42
223
+
224
+ end
225
+ end
@@ -0,0 +1,293 @@
1
+ module Arel
2
+ module Visitors
3
+ class SQLServerNG < SQLServer # Arel::Visitors::ToSql
4
+
5
+ OFFSET = " OFFSET "
6
+ ROWS = " ROWS"
7
+ FETCH = " FETCH NEXT "
8
+ FETCH0 = " FETCH FIRST (SELECT 0) "
9
+ ROWS_ONLY = " ROWS ONLY"
10
+
11
+ private
12
+
13
+ # SQLServer ToSql/Visitor (Overides)
14
+
15
+ #def visit_Arel_Nodes_BindParam o, collector
16
+ # collector.add_bind(o) { |i| "@#{i-1}" }
17
+ #end
18
+
19
+ def visit_Arel_Nodes_Bin o, collector
20
+ visit o.expr, collector
21
+ if o.expr.val.is_a? Numeric
22
+ collector
23
+ else
24
+ collector << " #{::ArJdbc::MSSQL.cs_equality_operator} "
25
+ end
26
+ end
27
+
28
+ def visit_Arel_Nodes_UpdateStatement(o, a)
29
+ if o.orders.any? && o.limit.nil?
30
+ o.limit = Nodes::Limit.new(9_223_372_036_854_775_807)
31
+ end
32
+ super
33
+ end
34
+
35
+ def visit_Arel_Nodes_Lock o, collector
36
+ o.expr = Arel.sql('WITH(UPDLOCK)') if o.expr.to_s =~ /FOR UPDATE/
37
+ collector << SPACE
38
+ visit o.expr, collector
39
+ end
40
+
41
+ def visit_Arel_Nodes_Offset o, collector
42
+ collector << OFFSET
43
+ visit o.expr, collector
44
+ collector << ROWS
45
+ end
46
+
47
+ def visit_Arel_Nodes_Limit o, collector
48
+ if node_value(o) == 0
49
+ collector << FETCH0
50
+ collector << ROWS_ONLY
51
+ else
52
+ collector << FETCH
53
+ visit o.expr, collector
54
+ collector << ROWS_ONLY
55
+ end
56
+ end
57
+
58
+ def visit_Arel_Nodes_SelectStatement o, collector
59
+ distinct_One_As_One_Is_So_Not_Fetch o
60
+
61
+ set_select_statement_lock o.lock
62
+
63
+ if o.with
64
+ collector = visit o.with, collector
65
+ collector << SPACE
66
+ end
67
+
68
+ return _visit_Arel_Nodes_SelectStatement(o, collector) if ! o.limit && ! o.offset
69
+
70
+ # collector = o.cores.inject(collector) { |c,x|
71
+ # visit_Arel_Nodes_SelectCore(x, c)
72
+ # }
73
+
74
+ unless o.orders.empty?
75
+ select_order_by = do_visit_columns o.orders, collector, 'ORDER BY '
76
+ end
77
+
78
+ select_count = false
79
+ collector = o.cores.inject(collector) do |c, x|
80
+ unless core_order_by = select_order_by
81
+ core_order_by = generate_order_by determine_order_by(o, x)
82
+ end
83
+
84
+ if select_count? x
85
+ x.projections = [ Arel::Nodes::SqlLiteral.new(over_row_num(core_order_by)) ]
86
+ select_count = true
87
+ else
88
+ # NOTE: this should really be added here and we should built the
89
+ # wrapping SQL but than #replace_limit_offset! assumes it does that
90
+ # ... MS-SQL adapter code seems to be 'hacked' by a lot of people
91
+ #x.projections << Arel::Nodes::SqlLiteral.new(over_row_num(select_order_by))
92
+ end if core_order_by
93
+ visit_Arel_Nodes_SelectCore(x, c)
94
+ end
95
+ # END collector = o.cores.inject(collector) { |c,x|
96
+
97
+ # collector = visit_Orders_And_Let_Fetch_Happen o, collector
98
+ # collector = visit_Make_Fetch_Happen o, collector
99
+ # collector # __method__ END
100
+
101
+ self.class.collector_proxy(collector) do |sql|
102
+ select_order_by ||= "ORDER BY #{@connection.determine_order_clause(sql)}"
103
+ replace_limit_offset!(sql, limit_for(o.limit), o.offset && o.offset.value.to_i, select_order_by)
104
+ sql = "SELECT COUNT(*) AS count_id FROM (#{sql}) AS subquery" if select_count
105
+ sql
106
+ end
107
+
108
+ ensure
109
+ set_select_statement_lock nil
110
+ end
111
+
112
+ def visit_Arel_Nodes_JoinSource o, collector
113
+ if o.left
114
+ collector = visit o.left, collector
115
+ collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector
116
+ end
117
+ if o.right.any?
118
+ collector << " " if o.left
119
+ collector = inject_join o.right, collector, ' '
120
+ end
121
+ collector
122
+ end
123
+
124
+ def visit_Arel_Nodes_OuterJoin o, collector
125
+ collector << "LEFT OUTER JOIN "
126
+ collector = visit o.left, collector
127
+ collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, space: true
128
+ collector << " "
129
+ visit o.right, collector
130
+ end
131
+
132
+ # SQLServer ToSql/Visitor (Additions)
133
+
134
+ def visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, options = {}
135
+ if lock = select_statement_lock
136
+ collector = visit lock, collector
137
+ collector << SPACE if options[:space]
138
+ end
139
+ collector
140
+ end
141
+
142
+ def visit_Orders_And_Let_Fetch_Happen o, collector
143
+ make_Fetch_Possible_And_Deterministic o
144
+ unless o.orders.empty?
145
+ collector << SPACE
146
+ collector << ORDER_BY
147
+ len = o.orders.length - 1
148
+ o.orders.each_with_index { |x, i|
149
+ collector = visit(x, collector)
150
+ collector << COMMA unless len == i
151
+ }
152
+ end
153
+ collector
154
+ end
155
+
156
+ def visit_Make_Fetch_Happen o, collector
157
+ o.offset = Nodes::Offset.new(0) if o.limit && !o.offset
158
+ collector = visit o.offset, collector if o.offset
159
+ collector = visit o.limit, collector if o.limit
160
+ collector
161
+ end
162
+
163
+ # SQLServer Helpers
164
+
165
+ # attr_reader :select_statement_lock
166
+ def select_statement_lock
167
+ Thread.current[:'Arel::Visitors::SQLServerNG.select_statement_lock']
168
+ end
169
+
170
+ def set_select_statement_lock(lock) # @select_statement_lock = lock
171
+ Thread.current[:'Arel::Visitors::SQLServerNG.select_statement_lock'] = lock
172
+ end
173
+
174
+ def make_Fetch_Possible_And_Deterministic o
175
+ return if o.limit.nil? && o.offset.nil?
176
+ if o.orders.empty? # ORDER BY mandatory with OFFSET FETCH clause
177
+ t = table_From_Statement o
178
+ pk = primary_Key_From_Table t
179
+ return unless pk
180
+ # Prefer deterministic vs a simple `(SELECT NULL)` expr.
181
+ o.orders = [ pk.asc ]
182
+ end
183
+ end
184
+
185
+ def distinct_One_As_One_Is_So_Not_Fetch o
186
+ core = o.cores.first
187
+ distinct = Nodes::Distinct === core.set_quantifier
188
+ oneasone = core.projections.all? { |x| x == ActiveRecord::FinderMethods::ONE_AS_ONE }
189
+ limitone = node_value(o.limit) == 1
190
+ if distinct && oneasone && limitone && !o.offset
191
+ core.projections = [Arel.sql("TOP(1) 1 AS [one]")]
192
+ o.limit = nil
193
+ end
194
+ end
195
+
196
+ def table_From_Statement o
197
+ core = o.cores.first
198
+ if Arel::Table === core.from
199
+ core.from
200
+ elsif Arel::Nodes::SqlLiteral === core.from
201
+ Arel::Table.new(core.from)
202
+ elsif Arel::Nodes::JoinSource === core.source
203
+ Arel::Nodes::SqlLiteral === core.source.left ? Arel::Table.new(core.source.left, @engine) : core.source.left
204
+ end
205
+ end
206
+
207
+ def primary_Key_From_Table t
208
+ return unless t
209
+ return t.primary_key if t.primary_key
210
+ if engine_pk = t.engine.primary_key
211
+ pk = t.engine.arel_table[engine_pk]
212
+ return pk if pk
213
+ end
214
+ pk = t.engine.connection.schema_cache.primary_keys(t.engine.table_name)
215
+ return pk if pk
216
+ column_name = t.engine.columns.first.try(:name)
217
+ column_name ? t[column_name] : nil
218
+ end
219
+
220
+ def determine_order_by o, x
221
+ if o.orders.any?
222
+ o.orders
223
+ elsif x.groups.any?
224
+ x.groups
225
+ else
226
+ pk = find_left_table_pk(x)
227
+ pk ? [ pk ] : nil # []
228
+ end
229
+ end
230
+
231
+ def generate_order_by orders
232
+ do_visit_columns orders, nil, 'ORDER BY '
233
+ end
234
+
235
+ SQLString = ActiveRecord::ConnectionAdapters::AbstractAdapter::SQLString
236
+ # BindCollector = ActiveRecord::ConnectionAdapters::AbstractAdapter::BindCollector
237
+
238
+ def self.collector_proxy(collector, &block)
239
+ if collector.is_a?(SQLString)
240
+ return SQLStringProxy.new(collector, block)
241
+ end
242
+ BindCollectorProxy.new(collector, block)
243
+ end
244
+
245
+ class BindCollectorProxy < ActiveRecord::ConnectionAdapters::AbstractAdapter::BindCollector
246
+
247
+ def initialize(collector, block); @delegate = collector; @block = block end
248
+
249
+ def << str; @delegate << str; self end
250
+
251
+ def add_bind bind; @delegate.add_bind bind; self end
252
+
253
+ def value; @delegate.value; end
254
+
255
+ #def substitute_binds bvs; @delegate.substitute_binds(bvs); self end
256
+
257
+ def compile(bvs, conn)
258
+ _yield_str @delegate.compile(bvs, conn)
259
+ end
260
+
261
+ private
262
+
263
+ def method_missing(name, *args, &block); @delegate.send(name, args, &block) end
264
+
265
+ def _yield_str(str); @block ? @block.call(str) : str end
266
+
267
+ end
268
+
269
+ class SQLStringProxy < ActiveRecord::ConnectionAdapters::AbstractAdapter::SQLString
270
+
271
+ def initialize(collector, block); @delegate = collector; @block = block end
272
+
273
+ def << str; @delegate << str; self end
274
+
275
+ def add_bind bind; @delegate.add_bind bind; self end
276
+
277
+ def compile(bvs, conn)
278
+ _yield_str @delegate.compile(bvs, conn)
279
+ end
280
+
281
+ private
282
+
283
+ def method_missing(name, *args, &block); @delegate.send(name, args, &block) end
284
+
285
+ def _yield_str(str); @block ? @block.call(str) : str end
286
+
287
+ end
288
+
289
+ end
290
+ end
291
+ end
292
+
293
+ Arel::Visitors::VISITORS['mssql'] = Arel::Visitors::VISITORS['sqlserver'] = Arel::Visitors::SQLServerNG