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

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

send
Query {"String": "CREATE TABLE t (i INT8, t TEXT)"}
----

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

# COPY with both empty string and \N for NULL.
send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN"}
CopyData {"Data": "1\tblah\n"}
CopyData {"Data": "2\t\n"}
CopyData {"Data": "3\t\\N\n"}
CopyData {"Data": "4\t\"\"\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 0"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 4"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"blah"}]}
{"Type":"DataRow","Values":[{"text":"2"},null]}
{"Type":"DataRow","Values":[{"text":"3"},null]}
{"Type":"DataRow","Values":[{"text":"4"},{"text":"\"\""}]}
{"Type":"CommandComplete","CommandTag":"SELECT 4"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "COPY (SELECT * FROM t) TO STDOUT"}
----

until
ReadyForQuery
----
{"Type":"CopyOutResponse","ColumnFormatCodes":[0,0]}
{"Type":"CopyData","Data":"3109626c61680a"}
{"Type":"CopyData","Data":"32090a"}
{"Type":"CopyData","Data":"33095c4e0a"}
{"Type":"CopyData","Data":"340922220a"}
{"Type":"CopyDone"}
{"Type":"CommandComplete","CommandTag":"COPY 4"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "COPY (SELECT * FROM t) TO STDOUT CSV HEADER"}
----

until
ReadyForQuery
----
{"Type":"CopyOutResponse","ColumnFormatCodes":[0,0]}
{"Type":"CopyData","Data":"692c740a"}
{"Type":"CopyData","Data":"312c626c61680a"}
{"Type":"CopyData","Data":"322c22220a"}
{"Type":"CopyData","Data":"332c0a"}
{"Type":"CopyData","Data":"342c2222222222220a"}
{"Type":"CopyDone"}
{"Type":"CommandComplete","CommandTag":"COPY 4"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Extra fields.

send crdb_only
Query {"String": "CREATE TABLE copy_hidden_table (id INT, nv TEXT NOT VISIBLE, t TEXT)"}
----

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

send crdb_only
Query {"String": "COPY copy_hidden_table FROM STDIN"}
CopyData {"Data": "1\tblah\tbad\tpk\n"}
CopyDone
----

until crdb_only keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"ErrorResponse","Code":"22P04","Message":"expected 2 values, got 4"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send crdb_only
Query {"String": "COPY copy_hidden_table FROM STDIN CSV"}
CopyData {"Data": "2,blah,bad,pk\n"}
CopyDone
----

until crdb_only keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"ErrorResponse","Code":"22P04","Message":"read CSV record: record on line 1: wrong number of fields"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send crdb_only
Query {"String": "COPY copy_hidden_table FROM STDIN"}
CopyData {"Data": "3\tgood\n"}
CopyDone
----

until crdb_only
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Set expect_and_ignore_not_visible_columns_in_copy - now it should be allowed.
# We insert 4 columns because the rowid column is also implicit.
send crdb_only
Query {"String": "SET expect_and_ignore_not_visible_columns_in_copy = true"}
----

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

send crdb_only
Query {"String": "COPY copy_hidden_table FROM STDIN"}
CopyData {"Data": "1\tblah\tgood\tpk\n"}
CopyDone
----

until crdb_only
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send crdb_only
Query {"String": "COPY copy_hidden_table FROM STDIN CSV"}
CopyData {"Data": "2,blah,good,pk\n"}
CopyDone
----

until crdb_only
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send crdb_only
Query {"String": "COPY copy_hidden_table FROM STDIN"}
CopyData {"Data": "4\tnow_bad\n"}
CopyDone
----

until crdb_only keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"ErrorResponse","Code":"22P04","Message":"expected 4 values, got 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send crdb_only
Query {"String": "SELECT *, nv FROM copy_hidden_table ORDER BY id"}
----

until ignore=RowDescription crdb_only
ReadyForQuery
----
{"Type":"DataRow","Values":[{"text":"1"},{"text":"good"},null]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"good"},null]}
{"Type":"DataRow","Values":[{"text":"3"},{"text":"good"},null]}
{"Type":"CommandComplete","CommandTag":"SELECT 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send crdb_only
Query {"String": "SET expect_and_ignore_not_visible_columns_in_copy = false"}
----

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

# Test cancelling copy.

send
Query {"String": "COPY t FROM STDIN"}
CopyFail { "Message": "client received an error" }
----

until keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"ErrorResponse","Code":"57014","Message":"COPY from stdin failed: client received an error"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Invalid ESCAPE syntax.
send
Query {"String": "COPY t FROM STDIN ESCAPE 'xxx'"}
----

until
ErrorResponse
ReadyForQuery
----
{"Type":"ErrorResponse","Code":"0A000"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "COPY t FROM STDIN ESCAPE 'x'"}
----

until
ErrorResponse
ReadyForQuery
----
{"Type":"ErrorResponse","Code":"0A000"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Header without CSV.
send
Query {"String": "COPY t FROM STDIN HEADER"}
----

until
ErrorResponse
ReadyForQuery
----
{"Type":"ErrorResponse","Code":"0A000"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Wrong number of columns.
send
Query {"String": "COPY t FROM STDIN"}
CopyData {"Data": "1\n"}
CopyData {"Data": "\\.\n"}
CopyDone
----

until
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"ErrorResponse","Code":"22P04"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that only one COPY can run at once.
# This crashes PG, so only run on CRDB.
send crdb_only
Query {"String": "COPY t FROM STDIN"}
Query {"String": "COPY t FROM STDIN"}
----

until crdb_only
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"ErrorResponse","Code":"08P01"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that after a COPY has started another statement cannot run.
# This crashes PG, so only run on CRDB.
send crdb_only
Query {"String": "COPY t FROM STDIN"}
Query {"String": "SELECT 2"}
----

until ignore=RowDescription crdb_only
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"ErrorResponse","Code":"08P01"}
{"Type":"ReadyForQuery","TxStatus":"I"}

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

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

send
Query {"String": "CREATE TABLE t (i INT8, t TEXT)"}
----

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

send
Query {"String": "COPY t FROM STDIN"}
CopyData {"Data": "1\tblah\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"blah"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN DELIMITER ','"}
CopyData {"Data": "1,blah\n"}
CopyData {"Data": "2,\\N\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"blah"}]}
{"Type":"DataRow","Values":[{"text":"2"},null]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN HEADER CSV"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "COPY t FROM STDIN HEADER CSV"}
CopyData {"Data": "justonelinewithheader\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "COPY t FROM STDIN HEADER CSV"}
CopyData {"Data": "ignore,this,entire,line\n"}
CopyData {"Data": "1,blah\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 0"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 0"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"blah"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN NULL 'NS'"}
CopyData {"Data": "1\tblah\n"}
CopyData {"Data": "2\t\\N\n"}
CopyData {"Data": "3\tNS\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"blah"}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"N"}]}
{"Type":"DataRow","Values":[{"text":"3"},null]}
{"Type":"CommandComplete","CommandTag":"SELECT 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "COPY t FROM STDIN"}
CopyData {"Data": "1\n"}
CopyData {"Data": "\\.\n"}
CopyDone
----

until ignore=RowDescription
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"ErrorResponse","Code":"22P04"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN CSV"}
CopyData {"Data": "1,blah\n"}
CopyData {"Data": "2,\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"blah"}]}
{"Type":"DataRow","Values":[{"text":"2"},null]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN CSV NULL 'NS' DELIMITER '|'"}
CopyData {"Data": "1|blah\n"}
CopyData {"Data": "2|NS\n"}
CopyData {"Data": "3|\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"blah"}]}
{"Type":"DataRow","Values":[{"text":"2"},null]}
{"Type":"DataRow","Values":[{"text":"3"},null]}
{"Type":"CommandComplete","CommandTag":"SELECT 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN CSV ESCAPE 'x'"}
CopyData {"Data": "1,\"x\"\"\n"}
CopyData {"Data": "2,\"xxx\",\"\n"}
CopyData {"Data": "3,\"xxx\",xx\"\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"\""}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"x\","}]}
{"Type":"DataRow","Values":[{"text":"3"},{"text":"x\",x"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "COPY t FROM STDIN CSV"}
CopyData {"Data": "1\n"}
CopyData {"Data": "\\.\n"}
CopyDone
----

until ignore=RowDescription
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"ErrorResponse","Code":"22P04"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN CSV"}
CopyData {"Data": "1,one\n2,two\n3,three"}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"one"}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"two"}]}
{"Type":"DataRow","Values":[{"text":"3"},{"text":"three"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN DELIMITER ',' NULL ''"}
CopyData {"Data": "1,one\n2,two\n3,three"}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"one"}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"two"}]}
{"Type":"DataRow","Values":[{"text":"3"},{"text":"three"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that the format code is reported as binary.
# This also verifies that the protocol checks for the correct
# binary signature.
send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN WITH BINARY"}
CopyData {"BinaryData": "UEdDT1BZCv8NCgAAAAAAAAAAAAACAAAACAAAAAAAAAABAAAAA2NhdAACAAAACAAAAAAAAAACAAAAA2RvZw=="}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[1,1]}
{"Type":"CommandComplete","CommandTag":"COPY 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"cat"}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"dog"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that COPY binary input can be split up at an arbitrary point.
send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN WITH BINARY"}
CopyData {"BinaryData": "UEdDT1BZCv8NCgAAAAAAAAAA"}
CopyData {"BinaryData": "AAACAAAACAAAAAAAAAABAAAAA2NhdAACAAAACAAAAAAAAAACAAAAA2RvZw=="}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[1,1]}
{"Type":"CommandComplete","CommandTag":"COPY 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"cat"}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"dog"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that COPY binary input can be split up at another arbitrary point.
send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN WITH BINARY"}
CopyData {"BinaryData": "UEdDT1BZCv8NCgAAAAAAAAAAAAACAAAACAAA"}
CopyData {"BinaryData": "AAAAAAABAAAAA2NhdAACAAAACAAAAAAAAAAC"}
CopyData {"BinaryData": "AAAAA2RvZw=="}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[1,1]}
{"Type":"CommandComplete","CommandTag":"COPY 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"cat"}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"dog"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Test that we distinguish an empty column from a quoted empty string.
# By default, an empty column is NULL.
# If We specify another NULL token, then the empty column does get interpreted
# as an empty string.

send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN WITH CSV"}
CopyData {"Data": "1,cat\n"}
CopyData {"Data": "2,\"\"\n"}
CopyData {"Data": "3,\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "COPY t FROM STDIN WITH CSV NULL 'N'"}
CopyData {"Data": "4,\"\"\n"}
CopyData {"Data": "5,\n"}
CopyData {"Data": "6,N\n"}
CopyData {"Data": "7,\"N\"\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT i, length(t) FROM t ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 4"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"3"}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"0"}]}
{"Type":"DataRow","Values":[{"text":"3"},null]}
{"Type":"DataRow","Values":[{"text":"4"},{"text":"0"}]}
{"Type":"DataRow","Values":[{"text":"5"},{"text":"0"}]}
{"Type":"DataRow","Values":[{"text":"6"},null]}
{"Type":"DataRow","Values":[{"text":"7"},{"text":"1"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 7"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that COPY CSV input can be split up at arbitrary points.
send
Query {"String": "DELETE FROM t"}
Query {"String": "COPY t FROM STDIN WITH CSV"}
CopyData {"Data": "1,o"}
CopyData {"Data": "ne\n2,"}
CopyData {"Data": "tw"}
CopyData {"Data": "o\n"}
CopyData {"Data": "3,\""}
CopyData {"Data": "three\""}
CopyData {"Data": "\"e"}
CopyData {"Data": "e\"\n4,\"four\n"}
CopyData {"Data": "r\nr"}
CopyData {"Data": "\"\n5,\"f\n\"\"ive\"\n6,\"six"}
CopyData {"Data": "\""}
CopyData {"Data": "\n7,seven\n8,eight\n9,\"n\nii"}
CopyData {"Data": "ii\n"}
CopyData {"Data": "ne\""}
CopyDone
Query {"String": "SELECT * FROM t ORDER BY i"}
----

until ignore=NoticeResponse ignore=RowDescription
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DELETE 7"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 9"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"one"}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"two"}]}
{"Type":"DataRow","Values":[{"text":"3"},{"text":"three\"ee"}]}
{"Type":"DataRow","Values":[{"text":"4"},{"binary":"666f75720a720a72"}]}
{"Type":"DataRow","Values":[{"text":"5"},{"binary":"660a22697665"}]}
{"Type":"DataRow","Values":[{"text":"6"},{"text":"six"}]}
{"Type":"DataRow","Values":[{"text":"7"},{"text":"seven"}]}
{"Type":"DataRow","Values":[{"text":"8"},{"text":"eight"}]}
{"Type":"DataRow","Values":[{"text":"9"},{"binary":"6e0a696969690a6e65"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 9"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that byte-escape sequences are processed in TEXT mode.
send
Query {"String": "DROP TABLE IF EXISTS tb"}
Query {"String": "CREATE TABLE tb (i INT, b BYTEA, c TEXT)"}
Query {"String": "COPY tb FROM STDIN DELIMITER ',' NULL ''"}
CopyData {"Data": "1,one,one\n"}
CopyData {"Data": "2,two\\x54,two\\x54\n"}
CopyData {"Data": "3,ab\\011\\143d,ab\\011\\143d"}
CopyDone
Query {"String": "SELECT i, encode(b, 'hex'), c FROM tb ORDER BY i"}
----

until ignore=RowDescription ignore=NoticeResponse
ReadyForQuery
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DROP TABLE"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CommandComplete","CommandTag":"CREATE TABLE"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"6f6e65"},{"text":"one"}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"74776f54"},{"text":"twoT"}]}
{"Type":"DataRow","Values":[{"text":"3"},{"text":"6162096364"},{"binary":"6162096364"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 3"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Verify that byte-escape sequences are NOT processed in CSV mode. Note that
# the octal-encoded input for the bytea column is properly decoded -- that is
# because of the way CRDB and PG process bytea literals, and *not* because of
# CSV escaping.
send
Query {"String": "DROP TABLE IF EXISTS tb"}
Query {"String": "CREATE TABLE tb (i INT, b BYTEA, c TEXT)"}
Query {"String": "COPY tb FROM STDIN WITH CSV"}
CopyData {"Data": "1,one,one\n"}
CopyData {"Data": "2,two,two\\x54\n"}
CopyData {"Data": "3,ab\\011\\143d,ab\\011\\143d\n"}
CopyData {"Data": "4,\"\\x6869\",hi\n"}
CopyData {"Data": "5,\\x6869,hi\n"}
CopyDone
Query {"String": "SELECT i, encode(b, 'hex'), c FROM tb ORDER BY i"}
----

until ignore=RowDescription ignore=NoticeResponse
ReadyForQuery
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"DROP TABLE"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CommandComplete","CommandTag":"CREATE TABLE"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 5"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"6f6e65"},{"text":"one"}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"74776f"},{"text":"two\\x54"}]}
{"Type":"DataRow","Values":[{"text":"3"},{"text":"6162096364"},{"text":"ab\\011\\143d"}]}
{"Type":"DataRow","Values":[{"text":"4"},{"text":"6869"},{"text":"hi"}]}
{"Type":"DataRow","Values":[{"text":"5"},{"text":"6869"},{"text":"hi"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 5"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Test error cases for COPY CSV.
send
Query {"String": "COPY t FROM STDIN WITH CSV"}
CopyData {"Data": "10,\"ten\"\n\n\n11,eleven"}
CopyDone
----

until
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"ErrorResponse","Code":"22P04"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "COPY t FROM STDIN WITH CSV"}
CopyData {"Data": "1,\"one\n"}
CopyDone
----

until
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"ErrorResponse","Code":"22P04"}
{"Type":"ReadyForQuery","TxStatus":"I"}

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

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

send
Query {"String": "CREATE TABLE t (i INT8, t TIMESTAMPTZ)"}
----

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

send
Query {"String": "SET TIME ZONE UTC"}
Query {"String": "COPY t FROM STDIN CSV"}
CopyData {"Data": "1,2021-09-20T06:05:04\n"}
CopyData {"Data": "\\.\n"}
CopyDone
----

until ignore=RowDescription ignore=ParameterStatus
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"SET"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

send
Query {"String": "SET TIME ZONE \"America/Chicago\""}
Query {"String": "COPY t FROM STDIN CSV"}
CopyData {"Data": "2,2021-09-20T06:05:04\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT i, t FROM t ORDER BY i"}
----

until ignore=RowDescription ignore=ParameterStatus
ReadyForQuery
ReadyForQuery
ReadyForQuery
----
{"Type":"CommandComplete","CommandTag":"SET"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"2021-09-20 01:05:04-05"}]}
{"Type":"DataRow","Values":[{"text":"2"},{"text":"2021-09-20 06:05:04-05"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}

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

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

send
Query {"String": "CREATE TABLE c (d INT ARRAY);"}
----

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

send
Query {"String": "COPY c(d) FROM STDIN WITH CSV"}
CopyData {"Data": "\"{0,1}\"\n"}
CopyData {"Data": "\"{2,3,4,5,6}\"\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT * FROM c"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0]}
{"Type":"CommandComplete","CommandTag":"COPY 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"{0,1}"}]}
{"Type":"DataRow","Values":[{"text":"{2,3,4,5,6}"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}


send crdb_only
Query {"String": "COPY c(d) FROM STDIN WITH CSV"}
CopyData {"Data": "\"{0,1}\"\n"}
CopyData {"Data": "\"{2,3,4,5,6}\"\n"}
CopyData {"Data": "\\.\n"}
CopyDone
----


until crdb_only ignore=RowDescription
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0]}
{"Type":"CommandComplete","CommandTag":"COPY 2"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# SHOW LAST QUERY STATISTICS cannot be used as a statement source, so we
# store the result as a variable in the test.
let $copy_service_latency crdb_only
Query {"String": "SHOW LAST QUERY STATISTICS RETURNING service_latency"}
----

send crdb_only
Query {"String": "SELECT '$copy_service_latency'::INTERVAL > '0 seconds'::INTERVAL"}
----

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

# Verify that a CopyFail message does not break the conn_executor state machine.
send
Query {"String": "DROP TABLE IF EXISTS copy_fail_test"}
Query {"String": "CREATE TABLE copy_fail_test(a INT PRIMARY KEY)"}
----

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

send
Query {"String": "COPY copy_fail_test(a) FROM STDIN"}
CopyFail
----

until
ErrorResponse
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0]}
{"Type":"ErrorResponse","Code":"57014"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Previously there was a bug that caused the Parse to fail with "query execution
# canceled" since the cancellation from the CopyFail message was not cleaned up.
send
Parse {"Query": "SELECT count(*) FROM copy_fail_test"}
Bind
Execute
Sync
----

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


### Tests for COPY ... TO with prepared statements.

send
Parse {"Query": "COPY (select 1) TO STDOUT"}
Bind
Describe {"ObjectType": "P"}
Execute
Sync
----

# Everything works fine with no placeholders.
until
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"NoData"}
{"Type":"CopyOutResponse","ColumnFormatCodes":[0]}
{"Type":"CopyData","Data":"310a"}
{"Type":"CopyDone"}
{"Type":"CommandComplete","CommandTag":"COPY 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# We match the PostgreSQL behavior when trying to bind a placeholder in COPY TO.
send
Parse {"Query": "COPY (select $1::int) TO STDOUT"}
Bind {"Parameters": [{"text":"1"}]}
Execute
Sync
----

until keepErrMessage
ErrorResponse
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"ErrorResponse","Code":"08P01","Message":"bind message supplies 1 parameters, but requires 0","Detail":"statement summary \"COPY (SELECT) TO STDOUT\""}
{"Type":"ReadyForQuery","TxStatus":"I"}

# And it's also an error to _not_ bind a placeholder.
send
Parse {"Query": "COPY (select $1::int) TO STDOUT"}
Bind
Execute
Sync
----

until keepErrMessage noncrdb_only
ErrorResponse
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"ErrorResponse","Code":"42P02","Message":"there is no parameter $1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# CockroachDB has the same error as PostgreSQL, with a slightly different message.
until keepErrMessage crdb_only
ErrorResponse
ReadyForQuery
----
{"Type":"ParseComplete"}
{"Type":"BindComplete"}
{"Type":"CopyOutResponse","ColumnFormatCodes":null}
{"Type":"ErrorResponse","Code":"42P02","Message":"COPY (SELECT $1::INT8) TO STDOUT: no value provided for placeholder: $1"}
{"Type":"ReadyForQuery","TxStatus":"I"}

# Regression test for unsetting the eval context on the COPY's planner
# incorrectly (#104456).
send
Query {"String": "CREATE TABLE t104456 (i INT8, t TEXT, ts TIMESTAMP DEFAULT now())"}
----

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

send
Query {"String": "COPY t104456 (i, t) FROM STDIN"}
CopyData {"Data": "1\tblah\n"}
CopyData {"Data": "\\.\n"}
CopyDone
Query {"String": "SELECT i, t FROM t104456 ORDER BY i"}
----

until ignore=RowDescription
ReadyForQuery
ReadyForQuery
----
{"Type":"CopyInResponse","ColumnFormatCodes":[0,0]}
{"Type":"CommandComplete","CommandTag":"COPY 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}
{"Type":"DataRow","Values":[{"text":"1"},{"text":"blah"}]}
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
{"Type":"ReadyForQuery","TxStatus":"I"}
