feat: partial multi-query support - #1432
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
sgrif
left a comment
There was a problem hiding this comment.
The transaction_safe check feels a little overboard to me, but this seems fine since we intend to move to implicit transactions down the line.
With the changes to how planning works that John and I are working on, we're thinking we may end up having communication with the shards always use the extended protocol if the query parser is enabled, which will make auto-transactions much easier both here and with any other 1->N rewrites we do going forward.
|
|
||
| #[tokio::test] | ||
| async fn test_multi_set_mixed_returns_error() { | ||
| async fn test_multi_set_mixed_works() { |
| /// Return true if we should ignore this query because | ||
| /// the simple query pipeline is in an error state, i.e., inside a failed | ||
| /// transaction. | ||
| pub(super) fn simple_pipeline_check(&self, context: &QueryEngineContext<'_>) -> bool { |
There was a problem hiding this comment.
What do you think about making this a bit more descriptive?
| pub(super) fn simple_pipeline_check(&self, context: &QueryEngineContext<'_>) -> bool { | |
| pub(super) fn in_errored_simple_pipeline(&self, context: &QueryEngineContext<'_>) -> bool { |
| /// Query engine pipeline state. | ||
| pub(crate) enum Pipeline { | ||
| Extended { requests_left: usize }, | ||
| Simple { requests_left: usize }, | ||
| None, | ||
| } |
There was a problem hiding this comment.
I like this structure. Long term I think it'd be nice to have more of the state bundled here (not asking for that to be changed in this PR)
What
Support multi-statement queries sent via the simple protocol if they can be safely executed without us having to do anything fancy with transactions.
Preface
A multi-statement query looks something like this:
They are sent inside a single
Querymessage and Postgres is expected to process all commands sequentially and inside a single, implicit transaction.This presents an issue for sharded deployments, since queries might need to go to different shards. So, what can we do about this?
Split and execute
Since we have the Postgres parser handy, we can split the query and execute each statement separately. One caveat here is we won't start a transaction inside Postgres automatically (at least, not yet), so we have to be careful about which statements we can execute safely.
SETmixed with one queryThis is totally safe (and quite common):
We can split these up, execute them separately, without breaking transactional guarantees. Only one statement actually reads data, while PgDog handles
SETinternally. This type of query will, as of this PR, be executed normally. Yay!Conversely, the following cannot be split safely (yet) and will continue to return an error from us:
You can set as many things as you want:
This is safe to execute because only one query actually cares about data, and the rest is handled by PgDog or is inconsequential if executed outside a transaction.
DDL
This is quite common (e.g., in migration scripts) and is quite safe to execute without splitting at all. We send this query to all shards concurrently. No problems.
Manual transactions
This happens sometimes and now works correctly:
This is safe to split and execute because client starts a transaction and we can handle those no problem. If the transaction returns an error, the remaining statements are not executed; same behavior as regular Postgres.
Checks
Other things we check for and block now:
BEGIN; SELECT 1;. Bad! Blocked.This is only relevant for a single
Querymessage. Normal query flow is not affected by this change.