# Verify that a completed portal can't be re-executed.

send
Parse {"Query": "SELECT 1"}
Bind
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Execute
Sync
----

until keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"ErrorResponse","Code":"34000","Message":"unknown portal \"\""}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that closing a bound portal prevents execution.

send
Parse {"Name": "s", "Query": "SELECT 1"}
Bind {"DestinationPortal": "p", "PreparedStatement": "s"}
Close {"ObjectType": "P", "Name": "p"}
Execute {"Portal": "p"}
Sync
----

until keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CloseComplete"}
{"Type":"ErrorResponse","Code":"34000","Message":"unknown portal \"p\""}
{"Type":"ReadyForQuery","TxStatus":"I"}

# The spec says that closing a prepared statement also closes its portals,
# but that doesn't seem to be the case. Below I would expect that Bind,
# Close, Execute causes the execute to return an error, but it instead
# returns the portal result. This happens in both Postgres and Cockroach.

# After closing, re-parse with the same name to make sure the execute
# happens on the old statement.
send
Bind {"DestinationPortal": "p", "PreparedStatement": "s"}
Close {"ObjectType": "S", "Name": "s"}
Parse {"Name": "s", "Query": "SELECT 2"}
Execute {"Portal": "p"}
Sync
----

until
ReadyForQuery
----
{"Type":"BindComplete"}
{"Type":"CloseComplete"}
{"Type":"ParseComplete"}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Portal still isn't destroyed within a transaction either, in PG or CR.

send
Query {"String": "BEGIN"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Bind {"DestinationPortal": "p", "PreparedStatement": "s"}
Close {"ObjectType": "S", "Name": "s"}
Parse {"Name": "s", "Query": "SELECT 3"}
Execute {"Portal": "p"}
Sync
----

until
ReadyForQuery
----
{"Type":"BindComplete"}
{"Type":"CloseComplete"}
{"Type":"ParseComplete"}
{"Type":"DataRow","Values":[{"text":"2"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Query {"String": "COMMIT"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Execute a portal with limited rows inside a transaction.
# This also tests that we can handle Flush during the portal execution.

send
Query {"String": "BEGIN"}
Parse {"Query": "SELECT * FROM generate_series(1, 2)"}
Bind
Execute {"MaxRows": 1}
Sync
----

until
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# This is the second of 2 rows, but we don't expect a command complete
# yet.

send
Execute {"MaxRows": 1}
Sync
----

until
ReadyForQuery
----
{"Type":"DataRow","Values":[{"text":"2"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# There were only 2 rows, so this third execute should return a command
# complete.

send
Execute {"MaxRows": 1}
Sync
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"SELECT 0"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Query {"String": "COMMIT"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Execute a portal with limited rows inside a transaction, and verify that we
# allow the Flush message.

send
Query {"String": "BEGIN"}
Parse {"Query": "SELECT * FROM generate_series(1, 2)"}
Bind
Execute {"MaxRows": 1}
Flush
Sync
----

until
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# This is the second of 2 rows, but we don't expect a command complete
# yet.

send
Execute {"MaxRows": 1}
Flush
Sync
----

until
ReadyForQuery
----
{"Type":"DataRow","Values":[{"text":"2"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# There were only 2 rows, so this third execute should return a command
# complete.

send
Execute {"MaxRows": 1}
Flush
Sync
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"SELECT 0"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Query {"String": "COMMIT"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "SELECT 'here'"}
----

until ignore=RowDescription
ReadyForQuery
----
{"Type":"DataRow","Values":[{"text":"here"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Execute a portal first with a row limit and then without.

send
Query {"String": "BEGIN"}
Parse {"Query": "SELECT * FROM generate_series(1, 4)"}
Bind
Execute {"MaxRows": 1}
Sync
----

until
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"DataRow","Values":[{"text":"2"}]}
{"Type":"DataRow","Values":[{"text":"3"}]}
{"Type":"DataRow","Values":[{"text":"4"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 3"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Query {"String": "COMMIT"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "SELECT 'here'"}
----

until ignore=RowDescription
ReadyForQuery
----
{"Type":"DataRow","Values":[{"text":"here"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Execute a portal with a result limit. This is outside of a transaction
# so we expect an error. This differs slightly from the postgres behavior,
# which will do the first execute, auto close the portal, and then fail
# on the second.

send
Parse {"Query": "SELECT * FROM generate_series(1, 2)"}
Bind
Execute {"MaxRows": 1}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Try the second execute, which we expect to fail because implicit
# transactions auto close portals after the first suspension.

send
Execute
Sync
----

until keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"ErrorResponse","Code":"34000","Message":"unknown portal \"\""}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "SELECT 'here'"}
----

until ignore=RowDescription
ReadyForQuery
----
{"Type":"DataRow","Values":[{"text":"here"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Execute a portal partially and close it.

send
Query {"String": "BEGIN"}
Parse {"Query": "SELECT * FROM generate_series(1, 2)"}
Bind
Execute {"MaxRows": 1}
Sync
----

until
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# Close the empty portal then try to execute it.
send
Close {"ObjectType": "P"}
Execute
Sync
----

until keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"CloseComplete"}
{"Type":"ErrorResponse","Code":"34000","Message":"unknown portal \"\""}
{"Type":"ReadyForQuery","TxStatus":"E"}

send
Query {"String": "ROLLBACK"}
Query {"String": "SELECT 'here'"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"ROLLBACK"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"here"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Regression for restarting portal's execution after it has been exhausted
# (#48448). We will execute a portal with a limit (so that it becomes
# suspended) and exhaust it later; afterwards, we'll attempt to execute it
# again, but we expect it to always return 0 rows after exhaustion.
send
Query {"String": "DROP TABLE IF EXISTS foo; CREATE TABLE foo (id INT8); INSERT INTO foo (id) VALUES (1), (2), (3)"}
Query {"String": "BEGIN"}
Parse {"Query": "SELECT * FROM foo ORDER BY id"}
Bind
Execute {"MaxRows": 2}
Sync
----

until ignore=NoticeResponse
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DROP TABLE"}
{"Type":"CommandComplete","CommandTag":"CREATE TABLE"}
{"Type":"CommandComplete","CommandTag":"INSERT 0 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"DataRow","Values":[{"text":"2"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Execute {"MaxRows": 2}
Sync
----

until
ReadyForQuery
----
{"Type":"DataRow","Values":[{"text":"3"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Execute {"MaxRows": 2}
Sync
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"SELECT 0"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"SELECT 0"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Query {"String": "COMMIT"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Try executing a "values clause" multiple times.

send
Query {"String": "BEGIN"}
Parse {"Query": "VALUES (0), (1), (2), (3)"}
Bind
Execute {"MaxRows": 2}
Sync
----

until
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Execute {"MaxRows": 2}
Sync
----

until
ReadyForQuery
----
{"Type":"DataRow","Values":[{"text":"2"}]}
{"Type":"DataRow","Values":[{"text":"3"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Execute {"MaxRows": 2}
Sync
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"SELECT 0"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"SELECT 0"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Query {"String": "COMMIT"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}


## No transaction; small limit

# 'S' for Statement
# ParameterFormatCodes = [0] for text format
send
Parse {"Name": "s1", "Query": "select n::int4 from generate_series(0,$1::int8) n", "ParameterOIDs": [20]}
Describe {"ObjectType": "S", "Name": "s1"}
Bind {"PreparedStatement": "s1", "ParameterFormatCodes": [0], "ResultFormatCodes": [0], "Parameters": [{"text":"1"}]}
Execute {"MaxRows": 1}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParameterDescription","ParameterOIDs":[20]}
{"Type":"RowDescription","Fields":[{"Name":"n","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":23,"DataTypeSize":4,"TypeModifier":-1,"Format":0}]}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"I"}


## No transaction; exact limit

# 'S' for Statement
# 49 = ASCII '1'
# ParameterFormatCodes = [0] for text format
send
Parse {"Name": "s2", "Query": "select n::int4 from generate_series(0,$1::int8) n", "ParameterOIDs": [20]}
Describe {"ObjectType": "S", "Name": "s2"}
Bind {"PreparedStatement": "s2", "ParameterFormatCodes": [0], "ResultFormatCodes": [0], "Parameters": [{"text":"1"}]}
Execute {"MaxRows": 2}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParameterDescription","ParameterOIDs":[20]}
{"Type":"RowDescription","Fields":[{"Name":"n","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":23,"DataTypeSize":4,"TypeModifier":-1,"Format":0}]}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"I"}


## No transaction; larger limit

# 'S' for Statement
# 49 = ASCII '1'
# ParameterFormatCodes = [0] for text format
send
Parse {"Name": "s3", "Query": "select n::int4 from generate_series(0,$1::int8) n", "ParameterOIDs": [20]}
Describe {"ObjectType": "S", "Name": "s3"}
Bind {"PreparedStatement": "s3", "ParameterFormatCodes": [0], "ResultFormatCodes": [0], "Parameters": [{"text":"1"}]}
Execute {"MaxRows": 3}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParameterDescription","ParameterOIDs":[20]}
{"Type":"RowDescription","Fields":[{"Name":"n","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":23,"DataTypeSize":4,"TypeModifier":-1,"Format":0}]}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}


## Transaction; smaller limit

send
Query {"String": "BEGIN"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# 'S' for Statement
# 49 = ASCII '1'
# ParameterFormatCodes = [0] for text format
send
Parse {"Name": "s4", "Query": "select n::int4 from generate_series(0,$1::int8) n", "ParameterOIDs": [20]}
Describe {"ObjectType": "S", "Name": "s4"}
Bind {"PreparedStatement": "s4", "ParameterFormatCodes": [0], "ResultFormatCodes": [0], "Parameters": [{"text":"1"}]}
Execute {"MaxRows": 1}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParameterDescription","ParameterOIDs":[20]}
{"Type":"RowDescription","Fields":[{"Name":"n","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":23,"DataTypeSize":4,"TypeModifier":-1,"Format":0}]}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Query {"String": "COMMIT"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}


## Transaction with exact limit.

send
Query {"String": "BEGIN"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# 'S' for Statement
# 49 = ASCII '1'
# ParameterFormatCodes = [0] for text format
send
Parse {"Name": "s5", "Query": "select n::int4 from generate_series(0,$1::int8) n", "ParameterOIDs": [20]}
Describe {"ObjectType": "S", "Name": "s5"}
Bind {"PreparedStatement": "s5", "ParameterFormatCodes": [0], "ResultFormatCodes": [0], "Parameters": [{"text":"1"}]}
Execute {"MaxRows": 2}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParameterDescription","ParameterOIDs":[20]}
{"Type":"RowDescription","Fields":[{"Name":"n","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":23,"DataTypeSize":4,"TypeModifier":-1,"Format":0}]}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Query {"String": "COMMIT"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}


## Transaction with larger limit.

send
Query {"String": "BEGIN"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# 'S' for Statement
# 49 = ASCII '1'
# ParameterFormatCodes = [0] for text format
send
Parse {"Name": "s6", "Query": "select n::int4 from generate_series(0,$1::int8) n", "ParameterOIDs": [20]}
Describe {"ObjectType": "S", "Name": "s6"}
Bind {"PreparedStatement": "s6", "ParameterFormatCodes": [0], "ResultFormatCodes": [0], "Parameters": [{"text":"1"}]}
Execute {"MaxRows": 3}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParameterDescription","ParameterOIDs":[20]}
{"Type":"RowDescription","Fields":[{"Name":"n","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":23,"DataTypeSize":4,"TypeModifier":-1,"Format":0}]}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Query {"String": "COMMIT"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}


## Transaction; smaller limit; COMMIT in extended protocol

send
Query {"String": "BEGIN"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# 'S' for Statement
# 49 = ASCII '1'
# ParameterFormatCodes = [0] for text format
send
Parse {"Name": "s7", "Query": "select n::int4 from generate_series(0,$1::int8) n", "ParameterOIDs": [20]}
Describe {"ObjectType": "S", "Name": "s7"}
Bind {"PreparedStatement": "s7", "ParameterFormatCodes": [0], "ResultFormatCodes": [0], "Parameters": [{"text":"1"}]}
Execute {"MaxRows": 1}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParameterDescription","ParameterOIDs":[20]}
{"Type":"RowDescription","Fields":[{"Name":"n","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":23,"DataTypeSize":4,"TypeModifier":-1,"Format":0}]}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Parse {"Name": "commit1", "Query": "COMMIT"}
Bind {"PreparedStatement": "commit1"}
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}


## Transaction with exact limit; COMMIT in extended protocol

send
Query {"String": "BEGIN"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# 'S' for Statement
# 49 = ASCII '1'
# ParameterFormatCodes = [0] for text format
send
Parse {"Name": "s8", "Query": "select n::int4 from generate_series(0,$1::int8) n", "ParameterOIDs": [20]}
Describe {"ObjectType": "S", "Name": "s8"}
Bind {"PreparedStatement": "s8", "ParameterFormatCodes": [0], "ResultFormatCodes": [0], "Parameters": [{"text":"1"}]}
Execute {"MaxRows": 2}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParameterDescription","ParameterOIDs":[20]}
{"Type":"RowDescription","Fields":[{"Name":"n","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":23,"DataTypeSize":4,"TypeModifier":-1,"Format":0}]}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Parse {"Name": "commit2", "Query": "COMMIT"}
Bind {"PreparedStatement": "commit2"}
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}


## Transaction with larger limit; COMMIT in extended protocol

send
Query {"String": "BEGIN"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# 'S' for Statement
# 49 = ASCII '1'
# ParameterFormatCodes = [0] for text format
send
Parse {"Name": "s9", "Query": "select n::int4 from generate_series(0,$1::int8) n", "ParameterOIDs": [20]}
Describe {"ObjectType": "S", "Name": "s9"}
Bind {"PreparedStatement": "s9", "ParameterFormatCodes": [0], "ResultFormatCodes": [0], "Parameters": [{"text":"1"}]}
Execute {"MaxRows": 3}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParameterDescription","ParameterOIDs":[20]}
{"Type":"RowDescription","Fields":[{"Name":"n","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":23,"DataTypeSize":4,"TypeModifier":-1,"Format":0}]}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Parse {"Name": "commit3", "Query": "COMMIT"}
Bind {"PreparedStatement": "commit3"}
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}


## Transaction with smaller limit; portals interleaved

send
Query {"String": "BEGIN"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send crdb_only
Query {"String": "SET multiple_active_portals_enabled = true"}
----

until crdb_only ignore=NoticeResponse
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"SET"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# 'S' for Statement
# 49 = ASCII '1'
# ParameterFormatCodes = [0] for text format
send
Parse {"Name": "s10", "Query": "select n::int4 from generate_series(0,$1::int8) n", "ParameterOIDs": [20]}
Describe {"ObjectType": "S", "Name": "s10"}
Bind {"PreparedStatement": "s10", "ParameterFormatCodes": [0], "ResultFormatCodes": [0], "Parameters": [{"text":"1"}]}
Execute {"MaxRows": 1}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParameterDescription","ParameterOIDs":[20]}
{"Type":"RowDescription","Fields":[{"Name":"n","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":23,"DataTypeSize":4,"TypeModifier":-1,"Format":0}]}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Parse {"Name": "c4", "Query": "COMMIT"}
Parse {"Name": "s11", "Query": "select n::int4 from generate_series(0,1) n"}
Bind {"DestinationPortal": "por", "PreparedStatement": "s11"}
Bind {"DestinationPortal": "pc4", "PreparedStatement": "c4"}
Execute {"Portal": "por"}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"0"}]}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Execute {"Portal": "pc4"}
Sync
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"COMMIT"}
{"Type":"ReadyForQuery","TxStatus":"I"}


# Test that we can use a portal with MaxRows from an implicit transaction.
send
Parse {"Name": "s12", "Query": "SELECT * FROM generate_series(1, 10)"}
Bind {"DestinationPortal": "C_1", "PreparedStatement": "s12"}
Execute {"Portal": "C_1", "MaxRows": 2}
Execute {"Portal": "C_1", "MaxRows": 2}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"DataRow","Values":[{"text":"2"}]}
{"Type":"PortalSuspended"}
{"Type":"DataRow","Values":[{"text":"3"}]}
{"Type":"DataRow","Values":[{"text":"4"}]}
{"Type":"PortalSuspended"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# We can reuse the portal name, but not the statement name.
# This also tests that when the rows are fully consumed, reading from the
# portal returns 0 rows.
send
Parse {"Name": "s13", "Query": "SELECT * FROM generate_series(1, 7)"}
Bind {"DestinationPortal": "C_1", "PreparedStatement": "s13"}
Execute {"Portal": "C_1", "MaxRows": 3}
Execute {"Portal": "C_1", "MaxRows": 3}
Execute {"Portal": "C_1", "MaxRows": 3}
Execute {"Portal": "C_1", "MaxRows": 3}
Execute {"Portal": "C_1", "MaxRows": 3}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"DataRow","Values":[{"text":"2"}]}
{"Type":"DataRow","Values":[{"text":"3"}]}
{"Type":"PortalSuspended"}
{"Type":"DataRow","Values":[{"text":"4"}]}
{"Type":"DataRow","Values":[{"text":"5"}]}
{"Type":"DataRow","Values":[{"text":"6"}]}
{"Type":"PortalSuspended"}
{"Type":"DataRow","Values":[{"text":"7"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"CommandComplete","CommandTag":"SELECT 0"}
{"Type":"CommandComplete","CommandTag":"SELECT 0"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "DROP TABLE IF EXISTS portal_sync_test"}
----

until ignore=NoticeResponse
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DROP TABLE"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "CREATE TABLE portal_sync_test (a FLOAT)"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"CREATE TABLE"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Test that Sync is treated as an auto-commit and that it can deal with
# errors during the implicit transaction.
send
Parse {"Name": "s14", "Query": "INSERT INTO portal_sync_test VALUES(1.0/0);"}
Bind {"DestinationPortal": "C_1", "PreparedStatement": "s14"}
Execute {"Portal": "C_1", "MaxRows": 3}
Execute {"Portal": "C_1", "MaxRows": 3}
Sync
----

# CockroachDB sends a BindComplete here, but PostgreSQL does not.
until keepErrMessage ignore=BindComplete
ErrorResponse
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ErrorResponse","Code":"22012","Message":"division by zero"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "INSERT INTO portal_sync_test VALUES(1);"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"INSERT 0 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "SELECT * FROM portal_sync_test;"}
----

until ignore_table_oids
ReadyForQuery
----
{"Type":"RowDescription","Fields":[{"Name":"a","TableOID":0,"TableAttributeNumber":1,"DataTypeOID":701,"DataTypeSize":8,"TypeModifier":-1,"Format":0}]}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "DROP TABLE IF EXISTS portal_sync_test"}
----

until ignore=NoticeResponse
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DROP TABLE"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "CREATE TABLE portal_sync_test (a FLOAT CHECK(a > 1))"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"CREATE TABLE"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Parse {"Name": "s15", "Query": "INSERT INTO portal_sync_test VALUES($1);"}
Describe {"ObjectType": "S", "Name": "s15"}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ParameterDescription","ParameterOIDs":[701]}
{"Type":"NoData"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that the "insert fast path" does not cause an auto-commit before
# the Sync message is handled. This also tests behavior with the unnamed
# portal.
send
Bind {"PreparedStatement": "s15", "Parameters": [{"text":"2"}]}
Describe {"ObjectType": "P"}
Execute
Bind {"PreparedStatement": "s15", "Parameters": [{"text":"3"}]}
Describe {"ObjectType": "P"}
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"BindComplete"}
{"Type":"NoData"}
{"Type":"CommandComplete","CommandTag":"INSERT 0 1"}
{"Type":"BindComplete"}
{"Type":"NoData"}
{"Type":"CommandComplete","CommandTag":"INSERT 0 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that an error during the implicit transaction causes both
# INSERTs to be rolled back.
send
Bind {"PreparedStatement": "s15", "Parameters": [{"text":"4"}]}
Describe {"ObjectType": "P"}
Execute
Bind {"PreparedStatement": "s15", "Parameters": [{"text":"0"}]}
Describe {"ObjectType": "P"}
Execute
Sync
----

until keepErrMessage ignore_constraint_name
ErrorResponse
ReadyForQuery
----
{"Type":"BindComplete"}
{"Type":"NoData"}
{"Type":"CommandComplete","CommandTag":"INSERT 0 1"}
{"Type":"BindComplete"}
{"Type":"NoData"}
{"Type":"ErrorResponse","Code":"23514","Message":"failed to satisfy CHECK constraint (a \u003e 1.0:::FLOAT8)"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "SELECT * FROM portal_sync_test ORDER BY a;"}
----

until ignore_table_oids
ReadyForQuery
----
{"Type":"RowDescription","Fields":[{"Name":"a","TableOID":0,"TableAttributeNumber":1,"DataTypeOID":701,"DataTypeSize":8,"TypeModifier":-1,"Format":0}]}
{"Type":"DataRow","Values":[{"text":"2"}]}
{"Type":"DataRow","Values":[{"text":"3"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that Sync deletes all named portals, even if they haven't been
# executed. (Regression test of #71665.)
send
Parse {"Name": "s16", "Query": "SELECT 1"}
Bind {"DestinationPortal": "p16", "PreparedStatement": "s16"}
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Execute {"Portal": "p16"}
Sync
----

until keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"ErrorResponse","Code":"34000","Message":"unknown portal \"p16\""}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that it's not possible to DECLARE a cursor of the same name as an open
# portal.
send
Parse {"Query": "BEGIN"}
Bind
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Close {"ObjectType": "S", "Name": "s"}
Close {"ObjectType": "P", "Name": "p"}
Parse {"Name": "s", "Query": "SELECT 1"}
Bind {"DestinationPortal": "p", "PreparedStatement": "s"}
Parse {"Query": "DECLARE p CURSOR FOR SELECT 1"}
Bind
Execute
Sync
----

until keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"CloseComplete"}
{"Type":"CloseComplete"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"ErrorResponse","Code":"42P03","Message":"cursor \"p\" already exists as portal"}
{"Type":"ReadyForQuery","TxStatus":"E"}

send
Parse {"Query": "ROLLBACK"}
Bind
Execute
Parse {"Query": "BEGIN"}
Bind
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CommandComplete","CommandTag":"ROLLBACK"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# Test that creating a portal that declares a cursor with the same name as the
# portal fails with a "duplicate cursor" error.

send
Parse {"Query": "DECLARE fnord CURSOR FOR SELECT 1", "Name": "bloop"}
Bind {"DestinationPortal": "fnord", "PreparedStatement": "bloop"}
Execute {"Portal": "fnord"}
Sync
----

until keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"ErrorResponse","Code":"42P03","Message":"cursor \"fnord\" already exists as portal"}
{"Type":"ReadyForQuery","TxStatus":"E"}

# Test the converse case: ensure that a portal cannot be created with the same
# name as an open cursor.

send
Parse {"Query": "ROLLBACK"}
Bind
Execute
Parse {"Query": "BEGIN"}
Bind
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CommandComplete","CommandTag":"ROLLBACK"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Parse {"Query": "DECLARE sqlcursor CURSOR FOR SELECT 1"}
Bind
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CommandComplete","CommandTag":"DECLARE CURSOR"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Parse {"Name": "blah", "Query": "SELECT 1"}
Bind {"DestinationPortal": "sqlcursor", "PreparedStatement": "blah"}
Execute {"Portal": "sqlcursor"}
Sync
----

until keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ErrorResponse","Code":"42P03","Message":"portal \"sqlcursor\" already exists as cursor","Detail":"statement name \"blah\"\n--\nportal name \"sqlcursor\"\n--\nstatement summary \"SELECT _\""}
{"Type":"ReadyForQuery","TxStatus":"E"}

send
Parse {"Query": "ROLLBACK"}
Bind
Execute
Parse {"Query": "BEGIN"}
Bind
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CommandComplete","CommandTag":"ROLLBACK"}
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

# Check interop of SQL DECLARE and wire DESCRIBE

send
Parse {"Query": "DECLARE foo CURSOR FOR SELECT g::INT8 FROM generate_series(1, 10) g(g)"}
Bind
Describe {"ObjectType": "P", "Name": ""}
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"NoData"}
{"Type":"CommandComplete","CommandTag":"DECLARE CURSOR"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Describe {"ObjectType": "P", "Name": "foo"}
Sync
----

until
ReadyForQuery
----
{"Type":"RowDescription","Fields":[{"Name":"g","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":20,"DataTypeSize":8,"TypeModifier":-1,"Format":0}]}
{"Type":"ReadyForQuery","TxStatus":"T"}

# Test preparing a SQL-level DECLARE with placeholders

send
Parse {"Query": "DECLARE bar CURSOR FOR SELECT g::INT8 FROM generate_series(1, $1) g(g)", "ParameterOIDs": [21]}
Bind {"PreparedStatement": "", "ParameterFormatCodes": [0], "ResultFormatCodes": [0], "Parameters": [{"text":"2"}]}
Describe {"ObjectType": "P", "Name": ""}
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"NoData"}
{"Type":"CommandComplete","CommandTag":"DECLARE CURSOR"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Parse {"Query": "FETCH 2 bar"}
Bind
Describe {"ObjectType": "P", "Name": ""}
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"RowDescription","Fields":[{"Name":"g","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":20,"DataTypeSize":8,"TypeModifier":-1,"Format":0}]}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"DataRow","Values":[{"text":"2"}]}
{"Type":"CommandComplete","CommandTag":"FETCH 2"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Query {"String": "ROLLBACK"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"ROLLBACK"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Parse {"Query": "SELECT * FROM generate_series(1, 4)"}
Describe
Bind
Execute
Sync
----

until keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ErrorResponse","Code":"08P01","Message":"invalid DESCRIBE message subtype 0"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Check declaring cursor with a name enclosed in double quotes
send
Query {"String": "BEGIN"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"BEGIN"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Parse {"Query": "DECLARE \"a b\" CURSOR FOR SELECT generate_series(1, 10) AS bar"}
Bind
Describe {"ObjectType": "P", "Name": ""}
Execute
Sync
----

until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"NoData"}
{"Type":"CommandComplete","CommandTag":"DECLARE CURSOR"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Describe {"ObjectType": "P", "Name": "a b"}
Sync
----

until ignore_type_oids ignore_table_oids ignore_data_type_sizes
ReadyForQuery
----
{"Type":"RowDescription","Fields":[{"Name":"bar","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":0,"DataTypeSize":0,"TypeModifier":-1,"Format":0}]}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Parse {"Query": "FETCH 2 \"a b\""}
Bind
Describe {"ObjectType": "P", "Name": ""}
Execute
Sync
----

until ignore_type_oids ignore_table_oids ignore_data_type_sizes
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"RowDescription","Fields":[{"Name":"bar","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":0,"DataTypeSize":0,"TypeModifier":-1,"Format":0}]}
{"Type":"DataRow","Values":[{"text":"1"}]}
{"Type":"DataRow","Values":[{"text":"2"}]}
{"Type":"CommandComplete","CommandTag":"FETCH 2"}
{"Type":"ReadyForQuery","TxStatus":"T"}

send
Query {"String": "ROLLBACK"}
----

until
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"ROLLBACK"}
{"Type":"ReadyForQuery","TxStatus":"I"}
