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 );
2508
2509 let mut total_sent_rows = 0;
2510 let mut total_sent_bytes = 0;
2511 let mut want_rows = match max_rows {
2513 ExecuteCount::All => usize::MAX,
2514 ExecuteCount::Count(count) => count,
2515 };
2516
2517 loop {
2519 let batch = if rows.current.is_some() {
2522 FetchResult::Rows(rows.current.take())
2523 } else if want_rows == 0 {
2524 FetchResult::Rows(None)
2525 } else {
2526 let notice_fut = self.adapter_client.session().recv_notice();
2527 tokio::select! {
2542 biased;
2543 err = self.conn.wait_closed() => return Err(err),
2544 batch = rows.remaining.recv() => match batch {
2545 None => FetchResult::Rows(None),
2546 Some(PeekResponseUnary::Rows(rows)) => FetchResult::Rows(Some(rows)),
2547 Some(PeekResponseUnary::Error(err)) => {
2548 FetchResult::Error(ErrorResponse::error(SqlState::INTERNAL_ERROR, err))
2549 }
2550 Some(PeekResponseUnary::DependencyDropped(dep)) => {
2551 FetchResult::Error(
2552 dep.to_concurrent_dependency_drop()
2553 .into_response(Severity::Error),
2554 )
2555 }
2556 Some(PeekResponseUnary::Canceled) => FetchResult::Canceled,
2557 },
2558 notice = notice_fut => {
2559 FetchResult::Notice(notice)
2560 }
2561 _ = time::sleep_until(
2562 deadline.unwrap_or_else(tokio::time::Instant::now),
2563 ), if deadline.is_some() => FetchResult::Rows(None),
2564 }
2565 };
2566
2567 match batch {
2568 FetchResult::Rows(None) => break,
2569 FetchResult::Rows(Some(mut batch_rows)) => {
2570 if let Err(err) = verify_datum_desc(&row_desc, &mut batch_rows) {
2571 let msg = err.to_string();
2572 return self
2573 .send_error_and_get_state(err.into_response(Severity::Error))
2574 .await
2575 .map(|state| (state, SendRowsEndedReason::Errored { error: msg }));
2576 }
2577
2578 if wait_once && batch_rows.peek().is_some() {
2582 deadline = Some(tokio::time::Instant::now());
2583 wait_once = false;
2584 }
2585
2586 let mut sent_rows = 0;
2588 let mut sent_bytes = 0;
2589 let messages = (&mut batch_rows)
2590 .map(|row| {
2595 let row_len = row.byte_len();
2596 let values = mz_pgrepr::values_from_row(row, row_desc.typ());
2597 (row_len, BackendMessage::DataRow(values))
2598 })
2599 .inspect(|(row_len, _)| {
2600 sent_bytes += row_len;
2601 sent_rows += 1
2602 })
2603 .map(|(_row_len, row)| row)
2604 .take(want_rows);
2605 self.send_all(messages).await?;
2606
2607 total_sent_rows += sent_rows;
2608 total_sent_bytes += sent_bytes;
2609 want_rows -= sent_rows;
2610
2611 if want_rows == 0 {
2614 if batch_rows.peek().is_some() {
2615 rows.current = Some(batch_rows);
2616 }
2617 break;
2618 }
2619
2620 self.conn.flush().await?;
2621 }
2622 FetchResult::Notice(notice) => {
2623 self.send(notice.into_response()).await?;
2624 self.conn.flush().await?;
2625 }
2626 FetchResult::Error(err) => {
2627 let text = err.message.clone();
2628 return self
2629 .send_error_and_get_state(err)
2630 .await
2631 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2632 }
2633 FetchResult::Canceled => {
2634 return self
2635 .send_error_and_get_state(ErrorResponse::error(
2636 SqlState::QUERY_CANCELED,
2637 "canceling statement due to user request",
2638 ))
2639 .await
2640 .map(|state| (state, SendRowsEndedReason::Canceled));
2641 }
2642 }
2643 }
2644
2645 let portal = self
2646 .adapter_client
2647 .session()
2648 .get_portal_unverified_mut(&portal_name)
2649 .expect("valid portal name for send rows");
2650
2651 let saw_rows = rows.remaining.saw_rows;
2652 let no_more_rows = rows.no_more_rows();
2653 let metric_recorded = rows.remaining.metric_recorded;
2654 let recorded_first_row_instant = rows.remaining.recorded_first_row_instant;
2655
2656 if no_more_rows && !metric_recorded {
2657 rows.remaining.metric_recorded = true;
2658 }
2659
2660 *portal.state = PortalState::InProgress(Some(rows));
2663
2664 let fetch_portal = fetch_portal_name.map(|name| {
2665 self.adapter_client
2666 .session()
2667 .get_portal_unverified_mut(&name)
2668 .expect("valid fetch portal")
2669 });
2670 let response_message = get_response(max_rows, total_sent_rows, fetch_portal);
2671 self.send(response_message).await?;
2672
2673 if no_more_rows && !metric_recorded {
2676 let statement_type = if let Some(stmt) = &self
2677 .adapter_client
2678 .session()
2679 .get_portal_unverified(&portal_name)
2680 .expect("valid portal name for send_rows")
2681 .stmt
2682 {
2683 metrics::statement_type_label_value(stmt.deref())
2684 } else {
2685 "no-statement"
2686 };
2687 let duration = if saw_rows {
2688 recorded_first_row_instant
2689 .expect("recorded_first_row_instant because saw_rows")
2690 .elapsed()
2691 } else {
2692 Duration::ZERO
2696 };
2697 self.adapter_client
2698 .inner()
2699 .metrics()
2700 .result_rows_first_to_last_byte_seconds
2701 .with_label_values(&[statement_type])
2702 .observe(duration.as_secs_f64());
2703 }
2704
2705 Ok((
2706 State::Ready,
2707 SendRowsEndedReason::Success {
2708 result_size: u64::cast_from(total_sent_bytes),
2709 rows_returned: u64::cast_from(total_sent_rows),
2710 },
2711 ))
2712 }
2713
2714 #[mz_ore::instrument(level = "debug")]
2715 async fn copy_rows(
2716 &mut self,
2717 format: CopyFormat,
2718 row_desc: RelationDesc,
2719 mut stream: RecordFirstRowStream,
2720 ) -> Result<(State, SendRowsEndedReason), io::Error> {
2721 let (row_format, encode_format) = match format {
2722 CopyFormat::Text => (
2723 CopyFormatParams::Text(CopyTextFormatParams::default()),
2724 Format::Text,
2725 ),
2726 CopyFormat::Binary => (CopyFormatParams::Binary, Format::Binary),
2727 CopyFormat::Csv => (
2728 CopyFormatParams::Csv(CopyCsvFormatParams::default()),
2729 Format::Text,
2730 ),
2731 CopyFormat::Parquet => {
2732 let text = "Parquet format is not supported".to_string();
2733 return self
2734 .send_error_and_get_state(ErrorResponse::error(
2735 SqlState::INTERNAL_ERROR,
2736 text.clone(),
2737 ))
2738 .await
2739 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2740 }
2741 };
2742
2743 if let CopyFormat::Binary = format {
2751 if let Some(msg) = row_desc
2752 .iter_types()
2753 .find_map(|ty| mz_pgrepr::Value::binary_encoding_error(&ty.scalar_type).err())
2754 {
2755 return self
2756 .send_error_and_get_state(ErrorResponse::error(
2757 SqlState::UNDEFINED_FUNCTION,
2758 msg,
2759 ))
2760 .await
2761 .map(|state| {
2762 (
2763 state,
2764 SendRowsEndedReason::Errored {
2765 error: msg.to_string(),
2766 },
2767 )
2768 });
2769 }
2770 }
2771
2772 let encode_fn = |row: &RowRef, typ: &SqlRelationType, out: &mut Vec<u8>| {
2773 mz_pgcopy::encode_copy_format(&row_format, row, typ, out)
2774 };
2775
2776 let typ = row_desc.typ();
2777 let column_formats = iter::repeat(encode_format)
2778 .take(typ.column_types.len())
2779 .collect();
2780 self.send(BackendMessage::CopyOutResponse {
2781 overall_format: encode_format,
2782 column_formats,
2783 })
2784 .await?;
2785
2786 let mut out = Vec::new();
2791
2792 if let CopyFormat::Binary = format {
2793 out.extend(b"PGCOPY\n\xFF\r\n\0");
2795 out.extend([0, 0, 0, 0]);
2797 out.extend([0, 0, 0, 0]);
2799 }
2800
2801 let mut count = 0;
2802 let mut total_sent_bytes = 0;
2803 loop {
2804 tokio::select! {
2805 e = self.conn.wait_closed() => return Err(e),
2806 batch = stream.recv() => match batch {
2807 None => break,
2808 Some(PeekResponseUnary::Error(text)) => {
2809 let err =
2810 ErrorResponse::error(SqlState::INTERNAL_ERROR, text.clone());
2811 return self
2812 .send_error_and_get_state(err)
2813 .await
2814 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2815 }
2816 Some(PeekResponseUnary::DependencyDropped(dep)) => {
2817 let err = dep.to_concurrent_dependency_drop();
2818 let text = err.to_string();
2819 let resp = err.into_response(Severity::Error);
2820 return self
2821 .send_error_and_get_state(resp)
2822 .await
2823 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2824 }
2825 Some(PeekResponseUnary::Canceled) => {
2826 return self.send_error_and_get_state(ErrorResponse::error(
2827 SqlState::QUERY_CANCELED,
2828 "canceling statement due to user request",
2829 ))
2830 .await.map(|state| (state, SendRowsEndedReason::Canceled));
2831 }
2832 Some(PeekResponseUnary::Rows(mut rows)) => {
2833 count += rows.count();
2834 while let Some(row) = rows.next() {
2835 total_sent_bytes += row.byte_len();
2836 encode_fn(row, typ, &mut out)?;
2837 self.send(BackendMessage::CopyData(mem::take(&mut out)))
2838 .await?;
2839 }
2840 }
2841 },
2842 notice = self.adapter_client.session().recv_notice() => {
2843 self.send(notice.into_response())
2844 .await?;
2845 self.conn.flush().await?;
2846 }
2847 }
2848
2849 self.conn.flush().await?;
2850 }
2851 if let CopyFormat::Binary = format {
2853 let trailer: i16 = -1;
2854 out.extend(trailer.to_be_bytes());
2855 self.send(BackendMessage::CopyData(mem::take(&mut out)))
2856 .await?;
2857 }
2858
2859 let tag = format!("COPY {}", count);
2860 self.send(BackendMessage::CopyDone).await?;
2861 self.send(BackendMessage::CommandComplete { tag }).await?;
2862 Ok((
2863 State::Ready,
2864 SendRowsEndedReason::Success {
2865 result_size: u64::cast_from(total_sent_bytes),
2866 rows_returned: u64::cast_from(count),
2867 },
2868 ))
2869 }
2870
2871 #[instrument(level = "debug")]
2874 async fn copy_from(
2875 &mut self,
2876 target_id: CatalogItemId,
2877 target_name: String,
2878 columns: Vec<ColumnIndex>,
2879 params: CopyFormatParams<'static>,
2880 row_desc: RelationDesc,
2881 mut ctx_extra: ExecuteContextGuard,
2882 ) -> Result<State, io::Error> {
2883 let res = self
2884 .copy_from_inner(
2885 target_id,
2886 target_name,
2887 columns,
2888 params,
2889 row_desc,
2890 &mut ctx_extra,
2891 )
2892 .await;
2893 match &res {
2894 Ok(State::Ready) => {
2895 self.adapter_client.retire_execute(
2896 ctx_extra,
2897 StatementEndedExecutionReason::Success {
2898 result_size: None,
2899 rows_returned: None,
2900 execution_strategy: None,
2901 },
2902 );
2903 }
2904 Ok(State::Done) => {
2905 self.adapter_client
2909 .retire_execute(ctx_extra, StatementEndedExecutionReason::Canceled);
2910 }
2911 Err(e) => {
2912 self.adapter_client.retire_execute(
2913 ctx_extra,
2914 StatementEndedExecutionReason::Errored {
2915 error: format!("{e}"),
2916 },
2917 );
2918 }
2919 Ok(State::Drain) => {}
2920 }
2921 res
2922 }
2923
2924 async fn copy_from_inner(
2925 &mut self,
2926 target_id: CatalogItemId,
2927 target_name: String,
2928 columns: Vec<ColumnIndex>,
2929 params: CopyFormatParams<'static>,
2930 row_desc: RelationDesc,
2931 ctx_extra: &mut ExecuteContextGuard,
2932 ) -> Result<State, io::Error> {
2933 let typ = row_desc.typ();
2934 let column_formats = vec![Format::Text; typ.column_types.len()];
2935 self.send(BackendMessage::CopyInResponse {
2936 overall_format: Format::Text,
2937 column_formats,
2938 })
2939 .await?;
2940 self.conn.flush().await?;
2941
2942 let writer = match self
2944 .adapter_client
2945 .start_copy_from_stdin(
2946 target_id,
2947 target_name.clone(),
2948 columns.clone(),
2949 row_desc.clone(),
2950 params.clone(),
2951 )
2952 .await
2953 {
2954 Ok(writer) => writer,
2955 Err(e) => {
2956 loop {
2962 match self.conn.recv().await? {
2963 Some(FrontendMessage::CopyData(_)) => {}
2964 Some(FrontendMessage::CopyDone) | Some(FrontendMessage::CopyFail(_)) => {
2965 break;
2966 }
2967 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
2968 Some(_) => break,
2969 None => return Ok(State::Done),
2970 }
2971 }
2972 self.adapter_client.retire_execute(
2973 std::mem::take(ctx_extra),
2974 StatementEndedExecutionReason::Errored {
2975 error: e.to_string(),
2976 },
2977 );
2978 return self
2979 .send_error_and_get_state(e.into_response(Severity::Error))
2980 .await;
2981 }
2982 };
2983
2984 self.conn.set_copy_mode(true);
2986
2987 const BATCH_SIZE: usize = 32 * 1024 * 1024;
2989 let max_copy_from_row_size = self
2990 .adapter_client
2991 .get_system_vars()
2992 .await
2993 .max_copy_from_row_size()
2994 .try_into()
2995 .unwrap_or(usize::MAX);
2996
2997 let mut data = Vec::new();
2998 let mut row_scanner = CopyRowScanner::new(¶ms);
2999 let num_workers = writer.batch_txs.len();
3000 let mut next_worker: usize = 0;
3001 let mut saw_copy_done = false;
3002 let mut saw_end_marker = false;
3003 let mut copy_from_error: Option<(SqlState, String)> = None;
3004
3005 loop {
3008 let message = self.conn.recv().await?;
3009 match message {
3010 Some(FrontendMessage::CopyData(buf)) => {
3011 if saw_end_marker {
3012 continue;
3015 }
3016 data.extend(buf);
3017 row_scanner.scan_new_bytes(&data);
3018
3019 if let Some(end_pos) = row_scanner.end_marker_end() {
3020 data.truncate(end_pos);
3021 row_scanner.on_truncate(end_pos);
3022 saw_end_marker = true;
3023 }
3024
3025 if row_scanner.current_row_size(data.len()) > max_copy_from_row_size {
3027 copy_from_error = Some((
3028 SqlState::INSUFFICIENT_RESOURCES,
3029 format!(
3030 "COPY FROM STDIN row exceeded max_copy_from_row_size \
3031 ({max_copy_from_row_size} bytes)"
3032 ),
3033 ));
3034 break;
3035 }
3036
3037 let mut send_failed = false;
3040 while data.len() >= BATCH_SIZE {
3041 let split_pos = match row_scanner.last_row_end() {
3042 Some(pos) => pos,
3043 None => break, };
3045 let remainder = data.split_off(split_pos);
3046 let chunk = std::mem::replace(&mut data, remainder);
3047 row_scanner.on_split(split_pos);
3048 if writer.batch_txs[next_worker].send(chunk).await.is_err() {
3049 send_failed = true;
3050 break;
3051 }
3052 next_worker = (next_worker + 1) % num_workers;
3053 }
3054 if send_failed {
3057 break;
3058 }
3059 }
3060 Some(FrontendMessage::CopyDone) => {
3061 if !data.is_empty() {
3063 let chunk = std::mem::take(&mut data);
3064 let _ = writer.batch_txs[next_worker].send(chunk).await;
3066 }
3067 saw_copy_done = true;
3068 break;
3069 }
3070 Some(FrontendMessage::CopyFail(err)) => {
3071 self.adapter_client.retire_execute(
3072 std::mem::take(ctx_extra),
3073 StatementEndedExecutionReason::Canceled,
3074 );
3075 drop(writer);
3077 self.conn.set_copy_mode(false);
3078 return self
3079 .send_error_and_get_state(ErrorResponse::error(
3080 SqlState::QUERY_CANCELED,
3081 format!("COPY from stdin failed: {}", err),
3082 ))
3083 .await;
3084 }
3085 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
3086 Some(_) => {
3087 let msg = "unexpected message type during COPY from stdin";
3088 self.adapter_client.retire_execute(
3089 std::mem::take(ctx_extra),
3090 StatementEndedExecutionReason::Errored {
3091 error: msg.to_string(),
3092 },
3093 );
3094 drop(writer);
3095 self.conn.set_copy_mode(false);
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 self.conn.set_copy_mode(false);
3106 return Ok(State::Done);
3107 }
3108 }
3109 }
3110
3111 if !saw_copy_done {
3115 loop {
3116 match self.conn.recv().await? {
3117 Some(FrontendMessage::CopyData(_)) => {}
3118 Some(FrontendMessage::CopyDone) | Some(FrontendMessage::CopyFail(_)) => {
3119 break;
3120 }
3121 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
3122 Some(_) => {
3123 let msg = "unexpected message type during COPY from stdin";
3124 self.adapter_client.retire_execute(
3125 std::mem::take(ctx_extra),
3126 StatementEndedExecutionReason::Errored {
3127 error: msg.to_string(),
3128 },
3129 );
3130 drop(writer);
3131 self.conn.set_copy_mode(false);
3132 return self
3133 .send_error_and_get_state(ErrorResponse::error(
3134 SqlState::PROTOCOL_VIOLATION,
3135 msg,
3136 ))
3137 .await;
3138 }
3139 None => {
3140 drop(writer);
3141 self.conn.set_copy_mode(false);
3142 return Ok(State::Done);
3143 }
3144 }
3145 }
3146 }
3147
3148 if let Some((code, msg)) = copy_from_error {
3149 self.adapter_client.retire_execute(
3150 std::mem::take(ctx_extra),
3151 StatementEndedExecutionReason::Errored { error: msg.clone() },
3152 );
3153 drop(writer);
3154 self.conn.set_copy_mode(false);
3155 return self
3156 .send_error_and_get_state(ErrorResponse::error(code, msg))
3157 .await;
3158 }
3159
3160 self.conn.set_copy_mode(false);
3161
3162 drop(writer.batch_txs);
3167
3168 let (proto_batches, row_count) = match writer.completion_rx.await {
3170 Ok(Ok(result)) => result,
3171 Ok(Err(e)) => {
3172 self.adapter_client.retire_execute(
3173 std::mem::take(ctx_extra),
3174 StatementEndedExecutionReason::Errored {
3175 error: e.to_string(),
3176 },
3177 );
3178 return self
3179 .send_error_and_get_state(e.into_response(Severity::Error))
3180 .await;
3181 }
3182 Err(_) => {
3183 let msg = "COPY FROM STDIN: background batch builder tasks dropped";
3184 self.adapter_client.retire_execute(
3185 std::mem::take(ctx_extra),
3186 StatementEndedExecutionReason::Errored {
3187 error: msg.to_string(),
3188 },
3189 );
3190 return self
3191 .send_error_and_get_state(ErrorResponse::error(SqlState::INTERNAL_ERROR, msg))
3192 .await;
3193 }
3194 };
3195
3196 if let Err(e) = self
3198 .adapter_client
3199 .stage_copy_from_stdin_batches(target_id, proto_batches)
3200 {
3201 self.adapter_client.retire_execute(
3202 std::mem::take(ctx_extra),
3203 StatementEndedExecutionReason::Errored {
3204 error: e.to_string(),
3205 },
3206 );
3207 return self
3208 .send_error_and_get_state(e.into_response(Severity::Error))
3209 .await;
3210 }
3211
3212 let tag = format!("COPY {}", row_count);
3213 self.send(BackendMessage::CommandComplete { tag }).await?;
3214
3215 Ok(State::Ready)
3216 }
3217
3218 #[instrument(level = "debug")]
3219 async fn send_pending_notices(&mut self) -> Result<(), io::Error> {
3220 let notices = self
3221 .adapter_client
3222 .session()
3223 .drain_notices()
3224 .into_iter()
3225 .map(|notice| BackendMessage::ErrorResponse(notice.into_response()));
3226 self.send_all(notices).await?;
3227 Ok(())
3228 }
3229
3230 #[instrument(level = "debug")]
3231 async fn send_error_and_get_state(&mut self, err: ErrorResponse) -> Result<State, io::Error> {
3232 assert!(err.severity.is_error());
3233 debug!(
3234 "cid={} error code={}",
3235 self.adapter_client.session().conn_id(),
3236 err.code.code()
3237 );
3238 let is_fatal = err.severity.is_fatal();
3239 self.send(BackendMessage::ErrorResponse(err)).await?;
3240
3241 let txn = self.adapter_client.session().transaction();
3242 match txn {
3243 TransactionStatus::Default | TransactionStatus::Failed(_) => {}
3246 TransactionStatus::Started(_) => {
3248 self.rollback_transaction().await?;
3249 }
3250 TransactionStatus::InTransactionImplicit(_) => {
3252 self.rollback_transaction().await?;
3253 }
3254 TransactionStatus::InTransaction(_) => {
3256 self.adapter_client.fail_transaction();
3257 }
3258 };
3259 if is_fatal {
3260 Ok(State::Done)
3261 } else {
3262 Ok(State::Drain)
3263 }
3264 }
3265
3266 #[instrument(level = "debug")]
3267 async fn aborted_txn_error(&mut self) -> Result<State, io::Error> {
3268 self.send(BackendMessage::ErrorResponse(ErrorResponse::error(
3269 SqlState::IN_FAILED_SQL_TRANSACTION,
3270 ABORTED_TXN_MSG,
3271 )))
3272 .await?;
3273 Ok(State::Drain)
3274 }
3275
3276 fn is_aborted_txn(&mut self) -> bool {
3277 matches!(
3278 self.adapter_client.session().transaction(),
3279 TransactionStatus::Failed(_)
3280 )
3281 }
3282}
3283
3284fn pad_formats(formats: Vec<Format>, n: usize) -> Result<Vec<Format>, String> {
3285 match (formats.len(), n) {
3286 (0, e) => Ok(vec![Format::Text; e]),
3287 (1, e) => Ok(iter::repeat(formats[0]).take(e).collect()),
3288 (a, e) if a == e => Ok(formats),
3289 (a, e) => Err(format!(
3290 "expected {} field format specifiers, but got {}",
3291 e, a
3292 )),
3293 }
3294}
3295
3296fn describe_rows(stmt_desc: &StatementDesc, formats: &[Format]) -> BackendMessage {
3297 match &stmt_desc.relation_desc {
3298 Some(desc) if !stmt_desc.is_copy => {
3299 BackendMessage::RowDescription(message::encode_row_description(desc, formats))
3300 }
3301 _ => BackendMessage::NoData,
3302 }
3303}
3304
3305type GetResponse = fn(
3306 max_rows: ExecuteCount,
3307 total_sent_rows: usize,
3308 fetch_portal: Option<PortalRefMut>,
3309) -> BackendMessage;
3310
3311fn portal_exec_message(
3314 max_rows: ExecuteCount,
3315 total_sent_rows: usize,
3316 _fetch_portal: Option<PortalRefMut>,
3317) -> BackendMessage {
3318 match max_rows {
3325 ExecuteCount::Count(max_rows) if max_rows <= total_sent_rows => {
3326 BackendMessage::PortalSuspended
3327 }
3328 _ => BackendMessage::CommandComplete {
3329 tag: format!("SELECT {}", total_sent_rows),
3330 },
3331 }
3332}
3333
3334fn fetch_message(
3336 _max_rows: ExecuteCount,
3337 total_sent_rows: usize,
3338 fetch_portal: Option<PortalRefMut>,
3339) -> BackendMessage {
3340 let tag = format!("FETCH {}", total_sent_rows);
3341 if let Some(portal) = fetch_portal {
3342 *portal.state = PortalState::Completed(Some(tag.clone()));
3343 }
3344 BackendMessage::CommandComplete { tag }
3345}
3346
3347fn get_authenticator(
3348 authenticator_kind: listeners::AuthenticatorKind,
3349 frontegg: Option<FronteggAuthenticator>,
3350 oidc: GenericOidcAuthenticator,
3351 adapter_client: mz_adapter::Client,
3352) -> Authenticator {
3353 match authenticator_kind {
3354 listeners::AuthenticatorKind::Frontegg => Authenticator::Frontegg(frontegg.expect(
3355 "Frontegg authenticator should exist with listeners::AuthenticatorKind::Frontegg",
3356 )),
3357 listeners::AuthenticatorKind::Password => Authenticator::Password(adapter_client),
3358 listeners::AuthenticatorKind::Sasl => Authenticator::Sasl(adapter_client),
3359 listeners::AuthenticatorKind::Oidc => Authenticator::Oidc(oidc),
3360 listeners::AuthenticatorKind::None => Authenticator::None,
3361 }
3362}
3363
3364#[derive(Debug, Copy, Clone)]
3365enum ExecuteCount {
3366 All,
3367 Count(usize),
3368}
3369
3370fn is_txn_exit_stmt(stmt: Option<&Statement<Raw>>) -> bool {
3372 match stmt {
3373 Some(stmt) => matches!(stmt, Statement::Commit(_) | Statement::Rollback(_)),
3375 None => false,
3376 }
3377}
3378
3379#[derive(Debug)]
3380enum FetchResult {
3381 Rows(Option<Box<dyn RowIterator + Send + Sync>>),
3382 Canceled,
3383 Error(ErrorResponse),
3384 Notice(AdapterNotice),
3385}
3386
3387#[derive(Debug)]
3388struct CopyRowScanner {
3389 scan_pos: usize,
3390 last_row_end: Option<usize>,
3391 end_marker_end: Option<usize>,
3392 record_start: usize,
3397 csv: Option<CsvScanState>,
3398}
3399
3400#[derive(Debug)]
3401struct CsvScanState {
3402 reader: csv_core::Reader,
3403 output: Vec<u8>,
3404 ends: Vec<usize>,
3405 skip_first_record: bool,
3406}
3407
3408impl CopyRowScanner {
3409 fn new(params: &CopyFormatParams<'_>) -> Self {
3410 let csv = match params {
3411 CopyFormatParams::Csv(CopyCsvFormatParams {
3412 delimiter,
3413 quote,
3414 escape,
3415 header,
3416 ..
3417 }) => Some(CsvScanState::new(*delimiter, *quote, *escape, *header)),
3418 _ => None,
3419 };
3420
3421 CopyRowScanner {
3422 scan_pos: 0,
3423 last_row_end: None,
3424 end_marker_end: None,
3425 record_start: 0,
3426 csv,
3427 }
3428 }
3429
3430 fn scan_new_bytes(&mut self, data: &[u8]) {
3431 if self.scan_pos >= data.len() {
3432 return;
3433 }
3434
3435 if let Some(csv) = self.csv.as_mut() {
3436 let mut input = &data[self.scan_pos..];
3437 let mut consumed = 0usize;
3438 while !input.is_empty() {
3439 let (result, n_input, _n_output, _n_ends) =
3440 csv.reader
3441 .read_record(input, &mut csv.output, &mut csv.ends);
3442 consumed += n_input;
3443 input = &input[n_input..];
3444
3445 match result {
3446 ReadRecordResult::InputEmpty => break,
3447 ReadRecordResult::OutputFull => {
3448 if n_input == 0 {
3449 csv.output
3450 .resize(csv.output.len().saturating_mul(2).max(1), 0);
3451 }
3452 }
3453 ReadRecordResult::OutputEndsFull => {
3454 if n_input == 0 {
3455 csv.ends.resize(csv.ends.len().saturating_mul(2).max(1), 0);
3456 }
3457 }
3458 ReadRecordResult::Record | ReadRecordResult::End => {
3459 let row_end = self.scan_pos + consumed;
3460 self.last_row_end = Some(row_end);
3461 if self.end_marker_end.is_none() {
3462 let is_marker = if csv.skip_first_record {
3463 csv.skip_first_record = false;
3464 false
3465 } else {
3466 let raw = &data[self.record_start..row_end];
3472 let start = raw
3483 .iter()
3484 .take_while(|&&b| b == b'\r' || b == b'\n')
3485 .count();
3486 let trailing = raw[start..]
3487 .iter()
3488 .rev()
3489 .take_while(|&&b| b == b'\r' || b == b'\n')
3490 .count();
3491 let trimmed = &raw[start..raw.len() - trailing];
3492 trimmed == b"\\."
3493 };
3494 if is_marker {
3495 self.end_marker_end = Some(row_end);
3496 self.record_start = row_end;
3497 break;
3498 }
3499 }
3500 self.record_start = row_end;
3501 }
3502 }
3503 }
3504 } else {
3505 let mut row_start = self.last_row_end.unwrap_or(0);
3506 for (offset, b) in data[self.scan_pos..].iter().enumerate() {
3507 if *b == b'\n' {
3508 let row_end = self.scan_pos + offset + 1;
3509 self.last_row_end = Some(row_end);
3510 if self.end_marker_end.is_none() {
3511 let row = &data[row_start..row_end];
3512 if row.get(0..2) == Some(b"\\.") {
3513 self.end_marker_end = Some(row_end);
3514 break;
3515 }
3516 }
3517 row_start = row_end;
3518 }
3519 }
3520 }
3521
3522 self.scan_pos = data.len();
3523 }
3524
3525 fn last_row_end(&self) -> Option<usize> {
3526 self.last_row_end
3527 }
3528
3529 fn end_marker_end(&self) -> Option<usize> {
3530 self.end_marker_end
3531 }
3532
3533 fn current_row_size(&self, data_len: usize) -> usize {
3534 data_len.saturating_sub(self.last_row_end.unwrap_or(0))
3535 }
3536
3537 fn on_split(&mut self, split_pos: usize) {
3538 self.scan_pos = self.scan_pos.saturating_sub(split_pos);
3539 self.last_row_end = None;
3540 self.end_marker_end = self
3541 .end_marker_end
3542 .and_then(|end| end.checked_sub(split_pos));
3543 soft_assert_or_log!(
3551 self.csv.is_none() || self.record_start >= split_pos,
3552 "split bisected an in-progress CSV record: record_start={} < split_pos={}",
3553 self.record_start,
3554 split_pos,
3555 );
3556 self.record_start = self.record_start.saturating_sub(split_pos);
3557 }
3558
3559 fn on_truncate(&mut self, new_len: usize) {
3560 self.scan_pos = self.scan_pos.min(new_len);
3561 self.last_row_end = self.last_row_end.filter(|&end| end <= new_len);
3562 self.end_marker_end = self.end_marker_end.filter(|&end| end <= new_len);
3563 self.record_start = self.record_start.min(new_len);
3564 }
3565}
3566
3567impl CsvScanState {
3568 fn new(delimiter: u8, quote: u8, escape: u8, header: bool) -> Self {
3569 let (double_quote, escape) = if quote == escape {
3570 (true, None)
3571 } else {
3572 (false, Some(escape))
3573 };
3574 CsvScanState {
3575 reader: csv_core::ReaderBuilder::new()
3576 .delimiter(delimiter)
3577 .quote(quote)
3578 .double_quote(double_quote)
3579 .escape(escape)
3580 .build(),
3581 output: vec![0; 1],
3582 ends: vec![0; 1],
3583 skip_first_record: header,
3584 }
3585 }
3586}
3587
3588#[cfg(test)]
3589mod test {
3590 use super::*;
3591
3592 #[mz_ore::test]
3593 fn test_copy_row_scanner_end_marker_line_endings() {
3594 let params = CopyFormatParams::Csv(CopyCsvFormatParams::default());
3602
3603 let marker_end = |data: &[u8]| -> Option<usize> {
3604 let mut scanner = CopyRowScanner::new(¶ms);
3605 scanner.scan_new_bytes(data);
3606 scanner.end_marker_end()
3607 };
3608
3609 for eol in [&b"\n"[..], b"\r\n", b"\r"] {
3610 let join = |lines: &[&str]| -> Vec<u8> {
3611 let mut out = Vec::new();
3612 for line in lines {
3613 out.extend_from_slice(line.as_bytes());
3614 out.extend_from_slice(eol);
3615 }
3616 out
3617 };
3618
3619 let data = join(&["first", "\\.", "after"]);
3624 let mut prefix = Vec::new();
3625 prefix.extend_from_slice(b"first");
3626 prefix.extend_from_slice(eol);
3627 prefix.extend_from_slice(b"\\.");
3628 assert_eq!(
3629 marker_end(&data),
3630 Some(prefix.len() + 1),
3631 "bare marker, eol={eol:?}"
3632 );
3633
3634 let data = join(&["before", "\"\\.\"", "after"]);
3636 assert_eq!(marker_end(&data), None, "quoted marker, eol={eol:?}");
3637 }
3638 }
3639
3640 #[mz_ore::test]
3641 fn test_copy_row_scanner_non_csv_split() {
3642 for params in [
3649 CopyFormatParams::Text(CopyTextFormatParams::default()),
3650 CopyFormatParams::Binary,
3651 ] {
3652 let mut scanner = CopyRowScanner::new(¶ms);
3653 let data = b"1\thello world\t2\tsome text value here\n\
3654 3\thello world\t6\tsome text value here\n";
3655 scanner.scan_new_bytes(data);
3656 let split_pos = scanner.last_row_end().expect("a complete row");
3657 assert!(split_pos > 0, "params={params:?}");
3658 scanner.on_split(split_pos);
3660 assert_eq!(scanner.record_start, 0, "params={params:?}");
3661 }
3662 }
3663
3664 #[mz_ore::test]
3665 fn test_parse_options() {
3666 struct TestCase {
3667 input: &'static str,
3668 expect: Result<Vec<(&'static str, &'static str)>, ()>,
3669 }
3670 let tests = vec![
3671 TestCase {
3672 input: "",
3673 expect: Ok(vec![]),
3674 },
3675 TestCase {
3676 input: "--key",
3677 expect: Err(()),
3678 },
3679 TestCase {
3680 input: "--key=val",
3681 expect: Ok(vec![("key", "val")]),
3682 },
3683 TestCase {
3684 input: r#"--key=val -ckey2=val2 -c key3=val3 -c key4=val4 -ckey5=val5"#,
3685 expect: Ok(vec![
3686 ("key", "val"),
3687 ("key2", "val2"),
3688 ("key3", "val3"),
3689 ("key4", "val4"),
3690 ("key5", "val5"),
3691 ]),
3692 },
3693 TestCase {
3694 input: r#"-c\ key=val"#,
3695 expect: Ok(vec![(" key", "val")]),
3696 },
3697 TestCase {
3698 input: "--key=val -ckey2 val2",
3699 expect: Err(()),
3700 },
3701 TestCase {
3703 input: "--key=",
3704 expect: Ok(vec![("key", "")]),
3705 },
3706 ];
3707 for test in tests {
3708 let got = parse_options(test.input);
3709 let expect = test.expect.map(|r| {
3710 r.into_iter()
3711 .map(|(k, v)| (k.to_owned(), v.to_owned()))
3712 .collect()
3713 });
3714 assert_eq!(got, expect, "input: {}", test.input);
3715 }
3716 }
3717
3718 #[mz_ore::test]
3719 fn test_parse_option() {
3720 struct TestCase {
3721 input: &'static str,
3722 expect: Result<(&'static str, &'static str), ()>,
3723 }
3724 let tests = vec![
3725 TestCase {
3726 input: "",
3727 expect: Err(()),
3728 },
3729 TestCase {
3730 input: "--",
3731 expect: Err(()),
3732 },
3733 TestCase {
3734 input: "--c",
3735 expect: Err(()),
3736 },
3737 TestCase {
3738 input: "a=b",
3739 expect: Err(()),
3740 },
3741 TestCase {
3742 input: "--a=b",
3743 expect: Ok(("a", "b")),
3744 },
3745 TestCase {
3746 input: "--ca=b",
3747 expect: Ok(("ca", "b")),
3748 },
3749 TestCase {
3750 input: "-ca=b",
3751 expect: Ok(("a", "b")),
3752 },
3753 TestCase {
3755 input: "--=",
3756 expect: Ok(("", "")),
3757 },
3758 ];
3759 for test in tests {
3760 let got = parse_option(test.input);
3761 assert_eq!(got, test.expect, "input: {}", test.input);
3762 }
3763 }
3764
3765 #[mz_ore::test]
3766 fn test_split_options() {
3767 struct TestCase {
3768 input: &'static str,
3769 expect: Vec<&'static str>,
3770 }
3771 let tests = vec![
3772 TestCase {
3773 input: "",
3774 expect: vec![],
3775 },
3776 TestCase {
3777 input: " ",
3778 expect: vec![],
3779 },
3780 TestCase {
3781 input: " a ",
3782 expect: vec!["a"],
3783 },
3784 TestCase {
3785 input: " ab cd ",
3786 expect: vec!["ab", "cd"],
3787 },
3788 TestCase {
3789 input: r#" ab\ cd "#,
3790 expect: vec!["ab ", "cd"],
3791 },
3792 TestCase {
3793 input: r#" ab\\ cd "#,
3794 expect: vec![r#"ab\"#, "cd"],
3795 },
3796 TestCase {
3797 input: r#" ab\\\ cd "#,
3798 expect: vec![r#"ab\ "#, "cd"],
3799 },
3800 TestCase {
3801 input: r#" ab\\\ cd "#,
3802 expect: vec![r#"ab\ cd"#],
3803 },
3804 TestCase {
3805 input: r#" ab\\\cd "#,
3806 expect: vec![r#"ab\cd"#],
3807 },
3808 TestCase {
3809 input: r#"a\"#,
3810 expect: vec!["a"],
3811 },
3812 TestCase {
3813 input: r#"a\ "#,
3814 expect: vec!["a "],
3815 },
3816 TestCase {
3817 input: r#"\"#,
3818 expect: vec![],
3819 },
3820 TestCase {
3821 input: r#"\ "#,
3822 expect: vec![r#" "#],
3823 },
3824 TestCase {
3825 input: r#" \ "#,
3826 expect: vec![r#" "#],
3827 },
3828 TestCase {
3829 input: r#"\ "#,
3830 expect: vec![r#" "#],
3831 },
3832 ];
3833 for test in tests {
3834 let got = split_options(test.input);
3835 assert_eq!(got, test.expect, "input: {}", test.input);
3836 }
3837 }
3838
3839 #[mz_ore::test]
3840 fn test_is_jwt() {
3841 assert!(is_jwt("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.signature"));
3843 for s in [
3845 "",
3846 "secure_password",
3847 "p4ss.w0rd",
3848 "aaa.bbb.ccc",
3849 "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0",
3850 "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.sig.extra",
3851 ] {
3852 assert!(!is_jwt(s), "is_jwt({s:?})");
3853 }
3854 }
3855}