Can Execute commands for different portals interleave?
От | Evgeny Smirnov |
---|---|
Тема | Can Execute commands for different portals interleave? |
Дата | |
Msg-id | CAB9opTEJaxY4DLkPB1S3vEGpv6Sp4bM3NK+EbcS5fVQxvGqwQw@mail.gmail.com обсуждение исходный текст |
Ответы |
Re: Can Execute commands for different portals interleave?
|
Список | pgsql-hackers |
Greetings!
The question (a short version): is it possible for a client to send two selects in the same transaction using the extended query protocol (without declaring cursors) and pull rows simultaneously by means of interleaving portal names and restricting fetch size in Execute commands.
The question (a long version with a motivation):
A Postgresql backend is capable of operating multiple portals within a transaction and switching between them on and off. For instance the following sequence (issued from a kotlin application via r2dbc-driver not from psql)
```
// The table users_Fetch contains users with ids between 1 and 20
BEGIN
DECLARE fetch_test1 SCROLL CURSOR FOR SELECT userId FROM users_Fetch;
DECLARE fetch_test2 SCROLL CURSOR FOR SELECT userId FROM users_Fetch;
MOVE FORWARD 3 FROM fetch_test1;
FETCH FORWARD 5 FROM fetch_test1;
FETCH FORWARD 5 FROM fetch_test2;
select userId from users_Fetch;
FETCH BACKWARD 5 FROM fetch_test1;
FETCH FORWARD 5 FROM fetch_test2;
COMMIT;
```
results in an expected outcome:
```
4, 5, 6, 7, 8, // MOVE FORWARD 3 FROM fetch_test1; FETCH FORWARD 5 FROM fetch_test1;
1, 2, 3, 4, 5, // FETCH FORWARD 5 FROM fetch_test2;
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, // select userId from users_Fetch;
7, 6, 5, 4, 3, // FETCH BACKWARD 5 FROM fetch_test1;
6, 7, 8, 9, 10, // FETCH FORWARD 5 FROM fetch_test2;
```
Is the same possible for conventional selects issued with extended query protocol? From the protocol perspective it would result in the following traffic:
```
231 53111 5432 PGSQL 109 >Q ———> BEGIN
232 5432 53111 TCP 56 5432 → 53111 [ACK] Seq=1 Ack=54 Win=6371 Len=0 TSval=2819351776 TSecr=589492423
237 5432 53111 PGSQL 73 <C/Z
238 53111 5432 TCP 56 53111 → 5432 [ACK] Seq=54 Ack=18 Win=6366 Len=0 TSval=589492435 TSecr=2819351788
// A client issues a select
239 53111 5432 PGSQL 276 >P/B/D/E/H ———> select * from …; bind B_1; execute B_1, fetch 2 rows; flush
240 5432 53111 TCP 56 5432 → 53111 [ACK] Seq=18 Ack=274 Win=6368 Len=0 TSval=2819351793 TSecr=589492440
245 5432 53111 PGSQL 552 <1/2/T/D/D/s ———> Data, Data, Portal suspended
…
// Then the same sequence for another prepared statement and portal (lets say B_2) but without a limit in the Execute command and sync at the end.
…
// Then the client proceeds with B_1 till the completion
270 53111 5432 PGSQL 69 > E ———> execute B_1, fetch 2 rows,
271 5432 53111 TCP 56 5432 → 53111 [ACK] Seq=925 Ack=323 Win=6367 Len=0 TSval=2819351846 TSecr=589492493
272 53111 5432 PGSQL 61 >H ———> Flush
274 5432 53111 TCP 56 5432 → 53111 [ACK] Seq=925 Ack=328 Win=6367 Len=0 TSval=2819351846 TSecr=589492493
282 5432 53111 PGSQL 144 <D/C ———> Command completion
283 53111 5432 TCP 56 53111 → 5432 [ACK] Seq=328 Ack=1013 Win=6351 Len=0 TSval=589492496 TSecr=2819351849
284 53111 5432 PGSQL 66 >C ———> Close B_1
285 5432 53111 TCP 56 5432 → 53111 [ACK] Seq=1013 Ack=338 Win=6367 Len=0 TSval=2819351849 TSecr=589492496
286 53111 5432 PGSQL 61 >S ———> Sync
287 5432 53111 TCP 56 5432 → 53111 [ACK] Seq=1013 Ack=343 Win=6366 Len=0 TSval=2819351849 TSecr=589492496
293 5432 53111 PGSQL 67 <3/Z
294 53111 5432 TCP 56 53111 → 5432 [ACK] Seq=343 Ack=1024 Win=6351 Len=0 TSval=589492498 TSecr=2819351851
295 53111 5432 PGSQL 68 >Q ———> COMMIT
```
I’m interested because such a communication is intrinsic to r2dbc scenarios like this
```
val usersWithAccouns = Flux.defer {
// Select all users
databaseClient.sql("select * from users where userId >= $1 and userId <= $2")
.bind("$1", 1)
.bind("$2", 255)
.flatMap { r -> r.map { row, meta -> … } }
.flatMap { user ->
// For each user select all its accounts
databaseClient.sql("select login from accounts where userId=$1 limit 1")
.bind("$1", user.id)
.flatMap { r -> r.map { row, meta -> … } }
.reduce …
}
}.`as`(transactionalOperator::transactional)
```
which results in a failure owing to inner requests building up a queue inside the driver (due to inability to suspend a limitless Execute for "select * from users…" ).
Thanks!
В списке pgsql-hackers по дате отправления:
Предыдущее
От: Dilip KumarДата:
Сообщение: Re: BitmapHeapScan streaming read user and prelim refactoring