# This test verifies some of the pgwire encoding process for ENUMs.

# Demonstrate that attempting to prepare a query which hints a user-defined
# type as the very first thing on a new connection does not cause a panic.
# Prior to the change which introduced this test logic, the below prepare
# would hit a nil-pointer panic.

# TODO(richardjcai): Support let command similar to logic tests to
# programmatically get the table id.
# The first table created has id 58.

send crdb_only
Parse {"Name": "s1", "Query": "SELECT $1", "ParameterOIDs": [100080]}
Sync
----

until crdb_only
ErrorResponse
ReadyForQuery
----
{"Type":"ErrorResponse","Code":"42704"}
{"Type":"ReadyForQuery","TxStatus":"I"}


# Prepare the environment.
send noncrdb_only
Query {"String": "DROP TYPE IF EXISTS te CASCADE"}
----

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

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

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

send
Query {"String": "CREATE TYPE te AS ENUM ('hi', 'hello')"}
----

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

# Use the enum now.
send
Query {"String": "SELECT 'hi'::te"}
----

# PostgreSQL uses float4 under the hood.
until ignore_type_oids noncrdb_only
RowDescription
----
{"Type":"RowDescription","Fields":[{"Name":"te","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":0,"DataTypeSize":4,"TypeModifier":-1,"Format":0}]}

# Note that this is slightly different than Postgres -- in Postgres the
# DataTypeSize for an enum is 4, as floats are used to represent enums
# internally (4 bytes). Since our encodings are variable size, we report
# the DataTypeSize to be -1, which is the variable length size.
until crdb_only
RowDescription
----
{"Type":"RowDescription","Fields":[{"Name":"te","TableOID":0,"TableAttributeNumber":0,"DataTypeOID":100104,"DataTypeSize":-1,"TypeModifier":-1,"Format":0}]}

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

# Regression for #53413. This test ensures that the wire protocol can handle
# user defined type OIDs.

send
Query {"String": "CREATE TABLE tb (x te)"}
----

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

# Prepare a query and type hint a user defined type. Then bind this prepared
# statement with a user defined type argument.
send crdb_only
Parse {"Name": "s1", "Query": "INSERT INTO tb VALUES ($1)", "ParameterOIDs": [100104]}
Bind {"DestinationPortal": "p", "PreparedStatement": "s1", "ParameterFormatCodes": [0], "Parameters": [{"text":"hi"}]}
Execute {"Portal": "p"}
Sync
----

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

send noncrdb_only
Parse {"Name": "s1", "Query": "INSERT INTO tb VALUES ($1)"}
Bind {"DestinationPortal": "p", "PreparedStatement": "s1", "ParameterFormatCodes": [0], "Parameters": [{"text":"hi"}]}
Execute {"Portal": "p"}
Sync
----

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

# Ensure that our value was successfully inserted.
send
Query {"String": "SELECT * FROM tb"}
----

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

# Prepare a query and use the binary format (ParameterFormatCodes = [1])
send
Parse {"Name": "s2", "Query": "INSERT INTO tb VALUES ($1)"}
Bind {"DestinationPortal": "p2", "PreparedStatement": "s2", "ParameterFormatCodes": [1], "Parameters": [{"text":"hi"}]}
Execute {"Portal": "p2"}
Sync
----

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

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

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

send
Query {"String": "CREATE TABLE tba (x te[])"}
----

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

# Prepare a query and use the binary format (ParameterFormatCodes = [1])
# This is crdb_only because the OID is part of the binary encoding, but
# PG and CRDB assign different OIDs for custom types.
send crdb_only
Parse {"Name": "s3", "Query": "SELECT '{hi}'::te[]"}
Bind {"DestinationPortal": "p3", "PreparedStatement": "s3", "ResultFormatCodes": [1]}
Execute {"Portal": "p3"}
Sync
----

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


# Prepare a query and use the binary format (ParameterFormatCodes = [1])
# This is crdb_only because the OID is part of the binary encoding, but
# PG and CRDB assign different OIDs for custom types.
# The "Parameters" field is the byte array representation of the binary string above.
send crdb_only
Parse {"Name": "s4", "Query": "INSERT INTO tba VALUES ($1)"}
Bind {"DestinationPortal": "p4", "PreparedStatement": "s4", "ParameterFormatCodes": [1], "Parameters": [{"binary":"0000000100000000000187080000000100000001000000026869"}]}
Execute {"Portal": "p4"}
Sync
----

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

send
Query {"String": "ALTER TYPE te ADD VALUE 'hola'"}
----

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

# Reuse original prepared statement now that there's a new enum value.
send
Bind {"DestinationPortal": "p", "PreparedStatement": "s1", "ParameterFormatCodes": [0], "Parameters": [{"text":"hola"}]}
Execute {"Portal": "p"}
Sync
----

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

# Ensure that our value was successfully inserted.
send
Query {"String": "SELECT * FROM tb WHERE x = 'hola'"}
----

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