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, redact_sql_for_logging};
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, info, 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 if let Some(message) = &message {
951 self.maybe_log_message_arrival(message).await;
952 }
953
954 let start = message.as_ref().map(|_| Instant::now());
955 let next_state = match message {
956 Some(FrontendMessage::Query { sql }) => {
957 let query_root_span =
958 tracing::info_span!(parent: None, "advance_ready", otel.name = message_name);
959 query_root_span.follows_from(tracing::Span::current());
960 self.query(sql, received)
961 .instrument(query_root_span)
962 .await?
963 }
964 Some(FrontendMessage::Parse {
965 name,
966 sql,
967 param_types,
968 }) => self.parse(name, sql, param_types).await?,
969 Some(FrontendMessage::Bind {
970 portal_name,
971 statement_name,
972 param_formats,
973 raw_params,
974 result_formats,
975 }) => {
976 self.bind(
977 portal_name,
978 statement_name,
979 param_formats,
980 raw_params,
981 result_formats,
982 )
983 .await?
984 }
985 Some(FrontendMessage::Execute {
986 portal_name,
987 max_rows,
988 }) => {
989 let max_rows = match usize::try_from(max_rows) {
990 Ok(0) | Err(_) => ExecuteCount::All, Ok(n) => ExecuteCount::Count(n),
992 };
993 let execute_root_span =
994 tracing::info_span!(parent: None, "advance_ready", otel.name = message_name);
995 execute_root_span.follows_from(tracing::Span::current());
996 let state = self
997 .execute(
998 portal_name,
999 max_rows,
1000 portal_exec_message,
1001 None,
1002 ExecuteTimeout::None,
1003 None,
1004 Some(received),
1005 )
1006 .instrument(execute_root_span)
1007 .await?;
1008 if self.adapter_client.session().transaction().is_implicit() {
1023 self.txn_needs_commit = true;
1024 }
1025 state
1026 }
1027 Some(FrontendMessage::DescribeStatement { name }) => {
1028 self.describe_statement(&name).await?
1029 }
1030 Some(FrontendMessage::DescribePortal { name }) => self.describe_portal(&name).await?,
1031 Some(FrontendMessage::CloseStatement { name }) => self.close_statement(name).await?,
1032 Some(FrontendMessage::ClosePortal { name }) => self.close_portal(name).await?,
1033 Some(FrontendMessage::Flush) => self.flush().await?,
1034 Some(FrontendMessage::Sync) => self.sync().await?,
1035 Some(FrontendMessage::Terminate) => State::Done,
1036
1037 Some(FrontendMessage::CopyData(_))
1044 | Some(FrontendMessage::CopyDone)
1045 | Some(FrontendMessage::CopyFail(_)) => State::Ready,
1046
1047 Some(FrontendMessage::Password { .. })
1048 | Some(FrontendMessage::RawAuthentication(_))
1049 | Some(FrontendMessage::SASLInitialResponse { .. })
1050 | Some(FrontendMessage::SASLResponse(_)) => State::Drain,
1051 None => State::Done,
1052 };
1053
1054 if let Some(start) = start {
1055 self.adapter_client
1056 .inner()
1057 .metrics()
1058 .pgwire_message_processing_seconds
1059 .with_label_values(&[message_name])
1060 .observe(start.elapsed().as_secs_f64());
1061 }
1062 self.adapter_client
1063 .inner()
1064 .metrics()
1065 .pgwire_recv_scheduling_delay_ms
1066 .with_label_values(&[message_name])
1067 .observe(recv_scheduling_delay_ms);
1068
1069 Ok(next_state)
1070 }
1071
1072 async fn advance_drain(&mut self) -> Result<State, io::Error> {
1073 let message = self.conn.recv().await?;
1074 if message.is_some() {
1075 self.adapter_client
1076 .remove_idle_in_transaction_session_timeout();
1077 }
1078 match message {
1079 Some(FrontendMessage::Sync) => self.sync().await,
1080 None => Ok(State::Done),
1081 _ => Ok(State::Drain),
1082 }
1083 }
1084
1085 #[instrument(level = "debug")]
1089 async fn one_query(
1090 &mut self,
1091 stmt: Statement<Raw>,
1092 sql: String,
1093 lifecycle_timestamps: LifecycleTimestamps,
1094 ) -> Result<State, io::Error> {
1095 const EMPTY_PORTAL: &str = "";
1098 if let Err(e) = self
1099 .adapter_client
1100 .declare(EMPTY_PORTAL.to_string(), stmt, sql)
1101 .await
1102 {
1103 return self
1104 .send_error_and_get_state(e.into_response(Severity::Error))
1105 .await;
1106 }
1107 let portal = self
1108 .adapter_client
1109 .session()
1110 .get_portal_unverified_mut(EMPTY_PORTAL)
1111 .expect("unnamed portal should be present");
1112
1113 *portal.lifecycle_timestamps = Some(lifecycle_timestamps);
1114
1115 let stmt_desc = portal.desc.clone();
1116 if !stmt_desc.param_types.is_empty() {
1117 return self
1118 .send_error_and_get_state(ErrorResponse::error(
1119 SqlState::UNDEFINED_PARAMETER,
1120 "there is no parameter $1",
1121 ))
1122 .await;
1123 }
1124
1125 if let Some(relation_desc) = &stmt_desc.relation_desc {
1127 if !stmt_desc.is_copy {
1128 let formats = vec![Format::Text; stmt_desc.arity()];
1129 self.send(BackendMessage::RowDescription(
1130 message::encode_row_description(relation_desc, &formats),
1131 ))
1132 .await?;
1133 }
1134 }
1135
1136 let result = match self
1137 .adapter_client
1138 .execute(EMPTY_PORTAL.to_string(), self.conn.wait_closed(), None)
1139 .await
1140 {
1141 Ok((response, execute_started)) => {
1142 self.send_pending_notices().await?;
1143 self.send_execute_response(
1144 response,
1145 stmt_desc.relation_desc,
1146 EMPTY_PORTAL.to_string(),
1147 ExecuteCount::All,
1148 portal_exec_message,
1149 None,
1150 ExecuteTimeout::None,
1151 execute_started,
1152 )
1153 .await
1154 }
1155 Err(e) => {
1156 self.send_pending_notices().await?;
1157 self.send_error_and_get_state(e.into_response(Severity::Error))
1158 .await
1159 }
1160 };
1161
1162 self.adapter_client.session().remove_portal(EMPTY_PORTAL);
1164
1165 result
1166 }
1167
1168 async fn ensure_transaction(
1169 &mut self,
1170 num_stmts: usize,
1171 message_type: &str,
1172 ) -> Result<(), io::Error> {
1173 let start = Instant::now();
1174 if self.txn_needs_commit {
1175 self.commit_transaction().await?;
1176 }
1177 let res = self.adapter_client.start_transaction(Some(num_stmts));
1180 assert_ok!(res);
1181 self.adapter_client
1182 .inner()
1183 .metrics()
1184 .pgwire_ensure_transaction_seconds
1185 .with_label_values(&[message_type])
1186 .observe(start.elapsed().as_secs_f64());
1187 Ok(())
1188 }
1189
1190 async fn maybe_log_message_arrival(&mut self, message: &FrontendMessage) {
1209 if !self
1210 .adapter_client
1211 .statement_arrival_logging_enabled()
1212 .await
1213 {
1214 return;
1215 }
1216 let session = self.adapter_client.session();
1217 let conn_id = session.conn_id();
1218 let session_uuid = session.uuid();
1219 let kind = message.name();
1220 match message {
1221 FrontendMessage::Query { sql } => {
1222 info!(
1223 %conn_id, %session_uuid, kind, sql = %redact_sql_for_logging(sql),
1224 "statement arrival"
1225 );
1226 }
1227 FrontendMessage::Parse { name, sql, .. } => {
1228 info!(
1229 %conn_id, %session_uuid, kind, name, sql = %redact_sql_for_logging(sql),
1230 "statement arrival"
1231 );
1232 }
1233 FrontendMessage::Bind {
1234 portal_name,
1235 statement_name,
1236 raw_params,
1237 ..
1238 } => {
1239 info!(
1240 %conn_id, %session_uuid, kind, portal_name, statement_name,
1241 num_params = raw_params.len(),
1242 "statement arrival"
1243 );
1244 }
1245 FrontendMessage::CopyData(data) => {
1247 info!(%conn_id, %session_uuid, kind, len = data.len(), "statement arrival");
1248 }
1249 FrontendMessage::Password { .. }
1251 | FrontendMessage::RawAuthentication(_)
1252 | FrontendMessage::SASLInitialResponse { .. }
1253 | FrontendMessage::SASLResponse(_) => {
1254 info!(%conn_id, %session_uuid, kind, "statement arrival");
1255 }
1256 FrontendMessage::CopyFail(_) => {
1259 info!(%conn_id, %session_uuid, kind, "statement arrival");
1260 }
1261 FrontendMessage::DescribeStatement { .. }
1264 | FrontendMessage::DescribePortal { .. }
1265 | FrontendMessage::Execute { .. }
1266 | FrontendMessage::Flush
1267 | FrontendMessage::Sync
1268 | FrontendMessage::CloseStatement { .. }
1269 | FrontendMessage::ClosePortal { .. }
1270 | FrontendMessage::Terminate
1271 | FrontendMessage::CopyDone => {
1272 info!(%conn_id, %session_uuid, kind, contents = ?message, "statement arrival");
1278 }
1279 }
1280 }
1281
1282 fn parse_sql<'b>(&self, sql: &'b str) -> Result<Vec<StatementParseResult<'b>>, ErrorResponse> {
1283 let parse_start = Instant::now();
1284 let result = match self.adapter_client.parse(sql) {
1285 Ok(result) => result.map_err(|e| {
1286 let pos = sql[..e.error.pos].chars().count() + 1;
1289 ErrorResponse::error(SqlState::SYNTAX_ERROR, e.error.message).with_position(pos)
1290 }),
1291 Err(msg) => Err(ErrorResponse::error(SqlState::PROGRAM_LIMIT_EXCEEDED, msg)),
1292 };
1293 self.adapter_client
1294 .inner()
1295 .metrics()
1296 .parse_seconds
1297 .observe(parse_start.elapsed().as_secs_f64());
1298 result
1299 }
1300
1301 #[instrument(level = "debug")]
1306 async fn query(&mut self, sql: String, received: EpochMillis) -> Result<State, io::Error> {
1307 let stmts = match self.parse_sql(&sql) {
1309 Ok(stmts) => stmts,
1310 Err(err) => {
1311 self.send_error_and_get_state(err).await?;
1312 return self.ready().await;
1313 }
1314 };
1315
1316 let num_stmts = stmts.len();
1317
1318 for StatementParseResult { ast: stmt, sql } in stmts {
1320 if self.is_aborted_txn() && !is_txn_exit_stmt(Some(&stmt)) {
1322 self.aborted_txn_error().await?;
1323 break;
1324 }
1325
1326 self.ensure_transaction(num_stmts, "query").await?;
1334
1335 match self
1336 .one_query(stmt, sql.to_string(), LifecycleTimestamps { received })
1337 .await?
1338 {
1339 State::Ready => (),
1340 State::Drain => break,
1341 State::Done => return Ok(State::Done),
1342 }
1343 }
1344
1345 {
1347 if self.adapter_client.session().transaction().is_implicit() {
1348 self.commit_transaction().await?;
1349 }
1350 }
1351
1352 if num_stmts == 0 {
1353 self.send(BackendMessage::EmptyQueryResponse).await?;
1354 }
1355
1356 self.ready().await
1357 }
1358
1359 #[instrument(level = "debug")]
1360 async fn parse(
1361 &mut self,
1362 name: String,
1363 sql: String,
1364 param_oids: Vec<u32>,
1365 ) -> Result<State, io::Error> {
1366 self.ensure_transaction(1, "parse").await?;
1368
1369 let mut param_types = vec![];
1370 for oid in param_oids {
1371 match mz_pgrepr::Type::from_oid(oid) {
1372 Ok(ty) => match SqlScalarType::try_from(&ty) {
1373 Ok(ty) => param_types.push(Some(ty)),
1374 Err(err) => {
1375 return self
1376 .send_error_and_get_state(ErrorResponse::error(
1377 SqlState::INVALID_PARAMETER_VALUE,
1378 err.to_string(),
1379 ))
1380 .await;
1381 }
1382 },
1383 Err(_) if oid == 0 => param_types.push(None),
1384 Err(e) => {
1385 return self
1386 .send_error_and_get_state(ErrorResponse::error(
1387 SqlState::PROTOCOL_VIOLATION,
1388 e.to_string(),
1389 ))
1390 .await;
1391 }
1392 }
1393 }
1394
1395 let stmts = match self.parse_sql(&sql) {
1396 Ok(stmts) => stmts,
1397 Err(err) => {
1398 return self.send_error_and_get_state(err).await;
1399 }
1400 };
1401 if stmts.len() > 1 {
1402 return self
1403 .send_error_and_get_state(ErrorResponse::error(
1404 SqlState::INTERNAL_ERROR,
1405 "cannot insert multiple commands into a prepared statement",
1406 ))
1407 .await;
1408 }
1409 let (maybe_stmt, sql) = match stmts.into_iter().next() {
1410 None => (None, ""),
1411 Some(StatementParseResult { ast, sql }) => (Some(ast), sql),
1412 };
1413 if self.is_aborted_txn() && !is_txn_exit_stmt(maybe_stmt.as_ref()) {
1414 return self.aborted_txn_error().await;
1415 }
1416 match self
1417 .adapter_client
1418 .prepare(name, maybe_stmt, sql.to_string(), param_types)
1419 .await
1420 {
1421 Ok(()) => {
1422 self.send(BackendMessage::ParseComplete).await?;
1423 Ok(State::Ready)
1424 }
1425 Err(e) => {
1426 self.send_error_and_get_state(e.into_response(Severity::Error))
1427 .await
1428 }
1429 }
1430 }
1431
1432 #[instrument(level = "debug")]
1434 async fn commit_transaction(&mut self) -> Result<(), io::Error> {
1435 self.end_transaction(EndTransactionAction::Commit).await
1436 }
1437
1438 #[instrument(level = "debug")]
1440 async fn rollback_transaction(&mut self) -> Result<(), io::Error> {
1441 self.end_transaction(EndTransactionAction::Rollback).await
1442 }
1443
1444 #[instrument(level = "debug")]
1446 async fn end_transaction(&mut self, action: EndTransactionAction) -> Result<(), io::Error> {
1447 self.txn_needs_commit = false;
1448 let resp = self.adapter_client.end_transaction(action).await;
1449 if let Err(err) = resp {
1450 self.send(BackendMessage::ErrorResponse(
1451 err.into_response(Severity::Error),
1452 ))
1453 .await?;
1454 }
1455 Ok(())
1456 }
1457
1458 #[instrument(level = "debug")]
1459 async fn bind(
1460 &mut self,
1461 portal_name: String,
1462 statement_name: String,
1463 param_formats: Vec<Format>,
1464 raw_params: Vec<Option<Vec<u8>>>,
1465 result_formats: Vec<Format>,
1466 ) -> Result<State, io::Error> {
1467 self.ensure_transaction(1, "bind").await?;
1469
1470 let aborted_txn = self.is_aborted_txn();
1471 let stmt = match self
1472 .adapter_client
1473 .get_prepared_statement(&statement_name)
1474 .await
1475 {
1476 Ok(stmt) => stmt,
1477 Err(err) => {
1478 return self
1479 .send_error_and_get_state(err.into_response(Severity::Error))
1480 .await;
1481 }
1482 };
1483
1484 let param_types = &stmt.desc().param_types;
1485 if param_types.len() != raw_params.len() {
1486 let message = format!(
1487 "bind message supplies {actual} parameters, \
1488 but prepared statement \"{name}\" requires {expected}",
1489 name = statement_name,
1490 actual = raw_params.len(),
1491 expected = param_types.len()
1492 );
1493 return self
1494 .send_error_and_get_state(ErrorResponse::error(
1495 SqlState::PROTOCOL_VIOLATION,
1496 message,
1497 ))
1498 .await;
1499 }
1500 let param_formats = match pad_formats(param_formats, raw_params.len()) {
1501 Ok(param_formats) => param_formats,
1502 Err(msg) => {
1503 return self
1504 .send_error_and_get_state(ErrorResponse::error(
1505 SqlState::PROTOCOL_VIOLATION,
1506 msg,
1507 ))
1508 .await;
1509 }
1510 };
1511 if aborted_txn && !is_txn_exit_stmt(stmt.stmt()) {
1512 return self.aborted_txn_error().await;
1513 }
1514 let buf = RowArena::new();
1515 let mut params = vec![];
1516 for ((raw_param, mz_typ), format) in raw_params
1517 .into_iter()
1518 .zip_eq(param_types)
1519 .zip_eq(param_formats)
1520 {
1521 let pg_typ = mz_pgrepr::Type::from(mz_typ);
1522 let datum = match raw_param {
1523 None => Datum::Null,
1524 Some(bytes) => match mz_pgrepr::Value::decode(format, &pg_typ, &bytes) {
1525 Ok(param) => match param.into_datum_decode_error(&buf, &pg_typ, "parameter") {
1526 Ok(datum) => datum,
1527 Err(msg) => {
1528 return self
1529 .send_error_and_get_state(ErrorResponse::error(
1530 SqlState::INVALID_PARAMETER_VALUE,
1531 msg,
1532 ))
1533 .await;
1534 }
1535 },
1536 Err(err) => {
1537 let (code, msg) = if err.is::<mz_pgrepr::NulCharacterError>() {
1540 (SqlState::CHARACTER_NOT_IN_REPERTOIRE, err.to_string())
1541 } else {
1542 (
1543 SqlState::INVALID_PARAMETER_VALUE,
1544 format!("unable to decode parameter: {}", err),
1545 )
1546 };
1547 return self
1548 .send_error_and_get_state(ErrorResponse::error(code, msg))
1549 .await;
1550 }
1551 },
1552 };
1553 params.push((datum, mz_typ.clone()))
1554 }
1555
1556 let result_formats = match pad_formats(
1557 result_formats,
1558 stmt.desc()
1559 .relation_desc
1560 .clone()
1561 .map(|desc| desc.typ().column_types.len())
1562 .unwrap_or(0),
1563 ) {
1564 Ok(result_formats) => result_formats,
1565 Err(msg) => {
1566 return self
1567 .send_error_and_get_state(ErrorResponse::error(
1568 SqlState::PROTOCOL_VIOLATION,
1569 msg,
1570 ))
1571 .await;
1572 }
1573 };
1574
1575 if !stmt.stmt().map_or(false, |stmt| match stmt {
1578 Statement::Copy(CopyStatement {
1579 direction: CopyDirection::To,
1580 ..
1581 }) => true,
1582 Statement::Copy(CopyStatement {
1583 direction: CopyDirection::From,
1584 target: CopyTarget::Expr(_),
1588 ..
1589 }) => true,
1590 _ => false,
1591 }) {
1592 if let Some(desc) = stmt.desc().relation_desc.clone() {
1593 for (format, ty) in result_formats.iter().zip_eq(desc.iter_types()) {
1594 if let Format::Binary = format {
1595 if let Err(msg) = mz_pgrepr::Value::binary_encoding_error(&ty.scalar_type) {
1596 return self
1597 .send_error_and_get_state(ErrorResponse::error(
1598 SqlState::UNDEFINED_FUNCTION,
1599 msg,
1600 ))
1601 .await;
1602 }
1603 }
1604 }
1605 }
1606 }
1607
1608 let desc = stmt.desc().clone();
1609 let logging = Arc::clone(stmt.logging());
1610 let stmt_ast = stmt.stmt().cloned();
1611 let state_revision = stmt.state_revision;
1612 if let Err(err) = self.adapter_client.session().set_portal(
1613 portal_name,
1614 desc,
1615 stmt_ast,
1616 logging,
1617 params,
1618 result_formats,
1619 state_revision,
1620 ) {
1621 return self
1622 .send_error_and_get_state(err.into_response(Severity::Error))
1623 .await;
1624 }
1625
1626 self.send(BackendMessage::BindComplete).await?;
1627 Ok(State::Ready)
1628 }
1629
1630 fn execute(
1633 &mut self,
1634 portal_name: String,
1635 max_rows: ExecuteCount,
1636 get_response: GetResponse,
1637 fetch_portal_name: Option<String>,
1638 timeout: ExecuteTimeout,
1639 outer_ctx_extra: Option<ExecuteContextGuard>,
1640 received: Option<EpochMillis>,
1641 ) -> BoxFuture<'_, Result<State, io::Error>> {
1642 async move {
1643 let aborted_txn = self.is_aborted_txn();
1644
1645 let portal = match self
1647 .adapter_client
1648 .session()
1649 .get_portal_unverified_mut(&portal_name)
1650 {
1651 Some(portal) => portal,
1652 None => {
1653 let msg = format!("portal {} does not exist", portal_name.quoted());
1654 if let Some(outer_ctx_extra) = outer_ctx_extra {
1655 self.adapter_client.retire_execute(
1656 outer_ctx_extra,
1657 StatementEndedExecutionReason::Errored { error: msg.clone() },
1658 );
1659 }
1660 return self
1661 .send_error_and_get_state(ErrorResponse::error(
1662 SqlState::INVALID_CURSOR_NAME,
1663 msg,
1664 ))
1665 .await;
1666 }
1667 };
1668
1669 *portal.lifecycle_timestamps = received.map(LifecycleTimestamps::new);
1670
1671 let txn_exit_stmt = is_txn_exit_stmt(portal.stmt.as_deref());
1673 if aborted_txn && !txn_exit_stmt {
1674 if let Some(outer_ctx_extra) = outer_ctx_extra {
1675 self.adapter_client.retire_execute(
1676 outer_ctx_extra,
1677 StatementEndedExecutionReason::Errored {
1678 error: ABORTED_TXN_MSG.to_string(),
1679 },
1680 );
1681 }
1682 return self.aborted_txn_error().await;
1683 }
1684
1685 let row_desc = portal.desc.relation_desc.clone();
1686 match portal.state {
1687 PortalState::NotStarted => {
1688 self.ensure_transaction(1, "execute").await?;
1690 match self
1691 .adapter_client
1692 .execute(
1693 portal_name.clone(),
1694 self.conn.wait_closed(),
1695 outer_ctx_extra,
1696 )
1697 .await
1698 {
1699 Ok((response, execute_started)) => {
1700 self.send_pending_notices().await?;
1701 self.send_execute_response(
1702 response,
1703 row_desc,
1704 portal_name,
1705 max_rows,
1706 get_response,
1707 fetch_portal_name,
1708 timeout,
1709 execute_started,
1710 )
1711 .await
1712 }
1713 Err(e) => {
1714 self.send_pending_notices().await?;
1715 self.send_error_and_get_state(e.into_response(Severity::Error))
1716 .await
1717 }
1718 }
1719 }
1720 PortalState::InProgress(rows) => {
1721 let rows = rows.take().expect("InProgress rows must be populated");
1722 let (result, statement_ended_execution_reason) = match self
1723 .send_rows(
1724 row_desc.expect("portal missing row desc on resumption"),
1725 portal_name,
1726 rows,
1727 max_rows,
1728 get_response,
1729 fetch_portal_name,
1730 timeout,
1731 )
1732 .await
1733 {
1734 Err(e) => {
1735 (Err(e), StatementEndedExecutionReason::Canceled)
1738 }
1739 Ok((ok, SendRowsEndedReason::Canceled)) => {
1740 (Ok(ok), StatementEndedExecutionReason::Canceled)
1741 }
1742 Ok((
1755 ok,
1756 SendRowsEndedReason::Success {
1757 result_size: _,
1758 rows_returned: _,
1759 },
1760 )) => (
1761 Ok(ok),
1762 StatementEndedExecutionReason::Success {
1763 result_size: None,
1764 rows_returned: None,
1765 execution_strategy: None,
1766 },
1767 ),
1768 Ok((ok, SendRowsEndedReason::Errored { error })) => {
1769 (Ok(ok), StatementEndedExecutionReason::Errored { error })
1770 }
1771 };
1772 if let Some(outer_ctx_extra) = outer_ctx_extra {
1773 self.adapter_client
1774 .retire_execute(outer_ctx_extra, statement_ended_execution_reason);
1775 }
1776 result
1777 }
1778 PortalState::Completed(Some(tag)) => {
1785 let tag = tag.to_string();
1786 if let Some(outer_ctx_extra) = outer_ctx_extra {
1787 self.adapter_client.retire_execute(
1788 outer_ctx_extra,
1789 StatementEndedExecutionReason::Success {
1790 result_size: None,
1791 rows_returned: None,
1792 execution_strategy: None,
1793 },
1794 );
1795 }
1796 self.send(BackendMessage::CommandComplete { tag }).await?;
1797 Ok(State::Ready)
1798 }
1799 PortalState::Completed(None) => {
1800 let error = format!(
1801 "portal {} cannot be run",
1802 Ident::new_unchecked(portal_name).to_ast_string_stable()
1803 );
1804 if let Some(outer_ctx_extra) = outer_ctx_extra {
1805 self.adapter_client.retire_execute(
1806 outer_ctx_extra,
1807 StatementEndedExecutionReason::Errored {
1808 error: error.clone(),
1809 },
1810 );
1811 }
1812 self.send_error_and_get_state(ErrorResponse::error(
1813 SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE,
1814 error,
1815 ))
1816 .await
1817 }
1818 }
1819 }
1820 .instrument(debug_span!("execute"))
1821 .boxed()
1822 }
1823
1824 #[instrument(level = "debug")]
1825 async fn describe_statement(&mut self, name: &str) -> Result<State, io::Error> {
1826 self.ensure_transaction(1, "describe_statement").await?;
1828
1829 let stmt = match self.adapter_client.get_prepared_statement(name).await {
1830 Ok(stmt) => stmt,
1831 Err(err) => {
1832 return self
1833 .send_error_and_get_state(err.into_response(Severity::Error))
1834 .await;
1835 }
1836 };
1837 let parameter_desc = BackendMessage::ParameterDescription(
1839 stmt.desc()
1840 .param_types
1841 .iter()
1842 .map(mz_pgrepr::Type::from)
1843 .collect(),
1844 );
1845 let formats = vec![Format::Text; stmt.desc().arity()];
1849 let row_desc = describe_rows(stmt.desc(), &formats);
1850 self.send_all([parameter_desc, row_desc]).await?;
1851 Ok(State::Ready)
1852 }
1853
1854 #[instrument(level = "debug")]
1855 async fn describe_portal(&mut self, name: &str) -> Result<State, io::Error> {
1856 self.ensure_transaction(1, "describe_portal").await?;
1858
1859 let session = self.adapter_client.session();
1860 let row_desc = session
1861 .get_portal_unverified(name)
1862 .map(|portal| describe_rows(&portal.desc, &portal.result_formats));
1863 match row_desc {
1864 Some(row_desc) => {
1865 self.send(row_desc).await?;
1866 Ok(State::Ready)
1867 }
1868 None => {
1869 self.send_error_and_get_state(ErrorResponse::error(
1870 SqlState::INVALID_CURSOR_NAME,
1871 format!("portal {} does not exist", name.quoted()),
1872 ))
1873 .await
1874 }
1875 }
1876 }
1877
1878 #[instrument(level = "debug")]
1879 async fn close_statement(&mut self, name: String) -> Result<State, io::Error> {
1880 self.adapter_client
1881 .session()
1882 .remove_prepared_statement(&name);
1883 self.send(BackendMessage::CloseComplete).await?;
1884 Ok(State::Ready)
1885 }
1886
1887 #[instrument(level = "debug")]
1888 async fn close_portal(&mut self, name: String) -> Result<State, io::Error> {
1889 self.adapter_client.session().remove_portal(&name);
1890 self.send(BackendMessage::CloseComplete).await?;
1891 Ok(State::Ready)
1892 }
1893
1894 fn complete_portal(&mut self, name: &str) {
1895 let portal = self
1896 .adapter_client
1897 .session()
1898 .get_portal_unverified_mut(name)
1899 .expect("portal should exist");
1900 *portal.state = PortalState::Completed(None);
1901 }
1902
1903 async fn fetch(
1904 &mut self,
1905 name: String,
1906 count: Option<FetchDirection>,
1907 max_rows: ExecuteCount,
1908 fetch_portal_name: Option<String>,
1909 timeout: ExecuteTimeout,
1910 ctx_extra: ExecuteContextGuard,
1911 ) -> Result<State, io::Error> {
1912 let count = count.unwrap_or(FetchDirection::ForwardCount(1));
1915
1916 let count = match (max_rows, count) {
1929 (ExecuteCount::Count(max_rows), FetchDirection::ForwardCount(count)) => {
1930 let count = usize::cast_from(count);
1931 if max_rows < count {
1932 let msg = "Execute with max_rows < a FETCH's count is not supported";
1933 self.adapter_client.retire_execute(
1934 ctx_extra,
1935 StatementEndedExecutionReason::Errored {
1936 error: msg.to_string(),
1937 },
1938 );
1939 return self
1940 .send_error_and_get_state(ErrorResponse::error(
1941 SqlState::FEATURE_NOT_SUPPORTED,
1942 msg,
1943 ))
1944 .await;
1945 }
1946 ExecuteCount::Count(count)
1947 }
1948 (ExecuteCount::Count(_), FetchDirection::ForwardAll) => {
1949 let msg = "Execute with max_rows of a FETCH ALL is not supported";
1950 self.adapter_client.retire_execute(
1951 ctx_extra,
1952 StatementEndedExecutionReason::Errored {
1953 error: msg.to_string(),
1954 },
1955 );
1956 return self
1957 .send_error_and_get_state(ErrorResponse::error(
1958 SqlState::FEATURE_NOT_SUPPORTED,
1959 msg,
1960 ))
1961 .await;
1962 }
1963 (ExecuteCount::All, FetchDirection::ForwardAll) => ExecuteCount::All,
1964 (ExecuteCount::All, FetchDirection::ForwardCount(count)) => {
1965 ExecuteCount::Count(usize::cast_from(count))
1966 }
1967 };
1968 let cursor_name = name.to_string();
1969 self.execute(
1970 cursor_name,
1971 count,
1972 fetch_message,
1973 fetch_portal_name,
1974 timeout,
1975 Some(ctx_extra),
1976 None,
1977 )
1978 .await
1979 }
1980
1981 async fn flush(&mut self) -> Result<State, io::Error> {
1982 self.conn.flush().await?;
1983 Ok(State::Ready)
1984 }
1985
1986 #[instrument(level = "debug")]
1991 async fn send<M>(&mut self, message: M) -> Result<(), io::Error>
1992 where
1993 M: Into<BackendMessage>,
1994 {
1995 let message: BackendMessage = message.into();
1996 let is_error =
1997 matches!(&message, BackendMessage::ErrorResponse(e) if e.severity.is_error());
1998
1999 self.conn.send(message).await?;
2000
2001 if is_error {
2008 self.conn.flush().await?;
2009 }
2010
2011 Ok(())
2012 }
2013
2014 #[instrument(level = "debug")]
2015 pub async fn send_all(
2016 &mut self,
2017 messages: impl IntoIterator<Item = BackendMessage>,
2018 ) -> Result<(), io::Error> {
2019 for m in messages {
2020 self.send(m).await?;
2021 }
2022 Ok(())
2023 }
2024
2025 #[instrument(level = "debug")]
2026 async fn sync(&mut self) -> Result<State, io::Error> {
2027 if self.adapter_client.session().transaction().is_implicit() {
2029 self.commit_transaction().await?;
2030 }
2031 self.ready().await
2032 }
2033
2034 #[instrument(level = "debug")]
2035 async fn ready(&mut self) -> Result<State, io::Error> {
2036 let txn_state = self.adapter_client.session().transaction().into();
2037 self.send(BackendMessage::ReadyForQuery(txn_state)).await?;
2038 self.flush().await
2039 }
2040
2041 #[allow(clippy::too_many_arguments)]
2042 #[instrument(level = "debug")]
2043 async fn send_execute_response(
2044 &mut self,
2045 response: ExecuteResponse,
2046 row_desc: Option<RelationDesc>,
2047 portal_name: String,
2048 max_rows: ExecuteCount,
2049 get_response: GetResponse,
2050 fetch_portal_name: Option<String>,
2051 timeout: ExecuteTimeout,
2052 execute_started: Instant,
2053 ) -> Result<State, io::Error> {
2054 let mut tag = response.tag();
2055
2056 macro_rules! command_complete {
2057 () => {{
2058 self.send(BackendMessage::CommandComplete {
2059 tag: tag
2060 .take()
2061 .expect("command_complete only called on tag-generating results"),
2062 })
2063 .await?;
2064 Ok(State::Ready)
2065 }};
2066 }
2067
2068 let r = match response {
2069 ExecuteResponse::ClosedCursor => {
2070 self.complete_portal(&portal_name);
2071 command_complete!()
2072 }
2073 ExecuteResponse::DeclaredCursor => {
2074 self.complete_portal(&portal_name);
2075 command_complete!()
2076 }
2077 ExecuteResponse::EmptyQuery => {
2078 self.send(BackendMessage::EmptyQueryResponse).await?;
2079 Ok(State::Ready)
2080 }
2081 ExecuteResponse::Fetch {
2082 name,
2083 count,
2084 timeout,
2085 ctx_extra,
2086 } => {
2087 self.fetch(
2088 name,
2089 count,
2090 max_rows,
2091 Some(portal_name.to_string()),
2092 timeout,
2093 ctx_extra,
2094 )
2095 .await
2096 }
2097 ExecuteResponse::SendingRowsStreaming {
2098 rows,
2099 instance_id,
2100 strategy,
2101 } => {
2102 let row_desc = row_desc
2103 .expect("missing row description for ExecuteResponse::SendingRowsStreaming");
2104
2105 let span = tracing::debug_span!("sending_rows_streaming");
2106
2107 self.send_rows(
2108 row_desc,
2109 portal_name,
2110 InProgressRows::new(RecordFirstRowStream::new(
2111 Box::new(rows),
2112 execute_started,
2113 &self.adapter_client,
2114 Some(instance_id),
2115 Some(strategy),
2116 )),
2117 max_rows,
2118 get_response,
2119 fetch_portal_name,
2120 timeout,
2121 )
2122 .instrument(span)
2123 .await
2124 .map(|(state, _)| state)
2125 }
2126 ExecuteResponse::SendingRowsImmediate { rows } => {
2127 let row_desc = row_desc
2128 .expect("missing row description for ExecuteResponse::SendingRowsImmediate");
2129
2130 let span = tracing::debug_span!("sending_rows_immediate");
2131
2132 let stream =
2133 futures::stream::once(futures::future::ready(PeekResponseUnary::Rows(rows)));
2134 self.send_rows(
2135 row_desc,
2136 portal_name,
2137 InProgressRows::new(RecordFirstRowStream::new(
2138 Box::new(stream),
2139 execute_started,
2140 &self.adapter_client,
2141 None,
2142 Some(StatementExecutionStrategy::Constant),
2143 )),
2144 max_rows,
2145 get_response,
2146 fetch_portal_name,
2147 timeout,
2148 )
2149 .instrument(span)
2150 .await
2151 .map(|(state, _)| state)
2152 }
2153 ExecuteResponse::SetVariable { name, .. } => {
2154 let qn = name.to_string();
2157 let msg = if let Some(var) = self
2158 .adapter_client
2159 .session()
2160 .vars_mut()
2161 .notify_set()
2162 .find(|v| v.name() == qn)
2163 {
2164 Some(BackendMessage::ParameterStatus(var.name(), var.value()))
2165 } else {
2166 None
2167 };
2168 if let Some(msg) = msg {
2169 self.send(msg).await?;
2170 }
2171 command_complete!()
2172 }
2173 ExecuteResponse::Subscribing {
2174 rx,
2175 ctx_extra,
2176 instance_id,
2177 } => {
2178 if fetch_portal_name.is_none() {
2179 let mut msg = ErrorResponse::notice(
2180 SqlState::WARNING,
2181 "streaming SUBSCRIBE rows directly requires a client that does not buffer output",
2182 );
2183 if self.adapter_client.session().vars().application_name() == "psql" {
2184 msg.hint = Some(
2185 "Wrap your SUBSCRIBE statement in `COPY (SUBSCRIBE ...) TO STDOUT`."
2186 .into(),
2187 )
2188 }
2189 self.send(msg).await?;
2190 self.conn.flush().await?;
2191 }
2192 let row_desc =
2193 row_desc.expect("missing row description for ExecuteResponse::Subscribing");
2194 let (result, statement_ended_execution_reason) = match self
2195 .send_rows(
2196 row_desc,
2197 portal_name,
2198 InProgressRows::new(RecordFirstRowStream::new(
2199 Box::new(UnboundedReceiverStream::new(rx)),
2200 execute_started,
2201 &self.adapter_client,
2202 Some(instance_id),
2203 None,
2204 )),
2205 max_rows,
2206 get_response,
2207 fetch_portal_name,
2208 timeout,
2209 )
2210 .await
2211 {
2212 Err(e) => {
2213 (Err(e), StatementEndedExecutionReason::Canceled)
2216 }
2217 Ok((ok, SendRowsEndedReason::Canceled)) => {
2218 (Ok(ok), StatementEndedExecutionReason::Canceled)
2219 }
2220 Ok((
2221 ok,
2222 SendRowsEndedReason::Success {
2223 result_size,
2224 rows_returned,
2225 },
2226 )) => (
2227 Ok(ok),
2228 StatementEndedExecutionReason::Success {
2229 result_size: Some(result_size),
2230 rows_returned: Some(rows_returned),
2231 execution_strategy: None,
2232 },
2233 ),
2234 Ok((ok, SendRowsEndedReason::Errored { error })) => {
2235 (Ok(ok), StatementEndedExecutionReason::Errored { error })
2236 }
2237 };
2238 self.adapter_client
2239 .retire_execute(ctx_extra, statement_ended_execution_reason);
2240 return result;
2241 }
2242 ExecuteResponse::CopyTo { format, resp } => {
2243 let row_desc =
2244 row_desc.expect("missing row description for ExecuteResponse::CopyTo");
2245 match *resp {
2246 ExecuteResponse::Subscribing {
2247 rx,
2248 ctx_extra,
2249 instance_id,
2250 } => {
2251 let (result, statement_ended_execution_reason) = match self
2252 .copy_rows(
2253 format,
2254 row_desc,
2255 RecordFirstRowStream::new(
2256 Box::new(UnboundedReceiverStream::new(rx)),
2257 execute_started,
2258 &self.adapter_client,
2259 Some(instance_id),
2260 None,
2261 ),
2262 )
2263 .await
2264 {
2265 Err(e) => {
2266 (Err(e), StatementEndedExecutionReason::Canceled)
2269 }
2270 Ok((
2271 state,
2272 SendRowsEndedReason::Success {
2273 result_size,
2274 rows_returned,
2275 },
2276 )) => (
2277 Ok(state),
2278 StatementEndedExecutionReason::Success {
2279 result_size: Some(result_size),
2280 rows_returned: Some(rows_returned),
2281 execution_strategy: None,
2282 },
2283 ),
2284 Ok((state, SendRowsEndedReason::Errored { error })) => {
2285 (Ok(state), StatementEndedExecutionReason::Errored { error })
2286 }
2287 Ok((state, SendRowsEndedReason::Canceled)) => {
2288 (Ok(state), StatementEndedExecutionReason::Canceled)
2289 }
2290 };
2291 self.adapter_client
2292 .retire_execute(ctx_extra, statement_ended_execution_reason);
2293 return result;
2294 }
2295 ExecuteResponse::SendingRowsStreaming {
2296 rows,
2297 instance_id,
2298 strategy,
2299 } => {
2300 return self
2305 .copy_rows(
2306 format,
2307 row_desc,
2308 RecordFirstRowStream::new(
2309 Box::new(rows),
2310 execute_started,
2311 &self.adapter_client,
2312 Some(instance_id),
2313 Some(strategy),
2314 ),
2315 )
2316 .await
2317 .map(|(state, _)| state);
2318 }
2319 ExecuteResponse::SendingRowsImmediate { rows } => {
2320 let span = tracing::debug_span!("sending_rows_immediate");
2321
2322 let rows = futures::stream::once(futures::future::ready(
2323 PeekResponseUnary::Rows(rows),
2324 ));
2325 return self
2330 .copy_rows(
2331 format,
2332 row_desc,
2333 RecordFirstRowStream::new(
2334 Box::new(rows),
2335 execute_started,
2336 &self.adapter_client,
2337 None,
2338 Some(StatementExecutionStrategy::Constant),
2339 ),
2340 )
2341 .instrument(span)
2342 .await
2343 .map(|(state, _)| state);
2344 }
2345 _ => {
2346 return self
2347 .send_error_and_get_state(ErrorResponse::error(
2348 SqlState::INTERNAL_ERROR,
2349 "unsupported COPY response type".to_string(),
2350 ))
2351 .await;
2352 }
2353 };
2354 }
2355 ExecuteResponse::CopyFrom {
2356 target_id,
2357 target_name,
2358 columns,
2359 params,
2360 ctx_extra,
2361 } => {
2362 let row_desc =
2363 row_desc.expect("missing row description for ExecuteResponse::CopyFrom");
2364 self.copy_from(target_id, target_name, columns, params, row_desc, ctx_extra)
2365 .await
2366 }
2367 ExecuteResponse::TransactionCommitted { params }
2368 | ExecuteResponse::TransactionRolledBack { params } => {
2369 let notify_set: mz_ore::collections::HashSet<String> = self
2370 .adapter_client
2371 .session()
2372 .vars()
2373 .notify_set()
2374 .map(|v| v.name().to_string())
2375 .collect();
2376
2377 for (name, value) in params
2379 .into_iter()
2380 .filter(|(name, _v)| notify_set.contains(*name))
2381 {
2382 let msg = BackendMessage::ParameterStatus(name, value);
2383 self.send(msg).await?;
2384 }
2385 command_complete!()
2386 }
2387
2388 ExecuteResponse::AlteredDefaultPrivileges
2389 | ExecuteResponse::AlteredObject(..)
2390 | ExecuteResponse::AlteredRole
2391 | ExecuteResponse::AlteredSystemConfiguration
2392 | ExecuteResponse::CreatedCluster { .. }
2393 | ExecuteResponse::CreatedClusterReplica { .. }
2394 | ExecuteResponse::CreatedConnection { .. }
2395 | ExecuteResponse::CreatedDatabase { .. }
2396 | ExecuteResponse::CreatedIndex { .. }
2397 | ExecuteResponse::CreatedIntrospectionSubscribe
2398 | ExecuteResponse::CreatedMaterializedView { .. }
2399 | ExecuteResponse::CreatedRole
2400 | ExecuteResponse::CreatedSchema { .. }
2401 | ExecuteResponse::CreatedSecret { .. }
2402 | ExecuteResponse::CreatedSink { .. }
2403 | ExecuteResponse::CreatedSource { .. }
2404 | ExecuteResponse::CreatedTable { .. }
2405 | ExecuteResponse::CreatedType
2406 | ExecuteResponse::CreatedView { .. }
2407 | ExecuteResponse::CreatedViews { .. }
2408 | ExecuteResponse::CreatedNetworkPolicy
2409 | ExecuteResponse::Comment
2410 | ExecuteResponse::Deallocate { .. }
2411 | ExecuteResponse::Deleted(..)
2412 | ExecuteResponse::DiscardedAll
2413 | ExecuteResponse::DiscardedTemp
2414 | ExecuteResponse::DroppedObject(_)
2415 | ExecuteResponse::DroppedOwned
2416 | ExecuteResponse::GrantedPrivilege
2417 | ExecuteResponse::GrantedRole
2418 | ExecuteResponse::Inserted(..)
2419 | ExecuteResponse::Copied(..)
2420 | ExecuteResponse::Prepare
2421 | ExecuteResponse::Raised
2422 | ExecuteResponse::ReassignOwned
2423 | ExecuteResponse::RevokedPrivilege
2424 | ExecuteResponse::RevokedRole
2425 | ExecuteResponse::StartedTransaction { .. }
2426 | ExecuteResponse::Updated(..)
2427 | ExecuteResponse::ValidatedConnection => {
2428 command_complete!()
2429 }
2430 };
2431
2432 assert_none!(tag, "tag created but not consumed: {:?}", tag);
2433 r
2434 }
2435
2436 #[allow(clippy::too_many_arguments)]
2437 #[mz_ore::instrument(level = "debug")]
2439 async fn send_rows(
2440 &mut self,
2441 row_desc: RelationDesc,
2442 portal_name: String,
2443 mut rows: InProgressRows,
2444 max_rows: ExecuteCount,
2445 get_response: GetResponse,
2446 fetch_portal_name: Option<String>,
2447 timeout: ExecuteTimeout,
2448 ) -> Result<(State, SendRowsEndedReason), io::Error> {
2449 let result_format_portal_name: &str = if let Some(ref name) = fetch_portal_name {
2452 name
2453 } else {
2454 &portal_name
2455 };
2456 let result_formats = self
2457 .adapter_client
2458 .session()
2459 .get_portal_unverified(result_format_portal_name)
2460 .expect("valid fetch portal name for send rows")
2461 .result_formats
2462 .clone();
2463
2464 let (mut wait_once, mut deadline) = match timeout {
2465 ExecuteTimeout::None => (false, None),
2466 ExecuteTimeout::Seconds(t) => (
2467 false,
2468 Some(tokio::time::Instant::now() + tokio::time::Duration::from_secs_f64(t)),
2469 ),
2470 ExecuteTimeout::WaitOnce => (true, None),
2471 };
2472
2473 {
2475 let portal_name_desc = &self
2476 .adapter_client
2477 .session()
2478 .get_portal_unverified(portal_name.as_str())
2479 .expect("portal should exist")
2480 .desc
2481 .relation_desc;
2482 if let Some(portal_name_desc) = portal_name_desc {
2483 soft_assert_eq_or_log!(portal_name_desc, &row_desc);
2484 }
2485 if let Some(fetch_portal_name) = &fetch_portal_name {
2486 let fetch_portal_desc = &self
2487 .adapter_client
2488 .session()
2489 .get_portal_unverified(fetch_portal_name)
2490 .expect("portal should exist")
2491 .desc
2492 .relation_desc;
2493 if let Some(fetch_portal_desc) = fetch_portal_desc {
2494 soft_assert_eq_or_log!(fetch_portal_desc, &row_desc);
2495 }
2496 }
2497 }
2498
2499 self.conn.set_encode_state(
2500 row_desc
2501 .typ()
2502 .column_types
2503 .iter()
2504 .map(|ty| mz_pgrepr::Type::from(&ty.scalar_type))
2505 .zip_eq(result_formats)
2506 .collect(),
2507 self.adapter_client.session().vars().text_encode_settings(),
2508 );
2509
2510 let mut total_sent_rows = 0;
2511 let mut total_sent_bytes = 0;
2512 let mut want_rows = match max_rows {
2514 ExecuteCount::All => usize::MAX,
2515 ExecuteCount::Count(count) => count,
2516 };
2517
2518 loop {
2520 let batch = if rows.current.is_some() {
2523 FetchResult::Rows(rows.current.take())
2524 } else if want_rows == 0 {
2525 FetchResult::Rows(None)
2526 } else {
2527 let notice_fut = self.adapter_client.session().recv_notice();
2528 tokio::select! {
2543 biased;
2544 err = self.conn.wait_closed() => return Err(err),
2545 batch = rows.remaining.recv() => match batch {
2546 None => FetchResult::Rows(None),
2547 Some(PeekResponseUnary::Rows(rows)) => FetchResult::Rows(Some(rows)),
2548 Some(PeekResponseUnary::Error(err)) => {
2549 FetchResult::Error(ErrorResponse::error(SqlState::INTERNAL_ERROR, err))
2550 }
2551 Some(PeekResponseUnary::DependencyDropped(dep)) => {
2552 FetchResult::Error(
2553 dep.to_concurrent_dependency_drop()
2554 .into_response(Severity::Error),
2555 )
2556 }
2557 Some(PeekResponseUnary::Canceled) => FetchResult::Canceled,
2558 },
2559 notice = notice_fut => {
2560 FetchResult::Notice(notice)
2561 }
2562 _ = time::sleep_until(
2563 deadline.unwrap_or_else(tokio::time::Instant::now),
2564 ), if deadline.is_some() => FetchResult::Rows(None),
2565 }
2566 };
2567
2568 match batch {
2569 FetchResult::Rows(None) => break,
2570 FetchResult::Rows(Some(mut batch_rows)) => {
2571 if let Err(err) = verify_datum_desc(&row_desc, &mut batch_rows) {
2572 let msg = err.to_string();
2573 return self
2574 .send_error_and_get_state(err.into_response(Severity::Error))
2575 .await
2576 .map(|state| (state, SendRowsEndedReason::Errored { error: msg }));
2577 }
2578
2579 if wait_once && batch_rows.peek().is_some() {
2583 deadline = Some(tokio::time::Instant::now());
2584 wait_once = false;
2585 }
2586
2587 let mut sent_rows = 0;
2589 let mut sent_bytes = 0;
2590 let messages = (&mut batch_rows)
2591 .map(|row| {
2596 let row_len = row.byte_len();
2597 let values = mz_pgrepr::values_from_row(row, row_desc.typ());
2598 (row_len, BackendMessage::DataRow(values))
2599 })
2600 .inspect(|(row_len, _)| {
2601 sent_bytes += row_len;
2602 sent_rows += 1
2603 })
2604 .map(|(_row_len, row)| row)
2605 .take(want_rows);
2606 self.send_all(messages).await?;
2607
2608 total_sent_rows += sent_rows;
2609 total_sent_bytes += sent_bytes;
2610 want_rows -= sent_rows;
2611
2612 if want_rows == 0 {
2615 if batch_rows.peek().is_some() {
2616 rows.current = Some(batch_rows);
2617 }
2618 break;
2619 }
2620
2621 self.conn.flush().await?;
2622 }
2623 FetchResult::Notice(notice) => {
2624 self.send(notice.into_response()).await?;
2625 self.conn.flush().await?;
2626 }
2627 FetchResult::Error(err) => {
2628 let text = err.message.clone();
2629 return self
2630 .send_error_and_get_state(err)
2631 .await
2632 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2633 }
2634 FetchResult::Canceled => {
2635 return self
2636 .send_error_and_get_state(ErrorResponse::error(
2637 SqlState::QUERY_CANCELED,
2638 "canceling statement due to user request",
2639 ))
2640 .await
2641 .map(|state| (state, SendRowsEndedReason::Canceled));
2642 }
2643 }
2644 }
2645
2646 let portal = self
2647 .adapter_client
2648 .session()
2649 .get_portal_unverified_mut(&portal_name)
2650 .expect("valid portal name for send rows");
2651
2652 let saw_rows = rows.remaining.saw_rows;
2653 let no_more_rows = rows.no_more_rows();
2654 let metric_recorded = rows.remaining.metric_recorded;
2655 let recorded_first_row_instant = rows.remaining.recorded_first_row_instant;
2656
2657 if no_more_rows && !metric_recorded {
2658 rows.remaining.metric_recorded = true;
2659 }
2660
2661 *portal.state = PortalState::InProgress(Some(rows));
2664
2665 let fetch_portal = fetch_portal_name.map(|name| {
2666 self.adapter_client
2667 .session()
2668 .get_portal_unverified_mut(&name)
2669 .expect("valid fetch portal")
2670 });
2671 let response_message = get_response(max_rows, total_sent_rows, fetch_portal);
2672 self.send(response_message).await?;
2673
2674 if no_more_rows && !metric_recorded {
2677 let statement_type = if let Some(stmt) = &self
2678 .adapter_client
2679 .session()
2680 .get_portal_unverified(&portal_name)
2681 .expect("valid portal name for send_rows")
2682 .stmt
2683 {
2684 metrics::statement_type_label_value(stmt.deref())
2685 } else {
2686 "no-statement"
2687 };
2688 let duration = if saw_rows {
2689 recorded_first_row_instant
2690 .expect("recorded_first_row_instant because saw_rows")
2691 .elapsed()
2692 } else {
2693 Duration::ZERO
2697 };
2698 self.adapter_client
2699 .inner()
2700 .metrics()
2701 .result_rows_first_to_last_byte_seconds
2702 .with_label_values(&[statement_type])
2703 .observe(duration.as_secs_f64());
2704 }
2705
2706 Ok((
2707 State::Ready,
2708 SendRowsEndedReason::Success {
2709 result_size: u64::cast_from(total_sent_bytes),
2710 rows_returned: u64::cast_from(total_sent_rows),
2711 },
2712 ))
2713 }
2714
2715 #[mz_ore::instrument(level = "debug")]
2716 async fn copy_rows(
2717 &mut self,
2718 format: CopyFormat,
2719 row_desc: RelationDesc,
2720 mut stream: RecordFirstRowStream,
2721 ) -> Result<(State, SendRowsEndedReason), io::Error> {
2722 let (row_format, encode_format) = match format {
2723 CopyFormat::Text => (
2724 CopyFormatParams::Text(CopyTextFormatParams::default()),
2725 Format::Text,
2726 ),
2727 CopyFormat::Binary => (CopyFormatParams::Binary, Format::Binary),
2728 CopyFormat::Csv => (
2729 CopyFormatParams::Csv(CopyCsvFormatParams::default()),
2730 Format::Text,
2731 ),
2732 CopyFormat::Parquet => {
2733 let text = "Parquet format is not supported".to_string();
2734 return self
2735 .send_error_and_get_state(ErrorResponse::error(
2736 SqlState::INTERNAL_ERROR,
2737 text.clone(),
2738 ))
2739 .await
2740 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2741 }
2742 };
2743
2744 if let CopyFormat::Binary = format {
2752 if let Some(msg) = row_desc
2753 .iter_types()
2754 .find_map(|ty| mz_pgrepr::Value::binary_encoding_error(&ty.scalar_type).err())
2755 {
2756 return self
2757 .send_error_and_get_state(ErrorResponse::error(
2758 SqlState::UNDEFINED_FUNCTION,
2759 msg,
2760 ))
2761 .await
2762 .map(|state| {
2763 (
2764 state,
2765 SendRowsEndedReason::Errored {
2766 error: msg.to_string(),
2767 },
2768 )
2769 });
2770 }
2771 }
2772
2773 let text_settings = self.adapter_client.session().vars().text_encode_settings();
2777 let encode_fn = |row: &RowRef, typ: &SqlRelationType, out: &mut Vec<u8>| {
2778 mz_pgcopy::encode_copy_format(&row_format, row, typ, out, text_settings)
2779 };
2780
2781 let typ = row_desc.typ();
2782 let column_formats = iter::repeat(encode_format)
2783 .take(typ.column_types.len())
2784 .collect();
2785 self.send(BackendMessage::CopyOutResponse {
2786 overall_format: encode_format,
2787 column_formats,
2788 })
2789 .await?;
2790
2791 let mut out = Vec::new();
2796
2797 if let CopyFormat::Binary = format {
2798 out.extend(b"PGCOPY\n\xFF\r\n\0");
2800 out.extend([0, 0, 0, 0]);
2802 out.extend([0, 0, 0, 0]);
2804 }
2805
2806 let mut count = 0;
2807 let mut total_sent_bytes = 0;
2808 loop {
2809 tokio::select! {
2810 e = self.conn.wait_closed() => return Err(e),
2811 batch = stream.recv() => match batch {
2812 None => break,
2813 Some(PeekResponseUnary::Error(text)) => {
2814 let err =
2815 ErrorResponse::error(SqlState::INTERNAL_ERROR, text.clone());
2816 return self
2817 .send_error_and_get_state(err)
2818 .await
2819 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2820 }
2821 Some(PeekResponseUnary::DependencyDropped(dep)) => {
2822 let err = dep.to_concurrent_dependency_drop();
2823 let text = err.to_string();
2824 let resp = err.into_response(Severity::Error);
2825 return self
2826 .send_error_and_get_state(resp)
2827 .await
2828 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2829 }
2830 Some(PeekResponseUnary::Canceled) => {
2831 return self.send_error_and_get_state(ErrorResponse::error(
2832 SqlState::QUERY_CANCELED,
2833 "canceling statement due to user request",
2834 ))
2835 .await.map(|state| (state, SendRowsEndedReason::Canceled));
2836 }
2837 Some(PeekResponseUnary::Rows(mut rows)) => {
2838 count += rows.count();
2839 while let Some(row) = rows.next() {
2840 total_sent_bytes += row.byte_len();
2841 encode_fn(row, typ, &mut out)?;
2842 self.send(BackendMessage::CopyData(mem::take(&mut out)))
2843 .await?;
2844 }
2845 }
2846 },
2847 notice = self.adapter_client.session().recv_notice() => {
2848 self.send(notice.into_response())
2849 .await?;
2850 self.conn.flush().await?;
2851 }
2852 }
2853
2854 self.conn.flush().await?;
2855 }
2856 if let CopyFormat::Binary = format {
2858 let trailer: i16 = -1;
2859 out.extend(trailer.to_be_bytes());
2860 self.send(BackendMessage::CopyData(mem::take(&mut out)))
2861 .await?;
2862 }
2863
2864 let tag = format!("COPY {}", count);
2865 self.send(BackendMessage::CopyDone).await?;
2866 self.send(BackendMessage::CommandComplete { tag }).await?;
2867 Ok((
2868 State::Ready,
2869 SendRowsEndedReason::Success {
2870 result_size: u64::cast_from(total_sent_bytes),
2871 rows_returned: u64::cast_from(count),
2872 },
2873 ))
2874 }
2875
2876 #[instrument(level = "debug")]
2879 async fn copy_from(
2880 &mut self,
2881 target_id: CatalogItemId,
2882 target_name: String,
2883 columns: Vec<ColumnIndex>,
2884 params: CopyFormatParams<'static>,
2885 row_desc: RelationDesc,
2886 mut ctx_extra: ExecuteContextGuard,
2887 ) -> Result<State, io::Error> {
2888 let res = self
2889 .copy_from_inner(
2890 target_id,
2891 target_name,
2892 columns,
2893 params,
2894 row_desc,
2895 &mut ctx_extra,
2896 )
2897 .await;
2898 match &res {
2899 Ok(State::Ready) => {
2900 self.adapter_client.retire_execute(
2901 ctx_extra,
2902 StatementEndedExecutionReason::Success {
2903 result_size: None,
2904 rows_returned: None,
2905 execution_strategy: None,
2906 },
2907 );
2908 }
2909 Ok(State::Done) => {
2910 self.adapter_client
2914 .retire_execute(ctx_extra, StatementEndedExecutionReason::Canceled);
2915 }
2916 Err(e) => {
2917 self.adapter_client.retire_execute(
2918 ctx_extra,
2919 StatementEndedExecutionReason::Errored {
2920 error: format!("{e}"),
2921 },
2922 );
2923 }
2924 Ok(State::Drain) => {}
2925 }
2926 res
2927 }
2928
2929 async fn copy_from_inner(
2930 &mut self,
2931 target_id: CatalogItemId,
2932 target_name: String,
2933 columns: Vec<ColumnIndex>,
2934 params: CopyFormatParams<'static>,
2935 row_desc: RelationDesc,
2936 ctx_extra: &mut ExecuteContextGuard,
2937 ) -> Result<State, io::Error> {
2938 let typ = row_desc.typ();
2939 let column_formats = vec![Format::Text; typ.column_types.len()];
2940 self.send(BackendMessage::CopyInResponse {
2941 overall_format: Format::Text,
2942 column_formats,
2943 })
2944 .await?;
2945 self.conn.flush().await?;
2946
2947 let writer = match self
2949 .adapter_client
2950 .start_copy_from_stdin(
2951 target_id,
2952 target_name.clone(),
2953 columns.clone(),
2954 row_desc.clone(),
2955 params.clone(),
2956 )
2957 .await
2958 {
2959 Ok(writer) => writer,
2960 Err(e) => {
2961 loop {
2967 match self.conn.recv().await? {
2968 Some(FrontendMessage::CopyData(_)) => {}
2969 Some(FrontendMessage::CopyDone) | Some(FrontendMessage::CopyFail(_)) => {
2970 break;
2971 }
2972 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
2973 Some(_) => break,
2974 None => return Ok(State::Done),
2975 }
2976 }
2977 self.adapter_client.retire_execute(
2978 std::mem::take(ctx_extra),
2979 StatementEndedExecutionReason::Errored {
2980 error: e.to_string(),
2981 },
2982 );
2983 return self
2984 .send_error_and_get_state(e.into_response(Severity::Error))
2985 .await;
2986 }
2987 };
2988
2989 const BATCH_SIZE: usize = 32 * 1024 * 1024;
2991 let max_copy_from_row_size = self
2992 .adapter_client
2993 .get_system_vars()
2994 .await
2995 .max_copy_from_row_size()
2996 .try_into()
2997 .unwrap_or(usize::MAX);
2998
2999 let mut data = Vec::new();
3000 let mut row_scanner = CopyRowScanner::new(¶ms);
3001 let num_workers = writer.batch_txs.len();
3002 let mut next_worker: usize = 0;
3003 let mut saw_copy_done = false;
3004 let mut saw_end_marker = false;
3005 let mut copy_from_error: Option<(SqlState, String)> = None;
3006
3007 loop {
3010 let message = self.conn.recv().await?;
3011 match message {
3012 Some(FrontendMessage::CopyData(buf)) => {
3013 if saw_end_marker {
3014 continue;
3017 }
3018 data.extend(buf);
3019 row_scanner.scan_new_bytes(&data);
3020
3021 if let Some(end_pos) = row_scanner.end_marker_end() {
3022 data.truncate(end_pos);
3023 row_scanner.on_truncate(end_pos);
3024 saw_end_marker = true;
3025 }
3026
3027 if row_scanner.current_row_size(data.len()) > max_copy_from_row_size {
3029 copy_from_error = Some((
3030 SqlState::INSUFFICIENT_RESOURCES,
3031 format!(
3032 "COPY FROM STDIN row exceeded max_copy_from_row_size \
3033 ({max_copy_from_row_size} bytes)"
3034 ),
3035 ));
3036 break;
3037 }
3038
3039 let mut send_failed = false;
3042 while data.len() >= BATCH_SIZE {
3043 let split_pos = match row_scanner.last_row_end() {
3044 Some(pos) => pos,
3045 None => break, };
3047 let remainder = data.split_off(split_pos);
3048 let chunk = std::mem::replace(&mut data, remainder);
3049 row_scanner.on_split(split_pos);
3050 if writer.batch_txs[next_worker].send(chunk).await.is_err() {
3051 send_failed = true;
3052 break;
3053 }
3054 next_worker = (next_worker + 1) % num_workers;
3055 }
3056 if send_failed {
3059 break;
3060 }
3061 }
3062 Some(FrontendMessage::CopyDone) => {
3063 if !data.is_empty() {
3065 let chunk = std::mem::take(&mut data);
3066 let _ = writer.batch_txs[next_worker].send(chunk).await;
3068 }
3069 saw_copy_done = true;
3070 break;
3071 }
3072 Some(FrontendMessage::CopyFail(err)) => {
3073 self.adapter_client.retire_execute(
3074 std::mem::take(ctx_extra),
3075 StatementEndedExecutionReason::Canceled,
3076 );
3077 drop(writer);
3079 return self
3080 .send_error_and_get_state(ErrorResponse::error(
3081 SqlState::QUERY_CANCELED,
3082 format!("COPY from stdin failed: {}", err),
3083 ))
3084 .await;
3085 }
3086 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
3087 Some(_) => {
3088 let msg = "unexpected message type during COPY from stdin";
3089 self.adapter_client.retire_execute(
3090 std::mem::take(ctx_extra),
3091 StatementEndedExecutionReason::Errored {
3092 error: msg.to_string(),
3093 },
3094 );
3095 drop(writer);
3096 return self
3097 .send_error_and_get_state(ErrorResponse::error(
3098 SqlState::PROTOCOL_VIOLATION,
3099 msg,
3100 ))
3101 .await;
3102 }
3103 None => {
3104 drop(writer);
3105 return Ok(State::Done);
3106 }
3107 }
3108 }
3109
3110 if !saw_copy_done {
3114 loop {
3115 match self.conn.recv().await? {
3116 Some(FrontendMessage::CopyData(_)) => {}
3117 Some(FrontendMessage::CopyDone) | Some(FrontendMessage::CopyFail(_)) => {
3118 break;
3119 }
3120 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
3121 Some(_) => {
3122 let msg = "unexpected message type during COPY from stdin";
3123 self.adapter_client.retire_execute(
3124 std::mem::take(ctx_extra),
3125 StatementEndedExecutionReason::Errored {
3126 error: msg.to_string(),
3127 },
3128 );
3129 drop(writer);
3130 return self
3131 .send_error_and_get_state(ErrorResponse::error(
3132 SqlState::PROTOCOL_VIOLATION,
3133 msg,
3134 ))
3135 .await;
3136 }
3137 None => {
3138 drop(writer);
3139 return Ok(State::Done);
3140 }
3141 }
3142 }
3143 }
3144
3145 if let Some((code, msg)) = copy_from_error {
3146 self.adapter_client.retire_execute(
3147 std::mem::take(ctx_extra),
3148 StatementEndedExecutionReason::Errored { error: msg.clone() },
3149 );
3150 drop(writer);
3151 return self
3152 .send_error_and_get_state(ErrorResponse::error(code, msg))
3153 .await;
3154 }
3155
3156 drop(writer.batch_txs);
3161
3162 let (proto_batches, row_count) = match writer.completion_rx.await {
3164 Ok(Ok(result)) => result,
3165 Ok(Err(e)) => {
3166 self.adapter_client.retire_execute(
3167 std::mem::take(ctx_extra),
3168 StatementEndedExecutionReason::Errored {
3169 error: e.to_string(),
3170 },
3171 );
3172 return self
3173 .send_error_and_get_state(e.into_response(Severity::Error))
3174 .await;
3175 }
3176 Err(_) => {
3177 let msg = "COPY FROM STDIN: background batch builder tasks dropped";
3178 self.adapter_client.retire_execute(
3179 std::mem::take(ctx_extra),
3180 StatementEndedExecutionReason::Errored {
3181 error: msg.to_string(),
3182 },
3183 );
3184 return self
3185 .send_error_and_get_state(ErrorResponse::error(SqlState::INTERNAL_ERROR, msg))
3186 .await;
3187 }
3188 };
3189
3190 if let Err(e) = self
3192 .adapter_client
3193 .stage_copy_from_stdin_batches(target_id, proto_batches)
3194 {
3195 self.adapter_client.retire_execute(
3196 std::mem::take(ctx_extra),
3197 StatementEndedExecutionReason::Errored {
3198 error: e.to_string(),
3199 },
3200 );
3201 return self
3202 .send_error_and_get_state(e.into_response(Severity::Error))
3203 .await;
3204 }
3205
3206 let tag = format!("COPY {}", row_count);
3207 self.send(BackendMessage::CommandComplete { tag }).await?;
3208
3209 Ok(State::Ready)
3210 }
3211
3212 #[instrument(level = "debug")]
3213 async fn send_pending_notices(&mut self) -> Result<(), io::Error> {
3214 let notices = self
3215 .adapter_client
3216 .session()
3217 .drain_notices()
3218 .into_iter()
3219 .map(|notice| BackendMessage::ErrorResponse(notice.into_response()));
3220 self.send_all(notices).await?;
3221 Ok(())
3222 }
3223
3224 #[instrument(level = "debug")]
3225 async fn send_error_and_get_state(&mut self, err: ErrorResponse) -> Result<State, io::Error> {
3226 assert!(err.severity.is_error());
3227 debug!(
3228 "cid={} error code={}",
3229 self.adapter_client.session().conn_id(),
3230 err.code.code()
3231 );
3232 let is_fatal = err.severity.is_fatal();
3233 self.send(BackendMessage::ErrorResponse(err)).await?;
3234
3235 let txn = self.adapter_client.session().transaction();
3236 match txn {
3237 TransactionStatus::Default | TransactionStatus::Failed(_) => {}
3240 TransactionStatus::Started(_) => {
3242 self.rollback_transaction().await?;
3243 }
3244 TransactionStatus::InTransactionImplicit(_) => {
3246 self.rollback_transaction().await?;
3247 }
3248 TransactionStatus::InTransaction(_) => {
3250 self.adapter_client.fail_transaction();
3251 }
3252 };
3253 if is_fatal {
3254 Ok(State::Done)
3255 } else {
3256 Ok(State::Drain)
3257 }
3258 }
3259
3260 #[instrument(level = "debug")]
3261 async fn aborted_txn_error(&mut self) -> Result<State, io::Error> {
3262 self.send(BackendMessage::ErrorResponse(ErrorResponse::error(
3263 SqlState::IN_FAILED_SQL_TRANSACTION,
3264 ABORTED_TXN_MSG,
3265 )))
3266 .await?;
3267 Ok(State::Drain)
3268 }
3269
3270 fn is_aborted_txn(&mut self) -> bool {
3271 matches!(
3272 self.adapter_client.session().transaction(),
3273 TransactionStatus::Failed(_)
3274 )
3275 }
3276}
3277
3278fn pad_formats(formats: Vec<Format>, n: usize) -> Result<Vec<Format>, String> {
3279 match (formats.len(), n) {
3280 (0, e) => Ok(vec![Format::Text; e]),
3281 (1, e) => Ok(iter::repeat(formats[0]).take(e).collect()),
3282 (a, e) if a == e => Ok(formats),
3283 (a, e) => Err(format!(
3284 "expected {} field format specifiers, but got {}",
3285 e, a
3286 )),
3287 }
3288}
3289
3290fn describe_rows(stmt_desc: &StatementDesc, formats: &[Format]) -> BackendMessage {
3291 match &stmt_desc.relation_desc {
3292 Some(desc) if !stmt_desc.is_copy => {
3293 BackendMessage::RowDescription(message::encode_row_description(desc, formats))
3294 }
3295 _ => BackendMessage::NoData,
3296 }
3297}
3298
3299type GetResponse = fn(
3300 max_rows: ExecuteCount,
3301 total_sent_rows: usize,
3302 fetch_portal: Option<PortalRefMut>,
3303) -> BackendMessage;
3304
3305fn portal_exec_message(
3308 max_rows: ExecuteCount,
3309 total_sent_rows: usize,
3310 _fetch_portal: Option<PortalRefMut>,
3311) -> BackendMessage {
3312 match max_rows {
3319 ExecuteCount::Count(max_rows) if max_rows <= total_sent_rows => {
3320 BackendMessage::PortalSuspended
3321 }
3322 _ => BackendMessage::CommandComplete {
3323 tag: format!("SELECT {}", total_sent_rows),
3324 },
3325 }
3326}
3327
3328fn fetch_message(
3330 _max_rows: ExecuteCount,
3331 total_sent_rows: usize,
3332 fetch_portal: Option<PortalRefMut>,
3333) -> BackendMessage {
3334 let tag = format!("FETCH {}", total_sent_rows);
3335 if let Some(portal) = fetch_portal {
3336 *portal.state = PortalState::Completed(Some(tag.clone()));
3337 }
3338 BackendMessage::CommandComplete { tag }
3339}
3340
3341fn get_authenticator(
3342 authenticator_kind: listeners::AuthenticatorKind,
3343 frontegg: Option<FronteggAuthenticator>,
3344 oidc: GenericOidcAuthenticator,
3345 adapter_client: mz_adapter::Client,
3346) -> Authenticator {
3347 match authenticator_kind {
3348 listeners::AuthenticatorKind::Frontegg => Authenticator::Frontegg(frontegg.expect(
3349 "Frontegg authenticator should exist with listeners::AuthenticatorKind::Frontegg",
3350 )),
3351 listeners::AuthenticatorKind::Password => Authenticator::Password(adapter_client),
3352 listeners::AuthenticatorKind::Sasl => Authenticator::Sasl(adapter_client),
3353 listeners::AuthenticatorKind::Oidc => Authenticator::Oidc(oidc),
3354 listeners::AuthenticatorKind::None => Authenticator::None,
3355 }
3356}
3357
3358#[derive(Debug, Copy, Clone)]
3359enum ExecuteCount {
3360 All,
3361 Count(usize),
3362}
3363
3364fn is_txn_exit_stmt(stmt: Option<&Statement<Raw>>) -> bool {
3366 match stmt {
3367 Some(stmt) => matches!(stmt, Statement::Commit(_) | Statement::Rollback(_)),
3369 None => false,
3370 }
3371}
3372
3373#[derive(Debug)]
3374enum FetchResult {
3375 Rows(Option<Box<dyn RowIterator + Send + Sync>>),
3376 Canceled,
3377 Error(ErrorResponse),
3378 Notice(AdapterNotice),
3379}
3380
3381#[derive(Debug)]
3382struct CopyRowScanner {
3383 scan_pos: usize,
3384 last_row_end: Option<usize>,
3385 end_marker_end: Option<usize>,
3386 record_start: usize,
3391 csv: Option<CsvScanState>,
3392}
3393
3394#[derive(Debug)]
3395struct CsvScanState {
3396 reader: csv_core::Reader,
3397 output: Vec<u8>,
3398 ends: Vec<usize>,
3399 skip_first_record: bool,
3400}
3401
3402impl CopyRowScanner {
3403 fn new(params: &CopyFormatParams<'_>) -> Self {
3404 let csv = match params {
3405 CopyFormatParams::Csv(CopyCsvFormatParams {
3406 delimiter,
3407 quote,
3408 escape,
3409 header,
3410 ..
3411 }) => Some(CsvScanState::new(*delimiter, *quote, *escape, *header)),
3412 _ => None,
3413 };
3414
3415 CopyRowScanner {
3416 scan_pos: 0,
3417 last_row_end: None,
3418 end_marker_end: None,
3419 record_start: 0,
3420 csv,
3421 }
3422 }
3423
3424 fn scan_new_bytes(&mut self, data: &[u8]) {
3425 if self.scan_pos >= data.len() {
3426 return;
3427 }
3428
3429 if let Some(csv) = self.csv.as_mut() {
3430 let mut input = &data[self.scan_pos..];
3431 let mut consumed = 0usize;
3432 while !input.is_empty() {
3433 let (result, n_input, _n_output, _n_ends) =
3434 csv.reader
3435 .read_record(input, &mut csv.output, &mut csv.ends);
3436 consumed += n_input;
3437 input = &input[n_input..];
3438
3439 match result {
3440 ReadRecordResult::InputEmpty => break,
3441 ReadRecordResult::OutputFull => {
3442 if n_input == 0 {
3443 csv.output
3444 .resize(csv.output.len().saturating_mul(2).max(1), 0);
3445 }
3446 }
3447 ReadRecordResult::OutputEndsFull => {
3448 if n_input == 0 {
3449 csv.ends.resize(csv.ends.len().saturating_mul(2).max(1), 0);
3450 }
3451 }
3452 ReadRecordResult::Record | ReadRecordResult::End => {
3453 let row_end = self.scan_pos + consumed;
3454 self.last_row_end = Some(row_end);
3455 if self.end_marker_end.is_none() {
3456 let is_marker = if csv.skip_first_record {
3457 csv.skip_first_record = false;
3458 false
3459 } else {
3460 let raw = &data[self.record_start..row_end];
3466 let start = raw
3477 .iter()
3478 .take_while(|&&b| b == b'\r' || b == b'\n')
3479 .count();
3480 let trailing = raw[start..]
3481 .iter()
3482 .rev()
3483 .take_while(|&&b| b == b'\r' || b == b'\n')
3484 .count();
3485 let trimmed = &raw[start..raw.len() - trailing];
3486 trimmed == b"\\."
3487 };
3488 if is_marker {
3489 self.end_marker_end = Some(row_end);
3490 self.record_start = row_end;
3491 break;
3492 }
3493 }
3494 self.record_start = row_end;
3495 }
3496 }
3497 }
3498 } else {
3499 let mut row_start = self.last_row_end.unwrap_or(0);
3500 for (offset, b) in data[self.scan_pos..].iter().enumerate() {
3501 if *b == b'\n' {
3502 let row_end = self.scan_pos + offset + 1;
3503 self.last_row_end = Some(row_end);
3504 if self.end_marker_end.is_none() {
3505 let row = &data[row_start..row_end];
3506 if row.get(0..2) == Some(b"\\.") {
3507 self.end_marker_end = Some(row_end);
3508 break;
3509 }
3510 }
3511 row_start = row_end;
3512 }
3513 }
3514 }
3515
3516 self.scan_pos = data.len();
3517 }
3518
3519 fn last_row_end(&self) -> Option<usize> {
3520 self.last_row_end
3521 }
3522
3523 fn end_marker_end(&self) -> Option<usize> {
3524 self.end_marker_end
3525 }
3526
3527 fn current_row_size(&self, data_len: usize) -> usize {
3528 data_len.saturating_sub(self.last_row_end.unwrap_or(0))
3529 }
3530
3531 fn on_split(&mut self, split_pos: usize) {
3532 self.scan_pos = self.scan_pos.saturating_sub(split_pos);
3533 self.last_row_end = None;
3534 self.end_marker_end = self
3535 .end_marker_end
3536 .and_then(|end| end.checked_sub(split_pos));
3537 soft_assert_or_log!(
3545 self.csv.is_none() || self.record_start >= split_pos,
3546 "split bisected an in-progress CSV record: record_start={} < split_pos={}",
3547 self.record_start,
3548 split_pos,
3549 );
3550 self.record_start = self.record_start.saturating_sub(split_pos);
3551 }
3552
3553 fn on_truncate(&mut self, new_len: usize) {
3554 self.scan_pos = self.scan_pos.min(new_len);
3555 self.last_row_end = self.last_row_end.filter(|&end| end <= new_len);
3556 self.end_marker_end = self.end_marker_end.filter(|&end| end <= new_len);
3557 self.record_start = self.record_start.min(new_len);
3558 }
3559}
3560
3561impl CsvScanState {
3562 fn new(delimiter: u8, quote: u8, escape: u8, header: bool) -> Self {
3563 let (double_quote, escape) = if quote == escape {
3564 (true, None)
3565 } else {
3566 (false, Some(escape))
3567 };
3568 CsvScanState {
3569 reader: csv_core::ReaderBuilder::new()
3570 .delimiter(delimiter)
3571 .quote(quote)
3572 .double_quote(double_quote)
3573 .escape(escape)
3574 .build(),
3575 output: vec![0; 1],
3576 ends: vec![0; 1],
3577 skip_first_record: header,
3578 }
3579 }
3580}
3581
3582#[cfg(test)]
3583mod test {
3584 use super::*;
3585
3586 #[mz_ore::test]
3587 fn test_copy_row_scanner_end_marker_line_endings() {
3588 let params = CopyFormatParams::Csv(CopyCsvFormatParams::default());
3596
3597 let marker_end = |data: &[u8]| -> Option<usize> {
3598 let mut scanner = CopyRowScanner::new(¶ms);
3599 scanner.scan_new_bytes(data);
3600 scanner.end_marker_end()
3601 };
3602
3603 for eol in [&b"\n"[..], b"\r\n", b"\r"] {
3604 let join = |lines: &[&str]| -> Vec<u8> {
3605 let mut out = Vec::new();
3606 for line in lines {
3607 out.extend_from_slice(line.as_bytes());
3608 out.extend_from_slice(eol);
3609 }
3610 out
3611 };
3612
3613 let data = join(&["first", "\\.", "after"]);
3618 let mut prefix = Vec::new();
3619 prefix.extend_from_slice(b"first");
3620 prefix.extend_from_slice(eol);
3621 prefix.extend_from_slice(b"\\.");
3622 assert_eq!(
3623 marker_end(&data),
3624 Some(prefix.len() + 1),
3625 "bare marker, eol={eol:?}"
3626 );
3627
3628 let data = join(&["before", "\"\\.\"", "after"]);
3630 assert_eq!(marker_end(&data), None, "quoted marker, eol={eol:?}");
3631 }
3632 }
3633
3634 #[mz_ore::test]
3635 fn test_copy_row_scanner_non_csv_split() {
3636 for params in [
3643 CopyFormatParams::Text(CopyTextFormatParams::default()),
3644 CopyFormatParams::Binary,
3645 ] {
3646 let mut scanner = CopyRowScanner::new(¶ms);
3647 let data = b"1\thello world\t2\tsome text value here\n\
3648 3\thello world\t6\tsome text value here\n";
3649 scanner.scan_new_bytes(data);
3650 let split_pos = scanner.last_row_end().expect("a complete row");
3651 assert!(split_pos > 0, "params={params:?}");
3652 scanner.on_split(split_pos);
3654 assert_eq!(scanner.record_start, 0, "params={params:?}");
3655 }
3656 }
3657
3658 #[mz_ore::test]
3659 fn test_parse_options() {
3660 struct TestCase {
3661 input: &'static str,
3662 expect: Result<Vec<(&'static str, &'static str)>, ()>,
3663 }
3664 let tests = vec![
3665 TestCase {
3666 input: "",
3667 expect: Ok(vec![]),
3668 },
3669 TestCase {
3670 input: "--key",
3671 expect: Err(()),
3672 },
3673 TestCase {
3674 input: "--key=val",
3675 expect: Ok(vec![("key", "val")]),
3676 },
3677 TestCase {
3678 input: r#"--key=val -ckey2=val2 -c key3=val3 -c key4=val4 -ckey5=val5"#,
3679 expect: Ok(vec![
3680 ("key", "val"),
3681 ("key2", "val2"),
3682 ("key3", "val3"),
3683 ("key4", "val4"),
3684 ("key5", "val5"),
3685 ]),
3686 },
3687 TestCase {
3688 input: r#"-c\ key=val"#,
3689 expect: Ok(vec![(" key", "val")]),
3690 },
3691 TestCase {
3692 input: "--key=val -ckey2 val2",
3693 expect: Err(()),
3694 },
3695 TestCase {
3697 input: "--key=",
3698 expect: Ok(vec![("key", "")]),
3699 },
3700 ];
3701 for test in tests {
3702 let got = parse_options(test.input);
3703 let expect = test.expect.map(|r| {
3704 r.into_iter()
3705 .map(|(k, v)| (k.to_owned(), v.to_owned()))
3706 .collect()
3707 });
3708 assert_eq!(got, expect, "input: {}", test.input);
3709 }
3710 }
3711
3712 #[mz_ore::test]
3713 fn test_parse_option() {
3714 struct TestCase {
3715 input: &'static str,
3716 expect: Result<(&'static str, &'static str), ()>,
3717 }
3718 let tests = vec![
3719 TestCase {
3720 input: "",
3721 expect: Err(()),
3722 },
3723 TestCase {
3724 input: "--",
3725 expect: Err(()),
3726 },
3727 TestCase {
3728 input: "--c",
3729 expect: Err(()),
3730 },
3731 TestCase {
3732 input: "a=b",
3733 expect: Err(()),
3734 },
3735 TestCase {
3736 input: "--a=b",
3737 expect: Ok(("a", "b")),
3738 },
3739 TestCase {
3740 input: "--ca=b",
3741 expect: Ok(("ca", "b")),
3742 },
3743 TestCase {
3744 input: "-ca=b",
3745 expect: Ok(("a", "b")),
3746 },
3747 TestCase {
3749 input: "--=",
3750 expect: Ok(("", "")),
3751 },
3752 ];
3753 for test in tests {
3754 let got = parse_option(test.input);
3755 assert_eq!(got, test.expect, "input: {}", test.input);
3756 }
3757 }
3758
3759 #[mz_ore::test]
3760 fn test_split_options() {
3761 struct TestCase {
3762 input: &'static str,
3763 expect: Vec<&'static str>,
3764 }
3765 let tests = vec![
3766 TestCase {
3767 input: "",
3768 expect: vec![],
3769 },
3770 TestCase {
3771 input: " ",
3772 expect: vec![],
3773 },
3774 TestCase {
3775 input: " a ",
3776 expect: vec!["a"],
3777 },
3778 TestCase {
3779 input: " ab cd ",
3780 expect: vec!["ab", "cd"],
3781 },
3782 TestCase {
3783 input: r#" ab\ cd "#,
3784 expect: vec!["ab ", "cd"],
3785 },
3786 TestCase {
3787 input: r#" ab\\ cd "#,
3788 expect: vec![r#"ab\"#, "cd"],
3789 },
3790 TestCase {
3791 input: r#" ab\\\ cd "#,
3792 expect: vec![r#"ab\ "#, "cd"],
3793 },
3794 TestCase {
3795 input: r#" ab\\\ cd "#,
3796 expect: vec![r#"ab\ cd"#],
3797 },
3798 TestCase {
3799 input: r#" ab\\\cd "#,
3800 expect: vec![r#"ab\cd"#],
3801 },
3802 TestCase {
3803 input: r#"a\"#,
3804 expect: vec!["a"],
3805 },
3806 TestCase {
3807 input: r#"a\ "#,
3808 expect: vec!["a "],
3809 },
3810 TestCase {
3811 input: r#"\"#,
3812 expect: vec![],
3813 },
3814 TestCase {
3815 input: r#"\ "#,
3816 expect: vec![r#" "#],
3817 },
3818 TestCase {
3819 input: r#" \ "#,
3820 expect: vec![r#" "#],
3821 },
3822 TestCase {
3823 input: r#"\ "#,
3824 expect: vec![r#" "#],
3825 },
3826 ];
3827 for test in tests {
3828 let got = split_options(test.input);
3829 assert_eq!(got, test.expect, "input: {}", test.input);
3830 }
3831 }
3832
3833 #[mz_ore::test]
3834 fn test_is_jwt() {
3835 assert!(is_jwt("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.signature"));
3837 for s in [
3839 "",
3840 "secure_password",
3841 "p4ss.w0rd",
3842 "aaa.bbb.ccc",
3843 "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0",
3844 "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.sig.extra",
3845 ] {
3846 assert!(!is_jwt(s), "is_jwt({s:?})");
3847 }
3848 }
3849}