Skip to content

Commit 71c59c6

Browse files
authored
Merge pull request rails#44010 from siegfault/dangerous_query_method_allow_nested_functions
Accept nested functions in Dangerous Query Methods
2 parents fa7f977 + 8fe1bd5 commit 71c59c6

File tree

6 files changed

+28
-8
lines changed

6 files changed

+28
-8
lines changed

activerecord/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
* Allow nested functions as safe SQL string
2+
3+
*Michael Siegfried*
4+
15
* Allow `destroy_association_async_job=` to be configured with a class string instead of a constant.
26

37
Defers an autoloading dependency between `ActiveRecord::Base` and `ActiveJob::Base`

activerecord/lib/active_record/connection_adapters/abstract/quoting.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def column_name_with_order_matcher # :nodoc:
167167
(
168168
(?:
169169
# table_name.column_name | function(one or no argument)
170-
((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
170+
((?:\w+\.)?\w+ | \w+\((?:|\g<2>)\))
171171
)
172172
(?:(?:\s+AS)?\s+\w+)?
173173
)
@@ -191,7 +191,7 @@ def column_name_with_order_matcher # :nodoc:
191191
(
192192
(?:
193193
# table_name.column_name | function(one or no argument)
194-
((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
194+
((?:\w+\.)?\w+ | \w+\((?:|\g<2>)\))
195195
)
196196
(?:\s+ASC|\s+DESC)?
197197
(?:\s+NULLS\s+(?:FIRST|LAST))?

activerecord/lib/active_record/connection_adapters/mysql/quoting.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def column_name_with_order_matcher
8484
(
8585
(?:
8686
# `table_name`.`column_name` | function(one or no argument)
87-
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
87+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
8888
)
8989
(?:(?:\s+AS)?\s+(?:\w+|`\w+`))?
9090
)
@@ -97,7 +97,7 @@ def column_name_with_order_matcher
9797
(
9898
(?:
9999
# `table_name`.`column_name` | function(one or no argument)
100-
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
100+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
101101
)
102102
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
103103
(?:\s+ASC|\s+DESC)?

activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def column_name_with_order_matcher
134134
(
135135
(?:
136136
# "schema_name"."table_name"."column_name"::type_name | function(one or no argument)::type_name
137-
((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
137+
((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)? | \w+\((?:|\g<2>)\)(?:::\w+)?)
138138
)
139139
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
140140
)
@@ -147,7 +147,7 @@ def column_name_with_order_matcher
147147
(
148148
(?:
149149
# "schema_name"."table_name"."column_name"::type_name | function(one or no argument)::type_name
150-
((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
150+
((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)? | \w+\((?:|\g<2>)\)(?:::\w+)?)
151151
)
152152
(?:\s+COLLATE\s+"\w+")?
153153
(?:\s+ASC|\s+DESC)?

activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def column_name_with_order_matcher
8686
(
8787
(?:
8888
# "table_name"."column_name" | function(one or no argument)
89-
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
89+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
9090
)
9191
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
9292
)
@@ -99,7 +99,7 @@ def column_name_with_order_matcher
9999
(
100100
(?:
101101
# "table_name"."column_name" | function(one or no argument)
102-
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
102+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
103103
)
104104
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
105105
(?:\s+ASC|\s+DESC)?

activerecord/test/cases/unsafe_raw_sql_test.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,14 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
180180
assert_equal ids_expected, ids
181181
end
182182

183+
test "order: allows nested functions" do
184+
ids_expected = Post.order(Arel.sql("author_id, length(trim(title))")).pluck(:id)
185+
186+
ids = Post.order("author_id, length(trim(title))").pluck(:id)
187+
188+
assert_equal ids_expected, ids
189+
end
190+
183191
test "order: logs deprecation warning for unrecognized column" do
184192
e = assert_raises(ActiveRecord::UnknownAttributeReference) do
185193
Post.order("REPLACE(title, 'misc', 'zzzz')")
@@ -253,6 +261,14 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
253261
assert_equal titles_expected, titles
254262
end
255263

264+
test "pluck: allows nested functions" do
265+
title_lengths_expected = Post.pluck(Arel.sql("length(trim(title))"))
266+
267+
title_lengths = Post.pluck("length(trim(title))")
268+
269+
assert_equal title_lengths_expected, title_lengths
270+
end
271+
256272
test "pluck: disallows invalid column name" do
257273
assert_raises(ActiveRecord::UnknownAttributeReference) do
258274
Post.pluck("REPLACE(title, 'misc', 'zzzz')")

0 commit comments

Comments
 (0)