11require 'arel/visitors/compat'
22
3- loaded = nil
4- if ArJdbc ::AR42
5- require 'arel/visitors/sql_server/ng42.rb'
6- loaded = true
7- end
8-
93module Arel
104 module Visitors
5+ ToSql . class_eval do
6+ alias_method :_visit_Arel_Nodes_SelectStatement , :visit_Arel_Nodes_SelectStatement
7+ end
118 # @note AREL set's up `Arel::Visitors::MSSQL` but its not usable as is ...
129 # @private
1310 class SQLServer < const_defined? ( :MSSQL ) ? MSSQL : ToSql
1411
12+ private
13+
1514 def visit_Arel_Nodes_SelectStatement ( *args ) # [o] AR <= 4.0 [o, a] on 4.1
1615 o , a = args . first , args . last
1716
18- return super if ! o . limit && ! o . offset
17+ return _visit_Arel_Nodes_SelectStatement ( * args ) if ! o . limit && ! o . offset
1918
2019 unless o . orders . empty?
2120 select_order_by = do_visit_columns o . orders , a , 'ORDER BY '
@@ -27,14 +26,14 @@ def visit_Arel_Nodes_SelectStatement(*args) # [o] AR <= 4.0 [o, a] on 4.1
2726 core_order_by = select_order_by || determine_order_by ( x , a )
2827 if select_count? x
2928 x . projections = [
30- core_order_by ? _row_num_literal ( core_order_by ) : Arel ::Nodes ::SqlLiteral . new ( "*" )
29+ Arel ::Nodes ::SqlLiteral . new ( core_order_by ? over_row_num ( core_order_by ) : '*' )
3130 ]
3231 select_count = true
3332 else
3433 # NOTE: this should really be added here and we should built the
3534 # wrapping SQL but than #replace_limit_offset! assumes it does that
3635 # ... MS-SQL adapter code seems to be 'hacked' by a lot of people
37- #x.projections << _row_num_literal (order_by)
36+ #x.projections << Arel::Nodes::SqlLiteral.new over_row_num (order_by)
3837 end
3938 sql << do_visit_select_core ( x , a )
4039 end
@@ -48,7 +47,7 @@ def visit_Arel_Nodes_SelectStatement(*args) # [o] AR <= 4.0 [o, a] on 4.1
4847 add_lock! ( sql , :lock => o . lock && true )
4948
5049 sql
51- end
50+ end unless ArJdbc :: AR42
5251
5352 # @private
5453 MAX_LIMIT_VALUE = 9_223_372_036_854_775_807
@@ -67,19 +66,19 @@ def visit_Arel_Nodes_Lock o, a = nil
6766 #
6867 # we return nothing here and add the appropriate stuff with #add_lock!
6968 #do_visit o.expr, a
70- end
69+ end unless ArJdbc :: AR42
7170
7271 def visit_Arel_Nodes_Top o , a = nil
7372 # `top` wouldn't really work here:
7473 # User.select("distinct first_name").limit(10)
7574 # would generate "select top 10 distinct first_name from users",
7675 # which is invalid should be "select distinct top 10 first_name ..."
77- ''
76+ a || ''
7877 end
7978
8079 def visit_Arel_Nodes_Limit o , a = nil
8180 "TOP (#{ do_visit o . expr , a } )"
82- end
81+ end unless ArJdbc :: AR42
8382
8483 def visit_Arel_Nodes_Ordering o , a = nil
8584 expr = do_visit o . expr , a
@@ -88,7 +87,7 @@ def visit_Arel_Nodes_Ordering o, a = nil
8887 else
8988 expr
9089 end
91- end
90+ end unless ArJdbc :: AR42
9291
9392 def visit_Arel_Nodes_Bin o , a = nil
9493 expr = o . expr ; sql = do_visit expr , a
@@ -98,7 +97,7 @@ def visit_Arel_Nodes_Bin o, a = nil
9897 sql << " #{ ::ArJdbc ::MSSQL . cs_equality_operator } "
9998 sql
10099 end
101- end
100+ end unless ArJdbc :: AR42
102101
103102 private
104103
@@ -110,19 +109,17 @@ def select_count? x
110109 x . projections . length == 1 && Arel ::Nodes ::Count === x . projections . first
111110 end unless possibly_private_method_defined? :select_count?
112111
113- unless possibly_private_method_defined? :determine_order_by
114- def determine_order_by x , a
115- unless x . groups . empty?
116- do_visit_columns x . groups , a , 'ORDER BY '
117- else
118- table_pk = find_left_table_pk ( x , a )
119- table_pk == 'NULL' ? nil : "ORDER BY #{ table_pk } "
120- end
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 } "
121118 end
119+ end
122120
123- def find_left_table_pk o , a
124- primary_key_from_table table_from_select_core ( o )
125- end
121+ def find_left_table_pk o
122+ primary_key_from_table table_from_select_core ( o )
126123 end
127124
128125 def do_visit_columns ( colls , a , sql )
@@ -133,6 +130,18 @@ def do_visit_columns(colls, a, sql)
133130 sql
134131 end
135132
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+
136145 def do_visit_columns ( colls , a , sql )
137146 non_simple_order = /\s ASC|\s DESC|\s CASE|\s COLLATE|[\. ,\[ \( ]/i # MIN(width)
138147
@@ -151,9 +160,9 @@ def do_visit_columns(colls, a, sql)
151160 sql
152161 end if Arel ::VERSION < '4.0.0'
153162
154- def _row_num_literal order_by
155- Arel :: Nodes :: SqlLiteral . new ( "ROW_NUMBER() OVER (#{ order_by } ) as _row_num" )
156- end
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
157166
158167 def table_from_select_core core
159168 if Arel ::Table === core . from
@@ -189,14 +198,14 @@ def primary_key_from_table t
189198 return pk if pk
190199 end
191200
192- pk = @primary_keys [ table_name = engine . table_name ] ||= begin
201+ pk = ( @primary_keys ||= { } ) . fetch ( table_name = engine . table_name ) do
193202 pk_name = @connection . primary_key ( table_name )
194203 # some tables might be without primary key
195- pk_name && t [ pk_name ]
204+ @primary_keys [ table_name ] = pk_name && t [ pk_name ]
196205 end
197206 return pk if pk
198207
199- column_name = engine . columns . first
208+ column_name = engine . columns . first . try ( :name )
200209 column_name && t [ column_name ]
201210 end
202211
@@ -209,5 +218,8 @@ def primary_key_from_table t
209218 class SQLServer2000 < SQLServer
210219 include ArJdbc ::MSSQL ::LimitHelpers ::SqlServer2000ReplaceLimitOffset
211220 end
221+
222+ load 'arel/visitors/sql_server/ng42.rb' if ArJdbc ::AR42
223+
212224 end
213- end unless loaded
225+ end
0 commit comments