1use std::collections::BTreeMap;
11use std::convert::TryFrom;
12use std::future::Future;
13use std::ops::Deref;
14use std::sync::Arc;
15use std::time::{Duration, Instant};
16use std::{iter, mem};
17
18use base64::prelude::*;
19use byteorder::{ByteOrder, NetworkEndian};
20use csv_core::ReadRecordResult;
21use futures::future::{BoxFuture, FutureExt, pending};
22use itertools::Itertools;
23use mz_adapter::client::{RecordFirstRowStream, redact_sql_for_logging};
24use mz_adapter::session::{
25 EndTransactionAction, InProgressRows, LifecycleTimestamps, PortalRefMut, PortalState, Session,
26 SessionConfig, TransactionStatus,
27};
28use mz_adapter::statement_logging::{StatementEndedExecutionReason, StatementExecutionStrategy};
29use mz_adapter::{
30 AdapterError, AdapterNotice, ExecuteContextGuard, ExecuteResponse, PeekResponseUnary, metrics,
31 verify_datum_desc,
32};
33use mz_adapter_types::dyncfgs::OIDC_GROUP_CLAIM;
34use mz_auth::Authenticated;
35use mz_auth::password::Password;
36use mz_authenticator::{Authenticator, GenericOidcAuthenticator};
37use mz_frontegg_auth::Authenticator as FronteggAuthenticator;
38use mz_ore::cast::CastFrom;
39use mz_ore::netio::AsyncReady;
40use mz_ore::now::{EpochMillis, SYSTEM_TIME};
41use mz_ore::str::StrExt;
42use mz_ore::{assert_none, assert_ok, instrument, soft_assert_eq_or_log, soft_assert_or_log};
43use mz_pgcopy::{CopyCsvFormatParams, CopyFormatParams, CopyTextFormatParams};
44use mz_pgwire_common::{
45 ConnectionCounter, Cursor, ErrorResponse, Format, FrontendMessage, Severity, VERSION_3,
46 VERSIONS,
47};
48use mz_repr::{
49 CatalogItemId, ColumnIndex, Datum, RelationDesc, RowArena, RowIterator, RowRef,
50 SqlRelationType, SqlScalarType,
51};
52use mz_server_core::TlsMode;
53use mz_server_core::listeners;
54use mz_server_core::listeners::AllowedRoles;
55use mz_sql::ast::display::AstDisplay;
56use mz_sql::ast::{
57 CopyDirection, CopyStatement, CopyTarget, FetchDirection, Ident, Raw, Statement,
58};
59use mz_sql::parse::StatementParseResult;
60use mz_sql::plan::{CopyFormat, ExecuteTimeout, StatementDesc};
61use mz_sql::session::metadata::SessionMetadata;
62use mz_sql::session::user::INTERNAL_USER_NAMES;
63use mz_sql::session::vars::VarInput;
64use postgres::error::SqlState;
65use tokio::io::{self, AsyncRead, AsyncWrite};
66use tokio::select;
67use tokio::time::{self};
68use tokio_metrics::TaskMetrics;
69use 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 let mut buf = vec![BackendMessage::AuthenticationOk];
617 for var in adapter_client.session().vars().notify_set() {
618 buf.push(BackendMessage::ParameterStatus(var.name(), var.value()));
619 }
620 buf.push(BackendMessage::BackendKeyData {
621 conn_id: adapter_client.session().conn_id().unhandled(),
622 secret_key: adapter_client.session().secret_key(),
623 });
624 buf.extend(
625 adapter_client
626 .session()
627 .drain_notices()
628 .into_iter()
629 .map(|notice| BackendMessage::ErrorResponse(notice.into_response())),
630 );
631 buf.push(BackendMessage::ReadyForQuery(
632 adapter_client.session().transaction().into(),
633 ));
634 conn.send_all(buf).await?;
635 conn.flush().await?;
636
637 let machine = StateMachine {
638 conn,
639 adapter_client,
640 txn_needs_commit: false,
641 tokio_metrics_intervals,
642 };
643
644 select! {
645 r = machine.run() => {
646 if let Err(err) = &r {
651 let _ = conn
652 .send(ErrorResponse::fatal(
653 SqlState::CONNECTION_FAILURE,
654 err.to_string(),
655 ))
656 .await;
657 let _ = conn.flush().await;
658 }
659 r
660 },
661 _ = expired => {
662 conn
663 .send(ErrorResponse::fatal(SqlState::INVALID_AUTHORIZATION_SPECIFICATION, "authentication expired"))
664 .await?;
665 conn.flush().await
666 }
667 }
668}
669
670fn is_jwt(password: &str) -> bool {
673 jsonwebtoken::decode_header(password).is_ok()
674}
675
676fn parse_options(value: &str) -> Result<Vec<(String, String)>, ()> {
681 let opts = split_options(value);
682 let mut pairs = Vec::with_capacity(opts.len());
683 let mut seen_prefix = false;
684 for opt in opts {
685 if !seen_prefix {
686 if opt == "-c" {
687 seen_prefix = true;
688 } else {
689 let (key, val) = parse_option(&opt)?;
690 pairs.push((key.to_owned(), val.to_owned()));
691 }
692 } else {
693 let (key, val) = opt.split_once('=').ok_or(())?;
694 pairs.push((key.to_owned(), val.to_owned()));
695 seen_prefix = false;
696 }
697 }
698 Ok(pairs)
699}
700
701fn parse_option(option: &str) -> Result<(&str, &str), ()> {
705 let (key, value) = option.split_once('=').ok_or(())?;
706 for prefix in &["-c", "--"] {
707 if let Some(key) = key.strip_prefix(prefix) {
708 return Ok((key, value));
709 }
710 }
711 Err(())
712}
713
714fn split_options(value: &str) -> Vec<String> {
716 let mut strs = Vec::new();
717 let mut current = String::new();
721 let mut was_slash = false;
722 for c in value.chars() {
723 was_slash = match c {
724 ' ' => {
725 if was_slash {
726 current.push(' ');
727 } else if !current.is_empty() {
728 strs.push(std::mem::take(&mut current));
731 }
732 false
733 }
734 '\\' => {
735 if was_slash {
736 current.push('\\');
739 false
740 } else {
741 true
742 }
743 }
744 _ => {
745 current.push(c);
746 false
747 }
748 };
749 }
750 if !current.is_empty() {
752 strs.push(current);
753 }
754 strs
755}
756
757enum PasswordRequestError {
758 InvalidPasswordError(ErrorResponse),
759 IoError(io::Error),
760}
761
762impl From<io::Error> for PasswordRequestError {
763 fn from(e: io::Error) -> Self {
764 PasswordRequestError::IoError(e)
765 }
766}
767
768async fn request_cleartext_password<A>(
772 conn: &mut FramedConn<A>,
773) -> Result<String, PasswordRequestError>
774where
775 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin,
776{
777 conn.send(BackendMessage::AuthenticationCleartextPassword)
778 .await?;
779 conn.flush().await?;
780
781 if let Some(message) = conn.recv().await? {
782 if let FrontendMessage::RawAuthentication(data) = message {
783 if let Some(FrontendMessage::Password { password }) =
784 decode_password(Cursor::new(&data)).ok()
785 {
786 return Ok(password);
787 }
788 }
789 }
790
791 Err(PasswordRequestError::InvalidPasswordError(
792 ErrorResponse::fatal(
793 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
794 "expected Password message",
795 ),
796 ))
797}
798
799async fn authenticate_with_password<A>(
802 conn: &FramedConn<A>,
803 adapter_client: &mz_adapter::Client,
804 user: String,
805 password: Password,
806 conn_uuid: Uuid,
807 helm_chart_version: Option<String>,
808) -> Result<Session, PasswordRequestError>
809where
810 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin,
811{
812 let authenticated = match adapter_client.authenticate(&user, &password).await {
813 Ok(authenticated) => authenticated,
814 Err(err) => {
815 warn!(?err, "pgwire connection failed authentication");
816 return Err(PasswordRequestError::InvalidPasswordError(
817 ErrorResponse::fatal(SqlState::INVALID_PASSWORD, "invalid password"),
818 ));
819 }
820 };
821
822 let session = adapter_client.new_session(
823 SessionConfig {
824 conn_id: conn.conn_id().clone(),
825 uuid: conn_uuid,
826 user,
827 client_ip: conn.peer_addr().clone(),
828 external_metadata_rx: None,
829 helm_chart_version,
830 authenticator_kind: mz_auth::AuthenticatorKind::Password,
831 groups: None,
832 },
833 authenticated,
834 );
835
836 Ok(session)
837}
838
839#[derive(Debug)]
840enum State {
841 Ready,
842 Drain,
843 Done,
844}
845
846struct StateMachine<'a, A, I>
847where
848 I: Iterator<Item = TaskMetrics> + Send + 'a,
849{
850 conn: &'a mut FramedConn<A>,
851 adapter_client: mz_adapter::SessionClient,
852 txn_needs_commit: bool,
853 tokio_metrics_intervals: I,
854}
855
856enum SendRowsEndedReason {
857 Success {
858 result_size: u64,
859 rows_returned: u64,
860 },
861 Errored {
862 error: String,
863 },
864 Canceled,
865}
866
867const ABORTED_TXN_MSG: &str =
868 "current transaction is aborted, commands ignored until end of transaction block";
869
870impl<'a, A, I> StateMachine<'a, A, I>
871where
872 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin + 'a,
873 I: Iterator<Item = TaskMetrics> + Send + 'a,
874{
875 #[allow(clippy::manual_async_fn)]
879 #[mz_ore::instrument(level = "debug")]
880 fn run(mut self) -> impl Future<Output = Result<(), io::Error>> + Send + 'a {
881 async move {
882 let mut state = State::Ready;
883 loop {
884 self.send_pending_notices().await?;
885 state = match state {
886 State::Ready => self.advance_ready().await?,
887 State::Drain => self.advance_drain().await?,
888 State::Done => return Ok(()),
889 };
890 self.adapter_client
891 .add_idle_in_transaction_session_timeout();
892 }
893 }
894 }
895
896 #[instrument(level = "debug")]
897 async fn advance_ready(&mut self) -> Result<State, io::Error> {
898 self.tokio_metrics_intervals
900 .next()
901 .expect("infinite iterator");
902
903 let message = select! {
905 biased;
906
907 Some(timeout) = self.adapter_client.recv_timeout() => {
909 let err: AdapterError = timeout.into();
910 let conn_id = self.adapter_client.session().conn_id();
911 tracing::warn!("session timed out, conn_id {}", conn_id);
912
913 let error_response = err.into_response(Severity::Fatal);
915 let error_state = self.send_error_and_get_state(error_response).await;
916
917 self.adapter_client.terminate().await;
919
920 let _ = self.conn.recv().await?;
924 return error_state;
925 },
926 message = self.conn.recv() => message?,
928 };
929
930 let interval = self
932 .tokio_metrics_intervals
933 .next()
934 .expect("infinite iterator");
935 let recv_scheduling_delay_ms = interval.total_scheduled_duration.as_secs_f64() * 1000.0;
936
937 let received = SYSTEM_TIME();
941
942 self.adapter_client
943 .remove_idle_in_transaction_session_timeout();
944
945 let message_name = message.as_ref().map(|m| m.name()).unwrap_or_default();
948
949 if let Some(message) = &message {
950 self.maybe_log_message_arrival(message).await;
951 }
952
953 let start = message.as_ref().map(|_| Instant::now());
954 let next_state = match message {
955 Some(FrontendMessage::Query { sql }) => {
956 let query_root_span =
957 tracing::info_span!(parent: None, "advance_ready", otel.name = message_name);
958 query_root_span.follows_from(tracing::Span::current());
959 self.query(sql, received)
960 .instrument(query_root_span)
961 .await?
962 }
963 Some(FrontendMessage::Parse {
964 name,
965 sql,
966 param_types,
967 }) => self.parse(name, sql, param_types).await?,
968 Some(FrontendMessage::Bind {
969 portal_name,
970 statement_name,
971 param_formats,
972 raw_params,
973 result_formats,
974 }) => {
975 self.bind(
976 portal_name,
977 statement_name,
978 param_formats,
979 raw_params,
980 result_formats,
981 )
982 .await?
983 }
984 Some(FrontendMessage::Execute {
985 portal_name,
986 max_rows,
987 }) => {
988 let max_rows = match usize::try_from(max_rows) {
989 Ok(0) | Err(_) => ExecuteCount::All, Ok(n) => ExecuteCount::Count(n),
991 };
992 let execute_root_span =
993 tracing::info_span!(parent: None, "advance_ready", otel.name = message_name);
994 execute_root_span.follows_from(tracing::Span::current());
995 let state = self
996 .execute(
997 portal_name,
998 max_rows,
999 portal_exec_message,
1000 None,
1001 ExecuteTimeout::None,
1002 None,
1003 Some(received),
1004 )
1005 .instrument(execute_root_span)
1006 .await?;
1007 let (is_implicit, may_span_pipeline) = {
1022 let txn = self.adapter_client.session().transaction();
1023 (txn.is_implicit(), txn.may_span_pipeline())
1024 };
1025 let spans_pipeline = may_span_pipeline
1028 && self
1029 .adapter_client
1030 .extended_protocol_implicit_transaction_enabled()
1031 .await;
1032 if is_implicit && !spans_pipeline {
1033 self.txn_needs_commit = true;
1034 }
1035 state
1036 }
1037 Some(FrontendMessage::DescribeStatement { name }) => {
1038 self.describe_statement(&name).await?
1039 }
1040 Some(FrontendMessage::DescribePortal { name }) => self.describe_portal(&name).await?,
1041 Some(FrontendMessage::CloseStatement { name }) => self.close_statement(name).await?,
1042 Some(FrontendMessage::ClosePortal { name }) => self.close_portal(name).await?,
1043 Some(FrontendMessage::Flush) => self.flush().await?,
1044 Some(FrontendMessage::Sync) => self.sync().await?,
1045 Some(FrontendMessage::Terminate) => State::Done,
1046
1047 Some(FrontendMessage::CopyData(_))
1054 | Some(FrontendMessage::CopyDone)
1055 | Some(FrontendMessage::CopyFail(_)) => State::Ready,
1056
1057 Some(FrontendMessage::Password { .. })
1058 | Some(FrontendMessage::RawAuthentication(_))
1059 | Some(FrontendMessage::SASLInitialResponse { .. })
1060 | Some(FrontendMessage::SASLResponse(_)) => State::Drain,
1061 None => State::Done,
1062 };
1063
1064 if let Some(start) = start {
1065 self.adapter_client
1066 .inner()
1067 .metrics()
1068 .pgwire_message_processing_seconds
1069 .with_label_values(&[message_name])
1070 .observe(start.elapsed().as_secs_f64());
1071 }
1072 self.adapter_client
1073 .inner()
1074 .metrics()
1075 .pgwire_recv_scheduling_delay_ms
1076 .with_label_values(&[message_name])
1077 .observe(recv_scheduling_delay_ms);
1078
1079 Ok(next_state)
1080 }
1081
1082 async fn advance_drain(&mut self) -> Result<State, io::Error> {
1083 let message = self.conn.recv().await?;
1084 if message.is_some() {
1085 self.adapter_client
1086 .remove_idle_in_transaction_session_timeout();
1087 }
1088 match message {
1089 Some(FrontendMessage::Sync) => self.sync().await,
1090 None => Ok(State::Done),
1091 _ => Ok(State::Drain),
1092 }
1093 }
1094
1095 #[instrument(level = "debug")]
1099 async fn one_query(
1100 &mut self,
1101 stmt: Statement<Raw>,
1102 sql: String,
1103 lifecycle_timestamps: LifecycleTimestamps,
1104 ) -> Result<State, io::Error> {
1105 const EMPTY_PORTAL: &str = "";
1108 if let Err(e) = self
1109 .adapter_client
1110 .declare(EMPTY_PORTAL.to_string(), stmt, sql)
1111 .await
1112 {
1113 return self
1114 .send_error_and_get_state(e.into_response(Severity::Error))
1115 .await;
1116 }
1117 let portal = self
1118 .adapter_client
1119 .session()
1120 .get_portal_unverified_mut(EMPTY_PORTAL)
1121 .expect("unnamed portal should be present");
1122
1123 *portal.lifecycle_timestamps = Some(lifecycle_timestamps);
1124
1125 let stmt_desc = portal.desc.clone();
1126 if !stmt_desc.param_types.is_empty() {
1127 return self
1128 .send_error_and_get_state(ErrorResponse::error(
1129 SqlState::UNDEFINED_PARAMETER,
1130 "there is no parameter $1",
1131 ))
1132 .await;
1133 }
1134
1135 if let Some(relation_desc) = &stmt_desc.relation_desc {
1137 if !stmt_desc.is_copy {
1138 let formats = vec![Format::Text; stmt_desc.arity()];
1139 self.send(BackendMessage::RowDescription(
1140 message::encode_row_description(relation_desc, &formats),
1141 ))
1142 .await?;
1143 }
1144 }
1145
1146 let result = match self
1147 .adapter_client
1148 .execute(EMPTY_PORTAL.to_string(), self.conn.wait_closed(), None)
1149 .await
1150 {
1151 Ok((response, execute_started)) => {
1152 self.send_pending_notices().await?;
1153 self.send_execute_response(
1154 response,
1155 stmt_desc.relation_desc,
1156 EMPTY_PORTAL.to_string(),
1157 ExecuteCount::All,
1158 portal_exec_message,
1159 None,
1160 ExecuteTimeout::None,
1161 execute_started,
1162 )
1163 .await
1164 }
1165 Err(e) => {
1166 self.send_pending_notices().await?;
1167 self.send_error_and_get_state(e.into_response(Severity::Error))
1168 .await
1169 }
1170 };
1171
1172 self.adapter_client.session().remove_portal(EMPTY_PORTAL);
1174
1175 result
1176 }
1177
1178 async fn ensure_transaction(
1179 &mut self,
1180 num_stmts: usize,
1181 message_type: &str,
1182 ) -> Result<(), io::Error> {
1183 let start = Instant::now();
1184 if self.txn_needs_commit {
1185 self.commit_transaction().await?;
1186 }
1187 let res = self.adapter_client.start_transaction(Some(num_stmts));
1190 assert_ok!(res);
1191 self.adapter_client
1192 .inner()
1193 .metrics()
1194 .pgwire_ensure_transaction_seconds
1195 .with_label_values(&[message_type])
1196 .observe(start.elapsed().as_secs_f64());
1197 Ok(())
1198 }
1199
1200 async fn maybe_log_message_arrival(&mut self, message: &FrontendMessage) {
1219 if !self
1220 .adapter_client
1221 .statement_arrival_logging_enabled()
1222 .await
1223 {
1224 return;
1225 }
1226 let session = self.adapter_client.session();
1227 let conn_id = session.conn_id();
1228 let session_uuid = session.uuid();
1229 let kind = message.name();
1230 match message {
1231 FrontendMessage::Query { sql } => {
1232 info!(
1233 %conn_id, %session_uuid, kind, sql = %redact_sql_for_logging(sql),
1234 "statement arrival"
1235 );
1236 }
1237 FrontendMessage::Parse { name, sql, .. } => {
1238 info!(
1239 %conn_id, %session_uuid, kind, name, sql = %redact_sql_for_logging(sql),
1240 "statement arrival"
1241 );
1242 }
1243 FrontendMessage::Bind {
1244 portal_name,
1245 statement_name,
1246 raw_params,
1247 ..
1248 } => {
1249 info!(
1250 %conn_id, %session_uuid, kind, portal_name, statement_name,
1251 num_params = raw_params.len(),
1252 "statement arrival"
1253 );
1254 }
1255 FrontendMessage::CopyData(data) => {
1257 info!(%conn_id, %session_uuid, kind, len = data.len(), "statement arrival");
1258 }
1259 FrontendMessage::Password { .. }
1261 | FrontendMessage::RawAuthentication(_)
1262 | FrontendMessage::SASLInitialResponse { .. }
1263 | FrontendMessage::SASLResponse(_) => {
1264 info!(%conn_id, %session_uuid, kind, "statement arrival");
1265 }
1266 FrontendMessage::CopyFail(_) => {
1269 info!(%conn_id, %session_uuid, kind, "statement arrival");
1270 }
1271 FrontendMessage::DescribeStatement { .. }
1274 | FrontendMessage::DescribePortal { .. }
1275 | FrontendMessage::Execute { .. }
1276 | FrontendMessage::Flush
1277 | FrontendMessage::Sync
1278 | FrontendMessage::CloseStatement { .. }
1279 | FrontendMessage::ClosePortal { .. }
1280 | FrontendMessage::Terminate
1281 | FrontendMessage::CopyDone => {
1282 info!(%conn_id, %session_uuid, kind, contents = ?message, "statement arrival");
1288 }
1289 }
1290 }
1291
1292 fn parse_sql<'b>(&self, sql: &'b str) -> Result<Vec<StatementParseResult<'b>>, ErrorResponse> {
1293 let parse_start = Instant::now();
1294 let result = match self.adapter_client.parse(sql) {
1295 Ok(result) => result.map_err(|e| {
1296 let pos = sql[..e.error.pos].chars().count() + 1;
1299 ErrorResponse::error(SqlState::SYNTAX_ERROR, e.error.message).with_position(pos)
1300 }),
1301 Err(msg) => Err(ErrorResponse::error(SqlState::PROGRAM_LIMIT_EXCEEDED, msg)),
1302 };
1303 self.adapter_client
1304 .inner()
1305 .metrics()
1306 .parse_seconds
1307 .observe(parse_start.elapsed().as_secs_f64());
1308 result
1309 }
1310
1311 #[instrument(level = "debug")]
1316 async fn query(&mut self, sql: String, received: EpochMillis) -> Result<State, io::Error> {
1317 let stmts = match self.parse_sql(&sql) {
1319 Ok(stmts) => stmts,
1320 Err(err) => {
1321 self.send_error_and_get_state(err).await?;
1322 return self.ready().await;
1323 }
1324 };
1325
1326 let num_stmts = stmts.len();
1327
1328 for StatementParseResult { ast: stmt, sql } in stmts {
1330 if self.is_aborted_txn() && !is_txn_exit_stmt(Some(&stmt)) {
1332 self.aborted_txn_error().await?;
1333 break;
1334 }
1335
1336 self.ensure_transaction(num_stmts, "query").await?;
1344
1345 match self
1346 .one_query(stmt, sql.to_string(), LifecycleTimestamps { received })
1347 .await?
1348 {
1349 State::Ready => (),
1350 State::Drain => break,
1351 State::Done => return Ok(State::Done),
1352 }
1353 }
1354
1355 {
1357 if self.adapter_client.session().transaction().is_implicit() {
1358 self.commit_transaction().await?;
1359 }
1360 }
1361
1362 if num_stmts == 0 {
1363 self.send(BackendMessage::EmptyQueryResponse).await?;
1364 }
1365
1366 self.ready().await
1367 }
1368
1369 #[instrument(level = "debug")]
1370 async fn parse(
1371 &mut self,
1372 name: String,
1373 sql: String,
1374 param_oids: Vec<u32>,
1375 ) -> Result<State, io::Error> {
1376 self.ensure_transaction(1, "parse").await?;
1378
1379 let mut param_types = vec![];
1380 for oid in param_oids {
1381 match mz_pgrepr::Type::from_oid(oid) {
1382 Ok(ty) => match SqlScalarType::try_from(&ty) {
1383 Ok(ty) => param_types.push(Some(ty)),
1384 Err(err) => {
1385 return self
1386 .send_error_and_get_state(ErrorResponse::error(
1387 SqlState::INVALID_PARAMETER_VALUE,
1388 err.to_string(),
1389 ))
1390 .await;
1391 }
1392 },
1393 Err(_) if oid == 0 => param_types.push(None),
1394 Err(e) => {
1395 return self
1396 .send_error_and_get_state(ErrorResponse::error(
1397 SqlState::PROTOCOL_VIOLATION,
1398 e.to_string(),
1399 ))
1400 .await;
1401 }
1402 }
1403 }
1404
1405 let stmts = match self.parse_sql(&sql) {
1406 Ok(stmts) => stmts,
1407 Err(err) => {
1408 return self.send_error_and_get_state(err).await;
1409 }
1410 };
1411 if stmts.len() > 1 {
1412 return self
1413 .send_error_and_get_state(ErrorResponse::error(
1414 SqlState::INTERNAL_ERROR,
1415 "cannot insert multiple commands into a prepared statement",
1416 ))
1417 .await;
1418 }
1419 let (maybe_stmt, sql) = match stmts.into_iter().next() {
1420 None => (None, ""),
1421 Some(StatementParseResult { ast, sql }) => (Some(ast), sql),
1422 };
1423 if self.is_aborted_txn() && !is_txn_exit_stmt(maybe_stmt.as_ref()) {
1424 return self.aborted_txn_error().await;
1425 }
1426 match self
1427 .adapter_client
1428 .prepare(name, maybe_stmt, sql.to_string(), param_types)
1429 .await
1430 {
1431 Ok(()) => {
1432 self.send(BackendMessage::ParseComplete).await?;
1433 Ok(State::Ready)
1434 }
1435 Err(e) => {
1436 self.send_error_and_get_state(e.into_response(Severity::Error))
1437 .await
1438 }
1439 }
1440 }
1441
1442 #[instrument(level = "debug")]
1444 async fn commit_transaction(&mut self) -> Result<(), io::Error> {
1445 self.end_transaction(EndTransactionAction::Commit).await
1446 }
1447
1448 #[instrument(level = "debug")]
1450 async fn rollback_transaction(&mut self) -> Result<(), io::Error> {
1451 self.end_transaction(EndTransactionAction::Rollback).await
1452 }
1453
1454 #[instrument(level = "debug")]
1461 async fn end_transaction(&mut self, action: EndTransactionAction) -> Result<(), io::Error> {
1462 self.txn_needs_commit = false;
1463 match self.adapter_client.end_transaction(action).await {
1464 Ok(
1465 ExecuteResponse::TransactionCommitted { params }
1466 | ExecuteResponse::TransactionRolledBack { params },
1467 ) => {
1468 self.send_parameter_statuses(params).await?;
1469 }
1470 Ok(_) => {}
1471 Err(err) => {
1472 self.send(BackendMessage::ErrorResponse(
1473 err.into_response(Severity::Error),
1474 ))
1475 .await?;
1476 }
1477 }
1478 Ok(())
1479 }
1480
1481 #[instrument(level = "debug")]
1484 async fn send_parameter_statuses(
1485 &mut self,
1486 params: BTreeMap<&'static str, String>,
1487 ) -> Result<(), io::Error> {
1488 let notify_set: mz_ore::collections::HashSet<String> = self
1489 .adapter_client
1490 .session()
1491 .vars()
1492 .notify_set()
1493 .map(|v| v.name().to_string())
1494 .collect();
1495
1496 for (name, value) in params
1497 .into_iter()
1498 .filter(|(name, _value)| notify_set.contains(*name))
1499 {
1500 self.send(BackendMessage::ParameterStatus(name, value))
1501 .await?;
1502 }
1503 Ok(())
1504 }
1505
1506 #[instrument(level = "debug")]
1507 async fn bind(
1508 &mut self,
1509 portal_name: String,
1510 statement_name: String,
1511 param_formats: Vec<Format>,
1512 raw_params: Vec<Option<Vec<u8>>>,
1513 result_formats: Vec<Format>,
1514 ) -> Result<State, io::Error> {
1515 self.ensure_transaction(1, "bind").await?;
1517
1518 let aborted_txn = self.is_aborted_txn();
1519 let stmt = match self
1520 .adapter_client
1521 .get_prepared_statement(&statement_name)
1522 .await
1523 {
1524 Ok(stmt) => stmt,
1525 Err(err) => {
1526 return self
1527 .send_error_and_get_state(err.into_response(Severity::Error))
1528 .await;
1529 }
1530 };
1531
1532 let param_types = &stmt.desc().param_types;
1533 if param_types.len() != raw_params.len() {
1534 let message = format!(
1535 "bind message supplies {actual} parameters, \
1536 but prepared statement \"{name}\" requires {expected}",
1537 name = statement_name,
1538 actual = raw_params.len(),
1539 expected = param_types.len()
1540 );
1541 return self
1542 .send_error_and_get_state(ErrorResponse::error(
1543 SqlState::PROTOCOL_VIOLATION,
1544 message,
1545 ))
1546 .await;
1547 }
1548 let param_formats = match pad_formats(param_formats, raw_params.len()) {
1549 Ok(param_formats) => param_formats,
1550 Err(msg) => {
1551 return self
1552 .send_error_and_get_state(ErrorResponse::error(
1553 SqlState::PROTOCOL_VIOLATION,
1554 msg,
1555 ))
1556 .await;
1557 }
1558 };
1559 if aborted_txn && !is_txn_exit_stmt(stmt.stmt()) {
1560 return self.aborted_txn_error().await;
1561 }
1562 let buf = RowArena::new();
1563 let mut params = vec![];
1564 for ((raw_param, mz_typ), format) in raw_params
1565 .into_iter()
1566 .zip_eq(param_types)
1567 .zip_eq(param_formats)
1568 {
1569 let pg_typ = mz_pgrepr::Type::from(mz_typ);
1570 let datum = match raw_param {
1571 None => Datum::Null,
1572 Some(bytes) => match mz_pgrepr::Value::decode(format, &pg_typ, &bytes) {
1573 Ok(param) => match param.into_datum_decode_error(&buf, &pg_typ, "parameter") {
1574 Ok(datum) => datum,
1575 Err(msg) => {
1576 return self
1577 .send_error_and_get_state(ErrorResponse::error(
1578 SqlState::INVALID_PARAMETER_VALUE,
1579 msg,
1580 ))
1581 .await;
1582 }
1583 },
1584 Err(err) => {
1585 let (code, msg) = if err.is::<mz_pgrepr::NulCharacterError>() {
1588 (SqlState::CHARACTER_NOT_IN_REPERTOIRE, err.to_string())
1589 } else {
1590 (
1591 SqlState::INVALID_PARAMETER_VALUE,
1592 format!("unable to decode parameter: {}", err),
1593 )
1594 };
1595 return self
1596 .send_error_and_get_state(ErrorResponse::error(code, msg))
1597 .await;
1598 }
1599 },
1600 };
1601 params.push((datum, mz_typ.clone()))
1602 }
1603
1604 let result_formats = match pad_formats(
1605 result_formats,
1606 stmt.desc()
1607 .relation_desc
1608 .clone()
1609 .map(|desc| desc.typ().column_types.len())
1610 .unwrap_or(0),
1611 ) {
1612 Ok(result_formats) => result_formats,
1613 Err(msg) => {
1614 return self
1615 .send_error_and_get_state(ErrorResponse::error(
1616 SqlState::PROTOCOL_VIOLATION,
1617 msg,
1618 ))
1619 .await;
1620 }
1621 };
1622
1623 if !stmt.stmt().map_or(false, |stmt| match stmt {
1626 Statement::Copy(CopyStatement {
1627 direction: CopyDirection::To,
1628 ..
1629 }) => true,
1630 Statement::Copy(CopyStatement {
1631 direction: CopyDirection::From,
1632 target: CopyTarget::Expr(_),
1636 ..
1637 }) => true,
1638 _ => false,
1639 }) {
1640 if let Some(desc) = stmt.desc().relation_desc.clone() {
1641 for (format, ty) in result_formats.iter().zip_eq(desc.iter_types()) {
1642 if let Format::Binary = format {
1643 if let Err(msg) = mz_pgrepr::Value::binary_encoding_error(&ty.scalar_type) {
1644 return self
1645 .send_error_and_get_state(ErrorResponse::error(
1646 SqlState::UNDEFINED_FUNCTION,
1647 msg,
1648 ))
1649 .await;
1650 }
1651 }
1652 }
1653 }
1654 }
1655
1656 let desc = stmt.desc().clone();
1657 let logging = Arc::clone(stmt.logging());
1658 let stmt_ast = stmt.stmt().cloned();
1659 let state_revision = stmt.state_revision;
1660 if let Err(err) = self.adapter_client.session().set_portal(
1661 portal_name,
1662 desc,
1663 stmt_ast,
1664 logging,
1665 params,
1666 result_formats,
1667 state_revision,
1668 ) {
1669 return self
1670 .send_error_and_get_state(err.into_response(Severity::Error))
1671 .await;
1672 }
1673
1674 self.send(BackendMessage::BindComplete).await?;
1675 Ok(State::Ready)
1676 }
1677
1678 fn execute(
1681 &mut self,
1682 portal_name: String,
1683 max_rows: ExecuteCount,
1684 get_response: GetResponse,
1685 fetch_portal_name: Option<String>,
1686 timeout: ExecuteTimeout,
1687 outer_ctx_extra: Option<ExecuteContextGuard>,
1688 received: Option<EpochMillis>,
1689 ) -> BoxFuture<'_, Result<State, io::Error>> {
1690 async move {
1691 let aborted_txn = self.is_aborted_txn();
1692
1693 let portal = match self
1695 .adapter_client
1696 .session()
1697 .get_portal_unverified_mut(&portal_name)
1698 {
1699 Some(portal) => portal,
1700 None => {
1701 let msg = format!("portal {} does not exist", portal_name.quoted());
1702 if let Some(outer_ctx_extra) = outer_ctx_extra {
1703 self.adapter_client.retire_execute(
1704 outer_ctx_extra,
1705 StatementEndedExecutionReason::Errored { error: msg.clone() },
1706 );
1707 }
1708 return self
1709 .send_error_and_get_state(ErrorResponse::error(
1710 SqlState::INVALID_CURSOR_NAME,
1711 msg,
1712 ))
1713 .await;
1714 }
1715 };
1716
1717 *portal.lifecycle_timestamps = received.map(LifecycleTimestamps::new);
1718
1719 let txn_exit_stmt = is_txn_exit_stmt(portal.stmt.as_deref());
1721 if aborted_txn && !txn_exit_stmt {
1722 if let Some(outer_ctx_extra) = outer_ctx_extra {
1723 self.adapter_client.retire_execute(
1724 outer_ctx_extra,
1725 StatementEndedExecutionReason::Errored {
1726 error: ABORTED_TXN_MSG.to_string(),
1727 },
1728 );
1729 }
1730 return self.aborted_txn_error().await;
1731 }
1732
1733 let row_desc = portal.desc.relation_desc.clone();
1734 match portal.state {
1735 PortalState::NotStarted => {
1736 self.ensure_transaction(1, "execute").await?;
1738 match self
1739 .adapter_client
1740 .execute(
1741 portal_name.clone(),
1742 self.conn.wait_closed(),
1743 outer_ctx_extra,
1744 )
1745 .await
1746 {
1747 Ok((response, execute_started)) => {
1748 self.send_pending_notices().await?;
1749 self.send_execute_response(
1750 response,
1751 row_desc,
1752 portal_name,
1753 max_rows,
1754 get_response,
1755 fetch_portal_name,
1756 timeout,
1757 execute_started,
1758 )
1759 .await
1760 }
1761 Err(e) => {
1762 self.send_pending_notices().await?;
1763 self.send_error_and_get_state(e.into_response(Severity::Error))
1764 .await
1765 }
1766 }
1767 }
1768 PortalState::InProgress(rows) => {
1769 let rows = rows.take().expect("InProgress rows must be populated");
1770 let (result, statement_ended_execution_reason) = match self
1771 .send_rows(
1772 row_desc.expect("portal missing row desc on resumption"),
1773 portal_name,
1774 rows,
1775 max_rows,
1776 get_response,
1777 fetch_portal_name,
1778 timeout,
1779 )
1780 .await
1781 {
1782 Err(e) => {
1783 (Err(e), StatementEndedExecutionReason::Canceled)
1786 }
1787 Ok((ok, SendRowsEndedReason::Canceled)) => {
1788 (Ok(ok), StatementEndedExecutionReason::Canceled)
1789 }
1790 Ok((
1803 ok,
1804 SendRowsEndedReason::Success {
1805 result_size: _,
1806 rows_returned: _,
1807 },
1808 )) => (
1809 Ok(ok),
1810 StatementEndedExecutionReason::Success {
1811 result_size: None,
1812 rows_returned: None,
1813 execution_strategy: None,
1814 },
1815 ),
1816 Ok((ok, SendRowsEndedReason::Errored { error })) => {
1817 (Ok(ok), StatementEndedExecutionReason::Errored { error })
1818 }
1819 };
1820 if let Some(outer_ctx_extra) = outer_ctx_extra {
1821 self.adapter_client
1822 .retire_execute(outer_ctx_extra, statement_ended_execution_reason);
1823 }
1824 result
1825 }
1826 PortalState::Completed(Some(tag)) => {
1833 let tag = tag.to_string();
1834 if let Some(outer_ctx_extra) = outer_ctx_extra {
1835 self.adapter_client.retire_execute(
1836 outer_ctx_extra,
1837 StatementEndedExecutionReason::Success {
1838 result_size: None,
1839 rows_returned: None,
1840 execution_strategy: None,
1841 },
1842 );
1843 }
1844 self.send(BackendMessage::CommandComplete { tag }).await?;
1845 Ok(State::Ready)
1846 }
1847 PortalState::Completed(None) => {
1848 let error = format!(
1849 "portal {} cannot be run",
1850 Ident::new_unchecked(portal_name).to_ast_string_stable()
1851 );
1852 if let Some(outer_ctx_extra) = outer_ctx_extra {
1853 self.adapter_client.retire_execute(
1854 outer_ctx_extra,
1855 StatementEndedExecutionReason::Errored {
1856 error: error.clone(),
1857 },
1858 );
1859 }
1860 self.send_error_and_get_state(ErrorResponse::error(
1861 SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE,
1862 error,
1863 ))
1864 .await
1865 }
1866 }
1867 }
1868 .instrument(debug_span!("execute"))
1869 .boxed()
1870 }
1871
1872 #[instrument(level = "debug")]
1873 async fn describe_statement(&mut self, name: &str) -> Result<State, io::Error> {
1874 self.ensure_transaction(1, "describe_statement").await?;
1876
1877 let stmt = match self.adapter_client.get_prepared_statement(name).await {
1878 Ok(stmt) => stmt,
1879 Err(err) => {
1880 return self
1881 .send_error_and_get_state(err.into_response(Severity::Error))
1882 .await;
1883 }
1884 };
1885 let parameter_desc = BackendMessage::ParameterDescription(
1887 stmt.desc()
1888 .param_types
1889 .iter()
1890 .map(mz_pgrepr::Type::from)
1891 .collect(),
1892 );
1893 let formats = vec![Format::Text; stmt.desc().arity()];
1897 let row_desc = describe_rows(stmt.desc(), &formats);
1898 self.send_all([parameter_desc, row_desc]).await?;
1899 Ok(State::Ready)
1900 }
1901
1902 #[instrument(level = "debug")]
1903 async fn describe_portal(&mut self, name: &str) -> Result<State, io::Error> {
1904 self.ensure_transaction(1, "describe_portal").await?;
1906
1907 let session = self.adapter_client.session();
1908 let row_desc = session
1909 .get_portal_unverified(name)
1910 .map(|portal| describe_rows(&portal.desc, &portal.result_formats));
1911 match row_desc {
1912 Some(row_desc) => {
1913 self.send(row_desc).await?;
1914 Ok(State::Ready)
1915 }
1916 None => {
1917 self.send_error_and_get_state(ErrorResponse::error(
1918 SqlState::INVALID_CURSOR_NAME,
1919 format!("portal {} does not exist", name.quoted()),
1920 ))
1921 .await
1922 }
1923 }
1924 }
1925
1926 #[instrument(level = "debug")]
1927 async fn close_statement(&mut self, name: String) -> Result<State, io::Error> {
1928 self.adapter_client
1929 .session()
1930 .remove_prepared_statement(&name);
1931 self.send(BackendMessage::CloseComplete).await?;
1932 Ok(State::Ready)
1933 }
1934
1935 #[instrument(level = "debug")]
1936 async fn close_portal(&mut self, name: String) -> Result<State, io::Error> {
1937 self.adapter_client.session().remove_portal(&name);
1938 self.send(BackendMessage::CloseComplete).await?;
1939 Ok(State::Ready)
1940 }
1941
1942 fn complete_portal(&mut self, name: &str) {
1943 let portal = self
1944 .adapter_client
1945 .session()
1946 .get_portal_unverified_mut(name)
1947 .expect("portal should exist");
1948 *portal.state = PortalState::Completed(None);
1949 }
1950
1951 async fn fetch(
1952 &mut self,
1953 name: String,
1954 count: Option<FetchDirection>,
1955 max_rows: ExecuteCount,
1956 fetch_portal_name: Option<String>,
1957 timeout: ExecuteTimeout,
1958 ctx_extra: ExecuteContextGuard,
1959 ) -> Result<State, io::Error> {
1960 let count = count.unwrap_or(FetchDirection::ForwardCount(1));
1963
1964 let count = match (max_rows, count) {
1977 (ExecuteCount::Count(max_rows), FetchDirection::ForwardCount(count)) => {
1978 let count = usize::cast_from(count);
1979 if max_rows < count {
1980 let msg = "Execute with max_rows < a FETCH's count is not supported";
1981 self.adapter_client.retire_execute(
1982 ctx_extra,
1983 StatementEndedExecutionReason::Errored {
1984 error: msg.to_string(),
1985 },
1986 );
1987 return self
1988 .send_error_and_get_state(ErrorResponse::error(
1989 SqlState::FEATURE_NOT_SUPPORTED,
1990 msg,
1991 ))
1992 .await;
1993 }
1994 ExecuteCount::Count(count)
1995 }
1996 (ExecuteCount::Count(_), FetchDirection::ForwardAll) => {
1997 let msg = "Execute with max_rows of a FETCH ALL is not supported";
1998 self.adapter_client.retire_execute(
1999 ctx_extra,
2000 StatementEndedExecutionReason::Errored {
2001 error: msg.to_string(),
2002 },
2003 );
2004 return self
2005 .send_error_and_get_state(ErrorResponse::error(
2006 SqlState::FEATURE_NOT_SUPPORTED,
2007 msg,
2008 ))
2009 .await;
2010 }
2011 (ExecuteCount::All, FetchDirection::ForwardAll) => ExecuteCount::All,
2012 (ExecuteCount::All, FetchDirection::ForwardCount(count)) => {
2013 ExecuteCount::Count(usize::cast_from(count))
2014 }
2015 };
2016 let cursor_name = name.to_string();
2017 self.execute(
2018 cursor_name,
2019 count,
2020 fetch_message,
2021 fetch_portal_name,
2022 timeout,
2023 Some(ctx_extra),
2024 None,
2025 )
2026 .await
2027 }
2028
2029 async fn flush(&mut self) -> Result<State, io::Error> {
2030 self.conn.flush().await?;
2031 Ok(State::Ready)
2032 }
2033
2034 #[instrument(level = "debug")]
2039 async fn send<M>(&mut self, message: M) -> Result<(), io::Error>
2040 where
2041 M: Into<BackendMessage>,
2042 {
2043 let message: BackendMessage = message.into();
2044 let is_error =
2045 matches!(&message, BackendMessage::ErrorResponse(e) if e.severity.is_error());
2046
2047 self.conn.send(message).await?;
2048
2049 if is_error {
2056 self.conn.flush().await?;
2057 }
2058
2059 Ok(())
2060 }
2061
2062 #[instrument(level = "debug")]
2063 pub async fn send_all(
2064 &mut self,
2065 messages: impl IntoIterator<Item = BackendMessage>,
2066 ) -> Result<(), io::Error> {
2067 for m in messages {
2068 self.send(m).await?;
2069 }
2070 Ok(())
2071 }
2072
2073 #[instrument(level = "debug")]
2074 async fn sync(&mut self) -> Result<State, io::Error> {
2075 if self.adapter_client.session().transaction().is_implicit() {
2077 self.commit_transaction().await?;
2078 }
2079 self.ready().await
2080 }
2081
2082 #[instrument(level = "debug")]
2083 async fn ready(&mut self) -> Result<State, io::Error> {
2084 let txn_state = self.adapter_client.session().transaction().into();
2085 self.send(BackendMessage::ReadyForQuery(txn_state)).await?;
2086 self.flush().await
2087 }
2088
2089 #[allow(clippy::too_many_arguments)]
2090 #[instrument(level = "debug")]
2091 async fn send_execute_response(
2092 &mut self,
2093 response: ExecuteResponse,
2094 row_desc: Option<RelationDesc>,
2095 portal_name: String,
2096 max_rows: ExecuteCount,
2097 get_response: GetResponse,
2098 fetch_portal_name: Option<String>,
2099 timeout: ExecuteTimeout,
2100 execute_started: Instant,
2101 ) -> Result<State, io::Error> {
2102 let mut tag = response.tag();
2103
2104 macro_rules! command_complete {
2105 () => {{
2106 self.send(BackendMessage::CommandComplete {
2107 tag: tag
2108 .take()
2109 .expect("command_complete only called on tag-generating results"),
2110 })
2111 .await?;
2112 Ok(State::Ready)
2113 }};
2114 }
2115
2116 let r = match response {
2117 ExecuteResponse::ClosedCursor => {
2118 self.complete_portal(&portal_name);
2119 command_complete!()
2120 }
2121 ExecuteResponse::DeclaredCursor => {
2122 self.complete_portal(&portal_name);
2123 command_complete!()
2124 }
2125 ExecuteResponse::EmptyQuery => {
2126 self.send(BackendMessage::EmptyQueryResponse).await?;
2127 Ok(State::Ready)
2128 }
2129 ExecuteResponse::Fetch {
2130 name,
2131 count,
2132 timeout,
2133 ctx_extra,
2134 } => {
2135 self.fetch(
2136 name,
2137 count,
2138 max_rows,
2139 Some(portal_name.to_string()),
2140 timeout,
2141 ctx_extra,
2142 )
2143 .await
2144 }
2145 ExecuteResponse::SendingRowsStreaming {
2146 rows,
2147 instance_id,
2148 strategy,
2149 } => {
2150 let row_desc = row_desc
2151 .expect("missing row description for ExecuteResponse::SendingRowsStreaming");
2152
2153 let span = tracing::debug_span!("sending_rows_streaming");
2154
2155 self.send_rows(
2156 row_desc,
2157 portal_name,
2158 InProgressRows::new(RecordFirstRowStream::new(
2159 Box::new(rows),
2160 execute_started,
2161 &self.adapter_client,
2162 Some(instance_id),
2163 Some(strategy),
2164 )),
2165 max_rows,
2166 get_response,
2167 fetch_portal_name,
2168 timeout,
2169 )
2170 .instrument(span)
2171 .await
2172 .map(|(state, _)| state)
2173 }
2174 ExecuteResponse::SendingRowsImmediate { rows } => {
2175 let row_desc = row_desc
2176 .expect("missing row description for ExecuteResponse::SendingRowsImmediate");
2177
2178 let span = tracing::debug_span!("sending_rows_immediate");
2179
2180 let stream =
2181 futures::stream::once(futures::future::ready(PeekResponseUnary::Rows(rows)));
2182 self.send_rows(
2183 row_desc,
2184 portal_name,
2185 InProgressRows::new(RecordFirstRowStream::new(
2186 Box::new(stream),
2187 execute_started,
2188 &self.adapter_client,
2189 None,
2190 Some(StatementExecutionStrategy::Constant),
2191 )),
2192 max_rows,
2193 get_response,
2194 fetch_portal_name,
2195 timeout,
2196 )
2197 .instrument(span)
2198 .await
2199 .map(|(state, _)| state)
2200 }
2201 ExecuteResponse::SetVariable { name, .. } => {
2202 let qn = name.to_string();
2205 let msg = if let Some(var) = self
2206 .adapter_client
2207 .session()
2208 .vars_mut()
2209 .notify_set()
2210 .find(|v| v.name() == qn)
2211 {
2212 Some(BackendMessage::ParameterStatus(var.name(), var.value()))
2213 } else {
2214 None
2215 };
2216 if let Some(msg) = msg {
2217 self.send(msg).await?;
2218 }
2219 command_complete!()
2220 }
2221 ExecuteResponse::Subscribing {
2222 rx,
2223 ctx_extra,
2224 instance_id,
2225 } => {
2226 if fetch_portal_name.is_none() {
2227 let mut msg = ErrorResponse::notice(
2228 SqlState::WARNING,
2229 "streaming SUBSCRIBE rows directly requires a client that does not buffer output",
2230 );
2231 if self.adapter_client.session().vars().application_name() == "psql" {
2232 msg.hint = Some(
2233 "Wrap your SUBSCRIBE statement in `COPY (SUBSCRIBE ...) TO STDOUT`."
2234 .into(),
2235 )
2236 }
2237 self.send(msg).await?;
2238 self.conn.flush().await?;
2239 }
2240 let row_desc =
2241 row_desc.expect("missing row description for ExecuteResponse::Subscribing");
2242 let (result, statement_ended_execution_reason) = match self
2243 .send_rows(
2244 row_desc,
2245 portal_name,
2246 InProgressRows::new(RecordFirstRowStream::new(
2247 rx,
2248 execute_started,
2249 &self.adapter_client,
2250 Some(instance_id),
2251 None,
2252 )),
2253 max_rows,
2254 get_response,
2255 fetch_portal_name,
2256 timeout,
2257 )
2258 .await
2259 {
2260 Err(e) => {
2261 (Err(e), StatementEndedExecutionReason::Canceled)
2264 }
2265 Ok((ok, SendRowsEndedReason::Canceled)) => {
2266 (Ok(ok), StatementEndedExecutionReason::Canceled)
2267 }
2268 Ok((
2269 ok,
2270 SendRowsEndedReason::Success {
2271 result_size,
2272 rows_returned,
2273 },
2274 )) => (
2275 Ok(ok),
2276 StatementEndedExecutionReason::Success {
2277 result_size: Some(result_size),
2278 rows_returned: Some(rows_returned),
2279 execution_strategy: None,
2280 },
2281 ),
2282 Ok((ok, SendRowsEndedReason::Errored { error })) => {
2283 (Ok(ok), StatementEndedExecutionReason::Errored { error })
2284 }
2285 };
2286 self.adapter_client
2287 .retire_execute(ctx_extra, statement_ended_execution_reason);
2288 return result;
2289 }
2290 ExecuteResponse::CopyTo { format, resp } => {
2291 let row_desc =
2292 row_desc.expect("missing row description for ExecuteResponse::CopyTo");
2293 match *resp {
2294 ExecuteResponse::Subscribing {
2295 rx,
2296 ctx_extra,
2297 instance_id,
2298 } => {
2299 let (result, statement_ended_execution_reason) = match self
2300 .copy_rows(
2301 format,
2302 row_desc,
2303 RecordFirstRowStream::new(
2304 rx,
2305 execute_started,
2306 &self.adapter_client,
2307 Some(instance_id),
2308 None,
2309 ),
2310 )
2311 .await
2312 {
2313 Err(e) => {
2314 (Err(e), StatementEndedExecutionReason::Canceled)
2317 }
2318 Ok((
2319 state,
2320 SendRowsEndedReason::Success {
2321 result_size,
2322 rows_returned,
2323 },
2324 )) => (
2325 Ok(state),
2326 StatementEndedExecutionReason::Success {
2327 result_size: Some(result_size),
2328 rows_returned: Some(rows_returned),
2329 execution_strategy: None,
2330 },
2331 ),
2332 Ok((state, SendRowsEndedReason::Errored { error })) => {
2333 (Ok(state), StatementEndedExecutionReason::Errored { error })
2334 }
2335 Ok((state, SendRowsEndedReason::Canceled)) => {
2336 (Ok(state), StatementEndedExecutionReason::Canceled)
2337 }
2338 };
2339 self.adapter_client
2340 .retire_execute(ctx_extra, statement_ended_execution_reason);
2341 return result;
2342 }
2343 ExecuteResponse::SendingRowsStreaming {
2344 rows,
2345 instance_id,
2346 strategy,
2347 } => {
2348 return self
2353 .copy_rows(
2354 format,
2355 row_desc,
2356 RecordFirstRowStream::new(
2357 Box::new(rows),
2358 execute_started,
2359 &self.adapter_client,
2360 Some(instance_id),
2361 Some(strategy),
2362 ),
2363 )
2364 .await
2365 .map(|(state, _)| state);
2366 }
2367 ExecuteResponse::SendingRowsImmediate { rows } => {
2368 let span = tracing::debug_span!("sending_rows_immediate");
2369
2370 let rows = futures::stream::once(futures::future::ready(
2371 PeekResponseUnary::Rows(rows),
2372 ));
2373 return self
2378 .copy_rows(
2379 format,
2380 row_desc,
2381 RecordFirstRowStream::new(
2382 Box::new(rows),
2383 execute_started,
2384 &self.adapter_client,
2385 None,
2386 Some(StatementExecutionStrategy::Constant),
2387 ),
2388 )
2389 .instrument(span)
2390 .await
2391 .map(|(state, _)| state);
2392 }
2393 _ => {
2394 return self
2395 .send_error_and_get_state(ErrorResponse::error(
2396 SqlState::INTERNAL_ERROR,
2397 "unsupported COPY response type".to_string(),
2398 ))
2399 .await;
2400 }
2401 };
2402 }
2403 ExecuteResponse::CopyFrom {
2404 target_id,
2405 target_name,
2406 columns,
2407 params,
2408 ctx_extra,
2409 } => {
2410 let row_desc =
2411 row_desc.expect("missing row description for ExecuteResponse::CopyFrom");
2412 self.copy_from(target_id, target_name, columns, params, row_desc, ctx_extra)
2413 .await
2414 }
2415 ExecuteResponse::TransactionCommitted { params }
2416 | ExecuteResponse::TransactionRolledBack { params } => {
2417 self.send_parameter_statuses(params).await?;
2418 command_complete!()
2419 }
2420
2421 ExecuteResponse::AlteredDefaultPrivileges
2422 | ExecuteResponse::AlteredObject(..)
2423 | ExecuteResponse::AlteredRole
2424 | ExecuteResponse::AlteredSystemConfiguration
2425 | ExecuteResponse::CreatedCluster { .. }
2426 | ExecuteResponse::CreatedClusterReplica { .. }
2427 | ExecuteResponse::CreatedConnection { .. }
2428 | ExecuteResponse::CreatedDatabase { .. }
2429 | ExecuteResponse::CreatedIndex { .. }
2430 | ExecuteResponse::CreatedMetricSink { .. }
2431 | ExecuteResponse::CreatedIntrospectionSubscribe
2432 | ExecuteResponse::CreatedMaterializedView { .. }
2433 | ExecuteResponse::CreatedRole
2434 | ExecuteResponse::CreatedSchema { .. }
2435 | ExecuteResponse::CreatedSecret { .. }
2436 | ExecuteResponse::CreatedSink { .. }
2437 | ExecuteResponse::CreatedSource { .. }
2438 | ExecuteResponse::CreatedTable { .. }
2439 | ExecuteResponse::CreatedType
2440 | ExecuteResponse::CreatedView { .. }
2441 | ExecuteResponse::CreatedViews { .. }
2442 | ExecuteResponse::CreatedNetworkPolicy
2443 | ExecuteResponse::Comment
2444 | ExecuteResponse::Deallocate { .. }
2445 | ExecuteResponse::Deleted(..)
2446 | ExecuteResponse::DiscardedAll
2447 | ExecuteResponse::DiscardedTemp
2448 | ExecuteResponse::DroppedObject(_)
2449 | ExecuteResponse::DroppedOwned
2450 | ExecuteResponse::GrantedPrivilege
2451 | ExecuteResponse::GrantedRole
2452 | ExecuteResponse::Inserted(..)
2453 | ExecuteResponse::Copied(..)
2454 | ExecuteResponse::Prepare
2455 | ExecuteResponse::Raised
2456 | ExecuteResponse::ReassignOwned
2457 | ExecuteResponse::RevokedPrivilege
2458 | ExecuteResponse::RevokedRole
2459 | ExecuteResponse::StartedTransaction { .. }
2460 | ExecuteResponse::Updated(..)
2461 | ExecuteResponse::ValidatedConnection => {
2462 command_complete!()
2463 }
2464 };
2465
2466 assert_none!(tag, "tag created but not consumed: {:?}", tag);
2467 r
2468 }
2469
2470 #[allow(clippy::too_many_arguments)]
2471 #[mz_ore::instrument(level = "debug")]
2473 async fn send_rows(
2474 &mut self,
2475 row_desc: RelationDesc,
2476 portal_name: String,
2477 mut rows: InProgressRows,
2478 max_rows: ExecuteCount,
2479 get_response: GetResponse,
2480 fetch_portal_name: Option<String>,
2481 timeout: ExecuteTimeout,
2482 ) -> Result<(State, SendRowsEndedReason), io::Error> {
2483 let result_format_portal_name: &str = if let Some(ref name) = fetch_portal_name {
2486 name
2487 } else {
2488 &portal_name
2489 };
2490 let result_formats = self
2491 .adapter_client
2492 .session()
2493 .get_portal_unverified(result_format_portal_name)
2494 .expect("valid fetch portal name for send rows")
2495 .result_formats
2496 .clone();
2497
2498 let (mut wait_once, mut deadline) = match timeout {
2499 ExecuteTimeout::None => (false, None),
2500 ExecuteTimeout::Seconds(t) => (
2501 false,
2502 Some(tokio::time::Instant::now() + tokio::time::Duration::from_secs_f64(t)),
2503 ),
2504 ExecuteTimeout::WaitOnce => (true, None),
2505 };
2506
2507 {
2509 let portal_name_desc = &self
2510 .adapter_client
2511 .session()
2512 .get_portal_unverified(portal_name.as_str())
2513 .expect("portal should exist")
2514 .desc
2515 .relation_desc;
2516 if let Some(portal_name_desc) = portal_name_desc {
2517 soft_assert_eq_or_log!(portal_name_desc, &row_desc);
2518 }
2519 if let Some(fetch_portal_name) = &fetch_portal_name {
2520 let fetch_portal_desc = &self
2521 .adapter_client
2522 .session()
2523 .get_portal_unverified(fetch_portal_name)
2524 .expect("portal should exist")
2525 .desc
2526 .relation_desc;
2527 if let Some(fetch_portal_desc) = fetch_portal_desc {
2528 soft_assert_eq_or_log!(fetch_portal_desc, &row_desc);
2529 }
2530 }
2531 }
2532
2533 self.conn.set_encode_state(
2534 row_desc
2535 .typ()
2536 .column_types
2537 .iter()
2538 .map(|ty| mz_pgrepr::Type::from(&ty.scalar_type))
2539 .zip_eq(result_formats)
2540 .collect(),
2541 self.adapter_client.session().vars().text_encode_settings(),
2542 );
2543
2544 let mut total_sent_rows = 0;
2545 let mut total_sent_bytes = 0;
2546 let mut want_rows = match max_rows {
2548 ExecuteCount::All => usize::MAX,
2549 ExecuteCount::Count(count) => count,
2550 };
2551
2552 loop {
2554 let batch = if rows.current.is_some() {
2557 FetchResult::Rows(rows.current.take())
2558 } else if want_rows == 0 {
2559 FetchResult::Rows(None)
2560 } else {
2561 let notice_fut = self.adapter_client.session().recv_notice();
2562 tokio::select! {
2577 biased;
2578 err = self.conn.wait_closed() => return Err(err),
2579 batch = rows.remaining.recv() => match batch {
2580 None => FetchResult::Rows(None),
2581 Some(PeekResponseUnary::Rows(rows)) => FetchResult::Rows(Some(rows)),
2582 Some(PeekResponseUnary::Error(err)) => {
2583 FetchResult::Error(ErrorResponse::error(SqlState::INTERNAL_ERROR, err))
2584 }
2585 Some(PeekResponseUnary::DependencyDropped(dep)) => {
2586 FetchResult::Error(
2587 dep.to_concurrent_dependency_drop()
2588 .into_response(Severity::Error),
2589 )
2590 }
2591 Some(PeekResponseUnary::Canceled) => FetchResult::Canceled,
2592 },
2593 notice = notice_fut => {
2594 FetchResult::Notice(notice)
2595 }
2596 _ = time::sleep_until(
2597 deadline.unwrap_or_else(tokio::time::Instant::now),
2598 ), if deadline.is_some() => FetchResult::Rows(None),
2599 }
2600 };
2601
2602 match batch {
2603 FetchResult::Rows(None) => break,
2604 FetchResult::Rows(Some(mut batch_rows)) => {
2605 if let Err(err) = verify_datum_desc(&row_desc, &mut batch_rows) {
2606 let msg = err.to_string();
2607 return self
2608 .send_error_and_get_state(err.into_response(Severity::Error))
2609 .await
2610 .map(|state| (state, SendRowsEndedReason::Errored { error: msg }));
2611 }
2612
2613 if wait_once && batch_rows.peek().is_some() {
2617 deadline = Some(tokio::time::Instant::now());
2618 wait_once = false;
2619 }
2620
2621 let mut sent_rows = 0;
2623 let mut sent_bytes = 0;
2624 let messages = (&mut batch_rows)
2625 .map(|row| {
2630 let row_len = row.byte_len();
2631 let values = mz_pgrepr::values_from_row(row, row_desc.typ());
2632 (row_len, BackendMessage::DataRow(values))
2633 })
2634 .inspect(|(row_len, _)| {
2635 sent_bytes += row_len;
2636 sent_rows += 1
2637 })
2638 .map(|(_row_len, row)| row)
2639 .take(want_rows);
2640 self.send_all(messages).await?;
2641
2642 total_sent_rows += sent_rows;
2643 total_sent_bytes += sent_bytes;
2644 want_rows -= sent_rows;
2645
2646 if want_rows == 0 {
2649 if batch_rows.peek().is_some() {
2650 rows.current = Some(batch_rows);
2651 }
2652 break;
2653 }
2654
2655 self.conn.flush().await?;
2656 }
2657 FetchResult::Notice(notice) => {
2658 self.send(notice.into_response()).await?;
2659 self.conn.flush().await?;
2660 }
2661 FetchResult::Error(err) => {
2662 let text = err.message.clone();
2663 return self
2664 .send_error_and_get_state(err)
2665 .await
2666 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2667 }
2668 FetchResult::Canceled => {
2669 return self
2670 .send_error_and_get_state(ErrorResponse::error(
2671 SqlState::QUERY_CANCELED,
2672 "canceling statement due to user request",
2673 ))
2674 .await
2675 .map(|state| (state, SendRowsEndedReason::Canceled));
2676 }
2677 }
2678 }
2679
2680 let portal = self
2681 .adapter_client
2682 .session()
2683 .get_portal_unverified_mut(&portal_name)
2684 .expect("valid portal name for send rows");
2685
2686 let saw_rows = rows.remaining.saw_rows;
2687 let no_more_rows = rows.no_more_rows();
2688 let metric_recorded = rows.remaining.metric_recorded;
2689 let recorded_first_row_instant = rows.remaining.recorded_first_row_instant;
2690
2691 if no_more_rows && !metric_recorded {
2692 rows.remaining.metric_recorded = true;
2693 }
2694
2695 *portal.state = PortalState::InProgress(Some(rows));
2698
2699 let fetch_portal = fetch_portal_name.map(|name| {
2700 self.adapter_client
2701 .session()
2702 .get_portal_unverified_mut(&name)
2703 .expect("valid fetch portal")
2704 });
2705 let response_message = get_response(max_rows, total_sent_rows, fetch_portal);
2706 self.send(response_message).await?;
2707
2708 if no_more_rows && !metric_recorded {
2711 let statement_type = if let Some(stmt) = &self
2712 .adapter_client
2713 .session()
2714 .get_portal_unverified(&portal_name)
2715 .expect("valid portal name for send_rows")
2716 .stmt
2717 {
2718 metrics::statement_type_label_value(stmt.deref())
2719 } else {
2720 "no-statement"
2721 };
2722 let duration = if saw_rows {
2723 recorded_first_row_instant
2724 .expect("recorded_first_row_instant because saw_rows")
2725 .elapsed()
2726 } else {
2727 Duration::ZERO
2731 };
2732 self.adapter_client
2733 .inner()
2734 .metrics()
2735 .result_rows_first_to_last_byte_seconds
2736 .with_label_values(&[statement_type])
2737 .observe(duration.as_secs_f64());
2738 }
2739
2740 Ok((
2741 State::Ready,
2742 SendRowsEndedReason::Success {
2743 result_size: u64::cast_from(total_sent_bytes),
2744 rows_returned: u64::cast_from(total_sent_rows),
2745 },
2746 ))
2747 }
2748
2749 #[mz_ore::instrument(level = "debug")]
2750 async fn copy_rows(
2751 &mut self,
2752 format: CopyFormat,
2753 row_desc: RelationDesc,
2754 mut stream: RecordFirstRowStream,
2755 ) -> Result<(State, SendRowsEndedReason), io::Error> {
2756 let (row_format, encode_format) = match format {
2757 CopyFormat::Text => (
2758 CopyFormatParams::Text(CopyTextFormatParams::default()),
2759 Format::Text,
2760 ),
2761 CopyFormat::Binary => (CopyFormatParams::Binary, Format::Binary),
2762 CopyFormat::Csv => (
2763 CopyFormatParams::Csv(CopyCsvFormatParams::default()),
2764 Format::Text,
2765 ),
2766 CopyFormat::Parquet => {
2767 let text = "Parquet format is not supported".to_string();
2768 return self
2769 .send_error_and_get_state(ErrorResponse::error(
2770 SqlState::INTERNAL_ERROR,
2771 text.clone(),
2772 ))
2773 .await
2774 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2775 }
2776 };
2777
2778 if let CopyFormat::Binary = format {
2786 if let Some(msg) = row_desc
2787 .iter_types()
2788 .find_map(|ty| mz_pgrepr::Value::binary_encoding_error(&ty.scalar_type).err())
2789 {
2790 return self
2791 .send_error_and_get_state(ErrorResponse::error(
2792 SqlState::UNDEFINED_FUNCTION,
2793 msg,
2794 ))
2795 .await
2796 .map(|state| {
2797 (
2798 state,
2799 SendRowsEndedReason::Errored {
2800 error: msg.to_string(),
2801 },
2802 )
2803 });
2804 }
2805 }
2806
2807 let text_settings = self.adapter_client.session().vars().text_encode_settings();
2811 let encode_fn = |row: &RowRef, typ: &SqlRelationType, out: &mut Vec<u8>| {
2812 mz_pgcopy::encode_copy_format(&row_format, row, typ, out, text_settings)
2813 };
2814
2815 let typ = row_desc.typ();
2816 let column_formats = iter::repeat(encode_format)
2817 .take(typ.column_types.len())
2818 .collect();
2819 self.send(BackendMessage::CopyOutResponse {
2820 overall_format: encode_format,
2821 column_formats,
2822 })
2823 .await?;
2824
2825 let mut out = Vec::new();
2830
2831 if let CopyFormat::Binary = format {
2832 out.extend(b"PGCOPY\n\xFF\r\n\0");
2834 out.extend([0, 0, 0, 0]);
2836 out.extend([0, 0, 0, 0]);
2838 }
2839
2840 let mut count = 0;
2841 let mut total_sent_bytes = 0;
2842 loop {
2843 tokio::select! {
2844 e = self.conn.wait_closed() => return Err(e),
2845 batch = stream.recv() => match batch {
2846 None => break,
2847 Some(PeekResponseUnary::Error(text)) => {
2848 let err =
2849 ErrorResponse::error(SqlState::INTERNAL_ERROR, text.clone());
2850 return self
2851 .send_error_and_get_state(err)
2852 .await
2853 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2854 }
2855 Some(PeekResponseUnary::DependencyDropped(dep)) => {
2856 let err = dep.to_concurrent_dependency_drop();
2857 let text = err.to_string();
2858 let resp = err.into_response(Severity::Error);
2859 return self
2860 .send_error_and_get_state(resp)
2861 .await
2862 .map(|state| (state, SendRowsEndedReason::Errored { error: text }));
2863 }
2864 Some(PeekResponseUnary::Canceled) => {
2865 return self.send_error_and_get_state(ErrorResponse::error(
2866 SqlState::QUERY_CANCELED,
2867 "canceling statement due to user request",
2868 ))
2869 .await.map(|state| (state, SendRowsEndedReason::Canceled));
2870 }
2871 Some(PeekResponseUnary::Rows(mut rows)) => {
2872 count += rows.count();
2873 while let Some(row) = rows.next() {
2874 total_sent_bytes += row.byte_len();
2875 encode_fn(row, typ, &mut out)?;
2876 self.send(BackendMessage::CopyData(mem::take(&mut out)))
2877 .await?;
2878 }
2879 }
2880 },
2881 notice = self.adapter_client.session().recv_notice() => {
2882 self.send(notice.into_response())
2883 .await?;
2884 self.conn.flush().await?;
2885 }
2886 }
2887
2888 self.conn.flush().await?;
2889 }
2890 if let CopyFormat::Binary = format {
2892 let trailer: i16 = -1;
2893 out.extend(trailer.to_be_bytes());
2894 self.send(BackendMessage::CopyData(mem::take(&mut out)))
2895 .await?;
2896 }
2897
2898 let tag = format!("COPY {}", count);
2899 self.send(BackendMessage::CopyDone).await?;
2900 self.send(BackendMessage::CommandComplete { tag }).await?;
2901 Ok((
2902 State::Ready,
2903 SendRowsEndedReason::Success {
2904 result_size: u64::cast_from(total_sent_bytes),
2905 rows_returned: u64::cast_from(count),
2906 },
2907 ))
2908 }
2909
2910 #[instrument(level = "debug")]
2913 async fn copy_from(
2914 &mut self,
2915 target_id: CatalogItemId,
2916 target_name: String,
2917 columns: Vec<ColumnIndex>,
2918 params: CopyFormatParams<'static>,
2919 row_desc: RelationDesc,
2920 mut ctx_extra: ExecuteContextGuard,
2921 ) -> Result<State, io::Error> {
2922 let res = self
2923 .copy_from_inner(
2924 target_id,
2925 target_name,
2926 columns,
2927 params,
2928 row_desc,
2929 &mut ctx_extra,
2930 )
2931 .await;
2932 match &res {
2933 Ok(State::Ready) => {
2934 self.adapter_client.retire_execute(
2935 ctx_extra,
2936 StatementEndedExecutionReason::Success {
2937 result_size: None,
2938 rows_returned: None,
2939 execution_strategy: None,
2940 },
2941 );
2942 }
2943 Ok(State::Done) => {
2944 self.adapter_client
2948 .retire_execute(ctx_extra, StatementEndedExecutionReason::Canceled);
2949 }
2950 Err(e) => {
2951 self.adapter_client.retire_execute(
2952 ctx_extra,
2953 StatementEndedExecutionReason::Errored {
2954 error: format!("{e}"),
2955 },
2956 );
2957 }
2958 Ok(State::Drain) => {}
2959 }
2960 res
2961 }
2962
2963 async fn copy_from_inner(
2964 &mut self,
2965 target_id: CatalogItemId,
2966 target_name: String,
2967 columns: Vec<ColumnIndex>,
2968 params: CopyFormatParams<'static>,
2969 row_desc: RelationDesc,
2970 ctx_extra: &mut ExecuteContextGuard,
2971 ) -> Result<State, io::Error> {
2972 let typ = row_desc.typ();
2973 let column_formats = vec![Format::Text; typ.column_types.len()];
2974 self.send(BackendMessage::CopyInResponse {
2975 overall_format: Format::Text,
2976 column_formats,
2977 })
2978 .await?;
2979 self.conn.flush().await?;
2980
2981 let writer = match self
2983 .adapter_client
2984 .start_copy_from_stdin(
2985 target_id,
2986 target_name.clone(),
2987 columns.clone(),
2988 row_desc.clone(),
2989 params.clone(),
2990 )
2991 .await
2992 {
2993 Ok(writer) => writer,
2994 Err(e) => {
2995 loop {
3001 match self.conn.recv().await? {
3002 Some(FrontendMessage::CopyData(_)) => {}
3003 Some(FrontendMessage::CopyDone) | Some(FrontendMessage::CopyFail(_)) => {
3004 break;
3005 }
3006 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
3007 Some(_) => break,
3008 None => return Ok(State::Done),
3009 }
3010 }
3011 self.adapter_client.retire_execute(
3012 std::mem::take(ctx_extra),
3013 StatementEndedExecutionReason::Errored {
3014 error: e.to_string(),
3015 },
3016 );
3017 return self
3018 .send_error_and_get_state(e.into_response(Severity::Error))
3019 .await;
3020 }
3021 };
3022
3023 const BATCH_SIZE: usize = 32 * 1024 * 1024;
3025 let max_copy_from_row_size = self
3026 .adapter_client
3027 .get_system_vars()
3028 .await
3029 .max_copy_from_row_size()
3030 .try_into()
3031 .unwrap_or(usize::MAX);
3032
3033 let mut data = Vec::new();
3034 let mut row_scanner = CopyRowScanner::new(¶ms);
3035 let num_workers = writer.batch_txs.len();
3036 let mut next_worker: usize = 0;
3037 let mut saw_copy_done = false;
3038 let mut saw_end_marker = false;
3039 let mut copy_from_error: Option<(SqlState, String)> = None;
3040
3041 loop {
3044 let message = self.conn.recv().await?;
3045 match message {
3046 Some(FrontendMessage::CopyData(buf)) => {
3047 if saw_end_marker {
3048 continue;
3051 }
3052 data.extend(buf);
3053 row_scanner.scan_new_bytes(&data);
3054
3055 if let Some(end_pos) = row_scanner.end_marker_end() {
3056 data.truncate(end_pos);
3057 row_scanner.on_truncate(end_pos);
3058 saw_end_marker = true;
3059 }
3060
3061 if row_scanner.current_row_size(data.len()) > max_copy_from_row_size {
3063 copy_from_error = Some((
3064 SqlState::INSUFFICIENT_RESOURCES,
3065 format!(
3066 "COPY FROM STDIN row exceeded max_copy_from_row_size \
3067 ({max_copy_from_row_size} bytes)"
3068 ),
3069 ));
3070 break;
3071 }
3072
3073 let mut send_failed = false;
3076 while data.len() >= BATCH_SIZE {
3077 let split_pos = match row_scanner.last_row_end() {
3078 Some(pos) => pos,
3079 None => break, };
3081 let remainder = data.split_off(split_pos);
3082 let chunk = std::mem::replace(&mut data, remainder);
3083 row_scanner.on_split(split_pos);
3084 if writer.batch_txs[next_worker].send(chunk).await.is_err() {
3085 send_failed = true;
3086 break;
3087 }
3088 next_worker = (next_worker + 1) % num_workers;
3089 }
3090 if send_failed {
3093 break;
3094 }
3095 }
3096 Some(FrontendMessage::CopyDone) => {
3097 if !data.is_empty() {
3099 let chunk = std::mem::take(&mut data);
3100 let _ = writer.batch_txs[next_worker].send(chunk).await;
3102 }
3103 saw_copy_done = true;
3104 break;
3105 }
3106 Some(FrontendMessage::CopyFail(err)) => {
3107 self.adapter_client.retire_execute(
3108 std::mem::take(ctx_extra),
3109 StatementEndedExecutionReason::Canceled,
3110 );
3111 drop(writer);
3113 return self
3114 .send_error_and_get_state(ErrorResponse::error(
3115 SqlState::QUERY_CANCELED,
3116 format!("COPY from stdin failed: {}", err),
3117 ))
3118 .await;
3119 }
3120 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
3121 Some(_) => {
3122 let msg = "unexpected message type during COPY from stdin";
3123 self.adapter_client.retire_execute(
3124 std::mem::take(ctx_extra),
3125 StatementEndedExecutionReason::Errored {
3126 error: msg.to_string(),
3127 },
3128 );
3129 drop(writer);
3130 return self
3131 .send_error_and_get_state(ErrorResponse::error(
3132 SqlState::PROTOCOL_VIOLATION,
3133 msg,
3134 ))
3135 .await;
3136 }
3137 None => {
3138 drop(writer);
3139 return Ok(State::Done);
3140 }
3141 }
3142 }
3143
3144 if !saw_copy_done {
3148 loop {
3149 match self.conn.recv().await? {
3150 Some(FrontendMessage::CopyData(_)) => {}
3151 Some(FrontendMessage::CopyDone) | Some(FrontendMessage::CopyFail(_)) => {
3152 break;
3153 }
3154 Some(FrontendMessage::Flush) | Some(FrontendMessage::Sync) => {}
3155 Some(_) => {
3156 let msg = "unexpected message type during COPY from stdin";
3157 self.adapter_client.retire_execute(
3158 std::mem::take(ctx_extra),
3159 StatementEndedExecutionReason::Errored {
3160 error: msg.to_string(),
3161 },
3162 );
3163 drop(writer);
3164 return self
3165 .send_error_and_get_state(ErrorResponse::error(
3166 SqlState::PROTOCOL_VIOLATION,
3167 msg,
3168 ))
3169 .await;
3170 }
3171 None => {
3172 drop(writer);
3173 return Ok(State::Done);
3174 }
3175 }
3176 }
3177 }
3178
3179 if let Some((code, msg)) = copy_from_error {
3180 self.adapter_client.retire_execute(
3181 std::mem::take(ctx_extra),
3182 StatementEndedExecutionReason::Errored { error: msg.clone() },
3183 );
3184 drop(writer);
3185 return self
3186 .send_error_and_get_state(ErrorResponse::error(code, msg))
3187 .await;
3188 }
3189
3190 drop(writer.batch_txs);
3195
3196 let (proto_batches, row_count) = match writer.completion_rx.await {
3198 Ok(Ok(result)) => result,
3199 Ok(Err(e)) => {
3200 self.adapter_client.retire_execute(
3201 std::mem::take(ctx_extra),
3202 StatementEndedExecutionReason::Errored {
3203 error: e.to_string(),
3204 },
3205 );
3206 return self
3207 .send_error_and_get_state(e.into_response(Severity::Error))
3208 .await;
3209 }
3210 Err(_) => {
3211 let msg = "COPY FROM STDIN: background batch builder tasks dropped";
3212 self.adapter_client.retire_execute(
3213 std::mem::take(ctx_extra),
3214 StatementEndedExecutionReason::Errored {
3215 error: msg.to_string(),
3216 },
3217 );
3218 return self
3219 .send_error_and_get_state(ErrorResponse::error(SqlState::INTERNAL_ERROR, msg))
3220 .await;
3221 }
3222 };
3223
3224 if let Err(e) = self
3226 .adapter_client
3227 .stage_copy_from_stdin_batches(target_id, proto_batches)
3228 {
3229 self.adapter_client.retire_execute(
3230 std::mem::take(ctx_extra),
3231 StatementEndedExecutionReason::Errored {
3232 error: e.to_string(),
3233 },
3234 );
3235 return self
3236 .send_error_and_get_state(e.into_response(Severity::Error))
3237 .await;
3238 }
3239
3240 let tag = format!("COPY {}", row_count);
3241 self.send(BackendMessage::CommandComplete { tag }).await?;
3242
3243 Ok(State::Ready)
3244 }
3245
3246 #[instrument(level = "debug")]
3247 async fn send_pending_notices(&mut self) -> Result<(), io::Error> {
3248 let notices = self
3249 .adapter_client
3250 .session()
3251 .drain_notices()
3252 .into_iter()
3253 .map(|notice| BackendMessage::ErrorResponse(notice.into_response()));
3254 self.send_all(notices).await?;
3255 Ok(())
3256 }
3257
3258 #[instrument(level = "debug")]
3259 async fn send_error_and_get_state(&mut self, err: ErrorResponse) -> Result<State, io::Error> {
3260 assert!(err.severity.is_error());
3261 debug!(
3262 "cid={} error code={}",
3263 self.adapter_client.session().conn_id(),
3264 err.code.code()
3265 );
3266 let is_fatal = err.severity.is_fatal();
3267 self.send(BackendMessage::ErrorResponse(err)).await?;
3268
3269 let txn = self.adapter_client.session().transaction();
3270 match txn {
3271 TransactionStatus::Default | TransactionStatus::Failed(_) => {}
3274 TransactionStatus::Started(_) => {
3276 self.rollback_transaction().await?;
3277 }
3278 TransactionStatus::InTransactionImplicit(_) => {
3280 self.rollback_transaction().await?;
3281 }
3282 TransactionStatus::InTransaction(_) => {
3284 self.adapter_client.fail_transaction();
3285 }
3286 };
3287 if is_fatal {
3288 Ok(State::Done)
3289 } else {
3290 Ok(State::Drain)
3291 }
3292 }
3293
3294 #[instrument(level = "debug")]
3295 async fn aborted_txn_error(&mut self) -> Result<State, io::Error> {
3296 self.send(BackendMessage::ErrorResponse(ErrorResponse::error(
3297 SqlState::IN_FAILED_SQL_TRANSACTION,
3298 ABORTED_TXN_MSG,
3299 )))
3300 .await?;
3301 Ok(State::Drain)
3302 }
3303
3304 fn is_aborted_txn(&mut self) -> bool {
3305 matches!(
3306 self.adapter_client.session().transaction(),
3307 TransactionStatus::Failed(_)
3308 )
3309 }
3310}
3311
3312fn pad_formats(formats: Vec<Format>, n: usize) -> Result<Vec<Format>, String> {
3313 match (formats.len(), n) {
3314 (0, e) => Ok(vec![Format::Text; e]),
3315 (1, e) => Ok(iter::repeat(formats[0]).take(e).collect()),
3316 (a, e) if a == e => Ok(formats),
3317 (a, e) => Err(format!(
3318 "expected {} field format specifiers, but got {}",
3319 e, a
3320 )),
3321 }
3322}
3323
3324fn describe_rows(stmt_desc: &StatementDesc, formats: &[Format]) -> BackendMessage {
3325 match &stmt_desc.relation_desc {
3326 Some(desc) if !stmt_desc.is_copy => {
3327 BackendMessage::RowDescription(message::encode_row_description(desc, formats))
3328 }
3329 _ => BackendMessage::NoData,
3330 }
3331}
3332
3333type GetResponse = fn(
3334 max_rows: ExecuteCount,
3335 total_sent_rows: usize,
3336 fetch_portal: Option<PortalRefMut>,
3337) -> BackendMessage;
3338
3339fn portal_exec_message(
3342 max_rows: ExecuteCount,
3343 total_sent_rows: usize,
3344 _fetch_portal: Option<PortalRefMut>,
3345) -> BackendMessage {
3346 match max_rows {
3353 ExecuteCount::Count(max_rows) if max_rows <= total_sent_rows => {
3354 BackendMessage::PortalSuspended
3355 }
3356 _ => BackendMessage::CommandComplete {
3357 tag: format!("SELECT {}", total_sent_rows),
3358 },
3359 }
3360}
3361
3362fn fetch_message(
3364 _max_rows: ExecuteCount,
3365 total_sent_rows: usize,
3366 fetch_portal: Option<PortalRefMut>,
3367) -> BackendMessage {
3368 let tag = format!("FETCH {}", total_sent_rows);
3369 if let Some(portal) = fetch_portal {
3370 *portal.state = PortalState::Completed(Some(tag.clone()));
3371 }
3372 BackendMessage::CommandComplete { tag }
3373}
3374
3375fn get_authenticator(
3376 authenticator_kind: listeners::AuthenticatorKind,
3377 frontegg: Option<FronteggAuthenticator>,
3378 oidc: GenericOidcAuthenticator,
3379 adapter_client: mz_adapter::Client,
3380) -> Authenticator {
3381 match authenticator_kind {
3382 listeners::AuthenticatorKind::Frontegg => Authenticator::Frontegg(frontegg.expect(
3383 "Frontegg authenticator should exist with listeners::AuthenticatorKind::Frontegg",
3384 )),
3385 listeners::AuthenticatorKind::Password => Authenticator::Password(adapter_client),
3386 listeners::AuthenticatorKind::Sasl => Authenticator::Sasl(adapter_client),
3387 listeners::AuthenticatorKind::Oidc => Authenticator::Oidc(oidc),
3388 listeners::AuthenticatorKind::None => Authenticator::None,
3389 }
3390}
3391
3392#[derive(Debug, Copy, Clone)]
3393enum ExecuteCount {
3394 All,
3395 Count(usize),
3396}
3397
3398fn is_txn_exit_stmt(stmt: Option<&Statement<Raw>>) -> bool {
3400 match stmt {
3401 Some(stmt) => matches!(stmt, Statement::Commit(_) | Statement::Rollback(_)),
3403 None => false,
3404 }
3405}
3406
3407#[derive(Debug)]
3408enum FetchResult {
3409 Rows(Option<Box<dyn RowIterator + Send + Sync>>),
3410 Canceled,
3411 Error(ErrorResponse),
3412 Notice(AdapterNotice),
3413}
3414
3415#[derive(Debug)]
3416struct CopyRowScanner {
3417 scan_pos: usize,
3418 last_row_end: Option<usize>,
3419 end_marker_end: Option<usize>,
3420 record_start: usize,
3425 csv: Option<CsvScanState>,
3426}
3427
3428#[derive(Debug)]
3429struct CsvScanState {
3430 reader: csv_core::Reader,
3431 output: Vec<u8>,
3432 ends: Vec<usize>,
3433 skip_first_record: bool,
3434}
3435
3436impl CopyRowScanner {
3437 fn new(params: &CopyFormatParams<'_>) -> Self {
3438 let csv = match params {
3439 CopyFormatParams::Csv(CopyCsvFormatParams {
3440 delimiter,
3441 quote,
3442 escape,
3443 header,
3444 ..
3445 }) => Some(CsvScanState::new(*delimiter, *quote, *escape, *header)),
3446 _ => None,
3447 };
3448
3449 CopyRowScanner {
3450 scan_pos: 0,
3451 last_row_end: None,
3452 end_marker_end: None,
3453 record_start: 0,
3454 csv,
3455 }
3456 }
3457
3458 fn scan_new_bytes(&mut self, data: &[u8]) {
3459 if self.scan_pos >= data.len() {
3460 return;
3461 }
3462
3463 if let Some(csv) = self.csv.as_mut() {
3464 let mut input = &data[self.scan_pos..];
3465 let mut consumed = 0usize;
3466 while !input.is_empty() {
3467 let (result, n_input, _n_output, _n_ends) =
3468 csv.reader
3469 .read_record(input, &mut csv.output, &mut csv.ends);
3470 consumed += n_input;
3471 input = &input[n_input..];
3472
3473 match result {
3474 ReadRecordResult::InputEmpty => break,
3475 ReadRecordResult::OutputFull => {
3476 if n_input == 0 {
3477 csv.output
3478 .resize(csv.output.len().saturating_mul(2).max(1), 0);
3479 }
3480 }
3481 ReadRecordResult::OutputEndsFull => {
3482 if n_input == 0 {
3483 csv.ends.resize(csv.ends.len().saturating_mul(2).max(1), 0);
3484 }
3485 }
3486 ReadRecordResult::Record | ReadRecordResult::End => {
3487 let row_end = self.scan_pos + consumed;
3488 self.last_row_end = Some(row_end);
3489 if self.end_marker_end.is_none() {
3490 let is_marker = if csv.skip_first_record {
3491 csv.skip_first_record = false;
3492 false
3493 } else {
3494 let raw = &data[self.record_start..row_end];
3500 let start = raw
3511 .iter()
3512 .take_while(|&&b| b == b'\r' || b == b'\n')
3513 .count();
3514 let trailing = raw[start..]
3515 .iter()
3516 .rev()
3517 .take_while(|&&b| b == b'\r' || b == b'\n')
3518 .count();
3519 let trimmed = &raw[start..raw.len() - trailing];
3520 trimmed == b"\\."
3521 };
3522 if is_marker {
3523 self.end_marker_end = Some(row_end);
3524 self.record_start = row_end;
3525 break;
3526 }
3527 }
3528 self.record_start = row_end;
3529 }
3530 }
3531 }
3532 } else {
3533 let mut row_start = self.last_row_end.unwrap_or(0);
3534 for (offset, b) in data[self.scan_pos..].iter().enumerate() {
3535 if *b == b'\n' {
3536 let row_end = self.scan_pos + offset + 1;
3537 self.last_row_end = Some(row_end);
3538 if self.end_marker_end.is_none() {
3539 let row = &data[row_start..row_end];
3540 if row.get(0..2) == Some(b"\\.") {
3541 self.end_marker_end = Some(row_end);
3542 break;
3543 }
3544 }
3545 row_start = row_end;
3546 }
3547 }
3548 }
3549
3550 self.scan_pos = data.len();
3551 }
3552
3553 fn last_row_end(&self) -> Option<usize> {
3554 self.last_row_end
3555 }
3556
3557 fn end_marker_end(&self) -> Option<usize> {
3558 self.end_marker_end
3559 }
3560
3561 fn current_row_size(&self, data_len: usize) -> usize {
3562 data_len.saturating_sub(self.last_row_end.unwrap_or(0))
3563 }
3564
3565 fn on_split(&mut self, split_pos: usize) {
3566 self.scan_pos = self.scan_pos.saturating_sub(split_pos);
3567 self.last_row_end = None;
3568 self.end_marker_end = self
3569 .end_marker_end
3570 .and_then(|end| end.checked_sub(split_pos));
3571 soft_assert_or_log!(
3579 self.csv.is_none() || self.record_start >= split_pos,
3580 "split bisected an in-progress CSV record: record_start={} < split_pos={}",
3581 self.record_start,
3582 split_pos,
3583 );
3584 self.record_start = self.record_start.saturating_sub(split_pos);
3585 }
3586
3587 fn on_truncate(&mut self, new_len: usize) {
3588 self.scan_pos = self.scan_pos.min(new_len);
3589 self.last_row_end = self.last_row_end.filter(|&end| end <= new_len);
3590 self.end_marker_end = self.end_marker_end.filter(|&end| end <= new_len);
3591 self.record_start = self.record_start.min(new_len);
3592 }
3593}
3594
3595impl CsvScanState {
3596 fn new(delimiter: u8, quote: u8, escape: u8, header: bool) -> Self {
3597 let (double_quote, escape) = if quote == escape {
3598 (true, None)
3599 } else {
3600 (false, Some(escape))
3601 };
3602 CsvScanState {
3603 reader: csv_core::ReaderBuilder::new()
3604 .delimiter(delimiter)
3605 .quote(quote)
3606 .double_quote(double_quote)
3607 .escape(escape)
3608 .build(),
3609 output: vec![0; 1],
3610 ends: vec![0; 1],
3611 skip_first_record: header,
3612 }
3613 }
3614}
3615
3616#[cfg(test)]
3617mod test {
3618 use super::*;
3619
3620 #[mz_ore::test]
3621 fn test_copy_row_scanner_end_marker_line_endings() {
3622 let params = CopyFormatParams::Csv(CopyCsvFormatParams::default());
3630
3631 let marker_end = |data: &[u8]| -> Option<usize> {
3632 let mut scanner = CopyRowScanner::new(¶ms);
3633 scanner.scan_new_bytes(data);
3634 scanner.end_marker_end()
3635 };
3636
3637 for eol in [&b"\n"[..], b"\r\n", b"\r"] {
3638 let join = |lines: &[&str]| -> Vec<u8> {
3639 let mut out = Vec::new();
3640 for line in lines {
3641 out.extend_from_slice(line.as_bytes());
3642 out.extend_from_slice(eol);
3643 }
3644 out
3645 };
3646
3647 let data = join(&["first", "\\.", "after"]);
3652 let mut prefix = Vec::new();
3653 prefix.extend_from_slice(b"first");
3654 prefix.extend_from_slice(eol);
3655 prefix.extend_from_slice(b"\\.");
3656 assert_eq!(
3657 marker_end(&data),
3658 Some(prefix.len() + 1),
3659 "bare marker, eol={eol:?}"
3660 );
3661
3662 let data = join(&["before", "\"\\.\"", "after"]);
3664 assert_eq!(marker_end(&data), None, "quoted marker, eol={eol:?}");
3665 }
3666 }
3667
3668 #[mz_ore::test]
3669 fn test_copy_row_scanner_non_csv_split() {
3670 for params in [
3677 CopyFormatParams::Text(CopyTextFormatParams::default()),
3678 CopyFormatParams::Binary,
3679 ] {
3680 let mut scanner = CopyRowScanner::new(¶ms);
3681 let data = b"1\thello world\t2\tsome text value here\n\
3682 3\thello world\t6\tsome text value here\n";
3683 scanner.scan_new_bytes(data);
3684 let split_pos = scanner.last_row_end().expect("a complete row");
3685 assert!(split_pos > 0, "params={params:?}");
3686 scanner.on_split(split_pos);
3688 assert_eq!(scanner.record_start, 0, "params={params:?}");
3689 }
3690 }
3691
3692 #[mz_ore::test]
3693 fn test_parse_options() {
3694 struct TestCase {
3695 input: &'static str,
3696 expect: Result<Vec<(&'static str, &'static str)>, ()>,
3697 }
3698 let tests = vec![
3699 TestCase {
3700 input: "",
3701 expect: Ok(vec![]),
3702 },
3703 TestCase {
3704 input: "--key",
3705 expect: Err(()),
3706 },
3707 TestCase {
3708 input: "--key=val",
3709 expect: Ok(vec![("key", "val")]),
3710 },
3711 TestCase {
3712 input: r#"--key=val -ckey2=val2 -c key3=val3 -c key4=val4 -ckey5=val5"#,
3713 expect: Ok(vec![
3714 ("key", "val"),
3715 ("key2", "val2"),
3716 ("key3", "val3"),
3717 ("key4", "val4"),
3718 ("key5", "val5"),
3719 ]),
3720 },
3721 TestCase {
3722 input: r#"-c\ key=val"#,
3723 expect: Ok(vec![(" key", "val")]),
3724 },
3725 TestCase {
3726 input: "--key=val -ckey2 val2",
3727 expect: Err(()),
3728 },
3729 TestCase {
3731 input: "--key=",
3732 expect: Ok(vec![("key", "")]),
3733 },
3734 ];
3735 for test in tests {
3736 let got = parse_options(test.input);
3737 let expect = test.expect.map(|r| {
3738 r.into_iter()
3739 .map(|(k, v)| (k.to_owned(), v.to_owned()))
3740 .collect()
3741 });
3742 assert_eq!(got, expect, "input: {}", test.input);
3743 }
3744 }
3745
3746 #[mz_ore::test]
3747 fn test_parse_option() {
3748 struct TestCase {
3749 input: &'static str,
3750 expect: Result<(&'static str, &'static str), ()>,
3751 }
3752 let tests = vec![
3753 TestCase {
3754 input: "",
3755 expect: Err(()),
3756 },
3757 TestCase {
3758 input: "--",
3759 expect: Err(()),
3760 },
3761 TestCase {
3762 input: "--c",
3763 expect: Err(()),
3764 },
3765 TestCase {
3766 input: "a=b",
3767 expect: Err(()),
3768 },
3769 TestCase {
3770 input: "--a=b",
3771 expect: Ok(("a", "b")),
3772 },
3773 TestCase {
3774 input: "--ca=b",
3775 expect: Ok(("ca", "b")),
3776 },
3777 TestCase {
3778 input: "-ca=b",
3779 expect: Ok(("a", "b")),
3780 },
3781 TestCase {
3783 input: "--=",
3784 expect: Ok(("", "")),
3785 },
3786 ];
3787 for test in tests {
3788 let got = parse_option(test.input);
3789 assert_eq!(got, test.expect, "input: {}", test.input);
3790 }
3791 }
3792
3793 #[mz_ore::test]
3794 fn test_split_options() {
3795 struct TestCase {
3796 input: &'static str,
3797 expect: Vec<&'static str>,
3798 }
3799 let tests = vec![
3800 TestCase {
3801 input: "",
3802 expect: vec![],
3803 },
3804 TestCase {
3805 input: " ",
3806 expect: vec![],
3807 },
3808 TestCase {
3809 input: " a ",
3810 expect: vec!["a"],
3811 },
3812 TestCase {
3813 input: " ab cd ",
3814 expect: vec!["ab", "cd"],
3815 },
3816 TestCase {
3817 input: r#" ab\ cd "#,
3818 expect: vec!["ab ", "cd"],
3819 },
3820 TestCase {
3821 input: r#" ab\\ cd "#,
3822 expect: vec![r#"ab\"#, "cd"],
3823 },
3824 TestCase {
3825 input: r#" ab\\\ cd "#,
3826 expect: vec![r#"ab\ "#, "cd"],
3827 },
3828 TestCase {
3829 input: r#" ab\\\ cd "#,
3830 expect: vec![r#"ab\ cd"#],
3831 },
3832 TestCase {
3833 input: r#" ab\\\cd "#,
3834 expect: vec![r#"ab\cd"#],
3835 },
3836 TestCase {
3837 input: r#"a\"#,
3838 expect: vec!["a"],
3839 },
3840 TestCase {
3841 input: r#"a\ "#,
3842 expect: vec!["a "],
3843 },
3844 TestCase {
3845 input: r#"\"#,
3846 expect: vec![],
3847 },
3848 TestCase {
3849 input: r#"\ "#,
3850 expect: vec![r#" "#],
3851 },
3852 TestCase {
3853 input: r#" \ "#,
3854 expect: vec![r#" "#],
3855 },
3856 TestCase {
3857 input: r#"\ "#,
3858 expect: vec![r#" "#],
3859 },
3860 ];
3861 for test in tests {
3862 let got = split_options(test.input);
3863 assert_eq!(got, test.expect, "input: {}", test.input);
3864 }
3865 }
3866
3867 #[mz_ore::test]
3868 fn test_is_jwt() {
3869 assert!(is_jwt("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.signature"));
3871 for s in [
3873 "",
3874 "secure_password",
3875 "p4ss.w0rd",
3876 "aaa.bbb.ccc",
3877 "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0",
3878 "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.sig.extra",
3879 ] {
3880 assert!(!is_jwt(s), "is_jwt({s:?})");
3881 }
3882 }
3883}