Skip to content

Commit e4a921a

Browse files
committed
whitelist NULLS { FIRST | LAST } in order clauses
1 parent 718e4c6 commit e4a921a

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

activerecord/lib/active_record/attribute_methods.rb

+8-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,14 @@ def attribute_names
177177
# "#{table_name}.#{column_name} #{direction}"
178178
# "#{column_name}"
179179
# "#{column_name} #{direction}"
180-
COLUMN_NAME_ORDER_WHITELIST = /\A(?:\w+\.)?\w+(?:\s+asc|\s+desc)?\z/i
180+
COLUMN_NAME_ORDER_WHITELIST = /
181+
\A
182+
(?:\w+\.)?
183+
\w+
184+
(?:\s+asc|\s+desc)?
185+
(?:\s+nulls\s+(?:first|last))?
186+
\z
187+
/ix
181188

182189
def enforce_raw_sql_whitelist(args, whitelist: COLUMN_NAME_WHITELIST) # :nodoc:
183190
unexpected = args.reject do |arg|

activerecord/test/cases/unsafe_raw_sql_test.rb

+20
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
107107
assert_equal ids_expected, ids_disabled
108108
end
109109

110+
test "order: allows NULLS FIRST and NULLS LAST too" do
111+
raise "precondition failed" if Post.count < 2
112+
113+
# Ensure there are NULL and non-NULL post types.
114+
Post.first.update_column(:type, nil)
115+
Post.last.update_column(:type, "Programming")
116+
117+
["asc", "desc", ""].each do |direction|
118+
%w(first last).each do |position|
119+
ids_expected = Post.order(Arel.sql("type #{direction} nulls #{position}")).pluck(:id)
120+
121+
ids_depr = with_unsafe_raw_sql_deprecated { Post.order("type #{direction} nulls #{position}").pluck(:id) }
122+
ids_disabled = with_unsafe_raw_sql_disabled { Post.order("type #{direction} nulls #{position}").pluck(:id) }
123+
124+
assert_equal ids_expected, ids_depr
125+
assert_equal ids_expected, ids_disabled
126+
end
127+
end
128+
end if current_adapter?(:PostgreSQLAdapter)
129+
110130
test "order: disallows invalid column name" do
111131
with_unsafe_raw_sql_disabled do
112132
assert_raises(ActiveRecord::UnknownAttributeReference) do

0 commit comments

Comments
 (0)