-
-
Notifications
You must be signed in to change notification settings - Fork 250
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
overhaul our Postgres Range support #1050
Conversation
Apologizes to @mhov... this isn't very faithful to your original impl from #663, but it has greatly improved ergonomics from the user-facing API side along with better interoperability with Rust's I'd appreciate it if you'd look it over and let me know what you think. My intention is to merge this in the next day or two. |
I wasn't attached to my implementation, no worries. As a serious RangeType end user, I'll try it out and review soon. Thanks @eeeebbbbrrrr |
Ok, 100% more ergonomic and doesn't look like it was someone first year doing Rust. My main concern with my implementation was Range->Range was an implicit @workingjubilee might be able to elaborate better than me, but in the 4.5.0->0.5.0 period there was an effort to move non-trivial conversion logic out of the Into/FromDatum to the user code so it wouldn't cost anything until you actually needed it. Corner-case as it may be if we had a With I can think of a bunch of other contrived cases which may, understandably, lose out to ergonomics. Please tell me if I'm over-optimizing. As a C extension developer of a very performance-sensitive project, I'm in the zero-copy pgx gang. I'm afraid of losing any time to pgx wrappers/overhead. I understand I'm a different user from those who have never done C and their first pg extension is in The great part about the Side question, would we ever want a |
Are you using Yes, this PR does the FromDatum conversion on both bounds when the Range itself is deconstructed, but these conversions only now only happen once per Range, whereas the current implementation would do that conversion every time the user asked for one of the bound values. There was also a problem where the Datums behind the lower/upper bounds could have been pfree'd out from underneath the user without them knowing (that's a problem with all "zero copy" type impls, especially the FromDatum impl for &str), leading to UAF. And this could be a problem for any pass-by-reference range type -- specifically As it is now, for pass-by-value ranges such as int4/8range and date/timerange types, I'd expect the compiler to basically optimize all the machinery away such that the bounds become the backing Datum value, as-is. However, Circling back to large arrays of values... the point is well received, and I think it underscores that we need to do more work on making array support fully zero-copy and lazily evaluated where we can. Although, |
Thinking about the TypeCache thing... I'm not sure how we can mitigate that right now. It would require some thought and changes to |
- We now go ahead and deconstruct the range value in the `FromDatum` implementation. Immediately, this fixes issues with `pg_sys::RangeBound.val` datums potentially being able to be used after free. - `RangeData` is gone and replaced with a more idiomatic `RangeBound` enum, to which the internal Postgres `pg_sys::RangeBound` struct can be mapped. - We provide `From<std::ops::Range*>` impls for all of Rust's built-in Range types. - Our `pgx::Range` can be constructed from any type that can be converted into a `RangeBound` and we provide direct impls for the set of supported `RangeSubType` types along with `Option<T: RangeSubType>` which maps `Some` to `::Inclusive` and `None` to `::Infinite`. - The idea that a Postgres range can be "empty" is properly relayed through `Range`'s public API - add an example (albeit puny)
18a8bc4
to
9922454
Compare
I had to recreate this branch with cherry-picks and do a force push because I have no idea. |
git be like that sometimes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry it took me a bit to get through things on top of the squirreling on other topics. I probably need to glance over it again still.
- add a few help methods to `RangeBound` - `impl Display for Range<T> where T: Display`
@workingjubilee I've addressed all your concerns and for fun, added a few |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Yes, this looks good now.
We now go ahead and deconstruct the range value in the
FromDatum
implementation. Immediately, this fixes issues withpg_sys::RangeBound.val
datums potentially being used after free.RangeData
is gone and replaced with a more idiomaticRangeBound
enum, to which the internal Postgrespg_sys::RangeBound
struct can be mapped.We provide
From<std::ops::Range*>
impls for all of Rust's built-in Range types.Our
pgx::Range
can be constructed from any type that can be converted into aRangeBound
and we provide direct impls for the set of supportedRangeSubType
types along withOption<T: RangeSubType>
which mapsSome
to::Inclusive
andNone
to::Infinite
.The idea that a Postgres range can be "empty" is properly relayed through
Range
's public APIadd an example (albeit puny)