1use std::collections::BTreeMap;
11use std::convert::TryFrom;
12use std::future::Future;
13use std::ops::Deref;
14use std::sync::Arc;
15use std::time::{Duration, Instant};
16use std::{iter, mem};
17
18use base64::prelude::*;
19use byteorder::{ByteOrder, NetworkEndian};
20use csv_core::ReadRecordResult;
21use futures::future::{BoxFuture, FutureExt, pending};
22use itertools::Itertools;
23use mz_adapter::client::RecordFirstRowStream;
24use mz_adapter::session::{
25 EndTransactionAction, InProgressRows, LifecycleTimestamps, PortalRefMut, PortalState, Session,
26 SessionConfig, TransactionStatus,
27};
28use mz_adapter::statement_logging::{StatementEndedExecutionReason, StatementExecutionStrategy};
29use mz_adapter::{
30 AdapterError, AdapterNotice, ExecuteContextGuard, ExecuteResponse, PeekResponseUnary, metrics,
31 verify_datum_desc,
32};
33use mz_adapter_types::dyncfgs::OIDC_GROUP_CLAIM;
34use mz_auth::Authenticated;
35use mz_auth::password::Password;
36use mz_authenticator::{Authenticator, GenericOidcAuthenticator};
37use mz_frontegg_auth::Authenticator as FronteggAuthenticator;
38use mz_ore::cast::CastFrom;
39use mz_ore::netio::AsyncReady;
40use mz_ore::now::{EpochMillis, SYSTEM_TIME};
41use mz_ore::str::StrExt;
42use mz_ore::{assert_none, assert_ok, instrument, soft_assert_eq_or_log, soft_assert_or_log};
43use mz_pgcopy::{CopyCsvFormatParams, CopyFormatParams, CopyTextFormatParams};
44use mz_pgwire_common::{
45 ConnectionCounter, Cursor, ErrorResponse, Format, FrontendMessage, Severity, VERSION_3,
46 VERSIONS,
47};
48use mz_repr::{
49 CatalogItemId, ColumnIndex, Datum, RelationDesc, RowArena, RowIterator, RowRef,
50 SqlRelationType, SqlScalarType,
51};
52use mz_server_core::TlsMode;
53use mz_server_core::listeners;
54use mz_server_core::listeners::AllowedRoles;
55use mz_sql::ast::display::AstDisplay;
56use mz_sql::ast::{
57 CopyDirection, CopyStatement, CopyTarget, FetchDirection, Ident, Raw, Statement,
58};
59use mz_sql::parse::StatementParseResult;
60use mz_sql::plan::{CopyFormat, ExecuteTimeout, StatementDesc};
61use mz_sql::session::metadata::SessionMetadata;
62use mz_sql::session::user::INTERNAL_USER_NAMES;
63use mz_sql::session::vars::VarInput;
64use postgres::error::SqlState;
65use tokio::io::{self, AsyncRead, AsyncWrite};
66use tokio::select;
67use tokio::time::{self};
68use tokio_metrics::TaskMetrics;
69use tokio_stream::wrappers::UnboundedReceiverStream;
70use tracing::{Instrument, debug, debug_span, warn};
71use uuid::Uuid;
72
73use crate::codec::{
74 FramedConn, decode_password, decode_sasl_initial_response, decode_sasl_response,
75};
76use crate::message::{
77 self, BackendMessage, SASLServerFinalMessage, SASLServerFinalMessageKinds,
78 SASLServerFirstMessage,
79};
80
81pub fn match_handshake(buf: &[u8]) -> bool {
85 if buf.len() < 8 {
95 return false;
96 }
97 let version = NetworkEndian::read_i32(&buf[4..8]);
98 VERSIONS.contains(&version)
99}
100
101pub struct RunParams<'a, A, I>
103where
104 I: Iterator<Item = TaskMetrics> + Send,
105{
106 pub tls_mode: Option<TlsMode>,
108 pub adapter_client: mz_adapter::Client,
110 pub conn: &'a mut FramedConn<A>,
112 pub conn_uuid: Uuid,
114 pub version: i32,
116 pub params: BTreeMap<String, String>,
118 pub frontegg: Option<FronteggAuthenticator>,
120 pub oidc: GenericOidcAuthenticator,
122 pub authenticator_kind: listeners::AuthenticatorKind,
125 pub active_connection_counter: ConnectionCounter,
127 pub helm_chart_version: Option<String>,
129 pub allowed_roles: AllowedRoles,
131 pub tokio_metrics_intervals: I,
133}
134
135#[mz_ore::instrument(level = "debug")]
145pub async fn run<'a, A, I>(
146 RunParams {
147 tls_mode,
148 adapter_client,
149 conn,
150 conn_uuid,
151 version,
152 mut params,
153 frontegg,
154 oidc,
155 authenticator_kind,
156 active_connection_counter,
157 helm_chart_version,
158 allowed_roles,
159 tokio_metrics_intervals,
160 }: RunParams<'a, A, I>,
161) -> Result<(), io::Error>
162where
163 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin,
164 I: Iterator<Item = TaskMetrics> + Send,
165{
166 if version != VERSION_3 {
167 return conn
168 .send(ErrorResponse::fatal(
169 SqlState::SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION,
170 "server does not support the client's requested protocol version",
171 ))
172 .await;
173 }
174
175 let user = params.remove("user").unwrap_or_else(String::new);
176 let options = parse_options(params.get("options").unwrap_or(&String::new()));
177 let authenticator =
178 get_authenticator(authenticator_kind, frontegg, oidc, adapter_client.clone());
179 let is_internal_user = INTERNAL_USER_NAMES.contains(&user);
181 let is_reserved_user = mz_adapter::catalog::is_reserved_role_name(user.as_str());
183 let role_allowed = match allowed_roles {
184 AllowedRoles::Normal => !is_reserved_user,
185 AllowedRoles::Internal => is_internal_user,
186 AllowedRoles::NormalAndInternal => !is_reserved_user || is_internal_user,
187 };
188 if !role_allowed {
189 let msg = format!("unauthorized login to user '{user}'");
190 return conn
191 .send(ErrorResponse::fatal(SqlState::INSUFFICIENT_PRIVILEGE, msg))
192 .await;
193 }
194
195 if let Err(err) = conn.inner().ensure_tls_compatibility(&tls_mode) {
196 return conn.send(err).await;
197 }
198
199 let authenticator_kind = authenticator.kind();
200
201 let (mut session, expired) = match authenticator {
202 Authenticator::Frontegg(frontegg) => {
203 let password = match request_cleartext_password(conn).await {
204 Ok(password) => password,
205 Err(PasswordRequestError::IoError(e)) => return Err(e),
206 Err(PasswordRequestError::InvalidPasswordError(e)) => {
207 return conn.send(e).await;
208 }
209 };
210
211 let group_claim =
212 OIDC_GROUP_CLAIM.get(adapter_client.get_system_vars().await.dyncfgs());
213 let auth_response = frontegg
214 .authenticate(&user, &password, Some(&group_claim))
215 .await;
216 match auth_response {
217 Ok((mut auth_session, authenticated)) => {
224 let groups = auth_session.groups();
225 let session = adapter_client.new_session(
226 SessionConfig {
227 conn_id: conn.conn_id().clone(),
228 uuid: conn_uuid,
229 user: auth_session.user().into(),
230 client_ip: conn.peer_addr().clone(),
231 external_metadata_rx: Some(auth_session.external_metadata_rx()),
232 helm_chart_version,
233 authenticator_kind,
234 groups,
235 },
236 authenticated,
237 );
238 let expired = async move { auth_session.expired().await };
239 (session, expired.left_future())
240 }
241 Err(err) => {
242 warn!(?err, "pgwire connection failed authentication");
243 return conn
244 .send(ErrorResponse::fatal(
245 SqlState::INVALID_PASSWORD,
246 "invalid password",
247 ))
248 .await;
249 }
250 }
251 }
252 Authenticator::Oidc(oidc) => {
253 let password = match request_cleartext_password(conn).await {
256 Ok(password) => password,
257 Err(PasswordRequestError::IoError(e)) => return Err(e),
258 Err(PasswordRequestError::InvalidPasswordError(e)) => {
259 return conn.send(e).await;
260 }
261 };
262 if is_jwt(&password) {
263 let auth_response = oidc.authenticate(&password, Some(&user)).await;
264 match auth_response {
265 Ok((mut claims, authenticated)) => {
266 let groups = claims.groups.take();
267 let session = adapter_client.new_session(
268 SessionConfig {
269 conn_id: conn.conn_id().clone(),
270 uuid: conn_uuid,
271 user: std::mem::take(&mut claims.user),
272 client_ip: conn.peer_addr().clone(),
273 external_metadata_rx: None,
274 helm_chart_version,
275 authenticator_kind,
276 groups,
277 },
278 authenticated,
279 );
280 (session, pending().right_future())
283 }
284 Err(err) => {
285 warn!(?err, "pgwire connection failed authentication");
286 return conn.send(err.into_response()).await;
287 }
288 }
289 } else {
290 let session = match authenticate_with_password(
291 conn,
292 &adapter_client,
293 user,
294 Password(password),
295 conn_uuid,
296 helm_chart_version,
297 )
298 .await
299 {
300 Ok(session) => session,
301 Err(PasswordRequestError::IoError(e)) => return Err(e),
302 Err(PasswordRequestError::InvalidPasswordError(e)) => {
303 return conn.send(e).await;
304 }
305 };
306 (session, pending().right_future())
307 }
308 }
309 Authenticator::Password(adapter_client) => {
310 let password = match request_cleartext_password(conn).await {
311 Ok(password) => password,
312 Err(PasswordRequestError::IoError(e)) => return Err(e),
313 Err(PasswordRequestError::InvalidPasswordError(e)) => {
314 return conn.send(e).await;
315 }
316 };
317 let session = match authenticate_with_password(
318 conn,
319 &adapter_client,
320 user,
321 Password(password),
322 conn_uuid,
323 helm_chart_version,
324 )
325 .await
326 {
327 Ok(session) => session,
328 Err(PasswordRequestError::IoError(e)) => return Err(e),
329 Err(PasswordRequestError::InvalidPasswordError(e)) => {
330 return conn.send(e).await;
331 }
332 };
333 (session, pending().right_future())
335 }
336 Authenticator::Sasl(adapter_client) => {
337 conn.send(BackendMessage::AuthenticationSASL).await?;
339 conn.flush().await?;
340 let (mechanism, initial_response) = match conn.recv().await? {
342 Some(FrontendMessage::RawAuthentication(data)) => {
343 match decode_sasl_initial_response(Cursor::new(&data)).ok() {
344 Some(FrontendMessage::SASLInitialResponse {
345 gs2_header,
346 mechanism,
347 initial_response,
348 }) => {
349 if gs2_header.channel_binding_enabled() {
351 return conn
352 .send(ErrorResponse::fatal(
353 SqlState::PROTOCOL_VIOLATION,
354 "channel binding not supported",
355 ))
356 .await;
357 }
358 (mechanism, initial_response)
359 }
360 _ => {
361 return conn
362 .send(ErrorResponse::fatal(
363 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
364 "expected SASLInitialResponse message",
365 ))
366 .await;
367 }
368 }
369 }
370 _ => {
371 return conn
372 .send(ErrorResponse::fatal(
373 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
374 "expected SASLInitialResponse message",
375 ))
376 .await;
377 }
378 };
379
380 if mechanism != "SCRAM-SHA-256" {
381 return conn
382 .send(ErrorResponse::fatal(
383 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
384 "unsupported SASL mechanism",
385 ))
386 .await;
387 }
388
389 if initial_response.nonce.len() > 256 {
390 return conn
391 .send(ErrorResponse::fatal(
392 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
393 "nonce too long",
394 ))
395 .await;
396 }
397
398 let (server_first_message_raw, mock_hash) = match adapter_client
399 .generate_sasl_challenge(&user, &initial_response.nonce)
400 .await
401 {
402 Ok(response) => {
403 let server_first_message_raw = format!(
404 "r={},s={},i={}",
405 response.nonce, response.salt, response.iteration_count
406 );
407
408 let client_key = [0u8; 32];
409 let server_key = [1u8; 32];
410 let mock_hash = format!(
411 "SCRAM-SHA-256${}:{}${}:{}",
412 response.iteration_count,
413 response.salt,
414 BASE64_STANDARD.encode(client_key),
415 BASE64_STANDARD.encode(server_key)
416 );
417
418 conn.send(BackendMessage::AuthenticationSASLContinue(
419 SASLServerFirstMessage {
420 iteration_count: response.iteration_count,
421 nonce: response.nonce,
422 salt: response.salt,
423 },
424 ))
425 .await?;
426 conn.flush().await?;
427 (server_first_message_raw, mock_hash)
428 }
429 Err(e) => {
430 return conn.send(e.into_response(Severity::Fatal)).await;
431 }
432 };
433
434 let authenticated = match conn.recv().await? {
435 Some(FrontendMessage::RawAuthentication(data)) => {
436 match decode_sasl_response(Cursor::new(&data)).ok() {
437 Some(FrontendMessage::SASLResponse(response)) => {
438 let auth_message = format!(
439 "{},{},{}",
440 initial_response.client_first_message_bare_raw,
441 server_first_message_raw,
442 response.client_final_message_bare_raw
443 );
444 if response.proof.len() > 1024 {
445 return conn
446 .send(ErrorResponse::fatal(
447 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
448 "proof too long",
449 ))
450 .await;
451 }
452 match adapter_client
453 .verify_sasl_proof(
454 &user,
455 &response.proof,
456 &auth_message,
457 &mock_hash,
458 )
459 .await
460 {
461 Ok((proof_response, authenticated)) => {
462 conn.send(BackendMessage::AuthenticationSASLFinal(
463 SASLServerFinalMessage {
464 kind: SASLServerFinalMessageKinds::Verifier(
465 proof_response.verifier,
466 ),
467 extensions: vec![],
468 },
469 ))
470 .await?;
471 conn.flush().await?;
472 authenticated
473 }
474 Err(_) => {
475 return conn
476 .send(ErrorResponse::fatal(
477 SqlState::INVALID_PASSWORD,
478 "invalid password",
479 ))
480 .await;
481 }
482 }
483 }
484 _ => {
485 return conn
486 .send(ErrorResponse::fatal(
487 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
488 "expected SASLResponse message",
489 ))
490 .await;
491 }
492 }
493 }
494 _ => {
495 return conn
496 .send(ErrorResponse::fatal(
497 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
498 "expected SASLResponse message",
499 ))
500 .await;
501 }
502 };
503
504 let session = adapter_client.new_session(
505 SessionConfig {
506 conn_id: conn.conn_id().clone(),
507 uuid: conn_uuid,
508 user,
509 client_ip: conn.peer_addr().clone(),
510 external_metadata_rx: None,
511 helm_chart_version,
512 authenticator_kind,
513 groups: None,
514 },
515 authenticated,
516 );
517 let auth_session = pending().right_future();
519 (session, auth_session)
520 }
521
522 Authenticator::None => {
523 let session = adapter_client.new_session(
524 SessionConfig {
525 conn_id: conn.conn_id().clone(),
526 uuid: conn_uuid,
527 user,
528 client_ip: conn.peer_addr().clone(),
529 external_metadata_rx: None,
530 helm_chart_version,
531 authenticator_kind,
532 groups: None,
533 },
534 Authenticated,
535 );
536 let auth_session = pending().right_future();
538 (session, auth_session)
539 }
540 };
541
542 let system_vars = adapter_client.get_system_vars().await;
543 let mut applied_params = vec![];
547 for (name, value) in params {
548 let settings = match name.as_str() {
549 "options" => match &options {
550 Ok(opts) => opts,
551 Err(()) => {
552 session.add_notice(AdapterNotice::BadStartupSetting {
553 name,
554 reason: "could not parse".into(),
555 });
556 continue;
557 }
558 },
559 _ => &vec![(name, value)],
560 };
561 for (key, val) in settings {
562 const LOCAL: bool = false;
563 match session
568 .vars_mut()
569 .set(&system_vars, key, VarInput::Flat(val), LOCAL)
570 {
571 Ok(()) => applied_params.push((key.clone(), val.clone())),
572 Err(err) => {
573 session.add_notice(AdapterNotice::BadStartupSetting {
574 name: key.clone(),
575 reason: err.to_string(),
576 });
577 }
578 }
579 }
580 }
581 session
582 .vars_mut()
583 .end_transaction(EndTransactionAction::Commit);
584
585 let _guard = match active_connection_counter.allocate_connection(session.user()) {
586 Ok(drop_connection) => drop_connection,
587 Err(e) => {
588 let e: AdapterError = e.into();
589 return conn.send(e.into_response(Severity::Fatal)).await;
590 }
591 };
592
593 let mut adapter_client = match adapter_client.startup(session).await {
595 Ok(adapter_client) => adapter_client,
596 Err(e) => return conn.send(e.into_response(Severity::Fatal)).await,
597 };
598
599 for (key, val) in applied_params {
607 if let Err(err) = adapter_client
608 .session()
609 .vars_mut()
610 .set_default(&key, VarInput::Flat(&val))
611 {
612 mz_ore::soft_panic_or_log!("failed to apply startup parameter as default: {err:?}");
614 }
615 }
616
617 let mut buf = vec![BackendMessage::AuthenticationOk];
618 for var in adapter_client.session().vars().notify_set() {
619 buf.push(BackendMessage::ParameterStatus(var.name(), var.value()));
620 }
621 buf.push(BackendMessage::BackendKeyData {
622 conn_id: adapter_client.session().conn_id().unhandled(),
623 secret_key: adapter_client.session().secret_key(),
624 });
625 buf.extend(
626 adapter_client
627 .session()
628 .drain_notices()
629 .into_iter()
630 .map(|notice| BackendMessage::ErrorResponse(notice.into_response())),
631 );
632 buf.push(BackendMessage::ReadyForQuery(
633 adapter_client.session().transaction().into(),
634 ));
635 conn.send_all(buf).await?;
636 conn.flush().await?;
637
638 let machine = StateMachine {
639 conn,
640 adapter_client,
641 txn_needs_commit: false,
642 tokio_metrics_intervals,
643 };
644
645 select! {
646 r = machine.run() => {
647 if let Err(err) = &r {
652 let _ = conn
653 .send(ErrorResponse::fatal(
654 SqlState::CONNECTION_FAILURE,
655 err.to_string(),
656 ))
657 .await;
658 let _ = conn.flush().await;
659 }
660 r
661 },
662 _ = expired => {
663 conn
664 .send(ErrorResponse::fatal(SqlState::INVALID_AUTHORIZATION_SPECIFICATION, "authentication expired"))
665 .await?;
666 conn.flush().await
667 }
668 }
669}
670
671fn is_jwt(password: &str) -> bool {
674 jsonwebtoken::decode_header(password).is_ok()
675}
676
677fn parse_options(value: &str) -> Result<Vec<(String, String)>, ()> {
682 let opts = split_options(value);
683 let mut pairs = Vec::with_capacity(opts.len());
684 let mut seen_prefix = false;
685 for opt in opts {
686 if !seen_prefix {
687 if opt == "-c" {
688 seen_prefix = true;
689 } else {
690 let (key, val) = parse_option(&opt)?;
691 pairs.push((key.to_owned(), val.to_owned()));
692 }
693 } else {
694 let (key, val) = opt.split_once('=').ok_or(())?;
695 pairs.push((key.to_owned(), val.to_owned()));
696 seen_prefix = false;
697 }
698 }
699 Ok(pairs)
700}
701
702fn parse_option(option: &str) -> Result<(&str, &str), ()> {
706 let (key, value) = option.split_once('=').ok_or(())?;
707 for prefix in &["-c", "--"] {
708 if let Some(key) = key.strip_prefix(prefix) {
709 return Ok((key, value));
710 }
711 }
712 Err(())
713}
714
715fn split_options(value: &str) -> Vec<String> {
717 let mut strs = Vec::new();
718 let mut current = String::new();
722 let mut was_slash = false;
723 for c in value.chars() {
724 was_slash = match c {
725 ' ' => {
726 if was_slash {
727 current.push(' ');
728 } else if !current.is_empty() {
729 strs.push(std::mem::take(&mut current));
732 }
733 false
734 }
735 '\\' => {
736 if was_slash {
737 current.push('\\');
740 false
741 } else {
742 true
743 }
744 }
745 _ => {
746 current.push(c);
747 false
748 }
749 };
750 }
751 if !current.is_empty() {
753 strs.push(current);
754 }
755 strs
756}
757
758enum PasswordRequestError {
759 InvalidPasswordError(ErrorResponse),
760 IoError(io::Error),
761}
762
763impl From<io::Error> for PasswordRequestError {
764 fn from(e: io::Error) -> Self {
765 PasswordRequestError::IoError(e)
766 }
767}
768
769async fn request_cleartext_password<A>(
773 conn: &mut FramedConn<A>,
774) -> Result<String, PasswordRequestError>
775where
776 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin,
777{
778 conn.send(BackendMessage::AuthenticationCleartextPassword)
779 .await?;
780 conn.flush().await?;
781
782 if let Some(message) = conn.recv().await? {
783 if let FrontendMessage::RawAuthentication(data) = message {
784 if let Some(FrontendMessage::Password { password }) =
785 decode_password(Cursor::new(&data)).ok()
786 {
787 return Ok(password);
788 }
789 }
790 }
791
792 Err(PasswordRequestError::InvalidPasswordError(
793 ErrorResponse::fatal(
794 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
795 "expected Password message",
796 ),
797 ))
798}
799
800async fn authenticate_with_password<A>(
803 conn: &FramedConn<A>,
804 adapter_client: &mz_adapter::Client,
805 user: String,
806 password: Password,
807 conn_uuid: Uuid,
808 helm_chart_version: Option<String>,
809) -> Result<Session, PasswordRequestError>
810where
811 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin,
812{
813 let authenticated = match adapter_client.authenticate(&user, &password).await {
814 Ok(authenticated) => authenticated,
815 Err(err) => {
816 warn!(?err, "pgwire connection failed authentication");
817 return Err(PasswordRequestError::InvalidPasswordError(
818 ErrorResponse::fatal(SqlState::INVALID_PASSWORD, "invalid password"),
819 ));
820 }
821 };
822
823 let session = adapter_client.new_session(
824 SessionConfig {
825 conn_id: conn.conn_id().clone(),
826 uuid: conn_uuid,
827 user,
828 client_ip: conn.peer_addr().clone(),
829 external_metadata_rx: None,
830 helm_chart_version,
831 authenticator_kind: mz_auth::AuthenticatorKind::Password,
832 groups: None,
833 },
834 authenticated,
835 );
836
837 Ok(session)
838}
839
840#[derive(Debug)]
841enum State {
842 Ready,
843 Drain,
844 Done,
845}
846
847struct StateMachine<'a, A, I>
848where
849 I: Iterator<Item = TaskMetrics> + Send + 'a,
850{
851 conn: &'a mut FramedConn<A>,
852 adapter_client: mz_adapter::SessionClient,
853 txn_needs_commit: bool,
854 tokio_metrics_intervals: I,
855}
856
857enum SendRowsEndedReason {
858 Success {
859 result_size: u64,
860 rows_returned: u64,
861 },
862 Errored {
863 error: String,
864 },
865 Canceled,
866}
867
868const ABORTED_TXN_MSG: &str =
869 "current transaction is aborted, commands ignored until end of transaction block";
870
871impl<'a, A, I> StateMachine<'a, A, I>
872where
873 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin + 'a,
874 I: Iterator<Item = TaskMetrics> + Send + 'a,
875{
876 #[allow(clippy::manual_async_fn)]
880 #[mz_ore::instrument(level = "debug")]
881 fn run(mut self) -> impl Future<Output = Result<(), io::Error>> + Send + 'a {
882 async move {
883 let mut state = State::Ready;
884 loop {
885 self.send_pending_notices().await?;
886 state = match state {
887 State::Ready => self.advance_ready().await?,
888 State::Drain => self.advance_drain().await?,
889 State::Done => return Ok(()),
890 };
891 self.adapter_client
892 .add_idle_in_transaction_session_timeout();
893 }
894 }
895 }
896
897 #[instrument(level = "debug")]
898 async fn advance_ready(&mut self) -> Result<State, io::Error> {
899 self.tokio_metrics_intervals
901 .next()
902 .expect("infinite iterator");
903
904 let message = select! {
906 biased;
907
908 Some(timeout) = self.adapter_client.recv_timeout() => {
910 let err: AdapterError = timeout.into();
911 let conn_id = self.adapter_client.session().conn_id();
912 tracing::warn!("session timed out, conn_id {}", conn_id);
913
914 let error_response = err.into_response(Severity::Fatal);
916 let error_state = self.send_error_and_get_state(error_response).await;
917
918 self.adapter_client.terminate().await;
920
921 let _ = self.conn.recv().await?;
925 return error_state;
926 },
927 message = self.conn.recv() => message?,
929 };
930
931 let interval = self
933 .tokio_metrics_intervals
934 .next()
935 .expect("infinite iterator");
936 let recv_scheduling_delay_ms = interval.total_scheduled_duration.as_secs_f64() * 1000.0;
937
938 let received = SYSTEM_TIME();
942
943 self.adapter_client
944 .remove_idle_in_transaction_session_timeout();
945
946 let message_name = message.as_ref().map(|m| m.name()).unwrap_or_default();
949
950 let start = message.as_ref().map(|_| Instant::now());
951 let next_state = match message {
952 Some(FrontendMessage::Query { sql }) => {
953 let query_root_span =
954 tracing::info_span!(parent: None, "advance_ready", otel.name = message_name);
955 query_root_span.follows_from(tracing::Span::current());
956 self.query(sql, received)
957 .instrument(query_root_span)
958 .await?
959 }
960 Some(FrontendMessage::Parse {
961 name,
962 sql,
963 param_types,
964 }) => self.parse(name, sql, param_types).await?,
965 Some(FrontendMessage::Bind {
966 portal_name,
967 statement_name,
968 param_formats,
969 raw_params,
970 result_formats,
971 }) => {
972 self.bind(
973 portal_name,
974 statement_name,
975 param_formats,
976 raw_params,
977 result_formats,
978 )
979 .await?
980 }
981 Some(FrontendMessage::Execute {
982 portal_name,
983 max_rows,
984 }) => {
985 let max_rows = match usize::try_from(max_rows) {
986 Ok(0) | Err(_) => ExecuteCount::All, Ok(n) => ExecuteCount::Count(n),
988 };
989 let execute_root_span =
990 tracing::info_span!(parent: None, "advance_ready", otel.name = message_name);
991 execute_root_span.follows_from(tracing::Span::current());
992 let state = self
993 .execute(
994 portal_name,
995 max_rows,
996 portal_exec_message,
997 None,
998 ExecuteTimeout::None,
999 None,
1000 Some(received),
1001 )
1002 .instrument(execute_root_span)
1003 .await?;
1004 if self.adapter_client.session().transaction().is_implicit() {
1019 self.txn_needs_commit = true;
1020 }
1021 state
1022 }
1023 Some(FrontendMessage::DescribeStatement { name }) => {
1024 self.describe_statement(&name).await?
1025 }
1026 Some(FrontendMessage::DescribePortal { name }) => self.describe_portal(&name).await?,
1027 Some(FrontendMessage::CloseStatement { name }) => self.close_statement(name).await?,
1028 Some(FrontendMessage::ClosePortal { name }) => self.close_portal(name).await?,
1029 Some(FrontendMessage::Flush) => self.flush().await?,
1030 Some(FrontendMessage::Sync) => self.sync().await?,
1031 Some(FrontendMessage::Terminate) => State::Done,
1032
1033 Some(FrontendMessage::CopyData(_))
1040 | Some(FrontendMessage::CopyDone)
1041 | Some(FrontendMessage::CopyFail(_)) => State::Ready,
1042
1043 Some(FrontendMessage::Password { .. })
1044 | Some(FrontendMessage::RawAuthentication(_))
1045 | Some(FrontendMessage::SASLInitialResponse { .. })
1046 | Some(FrontendMessage::SASLResponse(_)) => State::Drain,
1047 None => State::Done,
1048 };
1049
1050 if let Some(start) = start {
1051 self.adapter_client
1052 .inner()
1053 .metrics()
1054 .pgwire_message_processing_seconds
1055 .with_label_values(&[message_name])
1056 .observe(start.elapsed().as_secs_f64());
1057 }
1058 self.adapter_client
1059 .inner()
1060 .metrics()
1061 .pgwire_recv_scheduling_delay_ms
1062 .with_label_values(&[message_name])
1063 .observe(recv_scheduling_delay_ms);
1064
1065 Ok(next_state)
1066 }
1067
1068 async fn advance_drain(&mut self) -> Result<State, io::Error> {
1069 let message = self.conn.recv().await?;
1070 if message.is_some() {
1071 self.adapter_client
1072 .remove_idle_in_transaction_session_timeout();
1073 }
1074 match message {
1075 Some(FrontendMessage::Sync) => self.sync().await,
1076 None => Ok(State::Done),
1077 _ => Ok(State::Drain),
1078 }
1079 }
1080
1081 #[instrument(level = "debug")]
1085 async fn one_query(
1086 &mut self,
1087 stmt: Statement<Raw>,
1088 sql: String,
1089 lifecycle_timestamps: LifecycleTimestamps,
1090 ) -> Result<State, io::Error> {
1091 const EMPTY_PORTAL: &str = "";
1094 if let Err(e) = self
1095 .adapter_client
1096 .declare(EMPTY_PORTAL.to_string(), stmt, sql)
1097 .await
1098 {
1099 return self
1100 .send_error_and_get_state(e.into_response(Severity::Error))
1101 .await;
1102 }
1103 let portal = self
1104 .adapter_client
1105 .session()
1106 .get_portal_unverified_mut(EMPTY_PORTAL)
1107 .expect("unnamed portal should be present");
1108
1109 *portal.lifecycle_timestamps = Some(lifecycle_timestamps);
1110
1111 let stmt_desc = portal.desc.clone();
1112 if !stmt_desc.param_types.is_empty() {
1113 return self
1114 .send_error_and_get_state(ErrorResponse::error(
1115 SqlState::UNDEFINED_PARAMETER,
1116 "there is no parameter $1",
1117 ))
1118 .await;
1119 }
1120
1121 if let Some(relation_desc) = &stmt_desc.relation_desc {
1123 if !stmt_desc.is_copy {
1124 let formats = vec![Format::Text; stmt_desc.arity()];
1125 self.send(BackendMessage::RowDescription(
1126 message::encode_row_description(relation_desc, &formats),
1127 ))
1128 .await?;
1129 }
1130 }
1131
1132 let result = match self
1133 .adapter_client
1134 .execute(EMPTY_PORTAL.to_string(), self.conn.wait_closed(), None)
1135 .await
1136 {
1137 Ok((response, execute_started)) => {
1138 self.send_pending_notices().await?;
1139 self.send_execute_response(
1140 response,
1141 stmt_desc.relation_desc,
1142 EMPTY_PORTAL.to_string(),
1143 ExecuteCount::All,
1144 portal_exec_message,
1145 None,
1146 ExecuteTimeout::None,
1147 execute_started,
1148 )
1149 .await
1150 }
1151 Err(e) => {
1152 self.send_pending_notices().await?;
1153 self.send_error_and_get_state(e.into_response(Severity::Error))
1154 .await
1155 }
1156 };
1157
1158 self.adapter_client.session().remove_portal(EMPTY_PORTAL);
1160
1161 result
1162 }
1163
1164 async fn ensure_transaction(
1165 &mut self,
1166 num_stmts: usize,
1167 message_type: &str,
1168 ) -> Result<(), io::Error> {
1169 let start = Instant::now();
1170 if self.txn_needs_commit {
1171 self.commit_transaction().await?;
1172 }
1173 let res = self.adapter_client.start_transaction(Some(num_stmts));
1176 assert_ok!(res);
1177 self.adapter_client
1178 .inner()
1179 .metrics()
1180 .pgwire_ensure_transaction_seconds
1181 .with_label_values(&[message_type])
1182 .observe(start.elapsed().as_secs_f64());
1183 Ok(())
1184 }
1185
1186 fn parse_sql<'b>(&self, sql: &'b str) -> Result<Vec<StatementParseResult<'b>>, ErrorResponse> {
1187 let parse_start = Instant::now();
1188 let result = match self.adapter_client.parse(sql) {
1189 Ok(result) => result.map_err(|e| {
1190 let pos = sql[..e.error.pos].chars().count() + 1;
1193 ErrorResponse::error(SqlState::SYNTAX_ERROR, e.error.message).with_position(pos)
1194 }),
1195 Err(msg) => Err(ErrorResponse::error(SqlState::PROGRAM_LIMIT_EXCEEDED, msg)),
1196 };
1197 self.adapter_client
1198 .inner()
1199 .metrics()
1200 .parse_seconds
1201 .observe(parse_start.elapsed().as_secs_f64());
1202 result
1203 }
1204
1205 #[instrument(level = "debug")]
1210 async fn query(&mut self, sql: String, received: EpochMillis) -> Result<State, io::Error> {
1211 let stmts = match self.parse_sql(&sql) {
1213 Ok(stmts) => stmts,
1214 Err(err) => {
1215 self.send_error_and_get_state(err).await?;
1216 return self.ready().await;
1217 }
1218 };
1219
1220 let num_stmts = stmts.len();
1221
1222 for StatementParseResult { ast: stmt, sql } in stmts {
1224 if self.is_aborted_txn() && !is_txn_exit_stmt(Some(&stmt)) {
1226 self.aborted_txn_error().await?;
1227 break;
1228 }
1229
1230 self.ensure_transaction(num_stmts, "query").await?;
1238
1239 match self
1240 .one_query(stmt, sql.to_string(), LifecycleTimestamps { received })
1241 .await?
1242 {
1243 State::Ready => (),
1244 State::Drain => break,
1245 State::Done => return Ok(State::Done),
1246 }
1247 }
1248
1249 {
1251 if self.adapter_client.session().transaction().is_implicit() {
1252 self.commit_transaction().await?;
1253 }
1254 }
1255
1256 if num_stmts == 0 {
1257 self.send(BackendMessage::EmptyQueryResponse).await?;
1258 }
1259
1260 self.ready().await
1261 }
1262
1263 #[instrument(level = "debug")]
1264 async fn parse(
1265 &mut self,
1266 name: String,
1267 sql: String,
1268 param_oids: Vec<u32>,
1269 ) -> Result<State, io::Error> {
1270 self.ensure_transaction(1, "parse").await?;
1272
1273 let mut param_types = vec![];
1274 for oid in param_oids {
1275 match mz_pgrepr::Type::from_oid(oid) {
1276 Ok(ty) => match SqlScalarType::try_from(&ty) {
1277 Ok(ty) => param_types.push(Some(ty)),
1278 Err(err) => {
1279 return self
1280 .send_error_and_get_state(ErrorResponse::error(
1281 SqlState::INVALID_PARAMETER_VALUE,
1282 err.to_string(),
1283 ))
1284 .await;
1285 }
1286 },
1287 Err(_) if oid == 0 => param_types.push(None),
1288 Err(e) => {
1289 return self
1290 .send_error_and_get_state(ErrorResponse::error(
1291 SqlState::PROTOCOL_VIOLATION,
1292 e.to_string(),
1293 ))
1294 .await;
1295 }
1296 }
1297 }
1298
1299 let stmts = match self.parse_sql(&sql) {
1300 Ok(stmts) => stmts,
1301 Err(err) => {
1302 return self.send_error_and_get_state(err).await;
1303 }
1304 };
1305 if stmts.len() > 1 {
1306 return self
1307 .send_error_and_get_state(ErrorResponse::error(
1308 SqlState::INTERNAL_ERROR,
1309 "cannot insert multiple commands into a prepared statement",
1310 ))
1311 .await;
1312 }
1313 let (maybe_stmt, sql) = match stmts.into_iter().next() {
1314 None => (None, ""),
1315 Some(StatementParseResult { ast, sql }) => (Some(ast), sql),
1316 };
1317 if self.is_aborted_txn() && !is_txn_exit_stmt(maybe_stmt.as_ref()) {
1318 return self.aborted_txn_error().await;
1319 }
1320 match self
1321 .adapter_client
1322 .prepare(name, maybe_stmt, sql.to_string(), param_types)
1323 .await
1324 {
1325 Ok(()) => {
1326 self.send(BackendMessage::ParseComplete).await?;
1327 Ok(State::Ready)
1328 }
1329 Err(e) => {
1330 self.send_error_and_get_state(e.into_response(Severity::Error))
1331 .await
1332 }
1333 }
1334 }
1335
1336 #[instrument(level = "debug")]
1338 async fn commit_transaction(&mut self) -> Result<(), io::Error> {
1339 self.end_transaction(EndTransactionAction::Commit).await
1340 }
1341
1342 #[instrument(level = "debug")]
1344 async fn rollback_transaction(&mut self) -> Result<(), io::Error> {
1345 self.end_transaction(EndTransactionAction::Rollback).await
1346 }
1347
1348 #[instrument(level = "debug")]
1350 async fn end_transaction(&mut self, action: EndTransactionAction) -> Result<(), io::Error> {
1351 self.txn_needs_commit = false;
1352 let resp = self.adapter_client.end_transaction(action).await;
1353 if let Err(err) = resp {
1354 self.send(BackendMessage::ErrorResponse(
1355 err.into_response(Severity::Error),
1356 ))
1357 .await?;
1358 }
1359 Ok(())
1360 }
1361
1362 #[instrument(level = "debug")]
1363 async fn bind(
1364 &mut self,
1365 portal_name: String,
1366 statement_name: String,
1367 param_formats: Vec<Format>,
1368 raw_params: Vec<Option<Vec<u8>>>,
1369 result_formats: Vec<Format>,
1370 ) -> Result<State, io::Error> {
1371 self.ensure_transaction(1, "bind").await?;
1373
1374 let aborted_txn = self.is_aborted_txn();
1375 let stmt = match self
1376 .adapter_client
1377 .get_prepared_statement(&statement_name)
1378 .await
1379 {
1380 Ok(stmt) => stmt,
1381 Err(err) => {
1382 return self
1383 .send_error_and_get_state(err.into_response(Severity::Error))
1384 .await;
1385 }
1386 };
1387
1388 let param_types = &stmt.desc().param_types;
1389 if param_types.len() != raw_params.len() {
1390 let message = format!(
1391 "bind message supplies {actual} parameters, \
1392 but prepared statement \"{name}\" requires {expected}",
1393 name = statement_name,
1394 actual = raw_params.len(),
1395 expected = param_types.len()
1396 );
1397 return self
1398 .send_error_and_get_state(ErrorResponse::error(
1399 SqlState::PROTOCOL_VIOLATION,
1400 message,
1401 ))
1402 .await;
1403 }
1404 let param_formats = match pad_formats(param_formats, raw_params.len()) {
1405 Ok(param_formats) => param_formats,
1406 Err(msg) => {
1407 return self
1408 .send_error_and_get_state(ErrorResponse::error(
1409 SqlState::PROTOCOL_VIOLATION,
1410 msg,
1411 ))
1412 .await;
1413 }
1414 };
1415 if aborted_txn && !is_txn_exit_stmt(stmt.stmt()) {
1416 return self.aborted_txn_error().await;
1417 }
1418 let buf = RowArena::new();
1419 let mut params = vec![];
1420 for ((raw_param, mz_typ), format) in raw_params
1421 .into_iter()
1422 .zip_eq(param_types)
1423 .zip_eq(param_formats)
1424 {
1425 let pg_typ = mz_pgrepr::Type::from(mz_typ);
1426 let datum = match raw_param {
1427 None => Datum::Null,
1428 Some(bytes) => match mz_pgrepr::Value::decode(format, &pg_typ, &bytes) {
1429 Ok(param) => match param.into_datum_decode_error(&buf, &pg_typ, "parameter") {
1430 Ok(datum) => datum,
1431 Err(msg) => {
1432 return self
1433 .send_error_and_get_state(ErrorResponse::error(
1434 SqlState::INVALID_PARAMETER_VALUE,
1435 msg,
1436 ))
1437 .await;
1438 }
1439 },
1440 Err(err) => {
1441 let (code, msg) = if err.is::<mz_pgrepr::NulCharacterError>() {
1444 (SqlState::CHARACTER_NOT_IN_REPERTOIRE, err.to_string())
1445 } else {
1446 (
1447 SqlState::INVALID_PARAMETER_VALUE,
1448 format!("unable to decode parameter: {}", err),
1449 )
1450 };
1451 return self
1452 .send_error_and_get_state(ErrorResponse::error(code, msg))
1453 .await;
1454 }
1455 },
1456 };
1457 params.push((datum, mz_typ.clone()))
1458 }
1459
1460 let result_formats = match pad_formats(
1461 result_formats,
1462 stmt.desc()
1463 .relation_desc
1464 .clone()
1465 .map(|desc| desc.typ().column_types.len())
1466 .unwrap_or(0),
1467 ) {
1468 Ok(result_formats) => result_formats,
1469 Err(msg) => {
1470 return self
1471 .send_error_and_get_state(ErrorResponse::error(
1472 SqlState::PROTOCOL_VIOLATION,
1473 msg,
1474 ))
1475 .await;
1476 }
1477 };
1478
1479 if !stmt.stmt().map_or(false, |stmt| match stmt {
1482 Statement::Copy(CopyStatement {
1483 direction: CopyDirection::To,
1484 ..
1485 }) => true,
1486 Statement::Copy(CopyStatement {
1487 direction: CopyDirection::From,
1488 target: CopyTarget::Expr(_),
1492 ..
1493 }) => true,
1494 _ => false,
1495 }) {
1496 if let Some(desc) = stmt.desc().relation_desc.clone() {
1497 for (format, ty) in result_formats.iter().zip_eq(desc.iter_types()) {
1498 if let Format::Binary = format {
1499 if let Err(msg) = mz_pgrepr::Value::binary_encoding_error(&ty.scalar_type) {
1500 return self
1501 .send_error_and_get_state(ErrorResponse::error(
1502 SqlState::UNDEFINED_FUNCTION,
1503 msg,
1504 ))
1505 .await;
1506 }
1507 }
1508 }
1509 }
1510 }
1511
1512 let desc = stmt.desc().clone();
1513 let logging = Arc::clone(stmt.logging());
1514 let stmt_ast = stmt.stmt().cloned();
1515 let state_revision = stmt.state_revision;
1516 if let Err(err) = self.adapter_client.session().set_portal(
1517 portal_name,
1518 desc,
1519 stmt_ast,
1520 logging,
1521 params,
1522 result_formats,
1523 state_revision,
1524 ) {
1525 return self
1526 .send_error_and_get_state(err.into_response(Severity::Error))
1527 .await;
1528 }
1529
1530 self.send(BackendMessage::BindComplete).await?;
1531 Ok(State::Ready)
1532 }
1533
1534 fn execute(
1537 &mut self,
1538 portal_name: String,
1539 max_rows: ExecuteCount,
1540 get_response: GetResponse,
1541 fetch_portal_name: Option<String>,
1542 timeout: ExecuteTimeout,
1543 outer_ctx_extra: Option<ExecuteContextGuard>,
1544 received: Option<EpochMillis>,
1545 ) -> BoxFuture<'_, Result<State, io::Error>> {
1546 async move {
1547 let aborted_txn = self.is_aborted_txn();
1548
1549 let portal = match self
1551 .adapter_client
1552 .session()
1553 .get_portal_unverified_mut(&portal_name)
1554 {
1555 Some(portal) => portal,
1556 None => {
1557 let msg = format!("portal {} does not exist", portal_name.quoted());
1558 if let Some(outer_ctx_extra) = outer_ctx_extra {
1559 self.adapter_client.retire_execute(
1560 outer_ctx_extra,
1561 StatementEndedExecutionReason::Errored { error: msg.clone() },
1562 );
1563 }
1564 return self
1565 .send_error_and_get_state(ErrorResponse::error(
1566 SqlState::INVALID_CURSOR_NAME,
1567 msg,
1568 ))
1569 .await;
1570 }
1571 };
1572
1573 *portal.lifecycle_timestamps = received.map(LifecycleTimestamps::new);
1574
1575 let txn_exit_stmt = is_txn_exit_stmt(portal.stmt.as_deref());
1577 if aborted_txn && !txn_exit_stmt {
1578 if let Some(outer_ctx_extra) = outer_ctx_extra {
1579 self.adapter_client.retire_execute(
1580 outer_ctx_extra,
1581 StatementEndedExecutionReason::Errored {
1582 error: ABORTED_TXN_MSG.to_string(),
1583 },
1584 );
1585 }
1586 return self.aborted_txn_error().await;
1587 }
1588
1589 let row_desc = portal.desc.relation_desc.clone();
1590 match portal.state {
1591 PortalState::NotStarted => {
1592 self.ensure_transaction(1, "execute").await?;
1594 match self
1595 .adapter_client
1596 .execute(
1597 portal_name.clone(),
1598 self.conn.wait_closed(),
1599 outer_ctx_extra,
1600 )
1601 .await
1602 {
1603 Ok((response, execute_started)) => {
1604 self.send_pending_notices().await?;
1605 self.send_execute_response(
1606 response,
1607 row_desc,
1608 portal_name,
1609 max_rows,
1610 get_response,
1611 fetch_portal_name,
1612 timeout,
1613 execute_started,
1614 )
1615 .await
1616 }
1617 Err(e) => {
1618 self.send_pending_notices().await?;
1619 self.send_error_and_get_state(e.into_response(Severity::Error))
1620 .await
1621 }
1622 }
1623 }
1624 PortalState::InProgress(rows) => {
1625 let rows = rows.take().expect("InProgress rows must be populated");
1626 let (result, statement_ended_execution_reason) = match self
1627 .send_rows(
1628 row_desc.expect("portal missing row desc on resumption"),
1629 portal_name,
1630 rows,
1631 max_rows,
1632 get_response,
1633 fetch_portal_name,
1634 timeout,
1635 )
1636 .await
1637 {
1638 Err(e) => {
1639 (Err(e), StatementEndedExecutionReason::Canceled)
1642 }
1643 Ok((ok, SendRowsEndedReason::Canceled)) => {
1644 (Ok(ok), StatementEndedExecutionReason::Canceled)
1645 }
1646 Ok((
1659 ok,
1660 SendRowsEndedReason::Success {
1661 result_size: _,
1662 rows_returned: _,
1663 },
1664 )) => (
1665 Ok(ok),
1666 StatementEndedExecutionReason::Success {
1667 result_size: None,
1668 rows_returned: None,
1669 execution_strategy: None,
1670 },
1671 ),
1672 Ok((ok, SendRowsEndedReason::Errored { error })) => {
1673 (Ok(ok), StatementEndedExecutionReason::Errored { error })
1674 }
1675 };
1676 if let Some(outer_ctx_extra) = outer_ctx_extra {
1677 self.adapter_client
1678 .retire_execute(outer_ctx_extra, statement_ended_execution_reason);
1679 }
1680 result
1681 }
1682 PortalState::Completed(Some(tag)) => {
1689 let tag = tag.to_string();
1690 if let Some(outer_ctx_extra) = outer_ctx_extra {
1691 self.adapter_client.retire_execute(
1692 outer_ctx_extra,
1693 StatementEndedExecutionReason::Success {
1694 result_size: None,
1695 rows_returned: None,
1696 execution_strategy: None,
1697 },
1698 );
1699 }
1700 self.send(BackendMessage::CommandComplete { tag }).await?;
1701 Ok(State::Ready)
1702 }
1703 PortalState::Completed(None) => {
1704 let error = format!(
1705 "portal {} cannot be run",
1706 Ident::new_unchecked(portal_name).to_ast_string_stable()
1707 );
1708 if let Some(outer_ctx_extra) = outer_ctx_extra {
1709 self.adapter_client.retire_execute(
1710 outer_ctx_extra,
1711 StatementEndedExecutionReason::Errored {
1712 error: error.clone(),
1713 },
1714 );
1715 }
1716 self.send_error_and_get_state(ErrorResponse::error(
1717 SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE,
1718 error,
1719 ))
1720 .await
1721 }
1722 }
1723 }
1724 .instrument(debug_span!("execute"))
1725 .boxed()
1726 }
1727
1728 #[instrument(level = "debug")]
1729 async fn describe_statement(&mut self, name: &str) -> Result<State, io::Error> {
1730 self.ensure_transaction(1, "describe_statement").await?;
1732
1733 let stmt = match self.adapter_client.get_prepared_statement(name).await {
1734 Ok(stmt) => stmt,
1735 Err(err) => {
1736 return self
1737 .send_error_and_get_state(err.into_response(Severity::Error))
1738 .await;
1739 }
1740 };
1741 let parameter_desc = BackendMessage::ParameterDescription(
1743 stmt.desc()
1744 .param_types
1745 .iter()
1746 .map(mz_pgrepr::Type::from)
1747 .collect(),
1748 );
1749 let formats = vec![Format::Text; stmt.desc().arity()];
1753 let row_desc = describe_rows(stmt.desc(), &formats);
1754 self.send_all([parameter_desc, row_desc]).await?;
1755 Ok(State::Ready)
1756 }
1757
1758 #[instrument(level = "debug")]
1759 async fn describe_portal(&mut self, name: &str) -> Result<State, io::Error> {
1760 self.ensure_transaction(1, "describe_portal").await?;
1762
1763 let session = self.adapter_client.session();
1764 let row_desc = session
1765 .get_portal_unverified(name)
1766 .map(|portal| describe_rows(&portal.desc, &portal.result_formats));
1767 match row_desc {
1768 Some(row_desc) => {
1769 self.send(row_desc).await?;
1770 Ok(State::Ready)
1771 }
1772 None => {
1773 self.send_error_and_get_state(ErrorResponse::error(
1774 SqlState::INVALID_CURSOR_NAME,
1775 format!("portal {} does not exist", name.quoted()),
1776 ))
1777 .await
1778 }
1779 }
1780 }
1781
1782 #[instrument(level = "debug")]
1783 async fn close_statement(&mut self, name: String) -> Result<State, io::Error> {
1784 self.adapter_client
1785 .session()
1786 .remove_prepared_statement(&name);
1787 self.send(BackendMessage::CloseComplete).await?;
1788 Ok(State::Ready)
1789 }
1790
1791 #[instrument(level = "debug")]
1792 async fn close_portal(&mut self, name: String) -> Result<State, io::Error> {
1793 self.adapter_client.session().remove_portal(&name);
1794 self.send(BackendMessage::CloseComplete).await?;
1795 Ok(State::Ready)
1796 }
1797
1798 fn complete_portal(&mut self, name: &str) {
1799 let portal = self
1800 .adapter_client
1801 .session()
1802 .get_portal_unverified_mut(name)
1803 .expect("portal should exist");
1804 *portal.state = PortalState::Completed(None);
1805 }
1806
1807 async fn fetch(
1808 &mut self,
1809 name: String,
1810 count: Option<FetchDirection>,
1811 max_rows: ExecuteCount,
1812 fetch_portal_name: Option<String>,
1813 timeout: ExecuteTimeout,
1814 ctx_extra: ExecuteContextGuard,
1815 ) -> Result<State, io::Error> {
1816 let count = count.unwrap_or(FetchDirection::ForwardCount(1));
1819
1820 let count = match (max_rows, count) {
1833 (ExecuteCount::Count(max_rows), FetchDirection::ForwardCount(count)) => {
1834 let count = usize::cast_from(count);
1835 if max_rows < count {
1836 let msg = "Execute with max_rows < a FETCH's count is not supported";
1837 self.adapter_client.retire_execute(
1838 ctx_extra,
1839 StatementEndedExecutionReason::Errored {
1840 error: msg.to_string(),
1841 },
1842 );
1843 return self
1844 .send_error_and_get_state(ErrorResponse::error(
1845 SqlState::FEATURE_NOT_SUPPORTED,
1846 msg,
1847 ))
1848 .await;
1849 }
1850 ExecuteCount::Count(count)
1851 }
1852 (ExecuteCount::Count(_), FetchDirection::ForwardAll) => {
1853 let msg = "Execute with max_rows of a FETCH ALL is not supported";
1854 self.adapter_client.retire_execute(
1855 ctx_extra,
1856 StatementEndedExecutionReason::Errored {
1857 error: msg.to_string(),
1858 },
1859 );
1860 return self
1861 .send_error_and_get_state(ErrorResponse::error(
1862 SqlState::FEATURE_NOT_SUPPORTED,
1863 msg,
1864 ))
1865 .await;
1866 }
1867 (ExecuteCount::All, FetchDirection::ForwardAll) => ExecuteCount::All,
1868 (ExecuteCount::All, FetchDirection::ForwardCount(count)) => {
1869 ExecuteCount::Count(usize::cast_from(count))
1870 }
1871 };
1872 let cursor_name = name.to_string();
1873 self.execute(
1874 cursor_name,
1875 count,
1876 fetch_message,
1877 fetch_portal_name,
1878 timeout,
1879 Some(ctx_extra),
1880 None,
1881 )
1882 .await
1883 }
1884
1885 async fn flush(&mut self) -> Result<State, io::Error> {
1886 self.conn.flush().await?;
1887 Ok(State::Ready)
1888 }
1889
1890 #[instrument(level = "debug")]
1895 async fn send<M>(&mut self, message: M) -> Result<(), io::Error>
1896 where
1897 M: Into<BackendMessage>,
1898 {
1899 let message: BackendMessage = message.into();
1900 let is_error =
1901 matches!(&message, BackendMessage::ErrorResponse(e) if e.severity.is_error());
1902
1903 self.conn.send(message).await?;
1904
1905 if is_error {
1912 self.conn.flush().await?;
1913 }
1914
1915 Ok(())
1916 }
1917
1918 #[instrument(level = "debug")]
1919 pub async fn send_all(
1920 &mut self,
1921 messages: impl IntoIterator<Item = BackendMessage>,
1922 ) -> Result<(), io::Error> {
1923 for m in messages {
1924 self.send(m).await?;
1925 }
1926 Ok(())
1927 }
1928
1929 #[instrument(level = "debug")]
1930 async fn sync(&mut self) -> Result<State, io::Error> {
1931 if self.adapter_client.session().transaction().is_implicit() {
1933 self.commit_transaction().await?;
1934 }
1935 self.ready().await
1936 }
1937
1938 #[instrument(level = "debug")]
1939 async fn ready(&mut self) -> Result<State, io::Error> {
1940 let txn_state = self.adapter_client.session().transaction().into();
1941 self.send(BackendMessage::ReadyForQuery(txn_state)).await?;
1942 self.flush().await
1943 }
1944
1945 #[allow(clippy::too_many_arguments)]
1946 #[instrument(level = "debug")]
1947 async fn send_execute_response(
1948 &mut self,
1949 response: ExecuteResponse,
1950 row_desc: Option<RelationDesc>,
1951 portal_name: String,
1952 max_rows: ExecuteCount,
1953 get_response: GetResponse,
1954 fetch_portal_name: Option<String>,
1955 timeout: ExecuteTimeout,
1956 execute_started: Instant,
1957 ) -> Result<State, io::Error> {
1958 let mut tag = response.tag();
1959
1960 macro_rules! command_complete {
1961 () => {{
1962 self.send(BackendMessage::CommandComplete {
1963 tag: tag
1964 .take()
1965 .expect("command_complete only called on tag-generating results"),
1966 })
1967 .await?;
1968 Ok(State::Ready)
1969 }};
1970 }
1971
1972 let r = match response {
1973 ExecuteResponse::ClosedCursor => {
1974 self.complete_portal(&portal_name);
1975 command_complete!()
1976 }
1977 ExecuteResponse::DeclaredCursor => {
1978 self.complete_portal(&portal_name);
1979 command_complete!()
1980 }
1981 ExecuteResponse::EmptyQuery => {
1982 self.send(BackendMessage::EmptyQueryResponse).await?;
1983 Ok(State::Ready)
1984 }
1985 ExecuteResponse::Fetch {
1986 name,
1987 count,
1988 timeout,
1989 ctx_extra,
1990 } => {
1991 self.fetch(
1992 name,
1993 count,
1994 max_rows,
1995 Some(portal_name.to_string()),
1996 timeout,
1997 ctx_extra,
1998 )
1999 .await
2000 }
2001 ExecuteResponse::SendingRowsStreaming {
2002 rows,
2003 instance_id,
2004 strategy,
2005 } => {
2006 let row_desc = row_desc
2007 .expect("missing row description for ExecuteResponse::SendingRowsStreaming");
2008
2009 let span = tracing::debug_span!("sending_rows_streaming");
2010
2011 self.send_rows(
2012 row_desc,
2013 portal_name,
2014 InProgressRows::new(RecordFirstRowStream::new(
2015 Box::new(rows),
2016 execute_started,
2017 &self.adapter_client,
2018 Some(instance_id),
2019 Some(strategy),
2020 )),
2021 max_rows,
2022 get_response,
2023 fetch_portal_name,
2024 timeout,
2025 )
2026 .instrument(span)
2027 .await
2028 .map(|(state, _)| state)
2029 }
2030 ExecuteResponse::SendingRowsImmediate { rows } => {
2031 let row_desc = row_desc
2032 .expect("missing row description for ExecuteResponse::SendingRowsImmediate");
2033
2034 let span = tracing::debug_span!("sending_rows_immediate");
2035
2036 let stream =
2037 futures::stream::once(futures::future::ready(PeekResponseUnary::Rows(rows)));
2038 self.send_rows(
2039 row_desc,
2040 portal_name,
2041 InProgressRows::new(RecordFirstRowStream::new(
2042 Box::new(stream),
2043 execute_started,
2044 &self.adapter_client,
2045 None,
2046 Some(StatementExecutionStrategy::Constant),
2047 )),
2048 max_rows,
2049 get_response,
2050 fetch_portal_name,
2051 timeout,
2052 )
2053 .instrument(span)
2054 .await
2055 .map(|(state, _)| state)
2056 }
2057 ExecuteResponse::SetVariable { name, .. } => {
2058 let qn = name.to_string();
2061 let msg = if let Some(var) = self
2062 .adapter_client
2063 .session()
2064 .vars_mut()
2065 .notify_set()
2066 .find(|v| v.name() == qn)
2067 {
2068 Some(BackendMessage::ParameterStatus(var.name(), var.value()))
2069 } else {
2070 None
2071 };
2072 if let Some(msg) = msg {
2073 self.send(msg).await?;
2074 }
2075 command_complete!()
2076 }
2077 ExecuteResponse::Subscribing {
2078 rx,
2079 ctx_extra,
2080 instance_id,
2081 } => {
2082 if fetch_portal_name.is_none() {
2083 let mut msg = ErrorResponse::notice(
2084 SqlState::WARNING,
2085 "streaming SUBSCRIBE rows directly requires a client that does not buffer output",
2086 );
2087 if self.adapter_client.session().vars().application_name() == "psql" {
2088 msg.hint = Some(
2089 "Wrap your SUBSCRIBE statement in `COPY (SUBSCRIBE ...) TO STDOUT`."
2090 .into(),
2091 )
2092 }
2093 self.send(msg).await?;
2094 self.conn.flush().await?;
2095 }
2096 let row_desc =
2097 row_desc.expect("missing row description for ExecuteResponse::Subscribing");
2098 let (result, statement_ended_execution_reason) = match self
2099 .send_rows(
2100 row_desc,
2101 portal_name,
2102 InProgressRows::new(RecordFirstRowStream::new(
2103 Box::new(UnboundedReceiverStream::new(rx)),
2104 execute_started,
2105 &self.adapter_client,
2106 Some(instance_id),
2107 None,
2108 )),
2109 max_rows,
2110 get_response,
2111 fetch_portal_name,
2112 timeout,
2113 )
2114 .await
2115 {
2116 Err(e) => {
2117 (Err(e), StatementEndedExecutionReason::Canceled)
2120 }
2121 Ok((ok, SendRowsEndedReason::Canceled)) => {
2122 (Ok(ok), StatementEndedExecutionReason::Canceled)
2123 }
2124 Ok((
2125 ok,
2126 SendRowsEndedReason::Success {
2127 result_size,
2128 rows_returned,
2129 },
2130 )) => (
2131 Ok(ok),
2132 StatementEndedExecutionReason::Success {
2133 result_size: Some(result_size),
2134 rows_returned: Some(rows_returned),
2135 execution_strategy: None,
2136 },
2137 ),
2138 Ok((ok, SendRowsEndedReason::Errored { error })) => {
2139 (Ok(ok), StatementEndedExecutionReason::Errored { error })
2140 }
2141 };
2142 self.adapter_client
2143 .retire_execute(ctx_extra, statement_ended_execution_reason);
2144 return result;
2145 }
2146 ExecuteResponse::CopyTo { format, resp } => {
2147 let row_desc =
2148 row_desc.expect("missing row description for ExecuteResponse::CopyTo");
2149 match *resp {
2150 ExecuteResponse::Subscribing {
2151 rx,
2152 ctx_extra,
2153 instance_id,
2154 } => {
2155 let (result, statement_ended_execution_reason) = match self
2156 .copy_rows(
2157 format,
2158 row_desc,
2159 RecordFirstRowStream::new(
2160 Box::new(UnboundedReceiverStream::new(rx)),
2161 execute_started,
2162 &self.adapter_client,
2163 Some(instance_id),
2164 None,
2165 ),
2166 )
2167 .await
2168 {
2169 Err(e) => {
2170 (Err(e), StatementEndedExecutionReason::Canceled)
2173 }
2174 Ok((
2175 state,
2176 SendRowsEndedReason::Success {
2177 result_size,
2178 rows_returned,
2179 },
2180 )) => (
2181 Ok(state),
2182 StatementEndedExecutionReason::Success {
2183 result_size: Some(result_size),
2184 rows_returned: Some(rows_returned),
2185 execution_strategy: None,
2186 },
2187 ),
2188 Ok((state, SendRowsEndedReason::Errored { error })) => {
2189 (Ok(state), StatementEndedExecutionReason::Errored { error })
2190 }
2191 Ok((state, SendRowsEndedReason::Canceled)) => {
2192 (Ok(state), StatementEndedExecutionReason::Canceled)
2193 }
2194 };
2195 self.adapter_client
2196 .retire_execute(ctx_extra, statement_ended_execution_reason);
2197 return result;
2198 }
2199 ExecuteResponse::SendingRowsStreaming {
2200 rows,
2201 instance_id,
2202 strategy,
2203 } => {
2204 return self
2209 .copy_rows(
2210 format,
2211 row_desc,
2212 RecordFirstRowStream::new(
2213 Box::new(rows),
2214 execute_started,
2215 &self.adapter_client,
2216 Some(instance_id),
2217 Some(strategy),
2218 ),
2219 )
2220 .await
2221 .map(|(state, _)| state);
2222 }
2223 ExecuteResponse::SendingRowsImmediate { rows } => {
2224 let span = tracing::debug_span!("sending_rows_immediate");
2225
2226 let rows = futures::stream::once(futures::future::ready(
2227 PeekResponseUnary::Rows(rows),
2228 ));
2229 return self
2234 .copy_rows(
2235 format,
2236 row_desc,
2237 RecordFirstRowStream::new(
2238 Box::new(rows),
2239 execute_started,
2240 &self.adapter_client,
2241 None,
2242 Some(StatementExecutionStrategy::Constant),
2243 ),
2244 )
2245 .instrument(span)
2246 .await
2247 .map(|(state, _)| state);
2248 }
2249 _ => {
2250 return self
2251 .send_error_and_get_state(ErrorResponse::error(
2252 SqlState::INTERNAL_ERROR,
2253 "unsupported COPY response type".to_string(),
2254 ))
2255 .await;
2256 }
2257 };
2258 }
2259 ExecuteResponse::CopyFrom {
2260 target_id,
2261 target_name,
2262 columns,
2263 params,
2264 ctx_extra,
2265 } => {
2266 let row_desc =
2267 row_desc.expect("missing row description for ExecuteResponse::CopyFrom");
2268 self.copy_from(target_id, target_name, columns, params, row_desc, ctx_extra)
2269 .await
2270 }
2271 ExecuteResponse::TransactionCommitted { params }
2272 | ExecuteResponse::TransactionRolledBack { params } => {
2273 let notify_set: mz_ore::collections::HashSet<String> = self
2274 .adapter_client
2275 .session()
2276 .vars()
2277 .notify_set()
2278 .map(|v| v.name().to_string())
2279 .collect();
2280
2281 for (name, value) in params
2283 .into_iter()
2284 .filter(|(name, _v)| notify_set.contains(*name))
2285 {
2286 let msg = BackendMessage::ParameterStatus(name, value);
2287 self.send(msg).await?;
2288 }
2289 command_complete!()
2290 }
2291
2292 ExecuteResponse::AlteredDefaultPrivileges
2293 | ExecuteResponse::AlteredObject(..)
2294 | ExecuteResponse::AlteredRole
2295 | ExecuteResponse::AlteredSystemConfiguration
2296 | ExecuteResponse::CreatedCluster { .. }
2297 | ExecuteResponse::CreatedClusterReplica { .. }
2298 | ExecuteResponse::CreatedConnection { .. }
2299 | ExecuteResponse::CreatedDatabase { .. }
2300 | ExecuteResponse::CreatedIndex { .. }
2301 | ExecuteResponse::CreatedIntrospectionSubscribe
2302 | ExecuteResponse::CreatedMaterializedView { .. }
2303 | ExecuteResponse::CreatedRole
2304 | ExecuteResponse::CreatedSchema { .. }
2305 | ExecuteResponse::CreatedSecret { .. }
2306 | ExecuteResponse::CreatedSink { .. }
2307 | ExecuteResponse::CreatedSource { .. }
2308 | ExecuteResponse::CreatedTable { .. }
2309 | ExecuteResponse::CreatedType
2310 | ExecuteResponse::CreatedView { .. }
2311 | ExecuteResponse::CreatedViews { .. }
2312 | ExecuteResponse::CreatedNetworkPolicy
2313 | ExecuteResponse::Comment
2314 | ExecuteResponse::Deallocate { .. }
2315 | ExecuteResponse::Deleted(..)
2316 | ExecuteResponse::DiscardedAll
2317 | ExecuteResponse::DiscardedTemp
2318 | ExecuteResponse::DroppedObject(_)
2319 | ExecuteResponse::DroppedOwned
2320 | ExecuteResponse::GrantedPrivilege
2321 | ExecuteResponse::GrantedRole
2322 | ExecuteResponse::Inserted(..)
2323 | ExecuteResponse::Copied(..)
2324 | ExecuteResponse::Prepare
2325 | ExecuteResponse::Raised
2326 | ExecuteResponse::ReassignOwned
2327 | ExecuteResponse::RevokedPrivilege
2328 | ExecuteResponse::RevokedRole
2329 | ExecuteResponse::StartedTransaction { .. }
2330 | ExecuteResponse::Updated(..)
2331 | ExecuteResponse::ValidatedConnection => {
2332 command_complete!()
2333 }
2334 };
2335
2336 assert_none!(tag, "tag created but not consumed: {:?}", tag);
2337 r
2338 }
2339
2340 #[allow(clippy::too_many_arguments)]
2341 #[mz_ore::instrument(level = "debug")]
2343 async fn send_rows(
2344 &mut self,
2345 row_desc: RelationDesc,
2346 portal_name: String,
2347 mut rows: InProgressRows,
2348 max_rows: ExecuteCount,
2349 get_response: GetResponse,
2350 fetch_portal_name: Option<String>,
2351 timeout: ExecuteTimeout,
2352 ) -> Result<(State, SendRowsEndedReason), io::Error> {
2353 let result_format_portal_name: &str = if let Some(ref name) = fetch_portal_name {
2356 name
2357 } else {
2358 &portal_name
2359 };
2360 let result_formats = self
2361 .adapter_client
2362 .session()
2363 .get_portal_unverified(result_format_portal_name)
2364 .expect("valid fetch portal name for send rows")
2365 .result_formats
2366 .clone();
2367
2368 let (mut wait_once, mut deadline) = match timeout {
2369 ExecuteTimeout::None => (false, None),
2370 ExecuteTimeout::Seconds(t) => (
2371 false,
2372 Some(tokio::time::Instant::now() + tokio::time::Duration::from_secs_f64(t)),
2373 ),
2374 ExecuteTimeout::WaitOnce => (true, None),
2375 };
2376
2377 {
2379 let portal_name_desc = &self
2380 .adapter_client
2381 .session()
2382 .get_portal_unverified(portal_name.as_str())
2383 .expect("portal should exist")
2384 .desc
2385 .relation_desc;
2386 if let Some(portal_name_desc) = portal_name_desc {
2387 soft_assert_eq_or_log!(portal_name_desc, &row_desc);
2388 }
2389 if let Some(fetch_portal_name) = &fetch_portal_name {
2390 let fetch_portal_desc = &self
2391 .adapter_client
2392 .session()
2393 .get_portal_unverified(fetch_portal_name)
2394 .expect("portal should exist")
2395 .desc
2396 .relation_desc;
2397 if let Some(fetch_portal_desc) = fetch_portal_desc {
2398 soft_assert_eq_or_log!(fetch_portal_desc, &row_desc);
2399 }
2400 }
2401 }
2402
2403 self.conn.set_encode_state(
2404 row_desc
2405 .typ()
2406 .column_types
2407 .iter()
2408 .map(|ty| mz_pgrepr::Type::from(&ty.scalar_type))
2409 .zip_eq(result_formats)
2410 .collect(),
2411 );
2412
2413 let mut total_sent_rows = 0;
2414 let mut total_sent_bytes = 0;
2415 let mut want_rows = match max_rows {
2417 ExecuteCount::All => usize::MAX,
2418 ExecuteCount::Count(count) => count,
2419 };
2420
2421 loop {
2423 let batch = if rows.current.is_some() {
2426 FetchResult::Rows(rows.current.take())
2427 } else if want_rows == 0 {
2428 FetchResult::Rows(None)
2429 } else {
2430 let notice_fut = self.adapter_client.session().recv_notice();
2431 tokio::select! {
2446 biased;
2447 err = self.conn.wait_closed() => return Err(err),
2448 batch = rows.remaining.recv() => match batch {
2449 None => FetchResult::Rows(None),
2450 Some(PeekResponseUnary::Rows(rows)) => FetchResult::Rows(Some(rows)),
2451 Some(PeekResponseUnary::Error(err)) => {
2452 FetchResult::Error(ErrorResponse::error(SqlState::INTERNAL_ERROR, err))
2453 }
2454 Some(PeekResponseUnary::DependencyDropped(dep)) => {
2455 FetchResult::Error(
2456 dep.to_concurrent_dependency_drop()
2457 .into_response(Severity::Error),
2458 )
2459 }
2460 Some(PeekResponseUnary::Canceled) => FetchResult::Canceled,
2461 },
2462 notice = notice_fut => {
2463 FetchResult::Notice(notice)
2464 }
2465 _ = time::sleep_until(
2466 deadline.unwrap_or_else(tokio::time::Instant::now),
2467 ), if deadline.is_some() => FetchResult::Rows(None),
2468 }
2469 };
2470
2471 match batch {
2472 FetchResult::Rows(None) => break,
2473 FetchResult::Rows(Some(mut batch_rows)) => {
2474 if let Err(err) = verify_datum_desc(&row_desc, &mut batch_rows) {
2475 let msg = err.to_string();
2476 return self
2477 .send_error_and_get_state(err.into_response(Severity::Error))
2478 .await
2479 .map(|state| (state, SendRowsEndedReason::Errored { error: msg }));
2480 }
2481
2482 if wait_once && batch_rows.peek().is_some() {
2486 deadline = Some(tokio::time::Instant::now());
2487 wait_once = false;
2488 }
2489
2490 let mut sent_rows = 0;
2492 let mut sent_bytes = 0;
2493 let messages = (&mut batch_rows)
2494 .map(|row| {
2499 let row_len = row.byte_len();
2500 let values = mz_pgrepr::values_from_row(row, row_desc.typ());
2501 (row_len, BackendMessage::DataRow(values))
2502 })
2503 .inspect(|(row_len, _)| {
2504 sent_bytes += row_len;
2505 sent_rows += 1
2506 })
2507 .map(|(_row_len, row)| row)
2508 .take(want_rows);
2509 self.send_all(messages).await?;
2510
2511 total_sent_rows += sent_rows;
2512 total_sent_bytes += sent_bytes;
2513 want_rows -= sent_rows;
2514
2515 if want_rows == 0 {
2518 if batch_rows.peek().is_some() {
2519 rows.current = Some(batch_rows);
2520 }
2521 break;
2522 }
2523
2524 self.conn.flush().await?;
2525 }
2526 FetchResult::Notice(notice) => {
2527 self.send(notice.into_response()).await?;
2528 self.conn.flush().await?;
2529 }
2530 FetchResult::Error(err) => {
2531 let text = err.message.clone();
2532 return self
2533 .send_error_and_get_state(err)
2534 .await
2535 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2536 }
2537 FetchResult::Canceled => {
2538 return self
2539 .send_error_and_get_state(ErrorResponse::error(
2540 SqlState::QUERY_CANCELED,
2541 "canceling statement due to user request",
2542 ))
2543 .await
2544 .map(|state| (state, SendRowsEndedReason::Canceled));
2545 }
2546 }
2547 }
2548
2549 let portal = self
2550 .adapter_client
2551 .session()
2552 .get_portal_unverified_mut(&portal_name)
2553 .expect("valid portal name for send rows");
2554
2555 let saw_rows = rows.remaining.saw_rows;
2556 let no_more_rows = rows.no_more_rows();
2557 let metric_recorded = rows.remaining.metric_recorded;
2558 let recorded_first_row_instant = rows.remaining.recorded_first_row_instant;
2559
2560 if no_more_rows && !metric_recorded {
2561 rows.remaining.metric_recorded = true;
2562 }
2563
2564 *portal.state = PortalState::InProgress(Some(rows));
2567
2568 let fetch_portal = fetch_portal_name.map(|name| {
2569 self.adapter_client
2570 .session()
2571 .get_portal_unverified_mut(&name)
2572 .expect("valid fetch portal")
2573 });
2574 let response_message = get_response(max_rows, total_sent_rows, fetch_portal);
2575 self.send(response_message).await?;
2576
2577 if no_more_rows && !metric_recorded {
2580 let statement_type = if let Some(stmt) = &self
2581 .adapter_client
2582 .session()
2583 .get_portal_unverified(&portal_name)
2584 .expect("valid portal name for send_rows")
2585 .stmt
2586 {
2587 metrics::statement_type_label_value(stmt.deref())
2588 } else {
2589 "no-statement"
2590 };
2591 let duration = if saw_rows {
2592 recorded_first_row_instant
2593 .expect("recorded_first_row_instant because saw_rows")
2594 .elapsed()
2595 } else {
2596 Duration::ZERO
2600 };
2601 self.adapter_client
2602 .inner()
2603 .metrics()
2604 .result_rows_first_to_last_byte_seconds
2605 .with_label_values(&[statement_type])
2606 .observe(duration.as_secs_f64());
2607 }
2608
2609 Ok((
2610 State::Ready,
2611 SendRowsEndedReason::Success {
2612 result_size: u64::cast_from(total_sent_bytes),
2613 rows_returned: u64::cast_from(total_sent_rows),
2614 },
2615 ))
2616 }
2617
2618 #[mz_ore::instrument(level = "debug")]
2619 async fn copy_rows(
2620 &mut self,
2621 format: CopyFormat,
2622 row_desc: RelationDesc,
2623 mut stream: RecordFirstRowStream,
2624 ) -> Result<(State, SendRowsEndedReason), io::Error> {
2625 let (row_format, encode_format) = match format {
2626 CopyFormat::Text => (
2627 CopyFormatParams::Text(CopyTextFormatParams::default()),
2628 Format::Text,
2629 ),
2630 CopyFormat::Binary => (CopyFormatParams::Binary, Format::Binary),
2631 CopyFormat::Csv => (
2632 CopyFormatParams::Csv(CopyCsvFormatParams::default()),
2633 Format::Text,
2634 ),
2635 CopyFormat::Parquet => {
2636 let text = "Parquet format is not supported".to_string();
2637 return self
2638 .send_error_and_get_state(ErrorResponse::error(
2639 SqlState::INTERNAL_ERROR,
2640 text.clone(),
2641 ))
2642 .await
2643 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2644 }
2645 };
2646
2647 if let CopyFormat::Binary = format {
2655 if let Some(msg) = row_desc
2656 .iter_types()
2657 .find_map(|ty| mz_pgrepr::Value::binary_encoding_error(&ty.scalar_type).err())
2658 {
2659 return self
2660 .send_error_and_get_state(ErrorResponse::error(
2661 SqlState::UNDEFINED_FUNCTION,
2662 msg,
2663 ))
2664 .await
2665 .map(|state| {
2666 (
2667 state,
2668 SendRowsEndedReason::Errored {
2669 error: msg.to_string(),
2670 },
2671 )
2672 });
2673 }
2674 }
2675
2676 let encode_fn = |row: &RowRef, typ: &SqlRelationType, out: &mut Vec<u8>| {
2677 mz_pgcopy::encode_copy_format(&row_format, row, typ, out)
2678 };
2679
2680 let typ = row_desc.typ();
2681 let column_formats = iter::repeat(encode_format)
2682 .take(typ.column_types.len())
2683 .collect();
2684 self.send(BackendMessage::CopyOutResponse {
2685 overall_format: encode_format,
2686 column_formats,
2687 })
2688 .await?;
2689
2690 let mut out = Vec::new();
2695
2696 if let CopyFormat::Binary = format {
2697 out.extend(b"PGCOPY\n\xFF\r\n\0");
2699 out.extend([0, 0, 0, 0]);
2701 out.extend([0, 0, 0, 0]);
2703 }
2704
2705 let mut count = 0;
2706 let mut total_sent_bytes = 0;
2707 loop {
2708 tokio::select! {
2709 e = self.conn.wait_closed() => return Err(e),
2710 batch = stream.recv() => match batch {
2711 None => break,
2712 Some(PeekResponseUnary::Error(text)) => {
2713 let err =
2714 ErrorResponse::error(SqlState::INTERNAL_ERROR, text.clone());
2715 return self
2716 .send_error_and_get_state(err)
2717 .await
2718 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2719 }
2720 Some(PeekResponseUnary::DependencyDropped(dep)) => {
2721 let err = dep.to_concurrent_dependency_drop();
2722 let text = err.to_string();
2723 let resp = err.into_response(Severity::Error);
2724 return self
2725 .send_error_and_get_state(resp)
2726 .await
2727 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2728 }
2729 Some(PeekResponseUnary::Canceled) => {
2730 return self.send_error_and_get_state(ErrorResponse::error(
2731 SqlState::QUERY_CANCELED,
2732 "canceling statement due to user request",
2733 ))
2734 .await.map(|state| (state, SendRowsEndedReason::Canceled));
2735 }
2736 Some(PeekResponseUnary::Rows(mut rows)) => {
2737 count += rows.count();
2738 while let Some(row) = rows.next() {
2739 total_sent_bytes += row.byte_len();
2740 encode_fn(row, typ, &mut out)?;
2741 self.send(BackendMessage::CopyData(mem::take(&mut out)))
2742 .await?;
2743 }
2744 }
2745 },
2746 notice = self.adapter_client.session().recv_notice() => {
2747 self.send(notice.into_response())
2748 .await?;
2749 self.conn.flush().await?;
2750 }
2751 }
2752
2753 self.conn.flush().await?;
2754 }
2755 if let CopyFormat::Binary = format {
2757 let trailer: i16 = -1;
2758 out.extend(trailer.to_be_bytes());
2759 self.send(BackendMessage::CopyData(mem::take(&mut out)))
2760 .await?;
2761 }
2762
2763 let tag = format!("COPY {}", count);
2764 self.send(BackendMessage::CopyDone).await?;
2765 self.send(BackendMessage::CommandComplete { tag }).await?;
2766 Ok((
2767 State::Ready,
2768 SendRowsEndedReason::Success {
2769 result_size: u64::cast_from(total_sent_bytes),
2770 rows_returned: u64::cast_from(count),
2771 },
2772 ))
2773 }
2774
2775 #[instrument(level = "debug")]
2778 async fn copy_from(
2779 &mut self,
2780 target_id: CatalogItemId,
2781 target_name: String,
2782 columns: Vec<ColumnIndex>,
2783 params: CopyFormatParams<'static>,
2784 row_desc: RelationDesc,
2785 mut ctx_extra: ExecuteContextGuard,
2786 ) -> Result<State, io::Error> {
2787 let res = self
2788 .copy_from_inner(
2789 target_id,
2790 target_name,
2791 columns,
2792 params,
2793 row_desc,
2794 &mut ctx_extra,
2795 )
2796 .await;
2797 match &res {
2798 Ok(State::Ready) => {
2799 self.adapter_client.retire_execute(
2800 ctx_extra,
2801 StatementEndedExecutionReason::Success {
2802 result_size: None,
2803 rows_returned: None,
2804 execution_strategy: None,
2805 },
2806 );
2807 }
2808 Ok(State::Done) => {
2809 self.adapter_client
2813 .retire_execute(ctx_extra, StatementEndedExecutionReason::Canceled);
2814 }
2815 Err(e) => {
2816 self.adapter_client.retire_execute(
2817 ctx_extra,
2818 StatementEndedExecutionReason::Errored {
2819 error: format!("{e}"),
2820 },
2821 );
2822 }
2823 Ok(State::Drain) => {}
2824 }
2825 res
2826 }
2827
2828 async fn copy_from_inner(
2829 &mut self,
2830 target_id: CatalogItemId,
2831 target_name: String,
2832 columns: Vec<ColumnIndex>,
2833 params: CopyFormatParams<'static>,
2834 row_desc: RelationDesc,
2835 ctx_extra: &mut ExecuteContextGuard,
2836 ) -> Result<State, io::Error> {
2837 let typ = row_desc.typ();
2838 let column_formats = vec![Format::Text; typ.column_types.len()];
2839 self.send(BackendMessage::CopyInResponse {
2840 overall_format: Format::Text,
2841 column_formats,
2842 })
2843 .await?;
2844 self.conn.flush().await?;
2845
2846 let writer = match self
2848 .adapter_client
2849 .start_copy_from_stdin(
2850 target_id,
2851 target_name.clone(),
2852 columns.clone(),
2853 row_desc.clone(),
2854 params.clone(),
2855 )
2856 .await
2857 {
2858 Ok(writer) => writer,
2859 Err(e) => {
2860 loop {
2866 match self.conn.recv().await? {
2867 Some(FrontendMessage::CopyData(_)) => {}
2868 Some(FrontendMessage::CopyDone) | Some(FrontendMessage::CopyFail(_)) => {
2869 break;
2870 }
2871 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
2872 Some(_) => break,
2873 None => return Ok(State::Done),
2874 }
2875 }
2876 self.adapter_client.retire_execute(
2877 std::mem::take(ctx_extra),
2878 StatementEndedExecutionReason::Errored {
2879 error: e.to_string(),
2880 },
2881 );
2882 return self
2883 .send_error_and_get_state(e.into_response(Severity::Error))
2884 .await;
2885 }
2886 };
2887
2888 self.conn.set_copy_mode(true);
2890
2891 const BATCH_SIZE: usize = 32 * 1024 * 1024;
2893 let max_copy_from_row_size = self
2894 .adapter_client
2895 .get_system_vars()
2896 .await
2897 .max_copy_from_row_size()
2898 .try_into()
2899 .unwrap_or(usize::MAX);
2900
2901 let mut data = Vec::new();
2902 let mut row_scanner = CopyRowScanner::new(¶ms);
2903 let num_workers = writer.batch_txs.len();
2904 let mut next_worker: usize = 0;
2905 let mut saw_copy_done = false;
2906 let mut saw_end_marker = false;
2907 let mut copy_from_error: Option<(SqlState, String)> = None;
2908
2909 loop {
2912 let message = self.conn.recv().await?;
2913 match message {
2914 Some(FrontendMessage::CopyData(buf)) => {
2915 if saw_end_marker {
2916 continue;
2919 }
2920 data.extend(buf);
2921 row_scanner.scan_new_bytes(&data);
2922
2923 if let Some(end_pos) = row_scanner.end_marker_end() {
2924 data.truncate(end_pos);
2925 row_scanner.on_truncate(end_pos);
2926 saw_end_marker = true;
2927 }
2928
2929 if row_scanner.current_row_size(data.len()) > max_copy_from_row_size {
2931 copy_from_error = Some((
2932 SqlState::INSUFFICIENT_RESOURCES,
2933 format!(
2934 "COPY FROM STDIN row exceeded max_copy_from_row_size \
2935 ({max_copy_from_row_size} bytes)"
2936 ),
2937 ));
2938 break;
2939 }
2940
2941 let mut send_failed = false;
2944 while data.len() >= BATCH_SIZE {
2945 let split_pos = match row_scanner.last_row_end() {
2946 Some(pos) => pos,
2947 None => break, };
2949 let remainder = data.split_off(split_pos);
2950 let chunk = std::mem::replace(&mut data, remainder);
2951 row_scanner.on_split(split_pos);
2952 if writer.batch_txs[next_worker].send(chunk).await.is_err() {
2953 send_failed = true;
2954 break;
2955 }
2956 next_worker = (next_worker + 1) % num_workers;
2957 }
2958 if send_failed {
2961 break;
2962 }
2963 }
2964 Some(FrontendMessage::CopyDone) => {
2965 if !data.is_empty() {
2967 let chunk = std::mem::take(&mut data);
2968 let _ = writer.batch_txs[next_worker].send(chunk).await;
2970 }
2971 saw_copy_done = true;
2972 break;
2973 }
2974 Some(FrontendMessage::CopyFail(err)) => {
2975 self.adapter_client.retire_execute(
2976 std::mem::take(ctx_extra),
2977 StatementEndedExecutionReason::Canceled,
2978 );
2979 drop(writer);
2981 self.conn.set_copy_mode(false);
2982 return self
2983 .send_error_and_get_state(ErrorResponse::error(
2984 SqlState::QUERY_CANCELED,
2985 format!("COPY from stdin failed: {}", err),
2986 ))
2987 .await;
2988 }
2989 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
2990 Some(_) => {
2991 let msg = "unexpected message type during COPY from stdin";
2992 self.adapter_client.retire_execute(
2993 std::mem::take(ctx_extra),
2994 StatementEndedExecutionReason::Errored {
2995 error: msg.to_string(),
2996 },
2997 );
2998 drop(writer);
2999 self.conn.set_copy_mode(false);
3000 return self
3001 .send_error_and_get_state(ErrorResponse::error(
3002 SqlState::PROTOCOL_VIOLATION,
3003 msg,
3004 ))
3005 .await;
3006 }
3007 None => {
3008 drop(writer);
3009 self.conn.set_copy_mode(false);
3010 return Ok(State::Done);
3011 }
3012 }
3013 }
3014
3015 if !saw_copy_done {
3019 loop {
3020 match self.conn.recv().await? {
3021 Some(FrontendMessage::CopyData(_)) => {}
3022 Some(FrontendMessage::CopyDone) | Some(FrontendMessage::CopyFail(_)) => {
3023 break;
3024 }
3025 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
3026 Some(_) => {
3027 let msg = "unexpected message type during COPY from stdin";
3028 self.adapter_client.retire_execute(
3029 std::mem::take(ctx_extra),
3030 StatementEndedExecutionReason::Errored {
3031 error: msg.to_string(),
3032 },
3033 );
3034 drop(writer);
3035 self.conn.set_copy_mode(false);
3036 return self
3037 .send_error_and_get_state(ErrorResponse::error(
3038 SqlState::PROTOCOL_VIOLATION,
3039 msg,
3040 ))
3041 .await;
3042 }
3043 None => {
3044 drop(writer);
3045 self.conn.set_copy_mode(false);
3046 return Ok(State::Done);
3047 }
3048 }
3049 }
3050 }
3051
3052 if let Some((code, msg)) = copy_from_error {
3053 self.adapter_client.retire_execute(
3054 std::mem::take(ctx_extra),
3055 StatementEndedExecutionReason::Errored { error: msg.clone() },
3056 );
3057 drop(writer);
3058 self.conn.set_copy_mode(false);
3059 return self
3060 .send_error_and_get_state(ErrorResponse::error(code, msg))
3061 .await;
3062 }
3063
3064 self.conn.set_copy_mode(false);
3065
3066 drop(writer.batch_txs);
3071
3072 let (proto_batches, row_count) = match writer.completion_rx.await {
3074 Ok(Ok(result)) => result,
3075 Ok(Err(e)) => {
3076 self.adapter_client.retire_execute(
3077 std::mem::take(ctx_extra),
3078 StatementEndedExecutionReason::Errored {
3079 error: e.to_string(),
3080 },
3081 );
3082 return self
3083 .send_error_and_get_state(e.into_response(Severity::Error))
3084 .await;
3085 }
3086 Err(_) => {
3087 let msg = "COPY FROM STDIN: background batch builder tasks dropped";
3088 self.adapter_client.retire_execute(
3089 std::mem::take(ctx_extra),
3090 StatementEndedExecutionReason::Errored {
3091 error: msg.to_string(),
3092 },
3093 );
3094 return self
3095 .send_error_and_get_state(ErrorResponse::error(SqlState::INTERNAL_ERROR, msg))
3096 .await;
3097 }
3098 };
3099
3100 if let Err(e) = self
3102 .adapter_client
3103 .stage_copy_from_stdin_batches(target_id, proto_batches)
3104 {
3105 self.adapter_client.retire_execute(
3106 std::mem::take(ctx_extra),
3107 StatementEndedExecutionReason::Errored {
3108 error: e.to_string(),
3109 },
3110 );
3111 return self
3112 .send_error_and_get_state(e.into_response(Severity::Error))
3113 .await;
3114 }
3115
3116 let tag = format!("COPY {}", row_count);
3117 self.send(BackendMessage::CommandComplete { tag }).await?;
3118
3119 Ok(State::Ready)
3120 }
3121
3122 #[instrument(level = "debug")]
3123 async fn send_pending_notices(&mut self) -> Result<(), io::Error> {
3124 let notices = self
3125 .adapter_client
3126 .session()
3127 .drain_notices()
3128 .into_iter()
3129 .map(|notice| BackendMessage::ErrorResponse(notice.into_response()));
3130 self.send_all(notices).await?;
3131 Ok(())
3132 }
3133
3134 #[instrument(level = "debug")]
3135 async fn send_error_and_get_state(&mut self, err: ErrorResponse) -> Result<State, io::Error> {
3136 assert!(err.severity.is_error());
3137 debug!(
3138 "cid={} error code={}",
3139 self.adapter_client.session().conn_id(),
3140 err.code.code()
3141 );
3142 let is_fatal = err.severity.is_fatal();
3143 self.send(BackendMessage::ErrorResponse(err)).await?;
3144
3145 let txn = self.adapter_client.session().transaction();
3146 match txn {
3147 TransactionStatus::Default | TransactionStatus::Failed(_) => {}
3150 TransactionStatus::Started(_) => {
3152 self.rollback_transaction().await?;
3153 }
3154 TransactionStatus::InTransactionImplicit(_) => {
3156 self.rollback_transaction().await?;
3157 }
3158 TransactionStatus::InTransaction(_) => {
3160 self.adapter_client.fail_transaction();
3161 }
3162 };
3163 if is_fatal {
3164 Ok(State::Done)
3165 } else {
3166 Ok(State::Drain)
3167 }
3168 }
3169
3170 #[instrument(level = "debug")]
3171 async fn aborted_txn_error(&mut self) -> Result<State, io::Error> {
3172 self.send(BackendMessage::ErrorResponse(ErrorResponse::error(
3173 SqlState::IN_FAILED_SQL_TRANSACTION,
3174 ABORTED_TXN_MSG,
3175 )))
3176 .await?;
3177 Ok(State::Drain)
3178 }
3179
3180 fn is_aborted_txn(&mut self) -> bool {
3181 matches!(
3182 self.adapter_client.session().transaction(),
3183 TransactionStatus::Failed(_)
3184 )
3185 }
3186}
3187
3188fn pad_formats(formats: Vec<Format>, n: usize) -> Result<Vec<Format>, String> {
3189 match (formats.len(), n) {
3190 (0, e) => Ok(vec![Format::Text; e]),
3191 (1, e) => Ok(iter::repeat(formats[0]).take(e).collect()),
3192 (a, e) if a == e => Ok(formats),
3193 (a, e) => Err(format!(
3194 "expected {} field format specifiers, but got {}",
3195 e, a
3196 )),
3197 }
3198}
3199
3200fn describe_rows(stmt_desc: &StatementDesc, formats: &[Format]) -> BackendMessage {
3201 match &stmt_desc.relation_desc {
3202 Some(desc) if !stmt_desc.is_copy => {
3203 BackendMessage::RowDescription(message::encode_row_description(desc, formats))
3204 }
3205 _ => BackendMessage::NoData,
3206 }
3207}
3208
3209type GetResponse = fn(
3210 max_rows: ExecuteCount,
3211 total_sent_rows: usize,
3212 fetch_portal: Option<PortalRefMut>,
3213) -> BackendMessage;
3214
3215fn portal_exec_message(
3218 max_rows: ExecuteCount,
3219 total_sent_rows: usize,
3220 _fetch_portal: Option<PortalRefMut>,
3221) -> BackendMessage {
3222 match max_rows {
3229 ExecuteCount::Count(max_rows) if max_rows <= total_sent_rows => {
3230 BackendMessage::PortalSuspended
3231 }
3232 _ => BackendMessage::CommandComplete {
3233 tag: format!("SELECT {}", total_sent_rows),
3234 },
3235 }
3236}
3237
3238fn fetch_message(
3240 _max_rows: ExecuteCount,
3241 total_sent_rows: usize,
3242 fetch_portal: Option<PortalRefMut>,
3243) -> BackendMessage {
3244 let tag = format!("FETCH {}", total_sent_rows);
3245 if let Some(portal) = fetch_portal {
3246 *portal.state = PortalState::Completed(Some(tag.clone()));
3247 }
3248 BackendMessage::CommandComplete { tag }
3249}
3250
3251fn get_authenticator(
3252 authenticator_kind: listeners::AuthenticatorKind,
3253 frontegg: Option<FronteggAuthenticator>,
3254 oidc: GenericOidcAuthenticator,
3255 adapter_client: mz_adapter::Client,
3256) -> Authenticator {
3257 match authenticator_kind {
3258 listeners::AuthenticatorKind::Frontegg => Authenticator::Frontegg(frontegg.expect(
3259 "Frontegg authenticator should exist with listeners::AuthenticatorKind::Frontegg",
3260 )),
3261 listeners::AuthenticatorKind::Password => Authenticator::Password(adapter_client),
3262 listeners::AuthenticatorKind::Sasl => Authenticator::Sasl(adapter_client),
3263 listeners::AuthenticatorKind::Oidc => Authenticator::Oidc(oidc),
3264 listeners::AuthenticatorKind::None => Authenticator::None,
3265 }
3266}
3267
3268#[derive(Debug, Copy, Clone)]
3269enum ExecuteCount {
3270 All,
3271 Count(usize),
3272}
3273
3274fn is_txn_exit_stmt(stmt: Option<&Statement<Raw>>) -> bool {
3276 match stmt {
3277 Some(stmt) => matches!(stmt, Statement::Commit(_) | Statement::Rollback(_)),
3279 None => false,
3280 }
3281}
3282
3283#[derive(Debug)]
3284enum FetchResult {
3285 Rows(Option<Box<dyn RowIterator + Send + Sync>>),
3286 Canceled,
3287 Error(ErrorResponse),
3288 Notice(AdapterNotice),
3289}
3290
3291#[derive(Debug)]
3292struct CopyRowScanner {
3293 scan_pos: usize,
3294 last_row_end: Option<usize>,
3295 end_marker_end: Option<usize>,
3296 record_start: usize,
3301 csv: Option<CsvScanState>,
3302}
3303
3304#[derive(Debug)]
3305struct CsvScanState {
3306 reader: csv_core::Reader,
3307 output: Vec<u8>,
3308 ends: Vec<usize>,
3309 skip_first_record: bool,
3310}
3311
3312impl CopyRowScanner {
3313 fn new(params: &CopyFormatParams<'_>) -> Self {
3314 let csv = match params {
3315 CopyFormatParams::Csv(CopyCsvFormatParams {
3316 delimiter,
3317 quote,
3318 escape,
3319 header,
3320 ..
3321 }) => Some(CsvScanState::new(*delimiter, *quote, *escape, *header)),
3322 _ => None,
3323 };
3324
3325 CopyRowScanner {
3326 scan_pos: 0,
3327 last_row_end: None,
3328 end_marker_end: None,
3329 record_start: 0,
3330 csv,
3331 }
3332 }
3333
3334 fn scan_new_bytes(&mut self, data: &[u8]) {
3335 if self.scan_pos >= data.len() {
3336 return;
3337 }
3338
3339 if let Some(csv) = self.csv.as_mut() {
3340 let mut input = &data[self.scan_pos..];
3341 let mut consumed = 0usize;
3342 while !input.is_empty() {
3343 let (result, n_input, _n_output, _n_ends) =
3344 csv.reader
3345 .read_record(input, &mut csv.output, &mut csv.ends);
3346 consumed += n_input;
3347 input = &input[n_input..];
3348
3349 match result {
3350 ReadRecordResult::InputEmpty => break,
3351 ReadRecordResult::OutputFull => {
3352 if n_input == 0 {
3353 csv.output
3354 .resize(csv.output.len().saturating_mul(2).max(1), 0);
3355 }
3356 }
3357 ReadRecordResult::OutputEndsFull => {
3358 if n_input == 0 {
3359 csv.ends.resize(csv.ends.len().saturating_mul(2).max(1), 0);
3360 }
3361 }
3362 ReadRecordResult::Record | ReadRecordResult::End => {
3363 let row_end = self.scan_pos + consumed;
3364 self.last_row_end = Some(row_end);
3365 if self.end_marker_end.is_none() {
3366 let is_marker = if csv.skip_first_record {
3367 csv.skip_first_record = false;
3368 false
3369 } else {
3370 let raw = &data[self.record_start..row_end];
3376 let start = raw
3387 .iter()
3388 .take_while(|&&b| b == b'\r' || b == b'\n')
3389 .count();
3390 let trailing = raw[start..]
3391 .iter()
3392 .rev()
3393 .take_while(|&&b| b == b'\r' || b == b'\n')
3394 .count();
3395 let trimmed = &raw[start..raw.len() - trailing];
3396 trimmed == b"\\."
3397 };
3398 if is_marker {
3399 self.end_marker_end = Some(row_end);
3400 self.record_start = row_end;
3401 break;
3402 }
3403 }
3404 self.record_start = row_end;
3405 }
3406 }
3407 }
3408 } else {
3409 let mut row_start = self.last_row_end.unwrap_or(0);
3410 for (offset, b) in data[self.scan_pos..].iter().enumerate() {
3411 if *b == b'\n' {
3412 let row_end = self.scan_pos + offset + 1;
3413 self.last_row_end = Some(row_end);
3414 if self.end_marker_end.is_none() {
3415 let row = &data[row_start..row_end];
3416 if row.get(0..2) == Some(b"\\.") {
3417 self.end_marker_end = Some(row_end);
3418 break;
3419 }
3420 }
3421 row_start = row_end;
3422 }
3423 }
3424 }
3425
3426 self.scan_pos = data.len();
3427 }
3428
3429 fn last_row_end(&self) -> Option<usize> {
3430 self.last_row_end
3431 }
3432
3433 fn end_marker_end(&self) -> Option<usize> {
3434 self.end_marker_end
3435 }
3436
3437 fn current_row_size(&self, data_len: usize) -> usize {
3438 data_len.saturating_sub(self.last_row_end.unwrap_or(0))
3439 }
3440
3441 fn on_split(&mut self, split_pos: usize) {
3442 self.scan_pos = self.scan_pos.saturating_sub(split_pos);
3443 self.last_row_end = None;
3444 self.end_marker_end = self
3445 .end_marker_end
3446 .and_then(|end| end.checked_sub(split_pos));
3447 soft_assert_or_log!(
3455 self.csv.is_none() || self.record_start >= split_pos,
3456 "split bisected an in-progress CSV record: record_start={} < split_pos={}",
3457 self.record_start,
3458 split_pos,
3459 );
3460 self.record_start = self.record_start.saturating_sub(split_pos);
3461 }
3462
3463 fn on_truncate(&mut self, new_len: usize) {
3464 self.scan_pos = self.scan_pos.min(new_len);
3465 self.last_row_end = self.last_row_end.filter(|&end| end <= new_len);
3466 self.end_marker_end = self.end_marker_end.filter(|&end| end <= new_len);
3467 self.record_start = self.record_start.min(new_len);
3468 }
3469}
3470
3471impl CsvScanState {
3472 fn new(delimiter: u8, quote: u8, escape: u8, header: bool) -> Self {
3473 let (double_quote, escape) = if quote == escape {
3474 (true, None)
3475 } else {
3476 (false, Some(escape))
3477 };
3478 CsvScanState {
3479 reader: csv_core::ReaderBuilder::new()
3480 .delimiter(delimiter)
3481 .quote(quote)
3482 .double_quote(double_quote)
3483 .escape(escape)
3484 .build(),
3485 output: vec![0; 1],
3486 ends: vec![0; 1],
3487 skip_first_record: header,
3488 }
3489 }
3490}
3491
3492#[cfg(test)]
3493mod test {
3494 use super::*;
3495
3496 #[mz_ore::test]
3497 fn test_copy_row_scanner_end_marker_line_endings() {
3498 let params = CopyFormatParams::Csv(CopyCsvFormatParams::default());
3506
3507 let marker_end = |data: &[u8]| -> Option<usize> {
3508 let mut scanner = CopyRowScanner::new(¶ms);
3509 scanner.scan_new_bytes(data);
3510 scanner.end_marker_end()
3511 };
3512
3513 for eol in [&b"\n"[..], b"\r\n", b"\r"] {
3514 let join = |lines: &[&str]| -> Vec<u8> {
3515 let mut out = Vec::new();
3516 for line in lines {
3517 out.extend_from_slice(line.as_bytes());
3518 out.extend_from_slice(eol);
3519 }
3520 out
3521 };
3522
3523 let data = join(&["first", "\\.", "after"]);
3528 let mut prefix = Vec::new();
3529 prefix.extend_from_slice(b"first");
3530 prefix.extend_from_slice(eol);
3531 prefix.extend_from_slice(b"\\.");
3532 assert_eq!(
3533 marker_end(&data),
3534 Some(prefix.len() + 1),
3535 "bare marker, eol={eol:?}"
3536 );
3537
3538 let data = join(&["before", "\"\\.\"", "after"]);
3540 assert_eq!(marker_end(&data), None, "quoted marker, eol={eol:?}");
3541 }
3542 }
3543
3544 #[mz_ore::test]
3545 fn test_copy_row_scanner_non_csv_split() {
3546 for params in [
3553 CopyFormatParams::Text(CopyTextFormatParams::default()),
3554 CopyFormatParams::Binary,
3555 ] {
3556 let mut scanner = CopyRowScanner::new(¶ms);
3557 let data = b"1\thello world\t2\tsome text value here\n\
3558 3\thello world\t6\tsome text value here\n";
3559 scanner.scan_new_bytes(data);
3560 let split_pos = scanner.last_row_end().expect("a complete row");
3561 assert!(split_pos > 0, "params={params:?}");
3562 scanner.on_split(split_pos);
3564 assert_eq!(scanner.record_start, 0, "params={params:?}");
3565 }
3566 }
3567
3568 #[mz_ore::test]
3569 fn test_parse_options() {
3570 struct TestCase {
3571 input: &'static str,
3572 expect: Result<Vec<(&'static str, &'static str)>, ()>,
3573 }
3574 let tests = vec![
3575 TestCase {
3576 input: "",
3577 expect: Ok(vec![]),
3578 },
3579 TestCase {
3580 input: "--key",
3581 expect: Err(()),
3582 },
3583 TestCase {
3584 input: "--key=val",
3585 expect: Ok(vec![("key", "val")]),
3586 },
3587 TestCase {
3588 input: r#"--key=val -ckey2=val2 -c key3=val3 -c key4=val4 -ckey5=val5"#,
3589 expect: Ok(vec![
3590 ("key", "val"),
3591 ("key2", "val2"),
3592 ("key3", "val3"),
3593 ("key4", "val4"),
3594 ("key5", "val5"),
3595 ]),
3596 },
3597 TestCase {
3598 input: r#"-c\ key=val"#,
3599 expect: Ok(vec![(" key", "val")]),
3600 },
3601 TestCase {
3602 input: "--key=val -ckey2 val2",
3603 expect: Err(()),
3604 },
3605 TestCase {
3607 input: "--key=",
3608 expect: Ok(vec![("key", "")]),
3609 },
3610 ];
3611 for test in tests {
3612 let got = parse_options(test.input);
3613 let expect = test.expect.map(|r| {
3614 r.into_iter()
3615 .map(|(k, v)| (k.to_owned(), v.to_owned()))
3616 .collect()
3617 });
3618 assert_eq!(got, expect, "input: {}", test.input);
3619 }
3620 }
3621
3622 #[mz_ore::test]
3623 fn test_parse_option() {
3624 struct TestCase {
3625 input: &'static str,
3626 expect: Result<(&'static str, &'static str), ()>,
3627 }
3628 let tests = vec![
3629 TestCase {
3630 input: "",
3631 expect: Err(()),
3632 },
3633 TestCase {
3634 input: "--",
3635 expect: Err(()),
3636 },
3637 TestCase {
3638 input: "--c",
3639 expect: Err(()),
3640 },
3641 TestCase {
3642 input: "a=b",
3643 expect: Err(()),
3644 },
3645 TestCase {
3646 input: "--a=b",
3647 expect: Ok(("a", "b")),
3648 },
3649 TestCase {
3650 input: "--ca=b",
3651 expect: Ok(("ca", "b")),
3652 },
3653 TestCase {
3654 input: "-ca=b",
3655 expect: Ok(("a", "b")),
3656 },
3657 TestCase {
3659 input: "--=",
3660 expect: Ok(("", "")),
3661 },
3662 ];
3663 for test in tests {
3664 let got = parse_option(test.input);
3665 assert_eq!(got, test.expect, "input: {}", test.input);
3666 }
3667 }
3668
3669 #[mz_ore::test]
3670 fn test_split_options() {
3671 struct TestCase {
3672 input: &'static str,
3673 expect: Vec<&'static str>,
3674 }
3675 let tests = vec![
3676 TestCase {
3677 input: "",
3678 expect: vec![],
3679 },
3680 TestCase {
3681 input: " ",
3682 expect: vec![],
3683 },
3684 TestCase {
3685 input: " a ",
3686 expect: vec!["a"],
3687 },
3688 TestCase {
3689 input: " ab cd ",
3690 expect: vec!["ab", "cd"],
3691 },
3692 TestCase {
3693 input: r#" ab\ cd "#,
3694 expect: vec!["ab ", "cd"],
3695 },
3696 TestCase {
3697 input: r#" ab\\ cd "#,
3698 expect: vec![r#"ab\"#, "cd"],
3699 },
3700 TestCase {
3701 input: r#" ab\\\ cd "#,
3702 expect: vec![r#"ab\ "#, "cd"],
3703 },
3704 TestCase {
3705 input: r#" ab\\\ cd "#,
3706 expect: vec![r#"ab\ cd"#],
3707 },
3708 TestCase {
3709 input: r#" ab\\\cd "#,
3710 expect: vec![r#"ab\cd"#],
3711 },
3712 TestCase {
3713 input: r#"a\"#,
3714 expect: vec!["a"],
3715 },
3716 TestCase {
3717 input: r#"a\ "#,
3718 expect: vec!["a "],
3719 },
3720 TestCase {
3721 input: r#"\"#,
3722 expect: vec![],
3723 },
3724 TestCase {
3725 input: r#"\ "#,
3726 expect: vec![r#" "#],
3727 },
3728 TestCase {
3729 input: r#" \ "#,
3730 expect: vec![r#" "#],
3731 },
3732 TestCase {
3733 input: r#"\ "#,
3734 expect: vec![r#" "#],
3735 },
3736 ];
3737 for test in tests {
3738 let got = split_options(test.input);
3739 assert_eq!(got, test.expect, "input: {}", test.input);
3740 }
3741 }
3742
3743 #[mz_ore::test]
3744 fn test_is_jwt() {
3745 assert!(is_jwt("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.signature"));
3747 for s in [
3749 "",
3750 "secure_password",
3751 "p4ss.w0rd",
3752 "aaa.bbb.ccc",
3753 "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0",
3754 "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.sig.extra",
3755 ] {
3756 assert!(!is_jwt(s), "is_jwt({s:?})");
3757 }
3758 }
3759}