activerecord-jdbc-adapter-ficoh 1.3.21-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.travis.yml +462 -0
  4. data/.yardopts +4 -0
  5. data/Appraisals +36 -0
  6. data/CONTRIBUTING.md +49 -0
  7. data/Gemfile +68 -0
  8. data/History.md +1191 -0
  9. data/LICENSE.txt +25 -0
  10. data/README.md +277 -0
  11. data/RUNNING_TESTS.md +88 -0
  12. data/Rakefile +298 -0
  13. data/Rakefile.jdbc +20 -0
  14. data/activerecord-jdbc-adapter.gemspec +63 -0
  15. data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
  16. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
  17. data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
  18. data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
  19. data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
  20. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
  21. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  22. data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
  23. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  24. data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
  25. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  26. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
  28. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  29. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  30. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  31. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  32. data/lib/activerecord-jdbc-adapter.rb +1 -0
  33. data/lib/arel/visitors/compat.rb +64 -0
  34. data/lib/arel/visitors/db2.rb +137 -0
  35. data/lib/arel/visitors/derby.rb +112 -0
  36. data/lib/arel/visitors/firebird.rb +79 -0
  37. data/lib/arel/visitors/h2.rb +25 -0
  38. data/lib/arel/visitors/hsqldb.rb +32 -0
  39. data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
  40. data/lib/arel/visitors/sql_server.rb +225 -0
  41. data/lib/arel/visitors/sql_server/ng42.rb +293 -0
  42. data/lib/arjdbc.rb +22 -0
  43. data/lib/arjdbc/db2.rb +4 -0
  44. data/lib/arjdbc/db2/adapter.rb +802 -0
  45. data/lib/arjdbc/db2/as400.rb +137 -0
  46. data/lib/arjdbc/db2/column.rb +177 -0
  47. data/lib/arjdbc/db2/connection_methods.rb +45 -0
  48. data/lib/arjdbc/derby.rb +3 -0
  49. data/lib/arjdbc/derby/active_record_patch.rb +13 -0
  50. data/lib/arjdbc/derby/adapter.rb +567 -0
  51. data/lib/arjdbc/derby/connection_methods.rb +16 -0
  52. data/lib/arjdbc/derby/schema_creation.rb +15 -0
  53. data/lib/arjdbc/discover.rb +104 -0
  54. data/lib/arjdbc/firebird.rb +4 -0
  55. data/lib/arjdbc/firebird/adapter.rb +468 -0
  56. data/lib/arjdbc/firebird/connection_methods.rb +20 -0
  57. data/lib/arjdbc/h2.rb +3 -0
  58. data/lib/arjdbc/h2/adapter.rb +335 -0
  59. data/lib/arjdbc/h2/connection_methods.rb +22 -0
  60. data/lib/arjdbc/hsqldb.rb +3 -0
  61. data/lib/arjdbc/hsqldb/adapter.rb +304 -0
  62. data/lib/arjdbc/hsqldb/connection_methods.rb +23 -0
  63. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  64. data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
  65. data/lib/arjdbc/informix.rb +5 -0
  66. data/lib/arjdbc/informix/adapter.rb +160 -0
  67. data/lib/arjdbc/informix/connection_methods.rb +9 -0
  68. data/lib/arjdbc/jdbc.rb +62 -0
  69. data/lib/arjdbc/jdbc/adapter.rb +997 -0
  70. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  71. data/lib/arjdbc/jdbc/arel_support.rb +149 -0
  72. data/lib/arjdbc/jdbc/base_ext.rb +34 -0
  73. data/lib/arjdbc/jdbc/callbacks.rb +52 -0
  74. data/lib/arjdbc/jdbc/column.rb +83 -0
  75. data/lib/arjdbc/jdbc/connection.rb +26 -0
  76. data/lib/arjdbc/jdbc/connection_methods.rb +59 -0
  77. data/lib/arjdbc/jdbc/driver.rb +44 -0
  78. data/lib/arjdbc/jdbc/error.rb +75 -0
  79. data/lib/arjdbc/jdbc/extension.rb +69 -0
  80. data/lib/arjdbc/jdbc/java.rb +13 -0
  81. data/lib/arjdbc/jdbc/type_cast.rb +154 -0
  82. data/lib/arjdbc/jdbc/type_converter.rb +142 -0
  83. data/lib/arjdbc/mssql.rb +7 -0
  84. data/lib/arjdbc/mssql/adapter.rb +822 -0
  85. data/lib/arjdbc/mssql/column.rb +207 -0
  86. data/lib/arjdbc/mssql/connection_methods.rb +72 -0
  87. data/lib/arjdbc/mssql/explain_support.rb +99 -0
  88. data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
  89. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  90. data/lib/arjdbc/mssql/types.rb +343 -0
  91. data/lib/arjdbc/mssql/utils.rb +82 -0
  92. data/lib/arjdbc/mysql.rb +3 -0
  93. data/lib/arjdbc/mysql/adapter.rb +998 -0
  94. data/lib/arjdbc/mysql/bulk_change_table.rb +150 -0
  95. data/lib/arjdbc/mysql/column.rb +167 -0
  96. data/lib/arjdbc/mysql/connection_methods.rb +137 -0
  97. data/lib/arjdbc/mysql/explain_support.rb +82 -0
  98. data/lib/arjdbc/mysql/schema_creation.rb +58 -0
  99. data/lib/arjdbc/oracle.rb +4 -0
  100. data/lib/arjdbc/oracle/adapter.rb +968 -0
  101. data/lib/arjdbc/oracle/column.rb +136 -0
  102. data/lib/arjdbc/oracle/connection_methods.rb +21 -0
  103. data/lib/arjdbc/postgresql.rb +3 -0
  104. data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +21 -0
  105. data/lib/arjdbc/postgresql/adapter.rb +1498 -0
  106. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  107. data/lib/arjdbc/postgresql/base/oid.rb +412 -0
  108. data/lib/arjdbc/postgresql/base/pgconn.rb +8 -0
  109. data/lib/arjdbc/postgresql/base/schema_definitions.rb +132 -0
  110. data/lib/arjdbc/postgresql/column.rb +640 -0
  111. data/lib/arjdbc/postgresql/connection_methods.rb +44 -0
  112. data/lib/arjdbc/postgresql/explain_support.rb +53 -0
  113. data/lib/arjdbc/postgresql/oid/bytea.rb +3 -0
  114. data/lib/arjdbc/postgresql/oid_types.rb +265 -0
  115. data/lib/arjdbc/postgresql/schema_creation.rb +60 -0
  116. data/lib/arjdbc/railtie.rb +11 -0
  117. data/lib/arjdbc/sqlite3.rb +3 -0
  118. data/lib/arjdbc/sqlite3/adapter.rb +654 -0
  119. data/lib/arjdbc/sqlite3/connection_methods.rb +36 -0
  120. data/lib/arjdbc/sqlite3/explain_support.rb +29 -0
  121. data/lib/arjdbc/sybase.rb +2 -0
  122. data/lib/arjdbc/sybase/adapter.rb +47 -0
  123. data/lib/arjdbc/tasks.rb +13 -0
  124. data/lib/arjdbc/tasks/database_tasks.rb +66 -0
  125. data/lib/arjdbc/tasks/databases.rake +91 -0
  126. data/lib/arjdbc/tasks/databases3.rake +239 -0
  127. data/lib/arjdbc/tasks/databases4.rake +39 -0
  128. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  129. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  130. data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
  131. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  132. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
  133. data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
  134. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +297 -0
  135. data/lib/arjdbc/tasks/oracle_database_tasks.rb +65 -0
  136. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  137. data/lib/arjdbc/util/serialized_attributes.rb +98 -0
  138. data/lib/arjdbc/util/table_copier.rb +108 -0
  139. data/lib/arjdbc/version.rb +8 -0
  140. data/lib/generators/jdbc/USAGE +9 -0
  141. data/lib/generators/jdbc/jdbc_generator.rb +17 -0
  142. data/pom.xml +285 -0
  143. data/rails_generators/jdbc_generator.rb +15 -0
  144. data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
  145. data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
  146. data/rakelib/01-tomcat.rake +51 -0
  147. data/rakelib/02-test.rake +151 -0
  148. data/rakelib/bundler_ext.rb +11 -0
  149. data/rakelib/db.rake +58 -0
  150. data/rakelib/rails.rake +77 -0
  151. data/src/java/arjdbc/ArJdbcModule.java +288 -0
  152. data/src/java/arjdbc/db2/DB2Module.java +77 -0
  153. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +128 -0
  154. data/src/java/arjdbc/derby/DerbyModule.java +180 -0
  155. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +153 -0
  156. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +190 -0
  157. data/src/java/arjdbc/h2/H2Module.java +50 -0
  158. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +86 -0
  159. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +74 -0
  160. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +76 -0
  161. data/src/java/arjdbc/jdbc/AdapterJavaService.java +43 -0
  162. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  163. data/src/java/arjdbc/jdbc/ConnectionFactory.java +77 -0
  164. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +156 -0
  165. data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
  166. data/src/java/arjdbc/jdbc/DriverWrapper.java +128 -0
  167. data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +32 -0
  168. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +4541 -0
  169. data/src/java/arjdbc/jdbc/SQLBlock.java +54 -0
  170. data/src/java/arjdbc/jdbc/WithResultSet.java +37 -0
  171. data/src/java/arjdbc/mssql/MSSQLModule.java +91 -0
  172. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +193 -0
  173. data/src/java/arjdbc/mysql/MySQLModule.java +140 -0
  174. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +456 -0
  175. data/src/java/arjdbc/oracle/OracleModule.java +81 -0
  176. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +477 -0
  177. data/src/java/arjdbc/postgresql/ByteaUtils.java +171 -0
  178. data/src/java/arjdbc/postgresql/DriverImplementation.java +78 -0
  179. data/src/java/arjdbc/postgresql/PGDriverImplementation.java +535 -0
  180. data/src/java/arjdbc/postgresql/PostgreSQLModule.java +189 -0
  181. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +489 -0
  182. data/src/java/arjdbc/sqlite3/SQLite3Module.java +93 -0
  183. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +405 -0
  184. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  185. data/src/java/arjdbc/util/DateTimeUtils.java +517 -0
  186. data/src/java/arjdbc/util/NumberUtils.java +50 -0
  187. data/src/java/arjdbc/util/ObjectSupport.java +65 -0
  188. data/src/java/arjdbc/util/QuotingUtils.java +139 -0
  189. data/src/java/arjdbc/util/StringCache.java +60 -0
  190. data/src/java/arjdbc/util/StringHelper.java +155 -0
  191. metadata +288 -0
@@ -0,0 +1,79 @@
1
+ require 'arel/visitors/compat'
2
+
3
+ module Arel
4
+ module Visitors
5
+ class Firebird < Arel::Visitors::ToSql
6
+
7
+ if ArJdbc::AR42
8
+ def visit_Arel_Nodes_SelectStatement(o, a)
9
+ a = o.cores.inject(a) { |c, x| visit_Arel_Nodes_SelectCore(x, c) }
10
+
11
+ limit, offset = o.limit, o.offset
12
+ if limit || offset
13
+ select = a.parts[0]
14
+
15
+ sql = Arel::Collectors::SQLString.new
16
+ visit(limit, sql) if limit
17
+ if offset
18
+ sql << ' ' if limit
19
+ visit(offset, sql)
20
+ end
21
+
22
+ a.parts[0] = "#{select} #{sql.value}"
23
+ end
24
+
25
+ unless o.orders.empty?
26
+ a << ' ORDER BY '
27
+ last = o.orders.length - 1
28
+ o.orders.each_with_index do |x, i|
29
+ visit(x, a); a << ', ' unless last == i
30
+ end
31
+ end
32
+
33
+ a
34
+ end
35
+
36
+ def visit_Arel_Nodes_Limit(o, a)
37
+ a << "FIRST #{limit_for(o)}"
38
+ end
39
+
40
+ def visit_Arel_Nodes_Offset(o, a)
41
+ a << 'SKIP '; visit(o.value, a)
42
+ end
43
+
44
+ else
45
+
46
+ def visit_Arel_Nodes_SelectStatement o, a = nil
47
+ if o.limit
48
+ limit = do_visit o.limit.expr, a
49
+ else
50
+ limit = nil
51
+ end
52
+ if o.offset
53
+ offset = do_visit o.offset.expr, a
54
+ else
55
+ offset = nil
56
+ end
57
+
58
+ sql = o.cores.map { |x| do_visit_select_core x, a }.join
59
+ @connection.insert_limit_offset!(sql, limit, offset) if limit || offset
60
+
61
+ unless o.orders.empty?
62
+ sql << ' ORDER BY '
63
+ last = o.orders.length - 1
64
+ o.orders.each_with_index do |x, i|
65
+ sql << do_visit(x, a); sql << ', ' unless last == i
66
+ end
67
+ end
68
+
69
+ sql
70
+ end
71
+ end
72
+
73
+ end
74
+ end
75
+ end
76
+
77
+ Arel::Collectors::Bind.class_eval do
78
+ attr_reader :parts
79
+ end if defined? Arel::Collectors::Bind
@@ -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
@@ -0,0 +1,32 @@
1
+ require 'arel/visitors/compat'
2
+
3
+ module Arel
4
+ module Visitors
5
+ class HSQLDB < Arel::Visitors::ToSql
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
18
+
19
+ def limit_offset sql, o
20
+ offset = o.offset || 0
21
+ offset = offset.expr unless (offset.nil? || offset == 0)
22
+ if limit = o.limit
23
+ "SELECT LIMIT #{offset} #{limit_for(limit)} #{sql[7..-1]}"
24
+ elsif offset > 0
25
+ "SELECT LIMIT #{offset} 0 #{sql[7..-1]}" # removes "SELECT "
26
+ else
27
+ sql
28
+ end
29
+ end unless ArJdbc::AR42
30
+ end
31
+ end
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