(
&mut self,
format: CopyFormat,
row_desc: RelationDesc,
mut stream: RecordFirstRowStream,
)
| 2576 | |
| 2577 | #[mz_ore::instrument(level = "debug")] |
| 2578 | async fn copy_rows( |
| 2579 | &mut self, |
| 2580 | format: CopyFormat, |
| 2581 | row_desc: RelationDesc, |
| 2582 | mut stream: RecordFirstRowStream, |
| 2583 | ) -> Result<(State, SendRowsEndedReason), io::Error> { |
| 2584 | let (row_format, encode_format) = match format { |
| 2585 | CopyFormat::Text => ( |
| 2586 | CopyFormatParams::Text(CopyTextFormatParams::default()), |
| 2587 | Format::Text, |
| 2588 | ), |
| 2589 | CopyFormat::Binary => (CopyFormatParams::Binary, Format::Binary), |
| 2590 | CopyFormat::Csv => ( |
| 2591 | CopyFormatParams::Csv(CopyCsvFormatParams::default()), |
| 2592 | Format::Text, |
| 2593 | ), |
| 2594 | CopyFormat::Parquet => { |
| 2595 | let text = "Parquet format is not supported".to_string(); |
| 2596 | return self |
| 2597 | .send_error_and_get_state(ErrorResponse::error( |
| 2598 | SqlState::INTERNAL_ERROR, |
| 2599 | text.clone(), |
| 2600 | )) |
| 2601 | .await |
| 2602 | .map(|state| (state, SendRowsEndedReason::Errored { error: text })); |
| 2603 | } |
| 2604 | }; |
| 2605 | |
| 2606 | // Binary encoding is not implemented for some types (e.g., list, map, |
| 2607 | // and aclitem). Unlike the extended query protocol's Bind handler, COPY |
| 2608 | // does not validate this when binding the portal: the portal's result |
| 2609 | // formats describe the `CopyData` wrapper, not the COPY format itself, |
| 2610 | // so the Bind handler explicitly skips `COPY TO` statements. We must |
| 2611 | // therefore check here, before streaming any rows, otherwise |
| 2612 | // `encode_binary` would panic mid-stream (SQL-323). |
| 2613 | if let CopyFormat::Binary = format { |
| 2614 | if let Some(msg) = row_desc |
| 2615 | .iter_types() |
| 2616 | .find_map(|ty| mz_pgrepr::Value::binary_encoding_error(&ty.scalar_type).err()) |
| 2617 | { |
| 2618 | return self |
| 2619 | .send_error_and_get_state(ErrorResponse::error( |
| 2620 | SqlState::UNDEFINED_FUNCTION, |
| 2621 | msg, |
| 2622 | )) |
| 2623 | .await |
| 2624 | .map(|state| { |
| 2625 | ( |
| 2626 | state, |
| 2627 | SendRowsEndedReason::Errored { |
| 2628 | error: msg.to_string(), |
| 2629 | }, |
| 2630 | ) |
| 2631 | }); |
| 2632 | } |
| 2633 | } |
| 2634 | |
| 2635 | let encode_fn = |row: &RowRef, typ: &SqlRelationType, out: &mut Vec<u8>| { |
no test coverage detected