@@ -11,13 +11,14 @@ class SQLServer < Arel::Visitors::ToSql
1111
1212 private
1313
14- # SQLServer ToSql/Visitor (Overides )
14+ # SQLServer ToSql/Visitor (Overrides )
1515
16- def visit_Arel_Nodes_BindParam o , collector
17- collector . add_bind ( o . value ) { |i | "@#{ i - 1 } " }
18- end
16+ BIND_BLOCK = proc { |i | "@#{ i - 1 } " }
17+ private_constant :BIND_BLOCK
18+
19+ def bind_block ; BIND_BLOCK ; end
1920
20- def visit_Arel_Nodes_Bin o , collector
21+ def visit_Arel_Nodes_Bin ( o , collector )
2122 visit o . expr , collector
2223 collector << " #{ ActiveRecord ::ConnectionAdapters ::SQLServerAdapter . cs_equality_operator } "
2324 end
@@ -28,26 +29,26 @@ def visit_Arel_Nodes_Concat(o, collector)
2829 visit o . right , collector
2930 end
3031
31- def visit_Arel_Nodes_UpdateStatement ( o , a )
32+ def visit_Arel_Nodes_UpdateStatement ( o , collector )
3233 if o . orders . any? && o . limit . nil?
3334 o . limit = Nodes ::Limit . new ( 9_223_372_036_854_775_807 )
3435 end
3536 super
3637 end
3738
38- def visit_Arel_Nodes_Lock o , collector
39+ def visit_Arel_Nodes_Lock ( o , collector )
3940 o . expr = Arel . sql ( "WITH(UPDLOCK)" ) if o . expr . to_s =~ /FOR UPDATE/
4041 collector << " "
4142 visit o . expr , collector
4243 end
4344
44- def visit_Arel_Nodes_Offset o , collector
45+ def visit_Arel_Nodes_Offset ( o , collector )
4546 collector << OFFSET
4647 visit o . expr , collector
4748 collector << ROWS
4849 end
4950
50- def visit_Arel_Nodes_Limit o , collector
51+ def visit_Arel_Nodes_Limit ( o , collector )
5152 if node_value ( o ) == 0
5253 collector << FETCH0
5354 collector << ROWS_ONLY
@@ -63,7 +64,36 @@ def visit_Arel_Nodes_Grouping(o, collector)
6364 super
6465 end
6566
66- def visit_Arel_Nodes_SelectStatement o , collector
67+ def visit_Arel_Nodes_HomogeneousIn ( o , collector )
68+ collector . preparable = false
69+
70+ collector << quote_table_name ( o . table_name ) << "." << quote_column_name ( o . column_name )
71+
72+ if o . type == :in
73+ collector << " IN ("
74+ else
75+ collector << " NOT IN ("
76+ end
77+
78+ values = o . casted_values
79+
80+ if values . empty?
81+ collector << @connection . quote ( nil )
82+ else
83+ # Monkey-patch start. Add query attribute bindings rather than just values.
84+ column_name = o . column_name
85+ column_type = o . attribute . relation . type_for_attribute ( o . column_name )
86+ attrs = values . map { |value | ActiveRecord ::Relation ::QueryAttribute . new ( column_name , value , column_type ) }
87+
88+ collector . add_binds ( attrs , &bind_block )
89+ # Monkey-patch end.
90+ end
91+
92+ collector << ")"
93+ collector
94+ end
95+
96+ def visit_Arel_Nodes_SelectStatement ( o , collector )
6797 @select_statement = o
6898 distinct_One_As_One_Is_So_Not_Fetch o
6999 if o . with
@@ -90,7 +120,7 @@ def visit_Arel_Nodes_OptimizerHints(o, collector)
90120 collector << "OPTION (#{ hints } )"
91121 end
92122
93- def visit_Arel_Table o , collector
123+ def visit_Arel_Table ( o , collector )
94124 # Apparently, o.engine.connection can actually be a different adapter
95125 # than sqlserver. Can be removed if fixed in ActiveRecord. See:
96126 # github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/450
@@ -112,7 +142,7 @@ def visit_Arel_Table o, collector
112142 end
113143 end
114144
115- def visit_Arel_Nodes_JoinSource o , collector
145+ def visit_Arel_Nodes_JoinSource ( o , collector )
116146 if o . left
117147 collector = visit o . left , collector
118148 collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector
@@ -124,7 +154,7 @@ def visit_Arel_Nodes_JoinSource o, collector
124154 collector
125155 end
126156
127- def visit_Arel_Nodes_InnerJoin o , collector
157+ def visit_Arel_Nodes_InnerJoin ( o , collector )
128158 if o . left . is_a? ( Arel ::Nodes ::As ) && o . left . left . is_a? ( Arel ::Nodes ::Lateral )
129159 collector << "CROSS "
130160 visit o . left , collector
@@ -141,7 +171,7 @@ def visit_Arel_Nodes_InnerJoin o, collector
141171 end
142172 end
143173
144- def visit_Arel_Nodes_OuterJoin o , collector
174+ def visit_Arel_Nodes_OuterJoin ( o , collector )
145175 if o . left . is_a? ( Arel ::Nodes ::As ) && o . left . left . is_a? ( Arel ::Nodes ::Lateral )
146176 collector << "OUTER "
147177 visit o . left , collector
@@ -170,15 +200,15 @@ def collect_optimizer_hints(o, collector)
170200
171201 # SQLServer ToSql/Visitor (Additions)
172202
173- def visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector , options = { }
203+ def visit_Arel_Nodes_SelectStatement_SQLServer_Lock ( collector , options = { } )
174204 if select_statement_lock?
175205 collector = visit @select_statement . lock , collector
176206 collector << " " if options [ :space ]
177207 end
178208 collector
179209 end
180210
181- def visit_Orders_And_Let_Fetch_Happen o , collector
211+ def visit_Orders_And_Let_Fetch_Happen ( o , collector )
182212 make_Fetch_Possible_And_Deterministic o
183213 unless o . orders . empty?
184214 collector << " ORDER BY "
@@ -191,14 +221,14 @@ def visit_Orders_And_Let_Fetch_Happen o, collector
191221 collector
192222 end
193223
194- def visit_Make_Fetch_Happen o , collector
224+ def visit_Make_Fetch_Happen ( o , collector )
195225 o . offset = Nodes ::Offset . new ( 0 ) if o . limit && !o . offset
196226 collector = visit o . offset , collector if o . offset
197227 collector = visit o . limit , collector if o . limit
198228 collector
199229 end
200230
201- def visit_Arel_Nodes_Lateral o , collector
231+ def visit_Arel_Nodes_Lateral ( o , collector )
202232 collector << "APPLY"
203233 collector << " "
204234 if o . expr . is_a? ( Arel ::Nodes ::SelectStatement )
@@ -226,7 +256,7 @@ def select_statement_lock?
226256 @select_statement && @select_statement . lock
227257 end
228258
229- def make_Fetch_Possible_And_Deterministic o
259+ def make_Fetch_Possible_And_Deterministic ( o )
230260 return if o . limit . nil? && o . offset . nil?
231261
232262 t = table_From_Statement o
@@ -239,7 +269,7 @@ def make_Fetch_Possible_And_Deterministic o
239269 end
240270 end
241271
242- def distinct_One_As_One_Is_So_Not_Fetch o
272+ def distinct_One_As_One_Is_So_Not_Fetch ( o )
243273 core = o . cores . first
244274 distinct = Nodes ::Distinct === core . set_quantifier
245275 oneasone = core . projections . all? { |x | x == ActiveRecord ::FinderMethods ::ONE_AS_ONE }
@@ -250,7 +280,7 @@ def distinct_One_As_One_Is_So_Not_Fetch o
250280 end
251281 end
252282
253- def table_From_Statement o
283+ def table_From_Statement ( o )
254284 core = o . cores . first
255285 if Arel ::Table === core . from
256286 core . from
@@ -261,15 +291,15 @@ def table_From_Statement o
261291 end
262292 end
263293
264- def primary_Key_From_Table t
294+ def primary_Key_From_Table ( t )
265295 return unless t
266296
267297 column_name = @connection . schema_cache . primary_keys ( t . name ) ||
268- @connection . schema_cache . columns_hash ( t . name ) . first . try ( :second ) . try ( :name )
298+ @connection . schema_cache . columns_hash ( t . name ) . first . try ( :second ) . try ( :name )
269299 column_name ? t [ column_name ] : nil
270300 end
271301
272- def remote_server_table_name o
302+ def remote_server_table_name ( o )
273303 ActiveRecord ::ConnectionAdapters ::SQLServer ::Utils . extract_identifiers (
274304 "#{ o . class . engine . connection . database_prefix } #{ o . name } "
275305 ) . quoted
0 commit comments