Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/sql/src/plan/statement/dml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2119,9 +2119,18 @@ pub fn plan_copy(
if options.quote.is_some() {
sql_bail!("COPY TO does not support QUOTE option yet");
}
if options.escape.is_some() {
sql_bail!("COPY TO does not support ESCAPE option yet");
}
if options.null.is_some() {
sql_bail!("COPY TO does not support NULL option yet");
}
// `HEADER false` is the default and already honored; only an
// enabled header is unimplemented. Silently accepting it would
// make clients strip the first data row as a presumed header.
if options.header == Some(true) {
sql_bail!("COPY TO does not support HEADER option yet");
}
match relation {
CopyRelation::Named { .. } => sql_bail!("named with COPY TO STDOUT unsupported"),
CopyRelation::Select(stmt) => Ok(plan_select(
Expand Down
47 changes: 47 additions & 0 deletions test/pgtest/copy.pt
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,50 @@ CopyData "6,\n"
CopyDone
CommandComplete {"tag":"COPY 4"}
ReadyForQuery {"status":"I"}

# HEADER and ESCAPE are not implemented for COPY TO STDOUT. Ensure they error
# rather than being silently ignored: a client that requested a header would
# otherwise strip the first data row as a presumed header.
send
Query {"query": "COPY (VALUES (1, '2')) TO STDOUT WITH (FORMAT csv, HEADER)"}
----

until
ReadyForQuery
----
ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"XX000"},{"typ":"M","value":"COPY TO does not support HEADER option yet"}]}
ReadyForQuery {"status":"I"}

send
Query {"query": "COPY (VALUES (1, '2')) TO STDOUT WITH (FORMAT csv, HEADER true)"}
----

until
ReadyForQuery
----
ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"XX000"},{"typ":"M","value":"COPY TO does not support HEADER option yet"}]}
ReadyForQuery {"status":"I"}

send
Query {"query": "COPY (VALUES (1, '2')) TO STDOUT WITH (FORMAT csv, ESCAPE 'x')"}
----

until
ReadyForQuery
----
ErrorResponse {"fields":[{"typ":"S","value":"ERROR"},{"typ":"C","value":"XX000"},{"typ":"M","value":"COPY TO does not support ESCAPE option yet"}]}
ReadyForQuery {"status":"I"}

# HEADER false is the default behavior and remains accepted.
send
Query {"query": "COPY (VALUES (1, '2')) TO STDOUT WITH (FORMAT csv, HEADER false)"}
----

until
ReadyForQuery
----
CopyOut {"format":"text","column_formats":["text","text"]}
CopyData "1,2\n"
CopyDone
CommandComplete {"tag":"COPY 1"}
ReadyForQuery {"status":"I"}
Loading