Skip to content

Commit

Permalink
Handle broken encoding in #write_query?
Browse files Browse the repository at this point in the history
If the SQL encoding somehow is invalid, `Regexp#match?` raises `ArgumentError`.

Best we can do is to copy the string and try to match
the regexp in "binary" mode.

Hopefully these cases are rare enough that the string copy
should be an important overhead.
  • Loading branch information
byroot committed Dec 9, 2021
1 parent 86100a1 commit b629a5b
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 1 deletion.
Expand Up @@ -68,7 +68,7 @@ def self.type_cast_config_to_boolean(config)
def self.build_read_query_regexp(*parts) # :nodoc:
parts += DEFAULT_READ_QUERY
parts = parts.map { |part| /#{part}/i }
/\A(?:[(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
/\A(?:[(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/n
end

def self.quoted_column_names # :nodoc:
Expand Down
Expand Up @@ -26,6 +26,8 @@ def query(sql, name = nil) # :nodoc:

def write_query?(sql) # :nodoc:
!READ_QUERY.match?(sql)
rescue ArgumentError # Invalid encoding
!READ_QUERY.match?(sql.b)
end

def explain(arel, binds = [])
Expand Down
Expand Up @@ -28,6 +28,8 @@ def query(sql, name = nil) # :nodoc:

def write_query?(sql) # :nodoc:
!READ_QUERY.match?(sql)
rescue ArgumentError # Invalid encoding
!READ_QUERY.match?(sql.b)
end

# Executes an SQL statement, returning a PG::Result object on success
Expand Down
Expand Up @@ -11,6 +11,8 @@ module DatabaseStatements

def write_query?(sql) # :nodoc:
!READ_QUERY.match?(sql)
rescue ArgumentError # Invalid encoding
!READ_QUERY.match?(sql.b)
end

def explain(arel, binds = [])
Expand Down
19 changes: 19 additions & 0 deletions activerecord/test/cases/adapter_prevent_writes_test.rb
Expand Up @@ -51,6 +51,25 @@ def test_errors_when_a_delete_query_is_called_while_preventing_writes
end
end

if current_adapter?(:PostgreSQLAdapter)
def test_doesnt_error_when_a_select_query_has_encoding_errors
ActiveRecord::Base.while_preventing_writes do
# Contrary to other adapters, Postgres will eagerly fail on encoding errors.
# But at least we can assert it fails in the client and not before when trying to
# match the query.
assert_raises ActiveRecord::StatementInvalid do
@connection.select_all("SELECT '\xC8'")
end
end
end
else
def test_doesnt_error_when_a_select_query_has_encoding_errors
ActiveRecord::Base.while_preventing_writes do
@connection.select_all("SELECT '\xC8'")
end
end
end

def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
@connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')")

Expand Down

0 comments on commit b629a5b

Please sign in to comment.