New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ActiveRecord PostgreSQL adapter: escape range bound values during serialization #39585
base: main
Are you sure you want to change the base?
ActiveRecord PostgreSQL adapter: escape range bound values during serialization #39585
Conversation
621797b
to
ce86eb1
Compare
PostgreSQL uses nested quoting on output for values inside range or composite types under certain conditions(*), which include the format for timestamps. ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Range doesn't handle this in #cast_value. (*) If their string representation contains parentheses, commas, double quotes, backslashes or whitespace (manual section 8.17.5, 8.16.6). This results in a string containing nested quotes being passed to AR::CA::PostgreSQL::OID::DateTime, which causes two problems: * The special-case handling for BCE dates is bypassed, resulting in incorrect positive instead of negative year values. * ActiveModel::Type::DateTime's fast_string_to_time parser can't be used and falls back to Date._parse Note that this PR only implements the escaped range bound format when parsing Postgres output, not when serializing values for Postgres. Postgres also requires its input to be escaped in the same cases, with the exception of whitespace. Fortunately, none of Postgres' pre-defined range types use any characters requiring escaping other than whitespace. See Rails PR rails#39585 for the serialization side.
adccf27
to
4ee7336
Compare
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
4ee7336
to
acdacd9
Compare
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
acdacd9
to
87c3871
Compare
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
87c3871
to
52e7ce1
Compare
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
52e7ce1
to
67f685b
Compare
Is there anything I could do to progress this? |
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
67f685b
to
52d0ec1
Compare
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
52d0ec1
to
82252c9
Compare
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
82252c9
to
1b6c39b
Compare
Postgres requires range bound values containing parentheses, brackets, commas, double quotes, or backslashes to be escaped.
1b6c39b
to
f925656
Compare
Summary
When formatting the bound values of range types, PostgreSQL quotes the value using double-quotes in certain conditions: if its formatted representation contains parentheses, commas, double quotes, backslashes or whitespace (manual section 8.17.5, 8.16.6). When parsing input, it requires escaping in nearly the same conditions: with the exception of whitespace.
As of #37648, escaped output from Postgres is unescaped during deserialization of range values. However, Rails still does not escape values when serializing for Postgres.
Neglecting to escape doesn't actually cause issues with any of Postgres' pre-defined range types (integer, numeric, time, date), because none of them feature values that strictly require escaping on input (they are only escaped on output due to whitespace). However it's possible to define range types for which this would be an issue: for example, ranges defined over strings, enum values, or arrays.
This PR provides an implementation of bound escaping in
ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting#type_cast_range_value
.Questions about the proposed implementation:
type_cast
? In test runs, I seeInteger
andString
. Is it safe to assume that any complex types that would require escaping will have already have been serialized to a string?type_cast
guaranteed to be unaliased? If so the call togsub
could be changed to operate in place.