123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- # Verify we can pgwire Bind, Execute, then SQL FETCH and CLOSE, then
- # pgwire Execute fails (due to the close). This tests that pgwire portals
- # and SQL cursors are the same thing.
- send
- Query {"query": "BEGIN"}
- Parse {"name": "s", "query": "VALUES (2), (4), (6)"}
- Bind {"portal": "p", "statement": "s"}
- Execute {"portal": "p", "max_rows": 1}
- Sync
- Query {"query": "FETCH 1 p"}
- Query {"query": "CLOSE \"p\""}
- Execute {"portal": "p", "max_rows": 1}
- Sync
- Query {"query": "ROLLBACK"}
- ----
- until
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ----
- CommandComplete {"tag":"BEGIN"}
- ReadyForQuery {"status":"T"}
- ParseComplete
- BindComplete
- DataRow {"fields":["2"]}
- PortalSuspended
- ReadyForQuery {"status":"T"}
- RowDescription {"fields":[{"name":"column1"}]}
- DataRow {"fields":["4"]}
- CommandComplete {"tag":"FETCH 1"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"CLOSE CURSOR"}
- ReadyForQuery {"status":"T"}
- ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"34000"},{"typ":"M","value":"portal \"p\" does not exist"}]}
- ReadyForQuery {"status":"E"}
- CommandComplete {"tag":"ROLLBACK"}
- ReadyForQuery {"status":"I"}
- # Ensure FETCH with no count returns 1 row.
- send
- Query {"query": "BEGIN"}
- Query {"query": "DECLARE c CURSOR FOR VALUES (2), (4), (6)"}
- Query {"query": "FETCH c"}
- Query {"query": "CLOSE c"}
- Query {"query": "COMMIT"}
- ----
- until
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ----
- CommandComplete {"tag":"BEGIN"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"DECLARE CURSOR"}
- ReadyForQuery {"status":"T"}
- RowDescription {"fields":[{"name":"column1"}]}
- DataRow {"fields":["2"]}
- CommandComplete {"tag":"FETCH 1"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"CLOSE CURSOR"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"COMMIT"}
- ReadyForQuery {"status":"I"}
- # FETCH with a high count.
- send
- Query {"query": "BEGIN"}
- Query {"query": "DECLARE c CURSOR FOR VALUES (2), (4), (6)"}
- Query {"query": "FETCH 2000 c"}
- Query {"query": "CLOSE c"}
- Query {"query": "COMMIT"}
- ----
- until
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ----
- CommandComplete {"tag":"BEGIN"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"DECLARE CURSOR"}
- ReadyForQuery {"status":"T"}
- RowDescription {"fields":[{"name":"column1"}]}
- DataRow {"fields":["2"]}
- DataRow {"fields":["4"]}
- DataRow {"fields":["6"]}
- CommandComplete {"tag":"FETCH 3"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"CLOSE CURSOR"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"COMMIT"}
- ReadyForQuery {"status":"I"}
- # DECLARE outside a transaction should fail. A test like:
- # Query {"query": "DECLARE c CURSOR FOR VALUES (2), (4), (6)"}
- # would trigger this but we have slightly different transaction semantics
- # than Postgres that would require special casing this situation, and
- # it's safe to ignore, so we don't implement or test it.
- # Surprisingly, the same statement but with a SELECT added on passes. This
- # is because Postgres has some different transaction states. For a Query
- # message containing a single statement, it uses the DEFAULT state. If
- # there are multiple statements it uses INPROGRESS_IMPLICIT, which acts
- # similar to a BEGIN. The SELECT here triggers that, which then causes
- # DECLARE to error. Since we have fewer transaction states our DECLARE
- # doesn't detect this for the single statement case.
- send
- Query {"query": "DECLARE c CURSOR FOR VALUES (2), (4), (6); SELECT 1"}
- ----
- until
- ReadyForQuery
- ----
- CommandComplete {"tag":"DECLARE CURSOR"}
- RowDescription {"fields":[{"name":"?column?"}]}
- DataRow {"fields":["1"]}
- CommandComplete {"tag":"SELECT 1"}
- ReadyForQuery {"status":"I"}
- send
- Query {"query": "CLOSE c"}
- ----
- until err_field_typs=M
- ReadyForQuery
- ----
- ErrorResponse {"fields":[{"typ":"M","value":"cursor \"c\" does not exist"}]}
- ReadyForQuery {"status":"I"}
- send
- Query {"query": "FETCH c"}
- ----
- until err_field_typs=M
- ReadyForQuery
- ----
- ErrorResponse {"fields":[{"typ":"M","value":"cursor \"c\" does not exist"}]}
- ReadyForQuery {"status":"I"}
- # Verify that cursor and portal close messages differ.
- send
- Execute {"portal": "c"}
- Sync
- ----
- until err_field_typs=M
- ReadyForQuery
- ----
- ErrorResponse {"fields":[{"typ":"M","value":"portal \"c\" does not exist"}]}
- ReadyForQuery {"status":"I"}
- # Verify that Describe will fail before and after a transaction, but work within one.
- send
- Describe {"variant": "P", "name": "c"}
- Sync
- Query {"query": "BEGIN"}
- Query {"query": "DECLARE c CURSOR FOR VALUES (2), (4), (6)"}
- Describe {"variant": "P", "name": "c"}
- Query {"query": "COMMIT"}
- Describe {"variant": "P", "name": "c"}
- Sync
- ----
- until
- ErrorResponse
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ----
- ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"34000"},{"typ":"M","value":"portal \"c\" does not exist"}]}
- ReadyForQuery {"status":"I"}
- CommandComplete {"tag":"BEGIN"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"DECLARE CURSOR"}
- ReadyForQuery {"status":"T"}
- RowDescription {"fields":[{"name":"column1"}]}
- CommandComplete {"tag":"COMMIT"}
- ReadyForQuery {"status":"I"}
- ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"34000"},{"typ":"M","value":"portal \"c\" does not exist"}]}
- ReadyForQuery {"status":"I"}
- # Verify that a single Query message can declare and fetch from a
- # portal. This tests that, even though DECLARE cannot be used outside
- # of a transaction, a single Query message with multiple statements is
- # a transaction. Also verify that it doesn't exist afterward.
- send
- Query {"query": "DECLARE c CURSOR FOR VALUES (2), (4), (6); FETCH 2 c; FETCH 10 c;"}
- Describe {"variant": "P", "name": "c"}
- Sync
- ----
- until
- ReadyForQuery
- ReadyForQuery
- ----
- CommandComplete {"tag":"DECLARE CURSOR"}
- RowDescription {"fields":[{"name":"column1"}]}
- DataRow {"fields":["2"]}
- DataRow {"fields":["4"]}
- CommandComplete {"tag":"FETCH 2"}
- RowDescription {"fields":[{"name":"column1"}]}
- DataRow {"fields":["6"]}
- CommandComplete {"tag":"FETCH 1"}
- ReadyForQuery {"status":"I"}
- ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"34000"},{"typ":"M","value":"portal \"c\" does not exist"}]}
- ReadyForQuery {"status":"I"}
- # Test cursors in extended protocol.
- send
- Query {"query": "BEGIN"}
- Parse {"query": "DECLARE c CURSOR FOR VALUES (1), (2), (3)"}
- Describe
- Bind
- Execute
- Parse {"query": "FETCH c"}
- Describe
- Bind
- Execute
- Execute {"portal": "c"}
- Parse {"query": "CLOSE c"}
- Describe
- Bind
- Execute
- Sync
- Query {"query": "COMMIT"}
- ----
- until
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ----
- CommandComplete {"tag":"BEGIN"}
- ReadyForQuery {"status":"T"}
- ParseComplete
- ParameterDescription {"parameters":[]}
- NoData
- BindComplete
- CommandComplete {"tag":"DECLARE CURSOR"}
- ParseComplete
- ParameterDescription {"parameters":[]}
- RowDescription {"fields":[{"name":"column1"}]}
- BindComplete
- DataRow {"fields":["1"]}
- CommandComplete {"tag":"FETCH 1"}
- DataRow {"fields":["2"]}
- DataRow {"fields":["3"]}
- CommandComplete {"tag":"SELECT 2"}
- ParseComplete
- ParameterDescription {"parameters":[]}
- NoData
- BindComplete
- CommandComplete {"tag":"CLOSE CURSOR"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"COMMIT"}
- ReadyForQuery {"status":"I"}
- # Here's a tricky one. Create a portal ("c") with 6 rows in it. Create
- # and bind another portal ("a") that fetches 2 rows from "c", but don't
- # execute "a" at all. Execute the empty portal pulling 2 rows from c
- # (1, 2). Execute portal "a" but only request 1 row (3). At this point
- # "a" has also cached row 4 because it's a 2 row FETCH. Row 4 is in some
- # cache somewhere, and no longer in portal "c". Verify this by pulling
- # 2 more rows from "c" (5, 6). Finally pull the remaining rows from "a"
- # (4). This test verifies that the first execution of a FETCH will pull
- # N rows from its target portal and cache them.
- # NOTE: We differ from postgres here so don't actually test this. The
- # test and comment are left here so future readers can understand what
- # should be happening if we were fully compliant.
- #send
- #Query {"query": "BEGIN"}
- #Query {"query": "DECLARE c CURSOR FOR VALUES (1), (2), (3), (4), (5), (6)"}
- #Parse {"query": "FETCH 2 c"}
- #Bind {"portal": "a"}
- #Sync
- #Query {"query": "FETCH 2 c"}
- #Execute {"portal": "a", "max_rows": 1}
- #Sync
- #Query {"query": "FETCH 2 c"}
- #Execute {"portal": "a"}
- #Sync
- #Query {"query": "FETCH 2 c"}
- #Query {"query": "COMMIT"}
- #----
- #
- #until
- #ReadyForQuery
- #ReadyForQuery
- #ReadyForQuery
- #ReadyForQuery
- #ReadyForQuery
- #ReadyForQuery
- #ReadyForQuery
- #ReadyForQuery
- #ReadyForQuery
- #----
- #CommandComplete {"tag":"BEGIN"}
- #ReadyForQuery {"status":"T"}
- #CommandComplete {"tag":"DECLARE CURSOR"}
- #ReadyForQuery {"status":"T"}
- #ParseComplete
- #BindComplete
- #ReadyForQuery {"status":"T"}
- #RowDescription {"fields":[{"name":"column1"}]}
- #DataRow {"fields":["1"]}
- #DataRow {"fields":["2"]}
- #CommandComplete {"tag":"FETCH 2"}
- #ReadyForQuery {"status":"T"}
- #DataRow {"fields":["3"]}
- #PortalSuspended
- #ReadyForQuery {"status":"T"}
- #RowDescription {"fields":[{"name":"column1"}]}
- #DataRow {"fields":["5"]}
- #DataRow {"fields":["6"]}
- #CommandComplete {"tag":"FETCH 2"}
- #ReadyForQuery {"status":"T"}
- #DataRow {"fields":["4"]}
- #CommandComplete {"tag":"FETCH 2"}
- #ReadyForQuery {"status":"T"}
- #RowDescription {"fields":[{"name":"column1"}]}
- #CommandComplete {"tag":"FETCH 0"}
- #ReadyForQuery {"status":"T"}
- #CommandComplete {"tag":"COMMIT"}
- #ReadyForQuery {"status":"I"}
- # Test FETCH 0. This should return 0 rows (not all remaining, like Execute).
- send
- Query {"query": "BEGIN"}
- Query {"query": "DECLARE c CURSOR FOR VALUES (1), (2), (3), (4), (5), (6)"}
- Query {"query": "FETCH 0 c"}
- Query {"query": "COMMIT"}
- ----
- until
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ----
- CommandComplete {"tag":"BEGIN"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"DECLARE CURSOR"}
- ReadyForQuery {"status":"T"}
- RowDescription {"fields":[{"name":"column1"}]}
- CommandComplete {"tag":"FETCH 0"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"COMMIT"}
- ReadyForQuery {"status":"I"}
- # Executing a DECLARE twice fails.
- send
- Query {"query": "BEGIN"}
- Parse {"query": "DECLARE c CURSOR FOR VALUES (1), (2), (3)"}
- Bind
- Execute
- Execute
- Sync
- Query {"query": "ROLLBACK"}
- ----
- until
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ----
- CommandComplete {"tag":"BEGIN"}
- ReadyForQuery {"status":"T"}
- ParseComplete
- BindComplete
- CommandComplete {"tag":"DECLARE CURSOR"}
- ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"55000"},{"typ":"M","value":"portal \"\" cannot be run"}]}
- ReadyForQuery {"status":"E"}
- CommandComplete {"tag":"ROLLBACK"}
- ReadyForQuery {"status":"I"}
- # Executing a FETCH twice does nothing the second time. It must be
- # rebound to get more rows.
- # Executing a CLOSE twice fails like DECLARE.
- send
- Query {"query": "BEGIN"}
- Parse {"query": "DECLARE c CURSOR FOR VALUES (1), (2), (3)"}
- Bind
- Execute
- Parse {"query": "FETCH c"}
- Bind
- Execute
- Execute
- Bind
- Execute
- Execute
- Parse {"query": "CLOSE c"}
- Bind
- Execute
- Execute
- Sync
- Query {"query": "ROLLBACK"}
- ----
- until
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ----
- CommandComplete {"tag":"BEGIN"}
- ReadyForQuery {"status":"T"}
- ParseComplete
- BindComplete
- CommandComplete {"tag":"DECLARE CURSOR"}
- ParseComplete
- BindComplete
- DataRow {"fields":["1"]}
- CommandComplete {"tag":"FETCH 1"}
- CommandComplete {"tag":"FETCH 1"}
- BindComplete
- DataRow {"fields":["2"]}
- CommandComplete {"tag":"FETCH 1"}
- CommandComplete {"tag":"FETCH 1"}
- ParseComplete
- BindComplete
- CommandComplete {"tag":"CLOSE CURSOR"}
- ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"55000"},{"typ":"M","value":"portal \"\" cannot be run"}]}
- ReadyForQuery {"status":"E"}
- CommandComplete {"tag":"ROLLBACK"}
- ReadyForQuery {"status":"I"}
- # Test FETCH with various combinations of row and execute counts. And
- # recall that since we don't support Execute with max_rows < FETCH's
- # count, we aren't testing that here, but should be if we add it.
- send
- Query {"query": "BEGIN"}
- Parse {"query": "DECLARE c CURSOR FOR VALUES (1), (2), (3), (4), (5), (6), (7), (8)"}
- Bind
- Execute
- Parse {"query": "FETCH 2 c"}
- Bind
- Execute
- Execute
- Bind
- Execute {"max_rows": 4}
- Execute {"max_rows": 4}
- Execute
- Parse {"query": "FETCH c"}
- Bind
- Execute {"max_rows": 2}
- Execute {"max_rows": 2}
- Sync
- Query {"query": "COMMIT"}
- ----
- until
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ----
- CommandComplete {"tag":"BEGIN"}
- ReadyForQuery {"status":"T"}
- ParseComplete
- BindComplete
- CommandComplete {"tag":"DECLARE CURSOR"}
- ParseComplete
- BindComplete
- DataRow {"fields":["1"]}
- DataRow {"fields":["2"]}
- CommandComplete {"tag":"FETCH 2"}
- CommandComplete {"tag":"FETCH 2"}
- BindComplete
- DataRow {"fields":["3"]}
- DataRow {"fields":["4"]}
- CommandComplete {"tag":"FETCH 2"}
- CommandComplete {"tag":"FETCH 2"}
- CommandComplete {"tag":"FETCH 2"}
- ParseComplete
- BindComplete
- DataRow {"fields":["5"]}
- CommandComplete {"tag":"FETCH 1"}
- CommandComplete {"tag":"FETCH 1"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"COMMIT"}
- ReadyForQuery {"status":"I"}
- # Verify that the empty portal is removed after Query.
- send
- Query {"query": "BEGIN; DECLARE c CURSOR FOR VALUES (1), (2); FETCH c;"}
- Execute
- Sync
- Query {"query": "ROLLBACK"}
- ----
- until
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ----
- CommandComplete {"tag":"BEGIN"}
- CommandComplete {"tag":"DECLARE CURSOR"}
- RowDescription {"fields":[{"name":"column1"}]}
- DataRow {"fields":["1"]}
- CommandComplete {"tag":"FETCH 1"}
- ReadyForQuery {"status":"T"}
- ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"34000"},{"typ":"M","value":"portal \"\" does not exist"}]}
- ReadyForQuery {"status":"E"}
- CommandComplete {"tag":"ROLLBACK"}
- ReadyForQuery {"status":"I"}
- # Test binary cursors. This tests that a cursor declared over simple query
- # (i.e., text result format) can be requested in binary.
- send
- Query {"query": "BEGIN; DECLARE c CURSOR FOR VALUES (1), (2);"}
- Parse {"query": "FETCH c"}
- Bind {"result_formats": [1]}
- Execute
- Sync
- Query {"query": "COMMIT"}
- ----
- until
- ReadyForQuery
- ReadyForQuery
- ReadyForQuery
- ----
- CommandComplete {"tag":"BEGIN"}
- CommandComplete {"tag":"DECLARE CURSOR"}
- ReadyForQuery {"status":"T"}
- ParseComplete
- BindComplete
- DataRow {"fields":["\u0000\u0000\u0000\u0001"]}
- CommandComplete {"tag":"FETCH 1"}
- ReadyForQuery {"status":"T"}
- CommandComplete {"tag":"COMMIT"}
- ReadyForQuery {"status":"I"}
- # Verify that a complaint is issued if DECLARE is not in an implicit or
- # explicit transaction.
- send
- Query {"query": "DECLARE c CURSOR FOR SELECT 1"}
- ----
- until
- ReadyForQuery
- ----
- ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"25P01"},{"typ":"M","value":"DECLARE CURSOR can only be used in transaction blocks"}]}
- ReadyForQuery {"status":"I"}
- send
- Parse {"query": "DECLARE c CURSOR FOR SELECT 1"}
- Bind
- Execute
- Sync
- ----
- until
- ReadyForQuery
- ----
- ParseComplete
- BindComplete
- ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"25P01"},{"typ":"M","value":"DECLARE CURSOR can only be used in transaction blocks"}]}
- ReadyForQuery {"status":"I"}
|