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, ExecutionTime,
31 PeekResponseUnary, metrics, 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 tracing::{Instrument, debug, debug_span, info, warn};
70use uuid::Uuid;
71
72use crate::codec::{
73 FramedConn, decode_password, decode_sasl_initial_response, decode_sasl_response,
74};
75use crate::message::{
76 self, BackendMessage, SASLServerFinalMessage, SASLServerFinalMessageKinds,
77 SASLServerFirstMessage,
78};
79
80pub fn match_handshake(buf: &[u8]) -> bool {
84 if buf.len() < 8 {
94 return false;
95 }
96 let version = NetworkEndian::read_i32(&buf[4..8]);
97 VERSIONS.contains(&version)
98}
99
100pub struct RunParams<'a, A, I>
102where
103 I: Iterator<Item = TaskMetrics> + Send,
104{
105 pub tls_mode: Option<TlsMode>,
107 pub adapter_client: mz_adapter::Client,
109 pub conn: &'a mut FramedConn<A>,
111 pub conn_uuid: Uuid,
113 pub version: i32,
115 pub params: BTreeMap<String, String>,
117 pub frontegg: Option<FronteggAuthenticator>,
119 pub oidc: GenericOidcAuthenticator,
121 pub authenticator_kind: listeners::AuthenticatorKind,
124 pub active_connection_counter: ConnectionCounter,
126 pub helm_chart_version: Option<String>,
128 pub allowed_roles: AllowedRoles,
130 pub tokio_metrics_intervals: I,
132}
133
134#[mz_ore::instrument(level = "debug")]
144pub async fn run<'a, A, I>(
145 RunParams {
146 tls_mode,
147 adapter_client,
148 conn,
149 conn_uuid,
150 version,
151 mut params,
152 frontegg,
153 oidc,
154 authenticator_kind,
155 active_connection_counter,
156 helm_chart_version,
157 allowed_roles,
158 tokio_metrics_intervals,
159 }: RunParams<'a, A, I>,
160) -> Result<(), io::Error>
161where
162 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin,
163 I: Iterator<Item = TaskMetrics> + Send,
164{
165 if version != VERSION_3 {
166 return conn
167 .send(ErrorResponse::fatal(
168 SqlState::SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION,
169 "server does not support the client's requested protocol version",
170 ))
171 .await;
172 }
173
174 let user = params.remove("user").unwrap_or_else(String::new);
175 let options = parse_options(params.get("options").unwrap_or(&String::new()));
176 let authenticator =
177 get_authenticator(authenticator_kind, frontegg, oidc, adapter_client.clone());
178 let is_internal_user = INTERNAL_USER_NAMES.contains(&user);
180 let is_reserved_user = mz_adapter::catalog::is_reserved_role_name(user.as_str());
182 let role_allowed = match allowed_roles {
183 AllowedRoles::Normal => !is_reserved_user,
184 AllowedRoles::Internal => is_internal_user,
185 AllowedRoles::NormalAndInternal => !is_reserved_user || is_internal_user,
186 };
187 if !role_allowed {
188 let msg = format!("unauthorized login to user '{user}'");
189 return conn
190 .send(ErrorResponse::fatal(SqlState::INSUFFICIENT_PRIVILEGE, msg))
191 .await;
192 }
193
194 if let Err(err) = conn.inner().ensure_tls_compatibility(&tls_mode) {
195 return conn.send(err).await;
196 }
197
198 let authenticator_kind = authenticator.kind();
199
200 let (mut session, expired) = match authenticator {
201 Authenticator::Frontegg(frontegg) => {
202 let password = match request_cleartext_password(conn).await {
203 Ok(password) => password,
204 Err(PasswordRequestError::IoError(e)) => return Err(e),
205 Err(PasswordRequestError::InvalidPasswordError(e)) => {
206 return conn.send(e).await;
207 }
208 };
209
210 let group_claim =
211 OIDC_GROUP_CLAIM.get(adapter_client.get_system_vars().await.dyncfgs());
212 let auth_response = frontegg
213 .authenticate(&user, &password, Some(&group_claim))
214 .await;
215 match auth_response {
216 Ok((mut auth_session, authenticated)) => {
223 let groups = auth_session.groups();
224 let session = adapter_client.new_session(
225 SessionConfig {
226 conn_id: conn.conn_id().clone(),
227 uuid: conn_uuid,
228 user: auth_session.user().into(),
229 client_ip: conn.peer_addr().clone(),
230 external_metadata_rx: Some(auth_session.external_metadata_rx()),
231 helm_chart_version,
232 authenticator_kind,
233 groups,
234 },
235 authenticated,
236 );
237 let expired = async move { auth_session.expired().await };
238 (session, expired.left_future())
239 }
240 Err(err) => {
241 warn!(?err, "pgwire connection failed authentication");
242 return conn
243 .send(ErrorResponse::fatal(
244 SqlState::INVALID_PASSWORD,
245 "invalid password",
246 ))
247 .await;
248 }
249 }
250 }
251 Authenticator::Oidc(oidc) => {
252 let password = match request_cleartext_password(conn).await {
255 Ok(password) => password,
256 Err(PasswordRequestError::IoError(e)) => return Err(e),
257 Err(PasswordRequestError::InvalidPasswordError(e)) => {
258 return conn.send(e).await;
259 }
260 };
261 if is_jwt(&password) {
262 let auth_response = oidc.authenticate(&password, Some(&user)).await;
263 match auth_response {
264 Ok((mut claims, authenticated)) => {
265 let groups = claims.groups.take();
266 let session = adapter_client.new_session(
267 SessionConfig {
268 conn_id: conn.conn_id().clone(),
269 uuid: conn_uuid,
270 user: std::mem::take(&mut claims.user),
271 client_ip: conn.peer_addr().clone(),
272 external_metadata_rx: None,
273 helm_chart_version,
274 authenticator_kind,
275 groups,
276 },
277 authenticated,
278 );
279 (session, pending().right_future())
282 }
283 Err(err) => {
284 warn!(?err, "pgwire connection failed authentication");
285 return conn.send(err.into_response()).await;
286 }
287 }
288 } else {
289 let session = match authenticate_with_password(
290 conn,
291 &adapter_client,
292 user,
293 Password(password),
294 conn_uuid,
295 helm_chart_version,
296 )
297 .await
298 {
299 Ok(session) => session,
300 Err(PasswordRequestError::IoError(e)) => return Err(e),
301 Err(PasswordRequestError::InvalidPasswordError(e)) => {
302 return conn.send(e).await;
303 }
304 };
305 (session, pending().right_future())
306 }
307 }
308 Authenticator::Password(adapter_client) => {
309 let password = match request_cleartext_password(conn).await {
310 Ok(password) => password,
311 Err(PasswordRequestError::IoError(e)) => return Err(e),
312 Err(PasswordRequestError::InvalidPasswordError(e)) => {
313 return conn.send(e).await;
314 }
315 };
316 let session = match authenticate_with_password(
317 conn,
318 &adapter_client,
319 user,
320 Password(password),
321 conn_uuid,
322 helm_chart_version,
323 )
324 .await
325 {
326 Ok(session) => session,
327 Err(PasswordRequestError::IoError(e)) => return Err(e),
328 Err(PasswordRequestError::InvalidPasswordError(e)) => {
329 return conn.send(e).await;
330 }
331 };
332 (session, pending().right_future())
334 }
335 Authenticator::Sasl(adapter_client) => {
336 conn.send(BackendMessage::AuthenticationSASL).await?;
338 conn.flush().await?;
339 let (mechanism, initial_response) = match conn.recv().await? {
341 Some(FrontendMessage::RawAuthentication(data)) => {
342 match decode_sasl_initial_response(Cursor::new(&data)).ok() {
343 Some(FrontendMessage::SASLInitialResponse {
344 gs2_header,
345 mechanism,
346 initial_response,
347 }) => {
348 if gs2_header.channel_binding_enabled() {
350 return conn
351 .send(ErrorResponse::fatal(
352 SqlState::PROTOCOL_VIOLATION,
353 "channel binding not supported",
354 ))
355 .await;
356 }
357 (mechanism, initial_response)
358 }
359 _ => {
360 return conn
361 .send(ErrorResponse::fatal(
362 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
363 "expected SASLInitialResponse message",
364 ))
365 .await;
366 }
367 }
368 }
369 _ => {
370 return conn
371 .send(ErrorResponse::fatal(
372 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
373 "expected SASLInitialResponse message",
374 ))
375 .await;
376 }
377 };
378
379 if mechanism != "SCRAM-SHA-256" {
380 return conn
381 .send(ErrorResponse::fatal(
382 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
383 "unsupported SASL mechanism",
384 ))
385 .await;
386 }
387
388 if initial_response.nonce.len() > 256 {
389 return conn
390 .send(ErrorResponse::fatal(
391 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
392 "nonce too long",
393 ))
394 .await;
395 }
396
397 let (server_first_message_raw, mock_hash) = match adapter_client
398 .generate_sasl_challenge(&user, &initial_response.nonce)
399 .await
400 {
401 Ok(response) => {
402 let server_first_message_raw = format!(
403 "r={},s={},i={}",
404 response.nonce, response.salt, response.iteration_count
405 );
406
407 let client_key = [0u8; 32];
408 let server_key = [1u8; 32];
409 let mock_hash = format!(
410 "SCRAM-SHA-256${}:{}${}:{}",
411 response.iteration_count,
412 response.salt,
413 BASE64_STANDARD.encode(client_key),
414 BASE64_STANDARD.encode(server_key)
415 );
416
417 conn.send(BackendMessage::AuthenticationSASLContinue(
418 SASLServerFirstMessage {
419 iteration_count: response.iteration_count,
420 nonce: response.nonce,
421 salt: response.salt,
422 },
423 ))
424 .await?;
425 conn.flush().await?;
426 (server_first_message_raw, mock_hash)
427 }
428 Err(e) => {
429 return conn.send(e.into_response(Severity::Fatal)).await;
430 }
431 };
432
433 let authenticated = match conn.recv().await? {
434 Some(FrontendMessage::RawAuthentication(data)) => {
435 match decode_sasl_response(Cursor::new(&data)).ok() {
436 Some(FrontendMessage::SASLResponse(response)) => {
437 let auth_message = format!(
438 "{},{},{}",
439 initial_response.client_first_message_bare_raw,
440 server_first_message_raw,
441 response.client_final_message_bare_raw
442 );
443 if response.proof.len() > 1024 {
444 return conn
445 .send(ErrorResponse::fatal(
446 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
447 "proof too long",
448 ))
449 .await;
450 }
451 match adapter_client
452 .verify_sasl_proof(
453 &user,
454 &response.proof,
455 &auth_message,
456 &mock_hash,
457 )
458 .await
459 {
460 Ok((proof_response, authenticated)) => {
461 conn.send(BackendMessage::AuthenticationSASLFinal(
462 SASLServerFinalMessage {
463 kind: SASLServerFinalMessageKinds::Verifier(
464 proof_response.verifier,
465 ),
466 extensions: vec![],
467 },
468 ))
469 .await?;
470 conn.flush().await?;
471 authenticated
472 }
473 Err(_) => {
474 return conn
475 .send(ErrorResponse::fatal(
476 SqlState::INVALID_PASSWORD,
477 "invalid password",
478 ))
479 .await;
480 }
481 }
482 }
483 _ => {
484 return conn
485 .send(ErrorResponse::fatal(
486 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
487 "expected SASLResponse message",
488 ))
489 .await;
490 }
491 }
492 }
493 _ => {
494 return conn
495 .send(ErrorResponse::fatal(
496 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
497 "expected SASLResponse message",
498 ))
499 .await;
500 }
501 };
502
503 let session = adapter_client.new_session(
504 SessionConfig {
505 conn_id: conn.conn_id().clone(),
506 uuid: conn_uuid,
507 user,
508 client_ip: conn.peer_addr().clone(),
509 external_metadata_rx: None,
510 helm_chart_version,
511 authenticator_kind,
512 groups: None,
513 },
514 authenticated,
515 );
516 let auth_session = pending().right_future();
518 (session, auth_session)
519 }
520
521 Authenticator::None => {
522 let session = adapter_client.new_session(
523 SessionConfig {
524 conn_id: conn.conn_id().clone(),
525 uuid: conn_uuid,
526 user,
527 client_ip: conn.peer_addr().clone(),
528 external_metadata_rx: None,
529 helm_chart_version,
530 authenticator_kind,
531 groups: None,
532 },
533 Authenticated,
534 );
535 let auth_session = pending().right_future();
537 (session, auth_session)
538 }
539 };
540
541 let system_vars = adapter_client.get_system_vars().await;
542 let mut applied_params = vec![];
546 for (name, value) in params {
547 let settings = match name.as_str() {
548 "options" => match &options {
549 Ok(opts) => opts,
550 Err(()) => {
551 session.add_notice(AdapterNotice::BadStartupSetting {
552 name,
553 reason: "could not parse".into(),
554 });
555 continue;
556 }
557 },
558 _ => &vec![(name, value)],
559 };
560 for (key, val) in settings {
561 const LOCAL: bool = false;
562 match session
567 .vars_mut()
568 .set(&system_vars, key, VarInput::Flat(val), LOCAL)
569 {
570 Ok(()) => applied_params.push((key.clone(), val.clone())),
571 Err(err) => {
572 session.add_notice(AdapterNotice::BadStartupSetting {
573 name: key.clone(),
574 reason: err.to_string(),
575 });
576 }
577 }
578 }
579 }
580 session
581 .vars_mut()
582 .end_transaction(EndTransactionAction::Commit);
583
584 let _guard = match active_connection_counter.allocate_connection(session.user()) {
585 Ok(drop_connection) => drop_connection,
586 Err(e) => {
587 let e: AdapterError = e.into();
588 return conn.send(e.into_response(Severity::Fatal)).await;
589 }
590 };
591
592 let mut adapter_client = match adapter_client.startup(session).await {
594 Ok(adapter_client) => adapter_client,
595 Err(e) => return conn.send(e.into_response(Severity::Fatal)).await,
596 };
597
598 for (key, val) in applied_params {
606 if let Err(err) = adapter_client
607 .session()
608 .vars_mut()
609 .set_default(&key, VarInput::Flat(&val))
610 {
611 mz_ore::soft_panic_or_log!("failed to apply startup parameter as default: {err:?}");
613 }
614 }
615
616 conn.allow_post_auth_frames();
619
620 let mut buf = vec![BackendMessage::AuthenticationOk];
621 for var in adapter_client.session().vars().notify_set() {
622 buf.push(BackendMessage::ParameterStatus(var.name(), var.value()));
623 }
624 buf.push(BackendMessage::BackendKeyData {
625 conn_id: adapter_client.session().conn_id().unhandled(),
626 secret_key: adapter_client.session().secret_key(),
627 });
628 buf.extend(
629 adapter_client
630 .session()
631 .drain_notices()
632 .into_iter()
633 .map(|notice| BackendMessage::ErrorResponse(notice.into_response())),
634 );
635 buf.push(BackendMessage::ReadyForQuery(
636 adapter_client.session().transaction().into(),
637 ));
638 conn.send_all(buf).await?;
639 conn.flush().await?;
640
641 let machine = StateMachine {
642 conn,
643 adapter_client,
644 txn_needs_commit: false,
645 reverted_parameters: BTreeMap::new(),
646 tokio_metrics_intervals,
647 };
648
649 select! {
650 r = machine.run() => {
651 if let Err(err) = &r {
656 let _ = conn
657 .send(ErrorResponse::fatal(
658 SqlState::CONNECTION_FAILURE,
659 err.to_string(),
660 ))
661 .await;
662 let _ = conn.flush().await;
663 }
664 r
665 },
666 _ = expired => {
667 conn
668 .send(ErrorResponse::fatal(SqlState::INVALID_AUTHORIZATION_SPECIFICATION, "authentication expired"))
669 .await?;
670 conn.flush().await
671 }
672 }
673}
674
675fn is_jwt(password: &str) -> bool {
678 jsonwebtoken::decode_header(password).is_ok()
679}
680
681fn parse_options(value: &str) -> Result<Vec<(String, String)>, ()> {
686 let opts = split_options(value);
687 let mut pairs = Vec::with_capacity(opts.len());
688 let mut seen_prefix = false;
689 for opt in opts {
690 if !seen_prefix {
691 if opt == "-c" {
692 seen_prefix = true;
693 } else {
694 let (key, val) = parse_option(&opt)?;
695 pairs.push((key.to_owned(), val.to_owned()));
696 }
697 } else {
698 let (key, val) = opt.split_once('=').ok_or(())?;
699 pairs.push((key.to_owned(), val.to_owned()));
700 seen_prefix = false;
701 }
702 }
703 Ok(pairs)
704}
705
706fn parse_option(option: &str) -> Result<(&str, &str), ()> {
710 let (key, value) = option.split_once('=').ok_or(())?;
711 for prefix in &["-c", "--"] {
712 if let Some(key) = key.strip_prefix(prefix) {
713 return Ok((key, value));
714 }
715 }
716 Err(())
717}
718
719fn split_options(value: &str) -> Vec<String> {
721 let mut strs = Vec::new();
722 let mut current = String::new();
726 let mut was_slash = false;
727 for c in value.chars() {
728 was_slash = match c {
729 ' ' => {
730 if was_slash {
731 current.push(' ');
732 } else if !current.is_empty() {
733 strs.push(std::mem::take(&mut current));
736 }
737 false
738 }
739 '\\' => {
740 if was_slash {
741 current.push('\\');
744 false
745 } else {
746 true
747 }
748 }
749 _ => {
750 current.push(c);
751 false
752 }
753 };
754 }
755 if !current.is_empty() {
757 strs.push(current);
758 }
759 strs
760}
761
762enum PasswordRequestError {
763 InvalidPasswordError(ErrorResponse),
764 IoError(io::Error),
765}
766
767impl From<io::Error> for PasswordRequestError {
768 fn from(e: io::Error) -> Self {
769 PasswordRequestError::IoError(e)
770 }
771}
772
773async fn request_cleartext_password<A>(
777 conn: &mut FramedConn<A>,
778) -> Result<String, PasswordRequestError>
779where
780 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin,
781{
782 conn.send(BackendMessage::AuthenticationCleartextPassword)
783 .await?;
784 conn.flush().await?;
785
786 if let Some(message) = conn.recv().await? {
787 if let FrontendMessage::RawAuthentication(data) = message {
788 if let Some(FrontendMessage::Password { password }) =
789 decode_password(Cursor::new(&data)).ok()
790 {
791 return Ok(password);
792 }
793 }
794 }
795
796 Err(PasswordRequestError::InvalidPasswordError(
797 ErrorResponse::fatal(
798 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
799 "expected Password message",
800 ),
801 ))
802}
803
804async fn authenticate_with_password<A>(
807 conn: &FramedConn<A>,
808 adapter_client: &mz_adapter::Client,
809 user: String,
810 password: Password,
811 conn_uuid: Uuid,
812 helm_chart_version: Option<String>,
813) -> Result<Session, PasswordRequestError>
814where
815 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin,
816{
817 let authenticated = match adapter_client.authenticate(&user, &password).await {
818 Ok(authenticated) => authenticated,
819 Err(err) => {
820 warn!(?err, "pgwire connection failed authentication");
821 return Err(PasswordRequestError::InvalidPasswordError(
822 ErrorResponse::fatal(SqlState::INVALID_PASSWORD, "invalid password"),
823 ));
824 }
825 };
826
827 let session = adapter_client.new_session(
828 SessionConfig {
829 conn_id: conn.conn_id().clone(),
830 uuid: conn_uuid,
831 user,
832 client_ip: conn.peer_addr().clone(),
833 external_metadata_rx: None,
834 helm_chart_version,
835 authenticator_kind: mz_auth::AuthenticatorKind::Password,
836 groups: None,
837 },
838 authenticated,
839 );
840
841 Ok(session)
842}
843
844#[derive(Debug)]
845enum State {
846 Ready,
847 Drain,
848 Done,
849}
850
851struct StateMachine<'a, A, I>
852where
853 I: Iterator<Item = TaskMetrics> + Send + 'a,
854{
855 conn: &'a mut FramedConn<A>,
856 adapter_client: mz_adapter::SessionClient,
857 txn_needs_commit: bool,
858 reverted_parameters: BTreeMap<&'static str, String>,
860 tokio_metrics_intervals: I,
861}
862
863enum SendRowsEndedReason {
864 Success {
865 result_size: u64,
866 rows_returned: u64,
867 },
868 Errored {
869 error: String,
870 },
871 Canceled,
872}
873
874const ABORTED_TXN_MSG: &str =
875 "current transaction is aborted, commands ignored until end of transaction block";
876
877impl<'a, A, I> StateMachine<'a, A, I>
878where
879 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin + 'a,
880 I: Iterator<Item = TaskMetrics> + Send + 'a,
881{
882 #[allow(clippy::manual_async_fn)]
886 #[mz_ore::instrument(level = "debug")]
887 fn run(mut self) -> impl Future<Output = Result<(), io::Error>> + Send + 'a {
888 async move {
889 let mut state = State::Ready;
890 loop {
891 self.send_pending_notices().await?;
892 state = match state {
893 State::Ready => self.advance_ready().await?,
894 State::Drain => self.advance_drain().await?,
895 State::Done => return Ok(()),
896 };
897 self.adapter_client
898 .add_idle_in_transaction_session_timeout();
899 }
900 }
901 }
902
903 #[instrument(level = "debug")]
904 async fn advance_ready(&mut self) -> Result<State, io::Error> {
905 self.tokio_metrics_intervals
907 .next()
908 .expect("infinite iterator");
909
910 let message = select! {
912 biased;
913
914 Some(timeout) = self.adapter_client.recv_timeout() => {
916 let err: AdapterError = timeout.into();
917 let conn_id = self.adapter_client.session().conn_id();
918 tracing::warn!("session timed out, conn_id {}", conn_id);
919
920 let error_response = err.into_response(Severity::Fatal);
922 let error_state = self.send_error_and_get_state(error_response).await;
923
924 self.adapter_client.terminate().await;
926
927 let _ = self.conn.recv().await?;
931 return error_state;
932 },
933 message = self.conn.recv() => message?,
935 };
936
937 let interval = self
939 .tokio_metrics_intervals
940 .next()
941 .expect("infinite iterator");
942 let recv_scheduling_delay_ms = interval.total_scheduled_duration.as_secs_f64() * 1000.0;
943
944 let received = SYSTEM_TIME();
948
949 self.adapter_client
950 .remove_idle_in_transaction_session_timeout();
951
952 let message_name = message.as_ref().map(|m| m.name()).unwrap_or_default();
955
956 if let Some(message) = &message {
957 self.maybe_log_message_arrival(message).await;
958 }
959
960 let start = message.as_ref().map(|_| Instant::now());
961 let next_state = match message {
962 Some(FrontendMessage::Query { sql }) => {
963 let query_root_span =
964 tracing::info_span!(parent: None, "advance_ready", otel.name = message_name);
965 query_root_span.follows_from(tracing::Span::current());
966 self.query(sql, received)
967 .instrument(query_root_span)
968 .await?
969 }
970 Some(FrontendMessage::Parse {
971 name,
972 sql,
973 param_types,
974 }) => self.parse(name, sql, param_types).await?,
975 Some(FrontendMessage::Bind {
976 portal_name,
977 statement_name,
978 param_formats,
979 raw_params,
980 result_formats,
981 }) => {
982 self.bind(
983 portal_name,
984 statement_name,
985 param_formats,
986 raw_params,
987 result_formats,
988 )
989 .await?
990 }
991 Some(FrontendMessage::Execute {
992 portal_name,
993 max_rows,
994 }) => {
995 let max_rows = match usize::try_from(max_rows) {
996 Ok(0) | Err(_) => ExecuteCount::All, Ok(n) => ExecuteCount::Count(n),
998 };
999 let execute_root_span =
1000 tracing::info_span!(parent: None, "advance_ready", otel.name = message_name);
1001 execute_root_span.follows_from(tracing::Span::current());
1002 let state = self
1003 .execute(
1004 portal_name,
1005 max_rows,
1006 portal_exec_message,
1007 None,
1008 ExecuteTimeout::None,
1009 None,
1010 Some(received),
1011 false,
1014 )
1015 .instrument(execute_root_span)
1016 .await?;
1017 let (is_implicit, may_span_pipeline) = {
1032 let txn = self.adapter_client.session().transaction();
1033 (txn.is_implicit(), txn.may_span_pipeline())
1034 };
1035 let spans_pipeline = may_span_pipeline
1038 && self
1039 .adapter_client
1040 .extended_protocol_implicit_transaction_enabled()
1041 .await;
1042 if is_implicit && !spans_pipeline {
1043 self.txn_needs_commit = true;
1044 }
1045 state
1046 }
1047 Some(FrontendMessage::DescribeStatement { name }) => {
1048 self.describe_statement(&name).await?
1049 }
1050 Some(FrontendMessage::DescribePortal { name }) => self.describe_portal(&name).await?,
1051 Some(FrontendMessage::CloseStatement { name }) => self.close_statement(name).await?,
1052 Some(FrontendMessage::ClosePortal { name }) => self.close_portal(name).await?,
1053 Some(FrontendMessage::Flush) => self.flush().await?,
1054 Some(FrontendMessage::Sync) => self.sync().await?,
1055 Some(FrontendMessage::Terminate) => State::Done,
1056
1057 Some(FrontendMessage::CopyData(_))
1064 | Some(FrontendMessage::CopyDone)
1065 | Some(FrontendMessage::CopyFail(_)) => State::Ready,
1066
1067 Some(FrontendMessage::Password { .. })
1068 | Some(FrontendMessage::RawAuthentication(_))
1069 | Some(FrontendMessage::SASLInitialResponse { .. })
1070 | Some(FrontendMessage::SASLResponse(_)) => State::Drain,
1071 None => State::Done,
1072 };
1073
1074 if let Some(start) = start {
1075 self.adapter_client
1076 .inner()
1077 .metrics()
1078 .pgwire_message_processing_seconds
1079 .with_label_values(&[message_name])
1080 .observe(start.elapsed().as_secs_f64());
1081 }
1082 self.adapter_client
1083 .inner()
1084 .metrics()
1085 .pgwire_recv_scheduling_delay_ms
1086 .with_label_values(&[message_name])
1087 .observe(recv_scheduling_delay_ms);
1088
1089 Ok(next_state)
1090 }
1091
1092 async fn advance_drain(&mut self) -> Result<State, io::Error> {
1093 let message = self.conn.recv().await?;
1094 if message.is_some() {
1095 self.adapter_client
1096 .remove_idle_in_transaction_session_timeout();
1097 }
1098 match message {
1099 Some(FrontendMessage::Sync) => self.sync().await,
1100 None => Ok(State::Done),
1101 _ => Ok(State::Drain),
1102 }
1103 }
1104
1105 #[instrument(level = "debug")]
1109 async fn one_query(
1110 &mut self,
1111 stmt: Statement<Raw>,
1112 sql: String,
1113 lifecycle_timestamps: LifecycleTimestamps,
1114 ends_simple_query: bool,
1115 ) -> Result<State, io::Error> {
1116 const EMPTY_PORTAL: &str = "";
1119 if let Err(e) = self
1120 .adapter_client
1121 .declare(EMPTY_PORTAL.to_string(), stmt, sql)
1122 .await
1123 {
1124 return self
1125 .send_error_and_get_state(e.into_response(Severity::Error))
1126 .await;
1127 }
1128 let portal = self
1129 .adapter_client
1130 .session()
1131 .get_portal_unverified_mut(EMPTY_PORTAL)
1132 .expect("unnamed portal should be present");
1133
1134 *portal.lifecycle_timestamps = Some(lifecycle_timestamps);
1135
1136 let stmt_desc = portal.desc.clone();
1137 if !stmt_desc.param_types.is_empty() {
1138 return self
1139 .send_error_and_get_state(ErrorResponse::error(
1140 SqlState::UNDEFINED_PARAMETER,
1141 "there is no parameter $1",
1142 ))
1143 .await;
1144 }
1145
1146 if let Some(relation_desc) = &stmt_desc.relation_desc {
1148 if !stmt_desc.is_copy {
1149 let formats = vec![Format::Text; stmt_desc.arity()];
1150 self.send(BackendMessage::RowDescription(
1151 message::encode_row_description(relation_desc, &formats),
1152 ))
1153 .await?;
1154 }
1155 }
1156
1157 let result = match self
1158 .adapter_client
1159 .execute(EMPTY_PORTAL.to_string(), self.conn.wait_closed(), None)
1160 .await
1161 {
1162 Ok((response, execute_started)) => {
1163 self.send_execute_response(
1164 response,
1165 stmt_desc.relation_desc,
1166 EMPTY_PORTAL.to_string(),
1167 ExecuteCount::All,
1168 portal_exec_message,
1169 None,
1170 ExecuteTimeout::None,
1171 execute_started,
1172 ends_simple_query,
1173 )
1174 .await
1175 }
1176 Err(e) => {
1177 self.send_pending_notices().await?;
1178 self.send_error_and_get_state(e.into_response(Severity::Error))
1179 .await
1180 }
1181 };
1182
1183 self.adapter_client.session().remove_portal(EMPTY_PORTAL);
1185
1186 result
1187 }
1188
1189 async fn ensure_transaction(
1190 &mut self,
1191 num_stmts: usize,
1192 message_type: &str,
1193 ) -> Result<(), io::Error> {
1194 let start = Instant::now();
1195 if self.txn_needs_commit {
1196 self.commit_transaction().await?;
1197 }
1198 let res = self.adapter_client.start_transaction(Some(num_stmts));
1201 assert_ok!(res);
1202 self.adapter_client
1203 .inner()
1204 .metrics()
1205 .pgwire_ensure_transaction_seconds
1206 .with_label_values(&[message_type])
1207 .observe(start.elapsed().as_secs_f64());
1208 Ok(())
1209 }
1210
1211 async fn maybe_log_message_arrival(&mut self, message: &FrontendMessage) {
1230 if !self
1231 .adapter_client
1232 .statement_arrival_logging_enabled()
1233 .await
1234 {
1235 return;
1236 }
1237 let session = self.adapter_client.session();
1238 let conn_id = session.conn_id();
1239 let session_uuid = session.uuid();
1240 let kind = message.name();
1241 match message {
1242 FrontendMessage::Query { sql } => {
1243 info!(
1244 %conn_id, %session_uuid, kind, sql = %redact_sql_for_logging(sql),
1245 "statement arrival"
1246 );
1247 }
1248 FrontendMessage::Parse { name, sql, .. } => {
1249 info!(
1250 %conn_id, %session_uuid, kind, name, sql = %redact_sql_for_logging(sql),
1251 "statement arrival"
1252 );
1253 }
1254 FrontendMessage::Bind {
1255 portal_name,
1256 statement_name,
1257 raw_params,
1258 ..
1259 } => {
1260 info!(
1261 %conn_id, %session_uuid, kind, portal_name, statement_name,
1262 num_params = raw_params.len(),
1263 "statement arrival"
1264 );
1265 }
1266 FrontendMessage::CopyData(data) => {
1268 info!(%conn_id, %session_uuid, kind, len = data.len(), "statement arrival");
1269 }
1270 FrontendMessage::Password { .. }
1272 | FrontendMessage::RawAuthentication(_)
1273 | FrontendMessage::SASLInitialResponse { .. }
1274 | FrontendMessage::SASLResponse(_) => {
1275 info!(%conn_id, %session_uuid, kind, "statement arrival");
1276 }
1277 FrontendMessage::CopyFail(_) => {
1280 info!(%conn_id, %session_uuid, kind, "statement arrival");
1281 }
1282 FrontendMessage::DescribeStatement { .. }
1285 | FrontendMessage::DescribePortal { .. }
1286 | FrontendMessage::Execute { .. }
1287 | FrontendMessage::Flush
1288 | FrontendMessage::Sync
1289 | FrontendMessage::CloseStatement { .. }
1290 | FrontendMessage::ClosePortal { .. }
1291 | FrontendMessage::Terminate
1292 | FrontendMessage::CopyDone => {
1293 info!(%conn_id, %session_uuid, kind, contents = ?message, "statement arrival");
1299 }
1300 }
1301 }
1302
1303 fn parse_sql<'b>(&self, sql: &'b str) -> Result<Vec<StatementParseResult<'b>>, ErrorResponse> {
1304 let parse_start = Instant::now();
1305 let result = match self.adapter_client.parse(sql) {
1306 Ok(result) => result.map_err(|e| {
1307 let pos = sql[..e.error.pos].chars().count() + 1;
1310 ErrorResponse::error(SqlState::SYNTAX_ERROR, e.error.message).with_position(pos)
1311 }),
1312 Err(msg) => Err(ErrorResponse::error(SqlState::PROGRAM_LIMIT_EXCEEDED, msg)),
1313 };
1314 self.adapter_client
1315 .inner()
1316 .metrics()
1317 .parse_seconds
1318 .observe(parse_start.elapsed().as_secs_f64());
1319 result
1320 }
1321
1322 #[instrument(level = "debug")]
1327 async fn query(&mut self, sql: String, received: EpochMillis) -> Result<State, io::Error> {
1328 let stmts = match self.parse_sql(&sql) {
1330 Ok(stmts) => stmts,
1331 Err(err) => {
1332 self.send_error_and_get_state(err).await?;
1333 return self.ready().await;
1334 }
1335 };
1336
1337 let num_stmts = stmts.len();
1338
1339 for (idx, StatementParseResult { ast: stmt, sql }) in stmts.into_iter().enumerate() {
1341 if self.is_aborted_txn() && !is_txn_exit_stmt(Some(&stmt)) {
1343 self.aborted_txn_error().await?;
1344 break;
1345 }
1346
1347 self.ensure_transaction(num_stmts, "query").await?;
1355
1356 let ends_simple_query = idx + 1 == num_stmts;
1357 match self
1358 .one_query(
1359 stmt,
1360 sql.to_string(),
1361 LifecycleTimestamps { received },
1362 ends_simple_query,
1363 )
1364 .await?
1365 {
1366 State::Ready => (),
1367 State::Drain => break,
1368 State::Done => return Ok(State::Done),
1369 }
1370 }
1371
1372 {
1374 if self.adapter_client.session().transaction().is_implicit() {
1375 self.commit_transaction().await?;
1376 }
1377 }
1378
1379 if num_stmts == 0 {
1380 self.send(BackendMessage::EmptyQueryResponse).await?;
1381 }
1382
1383 self.ready().await
1384 }
1385
1386 #[instrument(level = "debug")]
1387 async fn parse(
1388 &mut self,
1389 name: String,
1390 sql: String,
1391 param_oids: Vec<u32>,
1392 ) -> Result<State, io::Error> {
1393 self.ensure_transaction(1, "parse").await?;
1395
1396 let mut param_types = vec![];
1397 for oid in param_oids {
1398 match mz_pgrepr::Type::from_oid(oid) {
1399 Ok(ty) => match SqlScalarType::try_from(&ty) {
1400 Ok(ty) => param_types.push(Some(ty)),
1401 Err(err) => {
1402 return self
1403 .send_error_and_get_state(ErrorResponse::error(
1404 SqlState::INVALID_PARAMETER_VALUE,
1405 err.to_string(),
1406 ))
1407 .await;
1408 }
1409 },
1410 Err(_) if oid == 0 => param_types.push(None),
1411 Err(e) => {
1412 return self
1413 .send_error_and_get_state(ErrorResponse::error(
1414 SqlState::PROTOCOL_VIOLATION,
1415 e.to_string(),
1416 ))
1417 .await;
1418 }
1419 }
1420 }
1421
1422 let stmts = match self.parse_sql(&sql) {
1423 Ok(stmts) => stmts,
1424 Err(err) => {
1425 return self.send_error_and_get_state(err).await;
1426 }
1427 };
1428 if stmts.len() > 1 {
1429 return self
1430 .send_error_and_get_state(ErrorResponse::error(
1431 SqlState::INTERNAL_ERROR,
1432 "cannot insert multiple commands into a prepared statement",
1433 ))
1434 .await;
1435 }
1436 let (maybe_stmt, sql) = match stmts.into_iter().next() {
1437 None => (None, ""),
1438 Some(StatementParseResult { ast, sql }) => (Some(ast), sql),
1439 };
1440 if self.is_aborted_txn() && !is_txn_exit_stmt(maybe_stmt.as_ref()) {
1441 return self.aborted_txn_error().await;
1442 }
1443 match self
1444 .adapter_client
1445 .prepare(name, maybe_stmt, sql.to_string(), param_types)
1446 .await
1447 {
1448 Ok(()) => {
1449 self.send(BackendMessage::ParseComplete).await?;
1450 Ok(State::Ready)
1451 }
1452 Err(e) => {
1453 self.send_error_and_get_state(e.into_response(Severity::Error))
1454 .await
1455 }
1456 }
1457 }
1458
1459 #[instrument(level = "debug")]
1461 async fn commit_transaction(&mut self) -> Result<(), io::Error> {
1462 self.end_transaction(EndTransactionAction::Commit).await
1463 }
1464
1465 #[instrument(level = "debug")]
1467 async fn rollback_transaction(&mut self) -> Result<(), io::Error> {
1468 self.end_transaction(EndTransactionAction::Rollback).await
1469 }
1470
1471 #[instrument(level = "debug")]
1478 async fn end_transaction(&mut self, action: EndTransactionAction) -> Result<(), io::Error> {
1479 self.txn_needs_commit = false;
1480 match self.adapter_client.end_transaction(action).await {
1481 Ok(
1482 ExecuteResponse::TransactionCommitted { params }
1483 | ExecuteResponse::TransactionRolledBack { params },
1484 ) => {
1485 self.send_parameter_statuses(params).await?;
1486 }
1487 Ok(_) => {}
1488 Err(err) if action == EndTransactionAction::Commit => {
1489 self.send(BackendMessage::ErrorResponse(
1490 err.into_response(Severity::Error),
1491 ))
1492 .await?;
1493 }
1494 Err(_) => {}
1497 }
1498 Ok(())
1499 }
1500
1501 async fn settle_statement(&mut self, ends_simple_query: bool) -> Option<ErrorResponse> {
1507 match self
1508 .adapter_client
1509 .settle_statement(ends_simple_query)
1510 .await
1511 {
1512 Ok(settled) => {
1513 self.reverted_parameters.extend(settled.reverted);
1514 None
1515 }
1516 Err(err) => Some(err.into_response(Severity::Error)),
1517 }
1518 }
1519
1520 async fn send_execution_time(&mut self, time: Option<ExecutionTime>) -> Result<(), io::Error> {
1521 if let Some(notice) =
1522 time.and_then(|time| self.adapter_client.session().execution_time_notice(time))
1523 {
1524 self.send(notice.into_response()).await?;
1525 }
1526 Ok(())
1527 }
1528
1529 #[instrument(level = "debug")]
1532 async fn send_parameter_statuses(
1533 &mut self,
1534 params: BTreeMap<&'static str, String>,
1535 ) -> Result<(), io::Error> {
1536 let notify_set: mz_ore::collections::HashSet<String> = self
1537 .adapter_client
1538 .session()
1539 .vars()
1540 .notify_set()
1541 .map(|v| v.name().to_string())
1542 .collect();
1543
1544 for (name, value) in params
1545 .into_iter()
1546 .filter(|(name, _value)| notify_set.contains(*name))
1547 {
1548 self.send(BackendMessage::ParameterStatus(name, value))
1549 .await?;
1550 }
1551 Ok(())
1552 }
1553
1554 #[instrument(level = "debug")]
1555 async fn bind(
1556 &mut self,
1557 portal_name: String,
1558 statement_name: String,
1559 param_formats: Vec<Format>,
1560 raw_params: Vec<Option<Vec<u8>>>,
1561 result_formats: Vec<Format>,
1562 ) -> Result<State, io::Error> {
1563 self.ensure_transaction(1, "bind").await?;
1565
1566 let aborted_txn = self.is_aborted_txn();
1567 let stmt = match self
1568 .adapter_client
1569 .get_prepared_statement(&statement_name)
1570 .await
1571 {
1572 Ok(stmt) => stmt,
1573 Err(err) => {
1574 return self
1575 .send_error_and_get_state(err.into_response(Severity::Error))
1576 .await;
1577 }
1578 };
1579
1580 let param_types = &stmt.desc().param_types;
1581 if param_types.len() != raw_params.len() {
1582 let message = format!(
1583 "bind message supplies {actual} parameters, \
1584 but prepared statement \"{name}\" requires {expected}",
1585 name = statement_name,
1586 actual = raw_params.len(),
1587 expected = param_types.len()
1588 );
1589 return self
1590 .send_error_and_get_state(ErrorResponse::error(
1591 SqlState::PROTOCOL_VIOLATION,
1592 message,
1593 ))
1594 .await;
1595 }
1596 let param_formats = match pad_formats(param_formats, raw_params.len()) {
1597 Ok(param_formats) => param_formats,
1598 Err(msg) => {
1599 return self
1600 .send_error_and_get_state(ErrorResponse::error(
1601 SqlState::PROTOCOL_VIOLATION,
1602 msg,
1603 ))
1604 .await;
1605 }
1606 };
1607 if aborted_txn && !is_txn_exit_stmt(stmt.stmt()) {
1608 return self.aborted_txn_error().await;
1609 }
1610 let buf = RowArena::new();
1611 let mut params = vec![];
1612 for ((raw_param, mz_typ), format) in raw_params
1613 .into_iter()
1614 .zip_eq(param_types)
1615 .zip_eq(param_formats)
1616 {
1617 let pg_typ = mz_pgrepr::Type::from(mz_typ);
1618 let datum = match raw_param {
1619 None => Datum::Null,
1620 Some(bytes) => match mz_pgrepr::Value::decode(format, &pg_typ, &bytes) {
1621 Ok(param) => match param.into_datum_decode_error(&buf, &pg_typ, "parameter") {
1622 Ok(datum) => datum,
1623 Err(msg) => {
1624 return self
1625 .send_error_and_get_state(ErrorResponse::error(
1626 SqlState::INVALID_PARAMETER_VALUE,
1627 msg,
1628 ))
1629 .await;
1630 }
1631 },
1632 Err(err) => {
1633 let (code, msg) = if err.is::<mz_pgrepr::NulCharacterError>() {
1636 (SqlState::CHARACTER_NOT_IN_REPERTOIRE, err.to_string())
1637 } else {
1638 (
1639 SqlState::INVALID_PARAMETER_VALUE,
1640 format!("unable to decode parameter: {}", err),
1641 )
1642 };
1643 return self
1644 .send_error_and_get_state(ErrorResponse::error(code, msg))
1645 .await;
1646 }
1647 },
1648 };
1649 params.push((datum, mz_typ.clone()))
1650 }
1651
1652 let result_formats = match pad_formats(
1653 result_formats,
1654 stmt.desc()
1655 .relation_desc
1656 .clone()
1657 .map(|desc| desc.typ().column_types.len())
1658 .unwrap_or(0),
1659 ) {
1660 Ok(result_formats) => result_formats,
1661 Err(msg) => {
1662 return self
1663 .send_error_and_get_state(ErrorResponse::error(
1664 SqlState::PROTOCOL_VIOLATION,
1665 msg,
1666 ))
1667 .await;
1668 }
1669 };
1670
1671 if !stmt.stmt().map_or(false, |stmt| match stmt {
1674 Statement::Copy(CopyStatement {
1675 direction: CopyDirection::To,
1676 ..
1677 }) => true,
1678 Statement::Copy(CopyStatement {
1679 direction: CopyDirection::From,
1680 target: CopyTarget::Expr(_),
1684 ..
1685 }) => true,
1686 _ => false,
1687 }) {
1688 if let Some(desc) = stmt.desc().relation_desc.clone() {
1689 for (format, ty) in result_formats.iter().zip_eq(desc.iter_types()) {
1690 if let Format::Binary = format {
1691 if let Err(msg) = mz_pgrepr::Value::binary_encoding_error(&ty.scalar_type) {
1692 return self
1693 .send_error_and_get_state(ErrorResponse::error(
1694 SqlState::UNDEFINED_FUNCTION,
1695 msg,
1696 ))
1697 .await;
1698 }
1699 }
1700 }
1701 }
1702 }
1703
1704 let desc = stmt.desc().clone();
1705 let logging = Arc::clone(stmt.logging());
1706 let stmt_ast = stmt.stmt().cloned();
1707 let state_revision = stmt.state_revision;
1708 if let Err(err) = self.adapter_client.session().set_portal(
1709 portal_name,
1710 desc,
1711 stmt_ast,
1712 logging,
1713 params,
1714 result_formats,
1715 state_revision,
1716 ) {
1717 return self
1718 .send_error_and_get_state(err.into_response(Severity::Error))
1719 .await;
1720 }
1721
1722 self.send(BackendMessage::BindComplete).await?;
1723 Ok(State::Ready)
1724 }
1725
1726 fn execute(
1729 &mut self,
1730 portal_name: String,
1731 max_rows: ExecuteCount,
1732 get_response: GetResponse,
1733 fetch_portal_name: Option<String>,
1734 timeout: ExecuteTimeout,
1735 outer_ctx_extra: Option<ExecuteContextGuard>,
1736 received: Option<EpochMillis>,
1737 ends_simple_query: bool,
1738 ) -> BoxFuture<'_, Result<State, io::Error>> {
1739 async move {
1740 let aborted_txn = self.is_aborted_txn();
1741
1742 let portal = match self
1744 .adapter_client
1745 .session()
1746 .get_portal_unverified_mut(&portal_name)
1747 {
1748 Some(portal) => portal,
1749 None => {
1750 let msg = format!("portal {} does not exist", portal_name.quoted());
1751 if let Some(outer_ctx_extra) = outer_ctx_extra {
1752 self.adapter_client.retire_execute(
1753 outer_ctx_extra,
1754 StatementEndedExecutionReason::Errored { error: msg.clone() },
1755 );
1756 }
1757 return self
1758 .send_error_and_get_state(ErrorResponse::error(
1759 SqlState::INVALID_CURSOR_NAME,
1760 msg,
1761 ))
1762 .await;
1763 }
1764 };
1765
1766 *portal.lifecycle_timestamps = received.map(LifecycleTimestamps::new);
1767
1768 let txn_exit_stmt = is_txn_exit_stmt(portal.stmt.as_deref());
1770 if aborted_txn && !txn_exit_stmt {
1771 if let Some(outer_ctx_extra) = outer_ctx_extra {
1772 self.adapter_client.retire_execute(
1773 outer_ctx_extra,
1774 StatementEndedExecutionReason::Errored {
1775 error: ABORTED_TXN_MSG.to_string(),
1776 },
1777 );
1778 }
1779 return self.aborted_txn_error().await;
1780 }
1781
1782 let row_desc = portal.desc.relation_desc.clone();
1783 match portal.state {
1784 PortalState::NotStarted => {
1785 self.ensure_transaction(1, "execute").await?;
1787 match self
1788 .adapter_client
1789 .execute(
1790 portal_name.clone(),
1791 self.conn.wait_closed(),
1792 outer_ctx_extra,
1793 )
1794 .await
1795 {
1796 Ok((response, execute_started)) => {
1797 self.send_execute_response(
1798 response,
1799 row_desc,
1800 portal_name,
1801 max_rows,
1802 get_response,
1803 fetch_portal_name,
1804 timeout,
1805 execute_started,
1806 ends_simple_query,
1807 )
1808 .await
1809 }
1810 Err(e) => {
1811 self.send_pending_notices().await?;
1812 self.send_error_and_get_state(e.into_response(Severity::Error))
1813 .await
1814 }
1815 }
1816 }
1817 PortalState::InProgress(rows) => {
1818 let rows = rows.take().expect("InProgress rows must be populated");
1819 let (result, statement_ended_execution_reason) = match self
1820 .send_rows(
1821 row_desc.expect("portal missing row desc on resumption"),
1822 portal_name,
1823 rows,
1824 max_rows,
1825 get_response,
1826 fetch_portal_name,
1827 timeout,
1828 ends_simple_query,
1829 )
1830 .await
1831 {
1832 Err(e) => {
1833 (Err(e), StatementEndedExecutionReason::Canceled)
1836 }
1837 Ok((ok, SendRowsEndedReason::Canceled)) => {
1838 (Ok(ok), StatementEndedExecutionReason::Canceled)
1839 }
1840 Ok((
1853 ok,
1854 SendRowsEndedReason::Success {
1855 result_size: _,
1856 rows_returned: _,
1857 },
1858 )) => (
1859 Ok(ok),
1860 StatementEndedExecutionReason::Success {
1861 result_size: None,
1862 rows_returned: None,
1863 execution_strategy: None,
1864 },
1865 ),
1866 Ok((ok, SendRowsEndedReason::Errored { error })) => {
1867 (Ok(ok), StatementEndedExecutionReason::Errored { error })
1868 }
1869 };
1870 if let Some(outer_ctx_extra) = outer_ctx_extra {
1871 self.adapter_client
1872 .retire_execute(outer_ctx_extra, statement_ended_execution_reason);
1873 }
1874 result
1875 }
1876 PortalState::Completed(Some(tag)) => {
1883 let tag = tag.to_string();
1884 if let Some(outer_ctx_extra) = outer_ctx_extra {
1885 self.adapter_client.retire_execute(
1886 outer_ctx_extra,
1887 StatementEndedExecutionReason::Success {
1888 result_size: None,
1889 rows_returned: None,
1890 execution_strategy: None,
1891 },
1892 );
1893 }
1894 if let Some(err) = self.settle_statement(ends_simple_query).await {
1895 return self.send_error_and_get_state(err).await;
1896 }
1897 self.send(BackendMessage::CommandComplete { tag }).await?;
1898 Ok(State::Ready)
1899 }
1900 PortalState::Completed(None) => {
1901 let error = format!(
1902 "portal {} cannot be run",
1903 Ident::new_unchecked(portal_name).to_ast_string_stable()
1904 );
1905 if let Some(outer_ctx_extra) = outer_ctx_extra {
1906 self.adapter_client.retire_execute(
1907 outer_ctx_extra,
1908 StatementEndedExecutionReason::Errored {
1909 error: error.clone(),
1910 },
1911 );
1912 }
1913 self.send_error_and_get_state(ErrorResponse::error(
1914 SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE,
1915 error,
1916 ))
1917 .await
1918 }
1919 }
1920 }
1921 .instrument(debug_span!("execute"))
1922 .boxed()
1923 }
1924
1925 #[instrument(level = "debug")]
1926 async fn describe_statement(&mut self, name: &str) -> Result<State, io::Error> {
1927 self.ensure_transaction(1, "describe_statement").await?;
1929
1930 let stmt = match self.adapter_client.get_prepared_statement(name).await {
1931 Ok(stmt) => stmt,
1932 Err(err) => {
1933 return self
1934 .send_error_and_get_state(err.into_response(Severity::Error))
1935 .await;
1936 }
1937 };
1938 let parameter_desc = BackendMessage::ParameterDescription(
1940 stmt.desc()
1941 .param_types
1942 .iter()
1943 .map(mz_pgrepr::Type::from)
1944 .collect(),
1945 );
1946 let formats = vec![Format::Text; stmt.desc().arity()];
1950 let row_desc = describe_rows(stmt.desc(), &formats);
1951 self.send_all([parameter_desc, row_desc]).await?;
1952 Ok(State::Ready)
1953 }
1954
1955 #[instrument(level = "debug")]
1956 async fn describe_portal(&mut self, name: &str) -> Result<State, io::Error> {
1957 self.ensure_transaction(1, "describe_portal").await?;
1959
1960 let session = self.adapter_client.session();
1961 let row_desc = session
1962 .get_portal_unverified(name)
1963 .map(|portal| describe_rows(&portal.desc, &portal.result_formats));
1964 match row_desc {
1965 Some(row_desc) => {
1966 self.send(row_desc).await?;
1967 Ok(State::Ready)
1968 }
1969 None => {
1970 self.send_error_and_get_state(ErrorResponse::error(
1971 SqlState::INVALID_CURSOR_NAME,
1972 format!("portal {} does not exist", name.quoted()),
1973 ))
1974 .await
1975 }
1976 }
1977 }
1978
1979 #[instrument(level = "debug")]
1980 async fn close_statement(&mut self, name: String) -> Result<State, io::Error> {
1981 self.adapter_client
1982 .session()
1983 .remove_prepared_statement(&name);
1984 self.send(BackendMessage::CloseComplete).await?;
1985 Ok(State::Ready)
1986 }
1987
1988 #[instrument(level = "debug")]
1989 async fn close_portal(&mut self, name: String) -> Result<State, io::Error> {
1990 self.adapter_client.session().remove_portal(&name);
1991 self.send(BackendMessage::CloseComplete).await?;
1992 Ok(State::Ready)
1993 }
1994
1995 fn complete_portal_after_close(&mut self, name: &str) {
2001 if let Some(portal) = self
2002 .adapter_client
2003 .session()
2004 .get_portal_unverified_mut(name)
2005 {
2006 *portal.state = PortalState::Completed(None);
2007 }
2008 }
2009
2010 fn complete_portal_after_declare(&mut self, name: &str) {
2016 match self
2017 .adapter_client
2018 .session()
2019 .get_portal_unverified_mut(name)
2020 {
2021 Some(portal) => *portal.state = PortalState::Completed(None),
2022 None => {
2023 mz_ore::soft_panic_or_log!("portal {} vanished across a DECLARE", name.quoted())
2024 }
2025 }
2026 }
2027
2028 async fn fetch(
2029 &mut self,
2030 name: String,
2031 count: Option<FetchDirection>,
2032 max_rows: ExecuteCount,
2033 fetch_portal_name: Option<String>,
2034 timeout: ExecuteTimeout,
2035 ctx_extra: ExecuteContextGuard,
2036 ends_simple_query: bool,
2037 ) -> Result<State, io::Error> {
2038 let count = count.unwrap_or(FetchDirection::ForwardCount(1));
2041
2042 let count = match (max_rows, count) {
2055 (ExecuteCount::Count(max_rows), FetchDirection::ForwardCount(count)) => {
2056 let count = usize::cast_from(count);
2057 if max_rows < count {
2058 let msg = "Execute with max_rows < a FETCH's count is not supported";
2059 self.adapter_client.retire_execute(
2060 ctx_extra,
2061 StatementEndedExecutionReason::Errored {
2062 error: msg.to_string(),
2063 },
2064 );
2065 return self
2066 .send_error_and_get_state(ErrorResponse::error(
2067 SqlState::FEATURE_NOT_SUPPORTED,
2068 msg,
2069 ))
2070 .await;
2071 }
2072 ExecuteCount::Count(count)
2073 }
2074 (ExecuteCount::Count(_), FetchDirection::ForwardAll) => {
2075 let msg = "Execute with max_rows of a FETCH ALL is not supported";
2076 self.adapter_client.retire_execute(
2077 ctx_extra,
2078 StatementEndedExecutionReason::Errored {
2079 error: msg.to_string(),
2080 },
2081 );
2082 return self
2083 .send_error_and_get_state(ErrorResponse::error(
2084 SqlState::FEATURE_NOT_SUPPORTED,
2085 msg,
2086 ))
2087 .await;
2088 }
2089 (ExecuteCount::All, FetchDirection::ForwardAll) => ExecuteCount::All,
2090 (ExecuteCount::All, FetchDirection::ForwardCount(count)) => {
2091 ExecuteCount::Count(usize::cast_from(count))
2092 }
2093 };
2094 let cursor_name = name.to_string();
2095 self.execute(
2096 cursor_name,
2097 count,
2098 fetch_message,
2099 fetch_portal_name,
2100 timeout,
2101 Some(ctx_extra),
2102 None,
2103 ends_simple_query,
2104 )
2105 .await
2106 }
2107
2108 async fn flush(&mut self) -> Result<State, io::Error> {
2109 self.conn.flush().await?;
2110 Ok(State::Ready)
2111 }
2112
2113 #[instrument(level = "debug")]
2118 async fn send<M>(&mut self, message: M) -> Result<(), io::Error>
2119 where
2120 M: Into<BackendMessage>,
2121 {
2122 let message: BackendMessage = message.into();
2123 let is_error =
2124 matches!(&message, BackendMessage::ErrorResponse(e) if e.severity.is_error());
2125
2126 self.conn.send(message).await?;
2127
2128 if is_error {
2135 self.conn.flush().await?;
2136 }
2137
2138 Ok(())
2139 }
2140
2141 #[instrument(level = "debug")]
2142 pub async fn send_all(
2143 &mut self,
2144 messages: impl IntoIterator<Item = BackendMessage>,
2145 ) -> Result<(), io::Error> {
2146 for m in messages {
2147 self.send(m).await?;
2148 }
2149 Ok(())
2150 }
2151
2152 #[instrument(level = "debug")]
2153 async fn sync(&mut self) -> Result<State, io::Error> {
2154 if self.adapter_client.session().transaction().is_implicit() {
2156 self.commit_transaction().await?;
2157 }
2158 self.ready().await
2159 }
2160
2161 #[instrument(level = "debug")]
2162 async fn ready(&mut self) -> Result<State, io::Error> {
2163 let reverted_parameters = mem::take(&mut self.reverted_parameters);
2164 self.send_parameter_statuses(reverted_parameters).await?;
2165 let txn_state = self.adapter_client.session().transaction().into();
2166 self.send(BackendMessage::ReadyForQuery(txn_state)).await?;
2167 self.flush().await
2168 }
2169
2170 #[allow(clippy::too_many_arguments)]
2171 #[instrument(level = "debug")]
2172 async fn send_execute_response(
2173 &mut self,
2174 response: ExecuteResponse,
2175 row_desc: Option<RelationDesc>,
2176 portal_name: String,
2177 max_rows: ExecuteCount,
2178 get_response: GetResponse,
2179 fetch_portal_name: Option<String>,
2180 timeout: ExecuteTimeout,
2181 execute_started: Instant,
2182 ends_simple_query: bool,
2183 ) -> Result<State, io::Error> {
2184 let execution_time = self
2185 .adapter_client
2186 .session()
2187 .maybe_mark_staged(ExecutionTime::completed(execute_started.elapsed()));
2188 self.send_pending_notices().await?;
2189 let mut tag = response.tag();
2190
2191 macro_rules! command_complete {
2192 () => {{
2193 if let Some(err) = self.settle_statement(ends_simple_query).await {
2194 return self.send_error_and_get_state(err).await;
2195 }
2196 self.send_execution_time(Some(execution_time)).await?;
2197 self.send(BackendMessage::CommandComplete {
2198 tag: tag
2199 .take()
2200 .expect("command_complete only called on tag-generating results"),
2201 })
2202 .await?;
2203 Ok(State::Ready)
2204 }};
2205 }
2206
2207 let r = match response {
2208 ExecuteResponse::ClosedCursor => {
2209 self.complete_portal_after_close(&portal_name);
2210 command_complete!()
2211 }
2212 ExecuteResponse::DeclaredCursor => {
2213 self.complete_portal_after_declare(&portal_name);
2214 command_complete!()
2215 }
2216 ExecuteResponse::EmptyQuery => {
2217 self.send(BackendMessage::EmptyQueryResponse).await?;
2218 Ok(State::Ready)
2219 }
2220 ExecuteResponse::Fetch {
2221 name,
2222 count,
2223 timeout,
2224 ctx_extra,
2225 } => {
2226 self.fetch(
2227 name,
2228 count,
2229 max_rows,
2230 Some(portal_name.to_string()),
2231 timeout,
2232 ctx_extra,
2233 ends_simple_query,
2234 )
2235 .await
2236 }
2237 ExecuteResponse::SendingRowsStreaming {
2238 rows,
2239 instance_id,
2240 strategy,
2241 } => {
2242 let row_desc = row_desc
2243 .expect("missing row description for ExecuteResponse::SendingRowsStreaming");
2244
2245 let span = tracing::debug_span!("sending_rows_streaming");
2246
2247 self.send_rows(
2248 row_desc,
2249 portal_name,
2250 InProgressRows::new(RecordFirstRowStream::new(
2251 Box::new(rows),
2252 execute_started,
2253 &self.adapter_client,
2254 Some(instance_id),
2255 Some(strategy),
2256 )),
2257 max_rows,
2258 get_response,
2259 fetch_portal_name,
2260 timeout,
2261 ends_simple_query,
2262 )
2263 .instrument(span)
2264 .await
2265 .map(|(state, _)| state)
2266 }
2267 ExecuteResponse::SendingRowsImmediate { rows } => {
2268 let row_desc = row_desc
2269 .expect("missing row description for ExecuteResponse::SendingRowsImmediate");
2270
2271 let span = tracing::debug_span!("sending_rows_immediate");
2272
2273 let stream =
2274 futures::stream::once(futures::future::ready(PeekResponseUnary::Rows(rows)));
2275 self.send_rows(
2276 row_desc,
2277 portal_name,
2278 InProgressRows::new(RecordFirstRowStream::new(
2279 Box::new(stream),
2280 execute_started,
2281 &self.adapter_client,
2282 None,
2283 Some(StatementExecutionStrategy::Constant),
2284 )),
2285 max_rows,
2286 get_response,
2287 fetch_portal_name,
2288 timeout,
2289 ends_simple_query,
2290 )
2291 .instrument(span)
2292 .await
2293 .map(|(state, _)| state)
2294 }
2295 ExecuteResponse::SetVariable { name, .. } => {
2296 let qn = name.to_string();
2299 let msg = if let Some(var) = self
2300 .adapter_client
2301 .session()
2302 .vars_mut()
2303 .notify_set()
2304 .find(|v| v.name() == qn)
2305 {
2306 Some(BackendMessage::ParameterStatus(var.name(), var.value()))
2307 } else {
2308 None
2309 };
2310 if let Some(msg) = msg {
2311 self.send(msg).await?;
2312 }
2313 command_complete!()
2314 }
2315 ExecuteResponse::Subscribing {
2316 rx,
2317 ctx_extra,
2318 instance_id,
2319 } => {
2320 if fetch_portal_name.is_none() {
2321 let mut msg = ErrorResponse::notice(
2322 SqlState::WARNING,
2323 "streaming SUBSCRIBE rows directly requires a client that does not buffer output",
2324 );
2325 if self.adapter_client.session().vars().application_name() == "psql" {
2326 msg.hint = Some(
2327 "Wrap your SUBSCRIBE statement in `COPY (SUBSCRIBE ...) TO STDOUT`."
2328 .into(),
2329 )
2330 }
2331 self.send(msg).await?;
2332 self.conn.flush().await?;
2333 }
2334 let row_desc =
2335 row_desc.expect("missing row description for ExecuteResponse::Subscribing");
2336 let (result, statement_ended_execution_reason) = match self
2337 .send_rows(
2338 row_desc,
2339 portal_name,
2340 InProgressRows::new(
2341 RecordFirstRowStream::new(
2342 rx,
2343 execute_started,
2344 &self.adapter_client,
2345 Some(instance_id),
2346 None,
2347 )
2348 .without_execution_time(),
2349 ),
2350 max_rows,
2351 get_response,
2352 fetch_portal_name,
2353 timeout,
2354 ends_simple_query,
2355 )
2356 .await
2357 {
2358 Err(e) => {
2359 (Err(e), StatementEndedExecutionReason::Canceled)
2362 }
2363 Ok((ok, SendRowsEndedReason::Canceled)) => {
2364 (Ok(ok), StatementEndedExecutionReason::Canceled)
2365 }
2366 Ok((
2367 ok,
2368 SendRowsEndedReason::Success {
2369 result_size,
2370 rows_returned,
2371 },
2372 )) => (
2373 Ok(ok),
2374 StatementEndedExecutionReason::Success {
2375 result_size: Some(result_size),
2376 rows_returned: Some(rows_returned),
2377 execution_strategy: None,
2378 },
2379 ),
2380 Ok((ok, SendRowsEndedReason::Errored { error })) => {
2381 (Ok(ok), StatementEndedExecutionReason::Errored { error })
2382 }
2383 };
2384 self.adapter_client
2385 .retire_execute(ctx_extra, statement_ended_execution_reason);
2386 return result;
2387 }
2388 ExecuteResponse::CopyTo { format, resp } => {
2389 let row_desc =
2390 row_desc.expect("missing row description for ExecuteResponse::CopyTo");
2391 match *resp {
2392 ExecuteResponse::Subscribing {
2393 rx,
2394 ctx_extra,
2395 instance_id,
2396 } => {
2397 let (result, statement_ended_execution_reason) = match self
2398 .copy_rows(
2399 format,
2400 row_desc,
2401 RecordFirstRowStream::new(
2402 rx,
2403 execute_started,
2404 &self.adapter_client,
2405 Some(instance_id),
2406 None,
2407 ),
2408 ends_simple_query,
2409 )
2410 .await
2411 {
2412 Err(e) => {
2413 (Err(e), StatementEndedExecutionReason::Canceled)
2416 }
2417 Ok((
2418 state,
2419 SendRowsEndedReason::Success {
2420 result_size,
2421 rows_returned,
2422 },
2423 )) => (
2424 Ok(state),
2425 StatementEndedExecutionReason::Success {
2426 result_size: Some(result_size),
2427 rows_returned: Some(rows_returned),
2428 execution_strategy: None,
2429 },
2430 ),
2431 Ok((state, SendRowsEndedReason::Errored { error })) => {
2432 (Ok(state), StatementEndedExecutionReason::Errored { error })
2433 }
2434 Ok((state, SendRowsEndedReason::Canceled)) => {
2435 (Ok(state), StatementEndedExecutionReason::Canceled)
2436 }
2437 };
2438 self.adapter_client
2439 .retire_execute(ctx_extra, statement_ended_execution_reason);
2440 return result;
2441 }
2442 ExecuteResponse::SendingRowsStreaming {
2443 rows,
2444 instance_id,
2445 strategy,
2446 } => {
2447 return self
2452 .copy_rows(
2453 format,
2454 row_desc,
2455 RecordFirstRowStream::new(
2456 Box::new(rows),
2457 execute_started,
2458 &self.adapter_client,
2459 Some(instance_id),
2460 Some(strategy),
2461 ),
2462 ends_simple_query,
2463 )
2464 .await
2465 .map(|(state, _)| state);
2466 }
2467 ExecuteResponse::SendingRowsImmediate { rows } => {
2468 let span = tracing::debug_span!("sending_rows_immediate");
2469
2470 let rows = futures::stream::once(futures::future::ready(
2471 PeekResponseUnary::Rows(rows),
2472 ));
2473 return self
2478 .copy_rows(
2479 format,
2480 row_desc,
2481 RecordFirstRowStream::new(
2482 Box::new(rows),
2483 execute_started,
2484 &self.adapter_client,
2485 None,
2486 Some(StatementExecutionStrategy::Constant),
2487 ),
2488 ends_simple_query,
2489 )
2490 .instrument(span)
2491 .await
2492 .map(|(state, _)| state);
2493 }
2494 _ => {
2495 return self
2496 .send_error_and_get_state(ErrorResponse::error(
2497 SqlState::INTERNAL_ERROR,
2498 "unsupported COPY response type".to_string(),
2499 ))
2500 .await;
2501 }
2502 };
2503 }
2504 ExecuteResponse::CopyFrom {
2505 target_id,
2506 target_name,
2507 columns,
2508 params,
2509 ctx_extra,
2510 } => {
2511 let row_desc =
2512 row_desc.expect("missing row description for ExecuteResponse::CopyFrom");
2513 self.copy_from(
2514 target_id,
2515 target_name,
2516 columns,
2517 params,
2518 row_desc,
2519 ctx_extra,
2520 ends_simple_query,
2521 )
2522 .await
2523 }
2524 ExecuteResponse::TransactionCommitted { params }
2525 | ExecuteResponse::TransactionRolledBack { params }
2526 | ExecuteResponse::DiscardedAll { params } => {
2527 self.send_parameter_statuses(params).await?;
2528 command_complete!()
2529 }
2530
2531 ExecuteResponse::AlteredDefaultPrivileges
2532 | ExecuteResponse::AlteredObject(..)
2533 | ExecuteResponse::AlteredRole
2534 | ExecuteResponse::AlteredSystemConfiguration
2535 | ExecuteResponse::CreatedCluster { .. }
2536 | ExecuteResponse::CreatedClusterReplica { .. }
2537 | ExecuteResponse::CreatedConnection { .. }
2538 | ExecuteResponse::CreatedDatabase { .. }
2539 | ExecuteResponse::CreatedIndex { .. }
2540 | ExecuteResponse::CreatedMetricSink { .. }
2541 | ExecuteResponse::CreatedIntrospectionSubscribe
2542 | ExecuteResponse::CreatedMaterializedView { .. }
2543 | ExecuteResponse::CreatedRole
2544 | ExecuteResponse::CreatedSchema { .. }
2545 | ExecuteResponse::CreatedSecret { .. }
2546 | ExecuteResponse::CreatedSink { .. }
2547 | ExecuteResponse::CreatedSource { .. }
2548 | ExecuteResponse::CreatedTable { .. }
2549 | ExecuteResponse::CreatedType
2550 | ExecuteResponse::CreatedView { .. }
2551 | ExecuteResponse::CreatedViews { .. }
2552 | ExecuteResponse::CreatedNetworkPolicy
2553 | ExecuteResponse::Comment
2554 | ExecuteResponse::Deallocate { .. }
2555 | ExecuteResponse::Deleted(..)
2556 | ExecuteResponse::DiscardedTemp
2557 | ExecuteResponse::DroppedObject(_)
2558 | ExecuteResponse::DroppedOwned
2559 | ExecuteResponse::GrantedPrivilege
2560 | ExecuteResponse::GrantedRole
2561 | ExecuteResponse::Inserted(..)
2562 | ExecuteResponse::Copied(..)
2563 | ExecuteResponse::Prepare
2564 | ExecuteResponse::Raised
2565 | ExecuteResponse::ReassignOwned
2566 | ExecuteResponse::RevokedPrivilege
2567 | ExecuteResponse::RevokedRole
2568 | ExecuteResponse::StartedTransaction { .. }
2569 | ExecuteResponse::Updated(..)
2570 | ExecuteResponse::ValidatedConnection => {
2571 command_complete!()
2572 }
2573 };
2574
2575 assert_none!(tag, "tag created but not consumed: {:?}", tag);
2576 r
2577 }
2578
2579 #[allow(clippy::too_many_arguments)]
2580 #[mz_ore::instrument(level = "debug")]
2582 async fn send_rows(
2583 &mut self,
2584 row_desc: RelationDesc,
2585 portal_name: String,
2586 mut rows: InProgressRows,
2587 max_rows: ExecuteCount,
2588 get_response: GetResponse,
2589 fetch_portal_name: Option<String>,
2590 timeout: ExecuteTimeout,
2591 ends_simple_query: bool,
2592 ) -> Result<(State, SendRowsEndedReason), io::Error> {
2593 let result_format_portal_name: &str = if let Some(ref name) = fetch_portal_name {
2596 name
2597 } else {
2598 &portal_name
2599 };
2600 let result_formats = self
2601 .adapter_client
2602 .session()
2603 .get_portal_unverified(result_format_portal_name)
2604 .expect("valid fetch portal name for send rows")
2605 .result_formats
2606 .clone();
2607
2608 let (mut wait_once, mut deadline) = match timeout {
2609 ExecuteTimeout::None => (false, None),
2610 ExecuteTimeout::Seconds(t) => (
2611 false,
2612 Some(tokio::time::Instant::now() + tokio::time::Duration::from_secs_f64(t)),
2613 ),
2614 ExecuteTimeout::WaitOnce => (true, None),
2615 };
2616
2617 {
2619 let portal_name_desc = &self
2620 .adapter_client
2621 .session()
2622 .get_portal_unverified(portal_name.as_str())
2623 .expect("portal should exist")
2624 .desc
2625 .relation_desc;
2626 if let Some(portal_name_desc) = portal_name_desc {
2627 soft_assert_eq_or_log!(portal_name_desc, &row_desc);
2628 }
2629 if let Some(fetch_portal_name) = &fetch_portal_name {
2630 let fetch_portal_desc = &self
2631 .adapter_client
2632 .session()
2633 .get_portal_unverified(fetch_portal_name)
2634 .expect("portal should exist")
2635 .desc
2636 .relation_desc;
2637 if let Some(fetch_portal_desc) = fetch_portal_desc {
2638 soft_assert_eq_or_log!(fetch_portal_desc, &row_desc);
2639 }
2640 }
2641 }
2642
2643 self.conn.set_encode_state(
2644 row_desc
2645 .typ()
2646 .column_types
2647 .iter()
2648 .map(|ty| mz_pgrepr::Type::from(&ty.scalar_type))
2649 .zip_eq(result_formats)
2650 .collect(),
2651 self.adapter_client.session().vars().text_encode_settings(),
2652 );
2653
2654 let mut total_sent_rows = 0;
2655 let mut total_sent_bytes = 0;
2656 let mut want_rows = match max_rows {
2658 ExecuteCount::All => usize::MAX,
2659 ExecuteCount::Count(count) => count,
2660 };
2661
2662 loop {
2664 let batch = if rows.current.is_some() {
2667 FetchResult::Rows(rows.current.take())
2668 } else if want_rows == 0 {
2669 FetchResult::Rows(None)
2670 } else {
2671 let notice_fut = self.adapter_client.session().recv_notice();
2672 tokio::select! {
2687 biased;
2688 err = self.conn.wait_closed() => return Err(err),
2689 batch = rows.remaining.recv() => match batch {
2690 None => FetchResult::Rows(None),
2691 Some(PeekResponseUnary::Rows(rows)) => FetchResult::Rows(Some(rows)),
2692 Some(PeekResponseUnary::Error(err)) => {
2693 FetchResult::Error(err.into_response(Severity::Error))
2694 }
2695 Some(PeekResponseUnary::DependencyDropped(dep)) => {
2696 FetchResult::Error(
2697 dep.to_concurrent_dependency_drop()
2698 .into_response(Severity::Error),
2699 )
2700 }
2701 Some(PeekResponseUnary::Canceled) => FetchResult::Canceled,
2702 },
2703 notice = notice_fut => {
2704 FetchResult::Notice(notice)
2705 }
2706 _ = time::sleep_until(
2707 deadline.unwrap_or_else(tokio::time::Instant::now),
2708 ), if deadline.is_some() => FetchResult::Rows(None),
2709 }
2710 };
2711
2712 match batch {
2713 FetchResult::Rows(None) => break,
2714 FetchResult::Rows(Some(mut batch_rows)) => {
2715 if let Err(err) = verify_datum_desc(&row_desc, &mut batch_rows) {
2716 let msg = err.to_string();
2717 return self
2718 .send_error_and_get_state(err.into_response(Severity::Error))
2719 .await
2720 .map(|state| (state, SendRowsEndedReason::Errored { error: msg }));
2721 }
2722
2723 if wait_once && batch_rows.peek().is_some() {
2727 deadline = Some(tokio::time::Instant::now());
2728 wait_once = false;
2729 }
2730
2731 let mut sent_rows = 0;
2733 let mut sent_bytes = 0;
2734 let messages = (&mut batch_rows)
2735 .map(|row| {
2740 let row_len = row.byte_len();
2741 let values = mz_pgrepr::values_from_row(row, row_desc.typ());
2742 (row_len, BackendMessage::DataRow(values))
2743 })
2744 .inspect(|(row_len, _)| {
2745 sent_bytes += row_len;
2746 sent_rows += 1
2747 })
2748 .map(|(_row_len, row)| row)
2749 .take(want_rows);
2750 self.send_all(messages).await?;
2751
2752 total_sent_rows += sent_rows;
2753 total_sent_bytes += sent_bytes;
2754 want_rows -= sent_rows;
2755
2756 if want_rows == 0 {
2759 if batch_rows.peek().is_some() {
2760 rows.current = Some(batch_rows);
2761 }
2762 break;
2763 }
2764
2765 self.conn.flush().await?;
2766 }
2767 FetchResult::Notice(notice) => {
2768 self.send(notice.into_response()).await?;
2769 self.conn.flush().await?;
2770 }
2771 FetchResult::Error(err) => {
2772 let text = err.message.clone();
2773 return self
2774 .send_error_and_get_state(err)
2775 .await
2776 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2777 }
2778 FetchResult::Canceled => {
2779 return self
2780 .send_error_and_get_state(ErrorResponse::error(
2781 SqlState::QUERY_CANCELED,
2782 "canceling statement due to user request",
2783 ))
2784 .await
2785 .map(|state| (state, SendRowsEndedReason::Canceled));
2786 }
2787 }
2788 }
2789
2790 let execution_time = rows
2791 .remaining
2792 .take_execution_time()
2793 .map(|time| self.adapter_client.session().maybe_mark_staged(time));
2794 let portal = self
2795 .adapter_client
2796 .session()
2797 .get_portal_unverified_mut(&portal_name)
2798 .expect("valid portal name for send rows");
2799
2800 let saw_rows = rows.remaining.saw_rows;
2801 let no_more_rows = rows.no_more_rows();
2802 let metric_recorded = rows.remaining.metric_recorded;
2803 let recorded_first_row_instant = rows.remaining.recorded_first_row_instant;
2804
2805 if no_more_rows && !metric_recorded {
2806 rows.remaining.metric_recorded = true;
2807 }
2808
2809 *portal.state = PortalState::InProgress(Some(rows));
2812
2813 let fetch_portal = fetch_portal_name.map(|name| {
2814 self.adapter_client
2815 .session()
2816 .get_portal_unverified_mut(&name)
2817 .expect("valid fetch portal")
2818 });
2819 let response_message = get_response(max_rows, total_sent_rows, fetch_portal);
2820 if no_more_rows && !metric_recorded {
2823 let statement_type = if let Some(stmt) = &self
2824 .adapter_client
2825 .session()
2826 .get_portal_unverified(&portal_name)
2827 .expect("valid portal name for send_rows")
2828 .stmt
2829 {
2830 metrics::statement_type_label_value(stmt.deref())
2831 } else {
2832 "no-statement"
2833 };
2834 let duration = if saw_rows {
2835 recorded_first_row_instant
2836 .expect("recorded_first_row_instant because saw_rows")
2837 .elapsed()
2838 } else {
2839 Duration::ZERO
2843 };
2844 self.adapter_client
2845 .inner()
2846 .metrics()
2847 .result_rows_first_to_last_byte_seconds
2848 .with_label_values(&[statement_type])
2849 .observe(duration.as_secs_f64());
2850 }
2851
2852 let state = match self.settle_statement(ends_simple_query).await {
2854 Some(err) => self.send_error_and_get_state(err).await?,
2855 None => {
2856 self.send_execution_time(execution_time).await?;
2857 self.send(response_message).await?;
2858 State::Ready
2859 }
2860 };
2861
2862 Ok((
2863 state,
2864 SendRowsEndedReason::Success {
2865 result_size: u64::cast_from(total_sent_bytes),
2866 rows_returned: u64::cast_from(total_sent_rows),
2867 },
2868 ))
2869 }
2870
2871 #[mz_ore::instrument(level = "debug")]
2872 async fn copy_rows(
2873 &mut self,
2874 format: CopyFormat,
2875 row_desc: RelationDesc,
2876 mut stream: RecordFirstRowStream,
2877 ends_simple_query: bool,
2878 ) -> Result<(State, SendRowsEndedReason), io::Error> {
2879 let (row_format, encode_format) = match format {
2880 CopyFormat::Text => (
2881 CopyFormatParams::Text(CopyTextFormatParams::default()),
2882 Format::Text,
2883 ),
2884 CopyFormat::Binary => (CopyFormatParams::Binary, Format::Binary),
2885 CopyFormat::Csv => (
2886 CopyFormatParams::Csv(CopyCsvFormatParams::default()),
2887 Format::Text,
2888 ),
2889 CopyFormat::Parquet => {
2890 let text = "Parquet format is not supported".to_string();
2891 return self
2892 .send_error_and_get_state(ErrorResponse::error(
2893 SqlState::INTERNAL_ERROR,
2894 text.clone(),
2895 ))
2896 .await
2897 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2898 }
2899 };
2900
2901 if let CopyFormat::Binary = format {
2909 if let Some(msg) = row_desc
2910 .iter_types()
2911 .find_map(|ty| mz_pgrepr::Value::binary_encoding_error(&ty.scalar_type).err())
2912 {
2913 return self
2914 .send_error_and_get_state(ErrorResponse::error(
2915 SqlState::UNDEFINED_FUNCTION,
2916 msg,
2917 ))
2918 .await
2919 .map(|state| {
2920 (
2921 state,
2922 SendRowsEndedReason::Errored {
2923 error: msg.to_string(),
2924 },
2925 )
2926 });
2927 }
2928 }
2929
2930 let text_settings = self.adapter_client.session().vars().text_encode_settings();
2934 let encode_fn = |row: &RowRef, typ: &SqlRelationType, out: &mut Vec<u8>| {
2935 mz_pgcopy::encode_copy_format(&row_format, row, typ, out, text_settings)
2936 };
2937
2938 let typ = row_desc.typ();
2939 let column_formats = iter::repeat(encode_format)
2940 .take(typ.column_types.len())
2941 .collect();
2942 self.send(BackendMessage::CopyOutResponse {
2943 overall_format: encode_format,
2944 column_formats,
2945 })
2946 .await?;
2947
2948 let mut out = Vec::new();
2953
2954 if let CopyFormat::Binary = format {
2955 out.extend(b"PGCOPY\n\xFF\r\n\0");
2957 out.extend([0, 0, 0, 0]);
2959 out.extend([0, 0, 0, 0]);
2961 }
2962
2963 let mut count = 0;
2964 let mut total_sent_bytes = 0;
2965 loop {
2966 tokio::select! {
2967 e = self.conn.wait_closed() => return Err(e),
2968 batch = stream.recv() => match batch {
2969 None => break,
2970 Some(PeekResponseUnary::Error(err)) => {
2971 let text = err.to_string();
2972 return self
2973 .send_error_and_get_state(err.into_response(Severity::Error))
2974 .await
2975 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2976 }
2977 Some(PeekResponseUnary::DependencyDropped(dep)) => {
2978 let err = dep.to_concurrent_dependency_drop();
2979 let text = err.to_string();
2980 let resp = err.into_response(Severity::Error);
2981 return self
2982 .send_error_and_get_state(resp)
2983 .await
2984 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2985 }
2986 Some(PeekResponseUnary::Canceled) => {
2987 return self.send_error_and_get_state(ErrorResponse::error(
2988 SqlState::QUERY_CANCELED,
2989 "canceling statement due to user request",
2990 ))
2991 .await.map(|state| (state, SendRowsEndedReason::Canceled));
2992 }
2993 Some(PeekResponseUnary::Rows(mut rows)) => {
2994 count += rows.count();
2995 while let Some(row) = rows.next() {
2996 total_sent_bytes += row.byte_len();
2997 encode_fn(row, typ, &mut out)?;
2998 self.send(BackendMessage::CopyData(mem::take(&mut out)))
2999 .await?;
3000 }
3001 }
3002 },
3003 notice = self.adapter_client.session().recv_notice() => {
3004 self.send(notice.into_response())
3005 .await?;
3006 self.conn.flush().await?;
3007 }
3008 }
3009
3010 self.conn.flush().await?;
3011 }
3012 if let CopyFormat::Binary = format {
3014 let trailer: i16 = -1;
3015 out.extend(trailer.to_be_bytes());
3016 self.send(BackendMessage::CopyData(mem::take(&mut out)))
3017 .await?;
3018 }
3019
3020 let tag = format!("COPY {}", count);
3021 self.send(BackendMessage::CopyDone).await?;
3022 let state = match self.settle_statement(ends_simple_query).await {
3023 Some(err) => self.send_error_and_get_state(err).await?,
3024 None => {
3025 self.send(BackendMessage::CommandComplete { tag }).await?;
3026 State::Ready
3027 }
3028 };
3029 Ok((
3030 state,
3031 SendRowsEndedReason::Success {
3032 result_size: u64::cast_from(total_sent_bytes),
3033 rows_returned: u64::cast_from(count),
3034 },
3035 ))
3036 }
3037
3038 #[instrument(level = "debug")]
3041 async fn copy_from(
3042 &mut self,
3043 target_id: CatalogItemId,
3044 target_name: String,
3045 columns: Vec<ColumnIndex>,
3046 params: CopyFormatParams<'static>,
3047 row_desc: RelationDesc,
3048 mut ctx_extra: ExecuteContextGuard,
3049 ends_simple_query: bool,
3050 ) -> Result<State, io::Error> {
3051 let res = self
3052 .copy_from_inner(
3053 target_id,
3054 target_name,
3055 columns,
3056 params,
3057 row_desc,
3058 &mut ctx_extra,
3059 ends_simple_query,
3060 )
3061 .await;
3062 match &res {
3063 Ok(State::Ready) => {
3064 self.adapter_client.retire_execute(
3065 ctx_extra,
3066 StatementEndedExecutionReason::Success {
3067 result_size: None,
3068 rows_returned: None,
3069 execution_strategy: None,
3070 },
3071 );
3072 }
3073 Ok(State::Done) => {
3074 self.adapter_client
3078 .retire_execute(ctx_extra, StatementEndedExecutionReason::Canceled);
3079 }
3080 Err(e) => {
3081 self.adapter_client.retire_execute(
3082 ctx_extra,
3083 StatementEndedExecutionReason::Errored {
3084 error: format!("{e}"),
3085 },
3086 );
3087 }
3088 Ok(State::Drain) => {}
3089 }
3090 res
3091 }
3092
3093 async fn copy_from_inner(
3094 &mut self,
3095 target_id: CatalogItemId,
3096 target_name: String,
3097 columns: Vec<ColumnIndex>,
3098 params: CopyFormatParams<'static>,
3099 row_desc: RelationDesc,
3100 ctx_extra: &mut ExecuteContextGuard,
3101 ends_simple_query: bool,
3102 ) -> Result<State, io::Error> {
3103 let typ = row_desc.typ();
3104 let column_formats = vec![Format::Text; typ.column_types.len()];
3105 self.send(BackendMessage::CopyInResponse {
3106 overall_format: Format::Text,
3107 column_formats,
3108 })
3109 .await?;
3110 self.conn.flush().await?;
3111
3112 let writer = match self
3114 .adapter_client
3115 .start_copy_from_stdin(
3116 target_id,
3117 target_name.clone(),
3118 columns.clone(),
3119 row_desc.clone(),
3120 params.clone(),
3121 )
3122 .await
3123 {
3124 Ok(writer) => writer,
3125 Err(e) => {
3126 loop {
3132 match self.conn.recv().await? {
3133 Some(FrontendMessage::CopyData(_)) => {}
3134 Some(FrontendMessage::CopyDone) | Some(FrontendMessage::CopyFail(_)) => {
3135 break;
3136 }
3137 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
3138 Some(_) => break,
3139 None => return Ok(State::Done),
3140 }
3141 }
3142 self.adapter_client.retire_execute(
3143 std::mem::take(ctx_extra),
3144 StatementEndedExecutionReason::Errored {
3145 error: e.to_string(),
3146 },
3147 );
3148 return self
3149 .send_error_and_get_state(e.into_response(Severity::Error))
3150 .await;
3151 }
3152 };
3153
3154 const BATCH_SIZE: usize = 32 * 1024 * 1024;
3156 let max_copy_from_row_size = self
3157 .adapter_client
3158 .get_system_vars()
3159 .await
3160 .max_copy_from_row_size()
3161 .try_into()
3162 .unwrap_or(usize::MAX);
3163
3164 let mut data = Vec::new();
3165 let mut row_scanner = CopyRowScanner::new(¶ms);
3166 let num_workers = writer.batch_txs.len();
3167 let mut next_worker: usize = 0;
3168 let mut saw_copy_done = false;
3169 let mut saw_end_marker = false;
3170 let mut copy_from_error: Option<(SqlState, String)> = None;
3171
3172 loop {
3175 let message = self.conn.recv().await?;
3176 match message {
3177 Some(FrontendMessage::CopyData(buf)) => {
3178 if saw_end_marker {
3179 continue;
3182 }
3183 data.extend(buf);
3184 row_scanner.scan_new_bytes(&data);
3185
3186 if let Some(end_pos) = row_scanner.end_marker_end() {
3187 data.truncate(end_pos);
3188 row_scanner.on_truncate(end_pos);
3189 saw_end_marker = true;
3190 }
3191
3192 if row_scanner.current_row_size(data.len()) > max_copy_from_row_size {
3194 copy_from_error = Some((
3195 SqlState::INSUFFICIENT_RESOURCES,
3196 format!(
3197 "COPY FROM STDIN row exceeded max_copy_from_row_size \
3198 ({max_copy_from_row_size} bytes)"
3199 ),
3200 ));
3201 break;
3202 }
3203
3204 let mut send_failed = false;
3207 while data.len() >= BATCH_SIZE {
3208 let split_pos = match row_scanner.last_row_end() {
3209 Some(pos) => pos,
3210 None => break, };
3212 let remainder = data.split_off(split_pos);
3213 let chunk = std::mem::replace(&mut data, remainder);
3214 row_scanner.on_split(split_pos);
3215 if writer.batch_txs[next_worker].send(chunk).await.is_err() {
3216 send_failed = true;
3217 break;
3218 }
3219 next_worker = (next_worker + 1) % num_workers;
3220 }
3221 if send_failed {
3224 break;
3225 }
3226 }
3227 Some(FrontendMessage::CopyDone) => {
3228 if !data.is_empty() {
3230 let chunk = std::mem::take(&mut data);
3231 let _ = writer.batch_txs[next_worker].send(chunk).await;
3233 }
3234 saw_copy_done = true;
3235 break;
3236 }
3237 Some(FrontendMessage::CopyFail(err)) => {
3238 self.adapter_client.retire_execute(
3239 std::mem::take(ctx_extra),
3240 StatementEndedExecutionReason::Canceled,
3241 );
3242 drop(writer);
3244 return self
3245 .send_error_and_get_state(ErrorResponse::error(
3246 SqlState::QUERY_CANCELED,
3247 format!("COPY from stdin failed: {}", err),
3248 ))
3249 .await;
3250 }
3251 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
3252 Some(_) => {
3253 let msg = "unexpected message type during COPY from stdin";
3254 self.adapter_client.retire_execute(
3255 std::mem::take(ctx_extra),
3256 StatementEndedExecutionReason::Errored {
3257 error: msg.to_string(),
3258 },
3259 );
3260 drop(writer);
3261 return self
3262 .send_error_and_get_state(ErrorResponse::error(
3263 SqlState::PROTOCOL_VIOLATION,
3264 msg,
3265 ))
3266 .await;
3267 }
3268 None => {
3269 drop(writer);
3270 return Ok(State::Done);
3271 }
3272 }
3273 }
3274
3275 if !saw_copy_done {
3279 loop {
3280 match self.conn.recv().await? {
3281 Some(FrontendMessage::CopyData(_)) => {}
3282 Some(FrontendMessage::CopyDone) | Some(FrontendMessage::CopyFail(_)) => {
3283 break;
3284 }
3285 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
3286 Some(_) => {
3287 let msg = "unexpected message type during COPY from stdin";
3288 self.adapter_client.retire_execute(
3289 std::mem::take(ctx_extra),
3290 StatementEndedExecutionReason::Errored {
3291 error: msg.to_string(),
3292 },
3293 );
3294 drop(writer);
3295 return self
3296 .send_error_and_get_state(ErrorResponse::error(
3297 SqlState::PROTOCOL_VIOLATION,
3298 msg,
3299 ))
3300 .await;
3301 }
3302 None => {
3303 drop(writer);
3304 return Ok(State::Done);
3305 }
3306 }
3307 }
3308 }
3309
3310 if let Some((code, msg)) = copy_from_error {
3311 self.adapter_client.retire_execute(
3312 std::mem::take(ctx_extra),
3313 StatementEndedExecutionReason::Errored { error: msg.clone() },
3314 );
3315 drop(writer);
3316 return self
3317 .send_error_and_get_state(ErrorResponse::error(code, msg))
3318 .await;
3319 }
3320
3321 drop(writer.batch_txs);
3326
3327 let (proto_batches, row_count) = match writer.completion_rx.await {
3329 Ok(Ok(result)) => result,
3330 Ok(Err(e)) => {
3331 self.adapter_client.retire_execute(
3332 std::mem::take(ctx_extra),
3333 StatementEndedExecutionReason::Errored {
3334 error: e.to_string(),
3335 },
3336 );
3337 return self
3338 .send_error_and_get_state(e.into_response(Severity::Error))
3339 .await;
3340 }
3341 Err(_) => {
3342 let msg = "COPY FROM STDIN: background batch builder tasks dropped";
3343 self.adapter_client.retire_execute(
3344 std::mem::take(ctx_extra),
3345 StatementEndedExecutionReason::Errored {
3346 error: msg.to_string(),
3347 },
3348 );
3349 return self
3350 .send_error_and_get_state(ErrorResponse::error(SqlState::INTERNAL_ERROR, msg))
3351 .await;
3352 }
3353 };
3354
3355 if let Err(e) = self
3357 .adapter_client
3358 .stage_copy_from_stdin_batches(target_id, proto_batches)
3359 {
3360 self.adapter_client.retire_execute(
3361 std::mem::take(ctx_extra),
3362 StatementEndedExecutionReason::Errored {
3363 error: e.to_string(),
3364 },
3365 );
3366 return self
3367 .send_error_and_get_state(e.into_response(Severity::Error))
3368 .await;
3369 }
3370
3371 if let Some(err) = self.settle_statement(ends_simple_query).await {
3372 self.adapter_client.retire_execute(
3373 std::mem::take(ctx_extra),
3374 StatementEndedExecutionReason::Errored {
3375 error: err.message.clone(),
3376 },
3377 );
3378 return self.send_error_and_get_state(err).await;
3379 }
3380 let tag = format!("COPY {}", row_count);
3381 self.send(BackendMessage::CommandComplete { tag }).await?;
3382
3383 Ok(State::Ready)
3384 }
3385
3386 #[instrument(level = "debug")]
3387 async fn send_pending_notices(&mut self) -> Result<(), io::Error> {
3388 let notices = self
3389 .adapter_client
3390 .session()
3391 .drain_notices()
3392 .into_iter()
3393 .map(|notice| BackendMessage::ErrorResponse(notice.into_response()));
3394 self.send_all(notices).await?;
3395 Ok(())
3396 }
3397
3398 #[instrument(level = "debug")]
3399 async fn send_error_and_get_state(&mut self, err: ErrorResponse) -> Result<State, io::Error> {
3400 assert!(err.severity.is_error());
3401 debug!(
3402 "cid={} error code={}",
3403 self.adapter_client.session().conn_id(),
3404 err.code.code()
3405 );
3406 let is_fatal = err.severity.is_fatal();
3407 self.send(BackendMessage::ErrorResponse(err)).await?;
3408
3409 let txn = self.adapter_client.session().transaction();
3410 match txn {
3411 TransactionStatus::Default | TransactionStatus::Failed(_) => {}
3414 TransactionStatus::Started(_) => {
3416 self.rollback_transaction().await?;
3417 }
3418 TransactionStatus::InTransactionImplicit(_) => {
3420 self.rollback_transaction().await?;
3421 }
3422 TransactionStatus::InTransaction(_) => {
3424 self.adapter_client.fail_transaction();
3425 }
3426 };
3427 if is_fatal {
3428 Ok(State::Done)
3429 } else {
3430 Ok(State::Drain)
3431 }
3432 }
3433
3434 #[instrument(level = "debug")]
3435 async fn aborted_txn_error(&mut self) -> Result<State, io::Error> {
3436 self.send(BackendMessage::ErrorResponse(ErrorResponse::error(
3437 SqlState::IN_FAILED_SQL_TRANSACTION,
3438 ABORTED_TXN_MSG,
3439 )))
3440 .await?;
3441 Ok(State::Drain)
3442 }
3443
3444 fn is_aborted_txn(&mut self) -> bool {
3445 matches!(
3446 self.adapter_client.session().transaction(),
3447 TransactionStatus::Failed(_)
3448 )
3449 }
3450}
3451
3452fn pad_formats(formats: Vec<Format>, n: usize) -> Result<Vec<Format>, String> {
3453 match (formats.len(), n) {
3454 (0, e) => Ok(vec![Format::Text; e]),
3455 (1, e) => Ok(iter::repeat(formats[0]).take(e).collect()),
3456 (a, e) if a == e => Ok(formats),
3457 (a, e) => Err(format!(
3458 "expected {} field format specifiers, but got {}",
3459 e, a
3460 )),
3461 }
3462}
3463
3464fn describe_rows(stmt_desc: &StatementDesc, formats: &[Format]) -> BackendMessage {
3465 match &stmt_desc.relation_desc {
3466 Some(desc) if !stmt_desc.is_copy => {
3467 BackendMessage::RowDescription(message::encode_row_description(desc, formats))
3468 }
3469 _ => BackendMessage::NoData,
3470 }
3471}
3472
3473type GetResponse = fn(
3474 max_rows: ExecuteCount,
3475 total_sent_rows: usize,
3476 fetch_portal: Option<PortalRefMut>,
3477) -> BackendMessage;
3478
3479fn portal_exec_message(
3482 max_rows: ExecuteCount,
3483 total_sent_rows: usize,
3484 _fetch_portal: Option<PortalRefMut>,
3485) -> BackendMessage {
3486 match max_rows {
3493 ExecuteCount::Count(max_rows) if max_rows <= total_sent_rows => {
3494 BackendMessage::PortalSuspended
3495 }
3496 _ => BackendMessage::CommandComplete {
3497 tag: format!("SELECT {}", total_sent_rows),
3498 },
3499 }
3500}
3501
3502fn fetch_message(
3504 _max_rows: ExecuteCount,
3505 total_sent_rows: usize,
3506 fetch_portal: Option<PortalRefMut>,
3507) -> BackendMessage {
3508 let tag = format!("FETCH {}", total_sent_rows);
3509 if let Some(portal) = fetch_portal {
3510 *portal.state = PortalState::Completed(Some(tag.clone()));
3511 }
3512 BackendMessage::CommandComplete { tag }
3513}
3514
3515fn get_authenticator(
3516 authenticator_kind: listeners::AuthenticatorKind,
3517 frontegg: Option<FronteggAuthenticator>,
3518 oidc: GenericOidcAuthenticator,
3519 adapter_client: mz_adapter::Client,
3520) -> Authenticator {
3521 match authenticator_kind {
3522 listeners::AuthenticatorKind::Frontegg => Authenticator::Frontegg(frontegg.expect(
3523 "Frontegg authenticator should exist with listeners::AuthenticatorKind::Frontegg",
3524 )),
3525 listeners::AuthenticatorKind::Password => Authenticator::Password(adapter_client),
3526 listeners::AuthenticatorKind::Sasl => Authenticator::Sasl(adapter_client),
3527 listeners::AuthenticatorKind::Oidc => Authenticator::Oidc(oidc),
3528 listeners::AuthenticatorKind::None => Authenticator::None,
3529 }
3530}
3531
3532#[derive(Debug, Copy, Clone)]
3533enum ExecuteCount {
3534 All,
3535 Count(usize),
3536}
3537
3538fn is_txn_exit_stmt(stmt: Option<&Statement<Raw>>) -> bool {
3540 match stmt {
3541 Some(stmt) => matches!(stmt, Statement::Commit(_) | Statement::Rollback(_)),
3543 None => false,
3544 }
3545}
3546
3547#[derive(Debug)]
3548enum FetchResult {
3549 Rows(Option<Box<dyn RowIterator + Send + Sync>>),
3550 Canceled,
3551 Error(ErrorResponse),
3552 Notice(AdapterNotice),
3553}
3554
3555#[derive(Debug)]
3556struct CopyRowScanner {
3557 scan_pos: usize,
3558 last_row_end: Option<usize>,
3559 end_marker_end: Option<usize>,
3560 record_start: usize,
3565 csv: Option<CsvScanState>,
3566}
3567
3568#[derive(Debug)]
3569struct CsvScanState {
3570 reader: csv_core::Reader,
3571 output: Vec<u8>,
3572 ends: Vec<usize>,
3573 skip_first_record: bool,
3574}
3575
3576impl CopyRowScanner {
3577 fn new(params: &CopyFormatParams<'_>) -> Self {
3578 let csv = match params {
3579 CopyFormatParams::Csv(CopyCsvFormatParams {
3580 delimiter,
3581 quote,
3582 escape,
3583 header,
3584 ..
3585 }) => Some(CsvScanState::new(*delimiter, *quote, *escape, *header)),
3586 _ => None,
3587 };
3588
3589 CopyRowScanner {
3590 scan_pos: 0,
3591 last_row_end: None,
3592 end_marker_end: None,
3593 record_start: 0,
3594 csv,
3595 }
3596 }
3597
3598 fn scan_new_bytes(&mut self, data: &[u8]) {
3599 if self.scan_pos >= data.len() {
3600 return;
3601 }
3602
3603 if let Some(csv) = self.csv.as_mut() {
3604 let mut input = &data[self.scan_pos..];
3605 let mut consumed = 0usize;
3606 while !input.is_empty() {
3607 let (result, n_input, _n_output, _n_ends) =
3608 csv.reader
3609 .read_record(input, &mut csv.output, &mut csv.ends);
3610 consumed += n_input;
3611 input = &input[n_input..];
3612
3613 match result {
3614 ReadRecordResult::InputEmpty => break,
3615 ReadRecordResult::OutputFull => {
3616 if n_input == 0 {
3617 csv.output
3618 .resize(csv.output.len().saturating_mul(2).max(1), 0);
3619 }
3620 }
3621 ReadRecordResult::OutputEndsFull => {
3622 if n_input == 0 {
3623 csv.ends.resize(csv.ends.len().saturating_mul(2).max(1), 0);
3624 }
3625 }
3626 ReadRecordResult::Record | ReadRecordResult::End => {
3627 let row_end = self.scan_pos + consumed;
3628 self.last_row_end = Some(row_end);
3629 if self.end_marker_end.is_none() {
3630 let is_marker = if csv.skip_first_record {
3631 csv.skip_first_record = false;
3632 false
3633 } else {
3634 let raw = &data[self.record_start..row_end];
3640 let start = raw
3651 .iter()
3652 .take_while(|&&b| b == b'\r' || b == b'\n')
3653 .count();
3654 let trailing = raw[start..]
3655 .iter()
3656 .rev()
3657 .take_while(|&&b| b == b'\r' || b == b'\n')
3658 .count();
3659 let trimmed = &raw[start..raw.len() - trailing];
3660 trimmed == b"\\."
3661 };
3662 if is_marker {
3663 self.end_marker_end = Some(row_end);
3664 self.record_start = row_end;
3665 break;
3666 }
3667 }
3668 self.record_start = row_end;
3669 }
3670 }
3671 }
3672 } else {
3673 let mut row_start = self.last_row_end.unwrap_or(0);
3674 for (offset, b) in data[self.scan_pos..].iter().enumerate() {
3675 if *b == b'\n' {
3676 let row_end = self.scan_pos + offset + 1;
3677 self.last_row_end = Some(row_end);
3678 if self.end_marker_end.is_none() {
3679 let row = &data[row_start..row_end];
3680 if row.get(0..2) == Some(b"\\.") {
3681 self.end_marker_end = Some(row_end);
3682 break;
3683 }
3684 }
3685 row_start = row_end;
3686 }
3687 }
3688 }
3689
3690 self.scan_pos = data.len();
3691 }
3692
3693 fn last_row_end(&self) -> Option<usize> {
3694 self.last_row_end
3695 }
3696
3697 fn end_marker_end(&self) -> Option<usize> {
3698 self.end_marker_end
3699 }
3700
3701 fn current_row_size(&self, data_len: usize) -> usize {
3702 data_len.saturating_sub(self.last_row_end.unwrap_or(0))
3703 }
3704
3705 fn on_split(&mut self, split_pos: usize) {
3706 self.scan_pos = self.scan_pos.saturating_sub(split_pos);
3707 self.last_row_end = None;
3708 self.end_marker_end = self
3709 .end_marker_end
3710 .and_then(|end| end.checked_sub(split_pos));
3711 soft_assert_or_log!(
3719 self.csv.is_none() || self.record_start >= split_pos,
3720 "split bisected an in-progress CSV record: record_start={} < split_pos={}",
3721 self.record_start,
3722 split_pos,
3723 );
3724 self.record_start = self.record_start.saturating_sub(split_pos);
3725 }
3726
3727 fn on_truncate(&mut self, new_len: usize) {
3728 self.scan_pos = self.scan_pos.min(new_len);
3729 self.last_row_end = self.last_row_end.filter(|&end| end <= new_len);
3730 self.end_marker_end = self.end_marker_end.filter(|&end| end <= new_len);
3731 self.record_start = self.record_start.min(new_len);
3732 }
3733}
3734
3735impl CsvScanState {
3736 fn new(delimiter: u8, quote: u8, escape: u8, header: bool) -> Self {
3737 let (double_quote, escape) = if quote == escape {
3738 (true, None)
3739 } else {
3740 (false, Some(escape))
3741 };
3742 CsvScanState {
3743 reader: csv_core::ReaderBuilder::new()
3744 .delimiter(delimiter)
3745 .quote(quote)
3746 .double_quote(double_quote)
3747 .escape(escape)
3748 .build(),
3749 output: vec![0; 1],
3750 ends: vec![0; 1],
3751 skip_first_record: header,
3752 }
3753 }
3754}
3755
3756#[cfg(test)]
3757mod test {
3758 use super::*;
3759
3760 #[mz_ore::test]
3761 fn test_copy_row_scanner_end_marker_line_endings() {
3762 let params = CopyFormatParams::Csv(CopyCsvFormatParams::default());
3770
3771 let marker_end = |data: &[u8]| -> Option<usize> {
3772 let mut scanner = CopyRowScanner::new(¶ms);
3773 scanner.scan_new_bytes(data);
3774 scanner.end_marker_end()
3775 };
3776
3777 for eol in [&b"\n"[..], b"\r\n", b"\r"] {
3778 let join = |lines: &[&str]| -> Vec<u8> {
3779 let mut out = Vec::new();
3780 for line in lines {
3781 out.extend_from_slice(line.as_bytes());
3782 out.extend_from_slice(eol);
3783 }
3784 out
3785 };
3786
3787 let data = join(&["first", "\\.", "after"]);
3792 let mut prefix = Vec::new();
3793 prefix.extend_from_slice(b"first");
3794 prefix.extend_from_slice(eol);
3795 prefix.extend_from_slice(b"\\.");
3796 assert_eq!(
3797 marker_end(&data),
3798 Some(prefix.len() + 1),
3799 "bare marker, eol={eol:?}"
3800 );
3801
3802 let data = join(&["before", "\"\\.\"", "after"]);
3804 assert_eq!(marker_end(&data), None, "quoted marker, eol={eol:?}");
3805 }
3806 }
3807
3808 #[mz_ore::test]
3809 fn test_copy_row_scanner_non_csv_split() {
3810 for params in [
3817 CopyFormatParams::Text(CopyTextFormatParams::default()),
3818 CopyFormatParams::Binary,
3819 ] {
3820 let mut scanner = CopyRowScanner::new(¶ms);
3821 let data = b"1\thello world\t2\tsome text value here\n\
3822 3\thello world\t6\tsome text value here\n";
3823 scanner.scan_new_bytes(data);
3824 let split_pos = scanner.last_row_end().expect("a complete row");
3825 assert!(split_pos > 0, "params={params:?}");
3826 scanner.on_split(split_pos);
3828 assert_eq!(scanner.record_start, 0, "params={params:?}");
3829 }
3830 }
3831
3832 #[mz_ore::test]
3833 fn test_parse_options() {
3834 struct TestCase {
3835 input: &'static str,
3836 expect: Result<Vec<(&'static str, &'static str)>, ()>,
3837 }
3838 let tests = vec![
3839 TestCase {
3840 input: "",
3841 expect: Ok(vec![]),
3842 },
3843 TestCase {
3844 input: "--key",
3845 expect: Err(()),
3846 },
3847 TestCase {
3848 input: "--key=val",
3849 expect: Ok(vec![("key", "val")]),
3850 },
3851 TestCase {
3852 input: r#"--key=val -ckey2=val2 -c key3=val3 -c key4=val4 -ckey5=val5"#,
3853 expect: Ok(vec![
3854 ("key", "val"),
3855 ("key2", "val2"),
3856 ("key3", "val3"),
3857 ("key4", "val4"),
3858 ("key5", "val5"),
3859 ]),
3860 },
3861 TestCase {
3862 input: r#"-c\ key=val"#,
3863 expect: Ok(vec![(" key", "val")]),
3864 },
3865 TestCase {
3866 input: "--key=val -ckey2 val2",
3867 expect: Err(()),
3868 },
3869 TestCase {
3871 input: "--key=",
3872 expect: Ok(vec![("key", "")]),
3873 },
3874 ];
3875 for test in tests {
3876 let got = parse_options(test.input);
3877 let expect = test.expect.map(|r| {
3878 r.into_iter()
3879 .map(|(k, v)| (k.to_owned(), v.to_owned()))
3880 .collect()
3881 });
3882 assert_eq!(got, expect, "input: {}", test.input);
3883 }
3884 }
3885
3886 #[mz_ore::test]
3887 fn test_parse_option() {
3888 struct TestCase {
3889 input: &'static str,
3890 expect: Result<(&'static str, &'static str), ()>,
3891 }
3892 let tests = vec![
3893 TestCase {
3894 input: "",
3895 expect: Err(()),
3896 },
3897 TestCase {
3898 input: "--",
3899 expect: Err(()),
3900 },
3901 TestCase {
3902 input: "--c",
3903 expect: Err(()),
3904 },
3905 TestCase {
3906 input: "a=b",
3907 expect: Err(()),
3908 },
3909 TestCase {
3910 input: "--a=b",
3911 expect: Ok(("a", "b")),
3912 },
3913 TestCase {
3914 input: "--ca=b",
3915 expect: Ok(("ca", "b")),
3916 },
3917 TestCase {
3918 input: "-ca=b",
3919 expect: Ok(("a", "b")),
3920 },
3921 TestCase {
3923 input: "--=",
3924 expect: Ok(("", "")),
3925 },
3926 ];
3927 for test in tests {
3928 let got = parse_option(test.input);
3929 assert_eq!(got, test.expect, "input: {}", test.input);
3930 }
3931 }
3932
3933 #[mz_ore::test]
3934 fn test_split_options() {
3935 struct TestCase {
3936 input: &'static str,
3937 expect: Vec<&'static str>,
3938 }
3939 let tests = vec![
3940 TestCase {
3941 input: "",
3942 expect: vec![],
3943 },
3944 TestCase {
3945 input: " ",
3946 expect: vec![],
3947 },
3948 TestCase {
3949 input: " a ",
3950 expect: vec!["a"],
3951 },
3952 TestCase {
3953 input: " ab cd ",
3954 expect: vec!["ab", "cd"],
3955 },
3956 TestCase {
3957 input: r#" ab\ cd "#,
3958 expect: vec!["ab ", "cd"],
3959 },
3960 TestCase {
3961 input: r#" ab\\ cd "#,
3962 expect: vec![r#"ab\"#, "cd"],
3963 },
3964 TestCase {
3965 input: r#" ab\\\ cd "#,
3966 expect: vec![r#"ab\ "#, "cd"],
3967 },
3968 TestCase {
3969 input: r#" ab\\\ cd "#,
3970 expect: vec![r#"ab\ cd"#],
3971 },
3972 TestCase {
3973 input: r#" ab\\\cd "#,
3974 expect: vec![r#"ab\cd"#],
3975 },
3976 TestCase {
3977 input: r#"a\"#,
3978 expect: vec!["a"],
3979 },
3980 TestCase {
3981 input: r#"a\ "#,
3982 expect: vec!["a "],
3983 },
3984 TestCase {
3985 input: r#"\"#,
3986 expect: vec![],
3987 },
3988 TestCase {
3989 input: r#"\ "#,
3990 expect: vec![r#" "#],
3991 },
3992 TestCase {
3993 input: r#" \ "#,
3994 expect: vec![r#" "#],
3995 },
3996 TestCase {
3997 input: r#"\ "#,
3998 expect: vec![r#" "#],
3999 },
4000 ];
4001 for test in tests {
4002 let got = split_options(test.input);
4003 assert_eq!(got, test.expect, "input: {}", test.input);
4004 }
4005 }
4006
4007 #[mz_ore::test]
4008 fn test_is_jwt() {
4009 assert!(is_jwt("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.signature"));
4011 for s in [
4013 "",
4014 "secure_password",
4015 "p4ss.w0rd",
4016 "aaa.bbb.ccc",
4017 "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0",
4018 "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.sig.extra",
4019 ] {
4020 assert!(!is_jwt(s), "is_jwt({s:?})");
4021 }
4022 }
4023}