1use std::collections::BTreeMap;
11use std::convert::TryFrom;
12use std::future::Future;
13use std::ops::Deref;
14use std::sync::Arc;
15use std::time::{Duration, Instant};
16use std::{iter, mem};
17
18use base64::prelude::*;
19use byteorder::{ByteOrder, NetworkEndian};
20use csv_core::ReadRecordResult;
21use futures::future::{BoxFuture, FutureExt, pending};
22use itertools::Itertools;
23use mz_adapter::client::{RecordFirstRowStream, redact_sql_for_logging};
24use mz_adapter::session::{
25 EndTransactionAction, InProgressRows, LifecycleTimestamps, PortalRefMut, PortalState, Session,
26 SessionConfig, TransactionStatus,
27};
28use mz_adapter::statement_logging::{StatementEndedExecutionReason, StatementExecutionStrategy};
29use mz_adapter::{
30 AdapterError, AdapterNotice, ExecuteContextGuard, ExecuteResponse, PeekResponseUnary, metrics,
31 verify_datum_desc,
32};
33use mz_adapter_types::dyncfgs::OIDC_GROUP_CLAIM;
34use mz_auth::Authenticated;
35use mz_auth::password::Password;
36use mz_authenticator::{Authenticator, GenericOidcAuthenticator};
37use mz_frontegg_auth::Authenticator as FronteggAuthenticator;
38use mz_ore::cast::CastFrom;
39use mz_ore::netio::AsyncReady;
40use mz_ore::now::{EpochMillis, SYSTEM_TIME};
41use mz_ore::str::StrExt;
42use mz_ore::{assert_none, assert_ok, instrument, soft_assert_eq_or_log, soft_assert_or_log};
43use mz_pgcopy::{CopyCsvFormatParams, CopyFormatParams, CopyTextFormatParams};
44use mz_pgwire_common::{
45 ConnectionCounter, Cursor, ErrorResponse, Format, FrontendMessage, Severity, VERSION_3,
46 VERSIONS,
47};
48use mz_repr::{
49 CatalogItemId, ColumnIndex, Datum, RelationDesc, RowArena, RowIterator, RowRef,
50 SqlRelationType, SqlScalarType,
51};
52use mz_server_core::TlsMode;
53use mz_server_core::listeners;
54use mz_server_core::listeners::AllowedRoles;
55use mz_sql::ast::display::AstDisplay;
56use mz_sql::ast::{
57 CopyDirection, CopyStatement, CopyTarget, FetchDirection, Ident, Raw, Statement,
58};
59use mz_sql::parse::StatementParseResult;
60use mz_sql::plan::{CopyFormat, ExecuteTimeout, StatementDesc};
61use mz_sql::session::metadata::SessionMetadata;
62use mz_sql::session::user::INTERNAL_USER_NAMES;
63use mz_sql::session::vars::VarInput;
64use postgres::error::SqlState;
65use tokio::io::{self, AsyncRead, AsyncWrite};
66use tokio::select;
67use tokio::time::{self};
68use tokio_metrics::TaskMetrics;
69use tokio_stream::wrappers::UnboundedReceiverStream;
70use tracing::{Instrument, debug, debug_span, info, warn};
71use uuid::Uuid;
72
73use crate::codec::{
74 FramedConn, decode_password, decode_sasl_initial_response, decode_sasl_response,
75};
76use crate::message::{
77 self, BackendMessage, SASLServerFinalMessage, SASLServerFinalMessageKinds,
78 SASLServerFirstMessage,
79};
80
81pub fn match_handshake(buf: &[u8]) -> bool {
85 if buf.len() < 8 {
95 return false;
96 }
97 let version = NetworkEndian::read_i32(&buf[4..8]);
98 VERSIONS.contains(&version)
99}
100
101pub struct RunParams<'a, A, I>
103where
104 I: Iterator<Item = TaskMetrics> + Send,
105{
106 pub tls_mode: Option<TlsMode>,
108 pub adapter_client: mz_adapter::Client,
110 pub conn: &'a mut FramedConn<A>,
112 pub conn_uuid: Uuid,
114 pub version: i32,
116 pub params: BTreeMap<String, String>,
118 pub frontegg: Option<FronteggAuthenticator>,
120 pub oidc: GenericOidcAuthenticator,
122 pub authenticator_kind: listeners::AuthenticatorKind,
125 pub active_connection_counter: ConnectionCounter,
127 pub helm_chart_version: Option<String>,
129 pub allowed_roles: AllowedRoles,
131 pub tokio_metrics_intervals: I,
133}
134
135#[mz_ore::instrument(level = "debug")]
145pub async fn run<'a, A, I>(
146 RunParams {
147 tls_mode,
148 adapter_client,
149 conn,
150 conn_uuid,
151 version,
152 mut params,
153 frontegg,
154 oidc,
155 authenticator_kind,
156 active_connection_counter,
157 helm_chart_version,
158 allowed_roles,
159 tokio_metrics_intervals,
160 }: RunParams<'a, A, I>,
161) -> Result<(), io::Error>
162where
163 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin,
164 I: Iterator<Item = TaskMetrics> + Send,
165{
166 if version != VERSION_3 {
167 return conn
168 .send(ErrorResponse::fatal(
169 SqlState::SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION,
170 "server does not support the client's requested protocol version",
171 ))
172 .await;
173 }
174
175 let user = params.remove("user").unwrap_or_else(String::new);
176 let options = parse_options(params.get("options").unwrap_or(&String::new()));
177 let authenticator =
178 get_authenticator(authenticator_kind, frontegg, oidc, adapter_client.clone());
179 let is_internal_user = INTERNAL_USER_NAMES.contains(&user);
181 let is_reserved_user = mz_adapter::catalog::is_reserved_role_name(user.as_str());
183 let role_allowed = match allowed_roles {
184 AllowedRoles::Normal => !is_reserved_user,
185 AllowedRoles::Internal => is_internal_user,
186 AllowedRoles::NormalAndInternal => !is_reserved_user || is_internal_user,
187 };
188 if !role_allowed {
189 let msg = format!("unauthorized login to user '{user}'");
190 return conn
191 .send(ErrorResponse::fatal(SqlState::INSUFFICIENT_PRIVILEGE, msg))
192 .await;
193 }
194
195 if let Err(err) = conn.inner().ensure_tls_compatibility(&tls_mode) {
196 return conn.send(err).await;
197 }
198
199 let authenticator_kind = authenticator.kind();
200
201 let (mut session, expired) = match authenticator {
202 Authenticator::Frontegg(frontegg) => {
203 let password = match request_cleartext_password(conn).await {
204 Ok(password) => password,
205 Err(PasswordRequestError::IoError(e)) => return Err(e),
206 Err(PasswordRequestError::InvalidPasswordError(e)) => {
207 return conn.send(e).await;
208 }
209 };
210
211 let group_claim =
212 OIDC_GROUP_CLAIM.get(adapter_client.get_system_vars().await.dyncfgs());
213 let auth_response = frontegg
214 .authenticate(&user, &password, Some(&group_claim))
215 .await;
216 match auth_response {
217 Ok((mut auth_session, authenticated)) => {
224 let groups = auth_session.groups();
225 let session = adapter_client.new_session(
226 SessionConfig {
227 conn_id: conn.conn_id().clone(),
228 uuid: conn_uuid,
229 user: auth_session.user().into(),
230 client_ip: conn.peer_addr().clone(),
231 external_metadata_rx: Some(auth_session.external_metadata_rx()),
232 helm_chart_version,
233 authenticator_kind,
234 groups,
235 },
236 authenticated,
237 );
238 let expired = async move { auth_session.expired().await };
239 (session, expired.left_future())
240 }
241 Err(err) => {
242 warn!(?err, "pgwire connection failed authentication");
243 return conn
244 .send(ErrorResponse::fatal(
245 SqlState::INVALID_PASSWORD,
246 "invalid password",
247 ))
248 .await;
249 }
250 }
251 }
252 Authenticator::Oidc(oidc) => {
253 let password = match request_cleartext_password(conn).await {
256 Ok(password) => password,
257 Err(PasswordRequestError::IoError(e)) => return Err(e),
258 Err(PasswordRequestError::InvalidPasswordError(e)) => {
259 return conn.send(e).await;
260 }
261 };
262 if is_jwt(&password) {
263 let auth_response = oidc.authenticate(&password, Some(&user)).await;
264 match auth_response {
265 Ok((mut claims, authenticated)) => {
266 let groups = claims.groups.take();
267 let session = adapter_client.new_session(
268 SessionConfig {
269 conn_id: conn.conn_id().clone(),
270 uuid: conn_uuid,
271 user: std::mem::take(&mut claims.user),
272 client_ip: conn.peer_addr().clone(),
273 external_metadata_rx: None,
274 helm_chart_version,
275 authenticator_kind,
276 groups,
277 },
278 authenticated,
279 );
280 (session, pending().right_future())
283 }
284 Err(err) => {
285 warn!(?err, "pgwire connection failed authentication");
286 return conn.send(err.into_response()).await;
287 }
288 }
289 } else {
290 let session = match authenticate_with_password(
291 conn,
292 &adapter_client,
293 user,
294 Password(password),
295 conn_uuid,
296 helm_chart_version,
297 )
298 .await
299 {
300 Ok(session) => session,
301 Err(PasswordRequestError::IoError(e)) => return Err(e),
302 Err(PasswordRequestError::InvalidPasswordError(e)) => {
303 return conn.send(e).await;
304 }
305 };
306 (session, pending().right_future())
307 }
308 }
309 Authenticator::Password(adapter_client) => {
310 let password = match request_cleartext_password(conn).await {
311 Ok(password) => password,
312 Err(PasswordRequestError::IoError(e)) => return Err(e),
313 Err(PasswordRequestError::InvalidPasswordError(e)) => {
314 return conn.send(e).await;
315 }
316 };
317 let session = match authenticate_with_password(
318 conn,
319 &adapter_client,
320 user,
321 Password(password),
322 conn_uuid,
323 helm_chart_version,
324 )
325 .await
326 {
327 Ok(session) => session,
328 Err(PasswordRequestError::IoError(e)) => return Err(e),
329 Err(PasswordRequestError::InvalidPasswordError(e)) => {
330 return conn.send(e).await;
331 }
332 };
333 (session, pending().right_future())
335 }
336 Authenticator::Sasl(adapter_client) => {
337 conn.send(BackendMessage::AuthenticationSASL).await?;
339 conn.flush().await?;
340 let (mechanism, initial_response) = match conn.recv().await? {
342 Some(FrontendMessage::RawAuthentication(data)) => {
343 match decode_sasl_initial_response(Cursor::new(&data)).ok() {
344 Some(FrontendMessage::SASLInitialResponse {
345 gs2_header,
346 mechanism,
347 initial_response,
348 }) => {
349 if gs2_header.channel_binding_enabled() {
351 return conn
352 .send(ErrorResponse::fatal(
353 SqlState::PROTOCOL_VIOLATION,
354 "channel binding not supported",
355 ))
356 .await;
357 }
358 (mechanism, initial_response)
359 }
360 _ => {
361 return conn
362 .send(ErrorResponse::fatal(
363 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
364 "expected SASLInitialResponse message",
365 ))
366 .await;
367 }
368 }
369 }
370 _ => {
371 return conn
372 .send(ErrorResponse::fatal(
373 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
374 "expected SASLInitialResponse message",
375 ))
376 .await;
377 }
378 };
379
380 if mechanism != "SCRAM-SHA-256" {
381 return conn
382 .send(ErrorResponse::fatal(
383 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
384 "unsupported SASL mechanism",
385 ))
386 .await;
387 }
388
389 if initial_response.nonce.len() > 256 {
390 return conn
391 .send(ErrorResponse::fatal(
392 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
393 "nonce too long",
394 ))
395 .await;
396 }
397
398 let (server_first_message_raw, mock_hash) = match adapter_client
399 .generate_sasl_challenge(&user, &initial_response.nonce)
400 .await
401 {
402 Ok(response) => {
403 let server_first_message_raw = format!(
404 "r={},s={},i={}",
405 response.nonce, response.salt, response.iteration_count
406 );
407
408 let client_key = [0u8; 32];
409 let server_key = [1u8; 32];
410 let mock_hash = format!(
411 "SCRAM-SHA-256${}:{}${}:{}",
412 response.iteration_count,
413 response.salt,
414 BASE64_STANDARD.encode(client_key),
415 BASE64_STANDARD.encode(server_key)
416 );
417
418 conn.send(BackendMessage::AuthenticationSASLContinue(
419 SASLServerFirstMessage {
420 iteration_count: response.iteration_count,
421 nonce: response.nonce,
422 salt: response.salt,
423 },
424 ))
425 .await?;
426 conn.flush().await?;
427 (server_first_message_raw, mock_hash)
428 }
429 Err(e) => {
430 return conn.send(e.into_response(Severity::Fatal)).await;
431 }
432 };
433
434 let authenticated = match conn.recv().await? {
435 Some(FrontendMessage::RawAuthentication(data)) => {
436 match decode_sasl_response(Cursor::new(&data)).ok() {
437 Some(FrontendMessage::SASLResponse(response)) => {
438 let auth_message = format!(
439 "{},{},{}",
440 initial_response.client_first_message_bare_raw,
441 server_first_message_raw,
442 response.client_final_message_bare_raw
443 );
444 if response.proof.len() > 1024 {
445 return conn
446 .send(ErrorResponse::fatal(
447 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
448 "proof too long",
449 ))
450 .await;
451 }
452 match adapter_client
453 .verify_sasl_proof(
454 &user,
455 &response.proof,
456 &auth_message,
457 &mock_hash,
458 )
459 .await
460 {
461 Ok((proof_response, authenticated)) => {
462 conn.send(BackendMessage::AuthenticationSASLFinal(
463 SASLServerFinalMessage {
464 kind: SASLServerFinalMessageKinds::Verifier(
465 proof_response.verifier,
466 ),
467 extensions: vec![],
468 },
469 ))
470 .await?;
471 conn.flush().await?;
472 authenticated
473 }
474 Err(_) => {
475 return conn
476 .send(ErrorResponse::fatal(
477 SqlState::INVALID_PASSWORD,
478 "invalid password",
479 ))
480 .await;
481 }
482 }
483 }
484 _ => {
485 return conn
486 .send(ErrorResponse::fatal(
487 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
488 "expected SASLResponse message",
489 ))
490 .await;
491 }
492 }
493 }
494 _ => {
495 return conn
496 .send(ErrorResponse::fatal(
497 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
498 "expected SASLResponse message",
499 ))
500 .await;
501 }
502 };
503
504 let session = adapter_client.new_session(
505 SessionConfig {
506 conn_id: conn.conn_id().clone(),
507 uuid: conn_uuid,
508 user,
509 client_ip: conn.peer_addr().clone(),
510 external_metadata_rx: None,
511 helm_chart_version,
512 authenticator_kind,
513 groups: None,
514 },
515 authenticated,
516 );
517 let auth_session = pending().right_future();
519 (session, auth_session)
520 }
521
522 Authenticator::None => {
523 let session = adapter_client.new_session(
524 SessionConfig {
525 conn_id: conn.conn_id().clone(),
526 uuid: conn_uuid,
527 user,
528 client_ip: conn.peer_addr().clone(),
529 external_metadata_rx: None,
530 helm_chart_version,
531 authenticator_kind,
532 groups: None,
533 },
534 Authenticated,
535 );
536 let auth_session = pending().right_future();
538 (session, auth_session)
539 }
540 };
541
542 let system_vars = adapter_client.get_system_vars().await;
543 let mut applied_params = vec![];
547 for (name, value) in params {
548 let settings = match name.as_str() {
549 "options" => match &options {
550 Ok(opts) => opts,
551 Err(()) => {
552 session.add_notice(AdapterNotice::BadStartupSetting {
553 name,
554 reason: "could not parse".into(),
555 });
556 continue;
557 }
558 },
559 _ => &vec![(name, value)],
560 };
561 for (key, val) in settings {
562 const LOCAL: bool = false;
563 match session
568 .vars_mut()
569 .set(&system_vars, key, VarInput::Flat(val), LOCAL)
570 {
571 Ok(()) => applied_params.push((key.clone(), val.clone())),
572 Err(err) => {
573 session.add_notice(AdapterNotice::BadStartupSetting {
574 name: key.clone(),
575 reason: err.to_string(),
576 });
577 }
578 }
579 }
580 }
581 session
582 .vars_mut()
583 .end_transaction(EndTransactionAction::Commit);
584
585 let _guard = match active_connection_counter.allocate_connection(session.user()) {
586 Ok(drop_connection) => drop_connection,
587 Err(e) => {
588 let e: AdapterError = e.into();
589 return conn.send(e.into_response(Severity::Fatal)).await;
590 }
591 };
592
593 let mut adapter_client = match adapter_client.startup(session).await {
595 Ok(adapter_client) => adapter_client,
596 Err(e) => return conn.send(e.into_response(Severity::Fatal)).await,
597 };
598
599 for (key, val) in applied_params {
607 if let Err(err) = adapter_client
608 .session()
609 .vars_mut()
610 .set_default(&key, VarInput::Flat(&val))
611 {
612 mz_ore::soft_panic_or_log!("failed to apply startup parameter as default: {err:?}");
614 }
615 }
616
617 let mut buf = vec![BackendMessage::AuthenticationOk];
618 for var in adapter_client.session().vars().notify_set() {
619 buf.push(BackendMessage::ParameterStatus(var.name(), var.value()));
620 }
621 buf.push(BackendMessage::BackendKeyData {
622 conn_id: adapter_client.session().conn_id().unhandled(),
623 secret_key: adapter_client.session().secret_key(),
624 });
625 buf.extend(
626 adapter_client
627 .session()
628 .drain_notices()
629 .into_iter()
630 .map(|notice| BackendMessage::ErrorResponse(notice.into_response())),
631 );
632 buf.push(BackendMessage::ReadyForQuery(
633 adapter_client.session().transaction().into(),
634 ));
635 conn.send_all(buf).await?;
636 conn.flush().await?;
637
638 let machine = StateMachine {
639 conn,
640 adapter_client,
641 txn_needs_commit: false,
642 tokio_metrics_intervals,
643 };
644
645 select! {
646 r = machine.run() => {
647 if let Err(err) = &r {
652 let _ = conn
653 .send(ErrorResponse::fatal(
654 SqlState::CONNECTION_FAILURE,
655 err.to_string(),
656 ))
657 .await;
658 let _ = conn.flush().await;
659 }
660 r
661 },
662 _ = expired => {
663 conn
664 .send(ErrorResponse::fatal(SqlState::INVALID_AUTHORIZATION_SPECIFICATION, "authentication expired"))
665 .await?;
666 conn.flush().await
667 }
668 }
669}
670
671fn is_jwt(password: &str) -> bool {
674 jsonwebtoken::decode_header(password).is_ok()
675}
676
677fn parse_options(value: &str) -> Result<Vec<(String, String)>, ()> {
682 let opts = split_options(value);
683 let mut pairs = Vec::with_capacity(opts.len());
684 let mut seen_prefix = false;
685 for opt in opts {
686 if !seen_prefix {
687 if opt == "-c" {
688 seen_prefix = true;
689 } else {
690 let (key, val) = parse_option(&opt)?;
691 pairs.push((key.to_owned(), val.to_owned()));
692 }
693 } else {
694 let (key, val) = opt.split_once('=').ok_or(())?;
695 pairs.push((key.to_owned(), val.to_owned()));
696 seen_prefix = false;
697 }
698 }
699 Ok(pairs)
700}
701
702fn parse_option(option: &str) -> Result<(&str, &str), ()> {
706 let (key, value) = option.split_once('=').ok_or(())?;
707 for prefix in &["-c", "--"] {
708 if let Some(key) = key.strip_prefix(prefix) {
709 return Ok((key, value));
710 }
711 }
712 Err(())
713}
714
715fn split_options(value: &str) -> Vec<String> {
717 let mut strs = Vec::new();
718 let mut current = String::new();
722 let mut was_slash = false;
723 for c in value.chars() {
724 was_slash = match c {
725 ' ' => {
726 if was_slash {
727 current.push(' ');
728 } else if !current.is_empty() {
729 strs.push(std::mem::take(&mut current));
732 }
733 false
734 }
735 '\\' => {
736 if was_slash {
737 current.push('\\');
740 false
741 } else {
742 true
743 }
744 }
745 _ => {
746 current.push(c);
747 false
748 }
749 };
750 }
751 if !current.is_empty() {
753 strs.push(current);
754 }
755 strs
756}
757
758enum PasswordRequestError {
759 InvalidPasswordError(ErrorResponse),
760 IoError(io::Error),
761}
762
763impl From<io::Error> for PasswordRequestError {
764 fn from(e: io::Error) -> Self {
765 PasswordRequestError::IoError(e)
766 }
767}
768
769async fn request_cleartext_password<A>(
773 conn: &mut FramedConn<A>,
774) -> Result<String, PasswordRequestError>
775where
776 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin,
777{
778 conn.send(BackendMessage::AuthenticationCleartextPassword)
779 .await?;
780 conn.flush().await?;
781
782 if let Some(message) = conn.recv().await? {
783 if let FrontendMessage::RawAuthentication(data) = message {
784 if let Some(FrontendMessage::Password { password }) =
785 decode_password(Cursor::new(&data)).ok()
786 {
787 return Ok(password);
788 }
789 }
790 }
791
792 Err(PasswordRequestError::InvalidPasswordError(
793 ErrorResponse::fatal(
794 SqlState::INVALID_AUTHORIZATION_SPECIFICATION,
795 "expected Password message",
796 ),
797 ))
798}
799
800async fn authenticate_with_password<A>(
803 conn: &FramedConn<A>,
804 adapter_client: &mz_adapter::Client,
805 user: String,
806 password: Password,
807 conn_uuid: Uuid,
808 helm_chart_version: Option<String>,
809) -> Result<Session, PasswordRequestError>
810where
811 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin,
812{
813 let authenticated = match adapter_client.authenticate(&user, &password).await {
814 Ok(authenticated) => authenticated,
815 Err(err) => {
816 warn!(?err, "pgwire connection failed authentication");
817 return Err(PasswordRequestError::InvalidPasswordError(
818 ErrorResponse::fatal(SqlState::INVALID_PASSWORD, "invalid password"),
819 ));
820 }
821 };
822
823 let session = adapter_client.new_session(
824 SessionConfig {
825 conn_id: conn.conn_id().clone(),
826 uuid: conn_uuid,
827 user,
828 client_ip: conn.peer_addr().clone(),
829 external_metadata_rx: None,
830 helm_chart_version,
831 authenticator_kind: mz_auth::AuthenticatorKind::Password,
832 groups: None,
833 },
834 authenticated,
835 );
836
837 Ok(session)
838}
839
840#[derive(Debug)]
841enum State {
842 Ready,
843 Drain,
844 Done,
845}
846
847struct StateMachine<'a, A, I>
848where
849 I: Iterator<Item = TaskMetrics> + Send + 'a,
850{
851 conn: &'a mut FramedConn<A>,
852 adapter_client: mz_adapter::SessionClient,
853 txn_needs_commit: bool,
854 tokio_metrics_intervals: I,
855}
856
857enum SendRowsEndedReason {
858 Success {
859 result_size: u64,
860 rows_returned: u64,
861 },
862 Errored {
863 error: String,
864 },
865 Canceled,
866}
867
868const ABORTED_TXN_MSG: &str =
869 "current transaction is aborted, commands ignored until end of transaction block";
870
871impl<'a, A, I> StateMachine<'a, A, I>
872where
873 A: AsyncRead + AsyncWrite + AsyncReady + Send + Sync + Unpin + 'a,
874 I: Iterator<Item = TaskMetrics> + Send + 'a,
875{
876 #[allow(clippy::manual_async_fn)]
880 #[mz_ore::instrument(level = "debug")]
881 fn run(mut self) -> impl Future<Output = Result<(), io::Error>> + Send + 'a {
882 async move {
883 let mut state = State::Ready;
884 loop {
885 self.send_pending_notices().await?;
886 state = match state {
887 State::Ready => self.advance_ready().await?,
888 State::Drain => self.advance_drain().await?,
889 State::Done => return Ok(()),
890 };
891 self.adapter_client
892 .add_idle_in_transaction_session_timeout();
893 }
894 }
895 }
896
897 #[instrument(level = "debug")]
898 async fn advance_ready(&mut self) -> Result<State, io::Error> {
899 self.tokio_metrics_intervals
901 .next()
902 .expect("infinite iterator");
903
904 let message = select! {
906 biased;
907
908 Some(timeout) = self.adapter_client.recv_timeout() => {
910 let err: AdapterError = timeout.into();
911 let conn_id = self.adapter_client.session().conn_id();
912 tracing::warn!("session timed out, conn_id {}", conn_id);
913
914 let error_response = err.into_response(Severity::Fatal);
916 let error_state = self.send_error_and_get_state(error_response).await;
917
918 self.adapter_client.terminate().await;
920
921 let _ = self.conn.recv().await?;
925 return error_state;
926 },
927 message = self.conn.recv() => message?,
929 };
930
931 let interval = self
933 .tokio_metrics_intervals
934 .next()
935 .expect("infinite iterator");
936 let recv_scheduling_delay_ms = interval.total_scheduled_duration.as_secs_f64() * 1000.0;
937
938 let received = SYSTEM_TIME();
942
943 self.adapter_client
944 .remove_idle_in_transaction_session_timeout();
945
946 let message_name = message.as_ref().map(|m| m.name()).unwrap_or_default();
949
950 if let Some(message) = &message {
951 self.maybe_log_message_arrival(message).await;
952 }
953
954 let start = message.as_ref().map(|_| Instant::now());
955 let next_state = match message {
956 Some(FrontendMessage::Query { sql }) => {
957 let query_root_span =
958 tracing::info_span!(parent: None, "advance_ready", otel.name = message_name);
959 query_root_span.follows_from(tracing::Span::current());
960 self.query(sql, received)
961 .instrument(query_root_span)
962 .await?
963 }
964 Some(FrontendMessage::Parse {
965 name,
966 sql,
967 param_types,
968 }) => self.parse(name, sql, param_types).await?,
969 Some(FrontendMessage::Bind {
970 portal_name,
971 statement_name,
972 param_formats,
973 raw_params,
974 result_formats,
975 }) => {
976 self.bind(
977 portal_name,
978 statement_name,
979 param_formats,
980 raw_params,
981 result_formats,
982 )
983 .await?
984 }
985 Some(FrontendMessage::Execute {
986 portal_name,
987 max_rows,
988 }) => {
989 let max_rows = match usize::try_from(max_rows) {
990 Ok(0) | Err(_) => ExecuteCount::All, Ok(n) => ExecuteCount::Count(n),
992 };
993 let execute_root_span =
994 tracing::info_span!(parent: None, "advance_ready", otel.name = message_name);
995 execute_root_span.follows_from(tracing::Span::current());
996 let state = self
997 .execute(
998 portal_name,
999 max_rows,
1000 portal_exec_message,
1001 None,
1002 ExecuteTimeout::None,
1003 None,
1004 Some(received),
1005 )
1006 .instrument(execute_root_span)
1007 .await?;
1008 let (is_implicit, may_span_pipeline) = {
1023 let txn = self.adapter_client.session().transaction();
1024 (txn.is_implicit(), txn.may_span_pipeline())
1025 };
1026 let spans_pipeline = may_span_pipeline
1029 && self
1030 .adapter_client
1031 .extended_protocol_implicit_transaction_enabled()
1032 .await;
1033 if is_implicit && !spans_pipeline {
1034 self.txn_needs_commit = true;
1035 }
1036 state
1037 }
1038 Some(FrontendMessage::DescribeStatement { name }) => {
1039 self.describe_statement(&name).await?
1040 }
1041 Some(FrontendMessage::DescribePortal { name }) => self.describe_portal(&name).await?,
1042 Some(FrontendMessage::CloseStatement { name }) => self.close_statement(name).await?,
1043 Some(FrontendMessage::ClosePortal { name }) => self.close_portal(name).await?,
1044 Some(FrontendMessage::Flush) => self.flush().await?,
1045 Some(FrontendMessage::Sync) => self.sync().await?,
1046 Some(FrontendMessage::Terminate) => State::Done,
1047
1048 Some(FrontendMessage::CopyData(_))
1055 | Some(FrontendMessage::CopyDone)
1056 | Some(FrontendMessage::CopyFail(_)) => State::Ready,
1057
1058 Some(FrontendMessage::Password { .. })
1059 | Some(FrontendMessage::RawAuthentication(_))
1060 | Some(FrontendMessage::SASLInitialResponse { .. })
1061 | Some(FrontendMessage::SASLResponse(_)) => State::Drain,
1062 None => State::Done,
1063 };
1064
1065 if let Some(start) = start {
1066 self.adapter_client
1067 .inner()
1068 .metrics()
1069 .pgwire_message_processing_seconds
1070 .with_label_values(&[message_name])
1071 .observe(start.elapsed().as_secs_f64());
1072 }
1073 self.adapter_client
1074 .inner()
1075 .metrics()
1076 .pgwire_recv_scheduling_delay_ms
1077 .with_label_values(&[message_name])
1078 .observe(recv_scheduling_delay_ms);
1079
1080 Ok(next_state)
1081 }
1082
1083 async fn advance_drain(&mut self) -> Result<State, io::Error> {
1084 let message = self.conn.recv().await?;
1085 if message.is_some() {
1086 self.adapter_client
1087 .remove_idle_in_transaction_session_timeout();
1088 }
1089 match message {
1090 Some(FrontendMessage::Sync) => self.sync().await,
1091 None => Ok(State::Done),
1092 _ => Ok(State::Drain),
1093 }
1094 }
1095
1096 #[instrument(level = "debug")]
1100 async fn one_query(
1101 &mut self,
1102 stmt: Statement<Raw>,
1103 sql: String,
1104 lifecycle_timestamps: LifecycleTimestamps,
1105 ) -> Result<State, io::Error> {
1106 const EMPTY_PORTAL: &str = "";
1109 if let Err(e) = self
1110 .adapter_client
1111 .declare(EMPTY_PORTAL.to_string(), stmt, sql)
1112 .await
1113 {
1114 return self
1115 .send_error_and_get_state(e.into_response(Severity::Error))
1116 .await;
1117 }
1118 let portal = self
1119 .adapter_client
1120 .session()
1121 .get_portal_unverified_mut(EMPTY_PORTAL)
1122 .expect("unnamed portal should be present");
1123
1124 *portal.lifecycle_timestamps = Some(lifecycle_timestamps);
1125
1126 let stmt_desc = portal.desc.clone();
1127 if !stmt_desc.param_types.is_empty() {
1128 return self
1129 .send_error_and_get_state(ErrorResponse::error(
1130 SqlState::UNDEFINED_PARAMETER,
1131 "there is no parameter $1",
1132 ))
1133 .await;
1134 }
1135
1136 if let Some(relation_desc) = &stmt_desc.relation_desc {
1138 if !stmt_desc.is_copy {
1139 let formats = vec![Format::Text; stmt_desc.arity()];
1140 self.send(BackendMessage::RowDescription(
1141 message::encode_row_description(relation_desc, &formats),
1142 ))
1143 .await?;
1144 }
1145 }
1146
1147 let result = match self
1148 .adapter_client
1149 .execute(EMPTY_PORTAL.to_string(), self.conn.wait_closed(), None)
1150 .await
1151 {
1152 Ok((response, execute_started)) => {
1153 self.send_pending_notices().await?;
1154 self.send_execute_response(
1155 response,
1156 stmt_desc.relation_desc,
1157 EMPTY_PORTAL.to_string(),
1158 ExecuteCount::All,
1159 portal_exec_message,
1160 None,
1161 ExecuteTimeout::None,
1162 execute_started,
1163 )
1164 .await
1165 }
1166 Err(e) => {
1167 self.send_pending_notices().await?;
1168 self.send_error_and_get_state(e.into_response(Severity::Error))
1169 .await
1170 }
1171 };
1172
1173 self.adapter_client.session().remove_portal(EMPTY_PORTAL);
1175
1176 result
1177 }
1178
1179 async fn ensure_transaction(
1180 &mut self,
1181 num_stmts: usize,
1182 message_type: &str,
1183 ) -> Result<(), io::Error> {
1184 let start = Instant::now();
1185 if self.txn_needs_commit {
1186 self.commit_transaction().await?;
1187 }
1188 let res = self.adapter_client.start_transaction(Some(num_stmts));
1191 assert_ok!(res);
1192 self.adapter_client
1193 .inner()
1194 .metrics()
1195 .pgwire_ensure_transaction_seconds
1196 .with_label_values(&[message_type])
1197 .observe(start.elapsed().as_secs_f64());
1198 Ok(())
1199 }
1200
1201 async fn maybe_log_message_arrival(&mut self, message: &FrontendMessage) {
1220 if !self
1221 .adapter_client
1222 .statement_arrival_logging_enabled()
1223 .await
1224 {
1225 return;
1226 }
1227 let session = self.adapter_client.session();
1228 let conn_id = session.conn_id();
1229 let session_uuid = session.uuid();
1230 let kind = message.name();
1231 match message {
1232 FrontendMessage::Query { sql } => {
1233 info!(
1234 %conn_id, %session_uuid, kind, sql = %redact_sql_for_logging(sql),
1235 "statement arrival"
1236 );
1237 }
1238 FrontendMessage::Parse { name, sql, .. } => {
1239 info!(
1240 %conn_id, %session_uuid, kind, name, sql = %redact_sql_for_logging(sql),
1241 "statement arrival"
1242 );
1243 }
1244 FrontendMessage::Bind {
1245 portal_name,
1246 statement_name,
1247 raw_params,
1248 ..
1249 } => {
1250 info!(
1251 %conn_id, %session_uuid, kind, portal_name, statement_name,
1252 num_params = raw_params.len(),
1253 "statement arrival"
1254 );
1255 }
1256 FrontendMessage::CopyData(data) => {
1258 info!(%conn_id, %session_uuid, kind, len = data.len(), "statement arrival");
1259 }
1260 FrontendMessage::Password { .. }
1262 | FrontendMessage::RawAuthentication(_)
1263 | FrontendMessage::SASLInitialResponse { .. }
1264 | FrontendMessage::SASLResponse(_) => {
1265 info!(%conn_id, %session_uuid, kind, "statement arrival");
1266 }
1267 FrontendMessage::CopyFail(_) => {
1270 info!(%conn_id, %session_uuid, kind, "statement arrival");
1271 }
1272 FrontendMessage::DescribeStatement { .. }
1275 | FrontendMessage::DescribePortal { .. }
1276 | FrontendMessage::Execute { .. }
1277 | FrontendMessage::Flush
1278 | FrontendMessage::Sync
1279 | FrontendMessage::CloseStatement { .. }
1280 | FrontendMessage::ClosePortal { .. }
1281 | FrontendMessage::Terminate
1282 | FrontendMessage::CopyDone => {
1283 info!(%conn_id, %session_uuid, kind, contents = ?message, "statement arrival");
1289 }
1290 }
1291 }
1292
1293 fn parse_sql<'b>(&self, sql: &'b str) -> Result<Vec<StatementParseResult<'b>>, ErrorResponse> {
1294 let parse_start = Instant::now();
1295 let result = match self.adapter_client.parse(sql) {
1296 Ok(result) => result.map_err(|e| {
1297 let pos = sql[..e.error.pos].chars().count() + 1;
1300 ErrorResponse::error(SqlState::SYNTAX_ERROR, e.error.message).with_position(pos)
1301 }),
1302 Err(msg) => Err(ErrorResponse::error(SqlState::PROGRAM_LIMIT_EXCEEDED, msg)),
1303 };
1304 self.adapter_client
1305 .inner()
1306 .metrics()
1307 .parse_seconds
1308 .observe(parse_start.elapsed().as_secs_f64());
1309 result
1310 }
1311
1312 #[instrument(level = "debug")]
1317 async fn query(&mut self, sql: String, received: EpochMillis) -> Result<State, io::Error> {
1318 let stmts = match self.parse_sql(&sql) {
1320 Ok(stmts) => stmts,
1321 Err(err) => {
1322 self.send_error_and_get_state(err).await?;
1323 return self.ready().await;
1324 }
1325 };
1326
1327 let num_stmts = stmts.len();
1328
1329 for StatementParseResult { ast: stmt, sql } in stmts {
1331 if self.is_aborted_txn() && !is_txn_exit_stmt(Some(&stmt)) {
1333 self.aborted_txn_error().await?;
1334 break;
1335 }
1336
1337 self.ensure_transaction(num_stmts, "query").await?;
1345
1346 match self
1347 .one_query(stmt, sql.to_string(), LifecycleTimestamps { received })
1348 .await?
1349 {
1350 State::Ready => (),
1351 State::Drain => break,
1352 State::Done => return Ok(State::Done),
1353 }
1354 }
1355
1356 {
1358 if self.adapter_client.session().transaction().is_implicit() {
1359 self.commit_transaction().await?;
1360 }
1361 }
1362
1363 if num_stmts == 0 {
1364 self.send(BackendMessage::EmptyQueryResponse).await?;
1365 }
1366
1367 self.ready().await
1368 }
1369
1370 #[instrument(level = "debug")]
1371 async fn parse(
1372 &mut self,
1373 name: String,
1374 sql: String,
1375 param_oids: Vec<u32>,
1376 ) -> Result<State, io::Error> {
1377 self.ensure_transaction(1, "parse").await?;
1379
1380 let mut param_types = vec![];
1381 for oid in param_oids {
1382 match mz_pgrepr::Type::from_oid(oid) {
1383 Ok(ty) => match SqlScalarType::try_from(&ty) {
1384 Ok(ty) => param_types.push(Some(ty)),
1385 Err(err) => {
1386 return self
1387 .send_error_and_get_state(ErrorResponse::error(
1388 SqlState::INVALID_PARAMETER_VALUE,
1389 err.to_string(),
1390 ))
1391 .await;
1392 }
1393 },
1394 Err(_) if oid == 0 => param_types.push(None),
1395 Err(e) => {
1396 return self
1397 .send_error_and_get_state(ErrorResponse::error(
1398 SqlState::PROTOCOL_VIOLATION,
1399 e.to_string(),
1400 ))
1401 .await;
1402 }
1403 }
1404 }
1405
1406 let stmts = match self.parse_sql(&sql) {
1407 Ok(stmts) => stmts,
1408 Err(err) => {
1409 return self.send_error_and_get_state(err).await;
1410 }
1411 };
1412 if stmts.len() > 1 {
1413 return self
1414 .send_error_and_get_state(ErrorResponse::error(
1415 SqlState::INTERNAL_ERROR,
1416 "cannot insert multiple commands into a prepared statement",
1417 ))
1418 .await;
1419 }
1420 let (maybe_stmt, sql) = match stmts.into_iter().next() {
1421 None => (None, ""),
1422 Some(StatementParseResult { ast, sql }) => (Some(ast), sql),
1423 };
1424 if self.is_aborted_txn() && !is_txn_exit_stmt(maybe_stmt.as_ref()) {
1425 return self.aborted_txn_error().await;
1426 }
1427 match self
1428 .adapter_client
1429 .prepare(name, maybe_stmt, sql.to_string(), param_types)
1430 .await
1431 {
1432 Ok(()) => {
1433 self.send(BackendMessage::ParseComplete).await?;
1434 Ok(State::Ready)
1435 }
1436 Err(e) => {
1437 self.send_error_and_get_state(e.into_response(Severity::Error))
1438 .await
1439 }
1440 }
1441 }
1442
1443 #[instrument(level = "debug")]
1445 async fn commit_transaction(&mut self) -> Result<(), io::Error> {
1446 self.end_transaction(EndTransactionAction::Commit).await
1447 }
1448
1449 #[instrument(level = "debug")]
1451 async fn rollback_transaction(&mut self) -> Result<(), io::Error> {
1452 self.end_transaction(EndTransactionAction::Rollback).await
1453 }
1454
1455 #[instrument(level = "debug")]
1462 async fn end_transaction(&mut self, action: EndTransactionAction) -> Result<(), io::Error> {
1463 self.txn_needs_commit = false;
1464 match self.adapter_client.end_transaction(action).await {
1465 Ok(
1466 ExecuteResponse::TransactionCommitted { params }
1467 | ExecuteResponse::TransactionRolledBack { params },
1468 ) => {
1469 self.send_parameter_statuses(params).await?;
1470 }
1471 Ok(_) => {}
1472 Err(err) => {
1473 self.send(BackendMessage::ErrorResponse(
1474 err.into_response(Severity::Error),
1475 ))
1476 .await?;
1477 }
1478 }
1479 Ok(())
1480 }
1481
1482 #[instrument(level = "debug")]
1485 async fn send_parameter_statuses(
1486 &mut self,
1487 params: BTreeMap<&'static str, String>,
1488 ) -> Result<(), io::Error> {
1489 let notify_set: mz_ore::collections::HashSet<String> = self
1490 .adapter_client
1491 .session()
1492 .vars()
1493 .notify_set()
1494 .map(|v| v.name().to_string())
1495 .collect();
1496
1497 for (name, value) in params
1498 .into_iter()
1499 .filter(|(name, _value)| notify_set.contains(*name))
1500 {
1501 self.send(BackendMessage::ParameterStatus(name, value))
1502 .await?;
1503 }
1504 Ok(())
1505 }
1506
1507 #[instrument(level = "debug")]
1508 async fn bind(
1509 &mut self,
1510 portal_name: String,
1511 statement_name: String,
1512 param_formats: Vec<Format>,
1513 raw_params: Vec<Option<Vec<u8>>>,
1514 result_formats: Vec<Format>,
1515 ) -> Result<State, io::Error> {
1516 self.ensure_transaction(1, "bind").await?;
1518
1519 let aborted_txn = self.is_aborted_txn();
1520 let stmt = match self
1521 .adapter_client
1522 .get_prepared_statement(&statement_name)
1523 .await
1524 {
1525 Ok(stmt) => stmt,
1526 Err(err) => {
1527 return self
1528 .send_error_and_get_state(err.into_response(Severity::Error))
1529 .await;
1530 }
1531 };
1532
1533 let param_types = &stmt.desc().param_types;
1534 if param_types.len() != raw_params.len() {
1535 let message = format!(
1536 "bind message supplies {actual} parameters, \
1537 but prepared statement \"{name}\" requires {expected}",
1538 name = statement_name,
1539 actual = raw_params.len(),
1540 expected = param_types.len()
1541 );
1542 return self
1543 .send_error_and_get_state(ErrorResponse::error(
1544 SqlState::PROTOCOL_VIOLATION,
1545 message,
1546 ))
1547 .await;
1548 }
1549 let param_formats = match pad_formats(param_formats, raw_params.len()) {
1550 Ok(param_formats) => param_formats,
1551 Err(msg) => {
1552 return self
1553 .send_error_and_get_state(ErrorResponse::error(
1554 SqlState::PROTOCOL_VIOLATION,
1555 msg,
1556 ))
1557 .await;
1558 }
1559 };
1560 if aborted_txn && !is_txn_exit_stmt(stmt.stmt()) {
1561 return self.aborted_txn_error().await;
1562 }
1563 let buf = RowArena::new();
1564 let mut params = vec![];
1565 for ((raw_param, mz_typ), format) in raw_params
1566 .into_iter()
1567 .zip_eq(param_types)
1568 .zip_eq(param_formats)
1569 {
1570 let pg_typ = mz_pgrepr::Type::from(mz_typ);
1571 let datum = match raw_param {
1572 None => Datum::Null,
1573 Some(bytes) => match mz_pgrepr::Value::decode(format, &pg_typ, &bytes) {
1574 Ok(param) => match param.into_datum_decode_error(&buf, &pg_typ, "parameter") {
1575 Ok(datum) => datum,
1576 Err(msg) => {
1577 return self
1578 .send_error_and_get_state(ErrorResponse::error(
1579 SqlState::INVALID_PARAMETER_VALUE,
1580 msg,
1581 ))
1582 .await;
1583 }
1584 },
1585 Err(err) => {
1586 let (code, msg) = if err.is::<mz_pgrepr::NulCharacterError>() {
1589 (SqlState::CHARACTER_NOT_IN_REPERTOIRE, err.to_string())
1590 } else {
1591 (
1592 SqlState::INVALID_PARAMETER_VALUE,
1593 format!("unable to decode parameter: {}", err),
1594 )
1595 };
1596 return self
1597 .send_error_and_get_state(ErrorResponse::error(code, msg))
1598 .await;
1599 }
1600 },
1601 };
1602 params.push((datum, mz_typ.clone()))
1603 }
1604
1605 let result_formats = match pad_formats(
1606 result_formats,
1607 stmt.desc()
1608 .relation_desc
1609 .clone()
1610 .map(|desc| desc.typ().column_types.len())
1611 .unwrap_or(0),
1612 ) {
1613 Ok(result_formats) => result_formats,
1614 Err(msg) => {
1615 return self
1616 .send_error_and_get_state(ErrorResponse::error(
1617 SqlState::PROTOCOL_VIOLATION,
1618 msg,
1619 ))
1620 .await;
1621 }
1622 };
1623
1624 if !stmt.stmt().map_or(false, |stmt| match stmt {
1627 Statement::Copy(CopyStatement {
1628 direction: CopyDirection::To,
1629 ..
1630 }) => true,
1631 Statement::Copy(CopyStatement {
1632 direction: CopyDirection::From,
1633 target: CopyTarget::Expr(_),
1637 ..
1638 }) => true,
1639 _ => false,
1640 }) {
1641 if let Some(desc) = stmt.desc().relation_desc.clone() {
1642 for (format, ty) in result_formats.iter().zip_eq(desc.iter_types()) {
1643 if let Format::Binary = format {
1644 if let Err(msg) = mz_pgrepr::Value::binary_encoding_error(&ty.scalar_type) {
1645 return self
1646 .send_error_and_get_state(ErrorResponse::error(
1647 SqlState::UNDEFINED_FUNCTION,
1648 msg,
1649 ))
1650 .await;
1651 }
1652 }
1653 }
1654 }
1655 }
1656
1657 let desc = stmt.desc().clone();
1658 let logging = Arc::clone(stmt.logging());
1659 let stmt_ast = stmt.stmt().cloned();
1660 let state_revision = stmt.state_revision;
1661 if let Err(err) = self.adapter_client.session().set_portal(
1662 portal_name,
1663 desc,
1664 stmt_ast,
1665 logging,
1666 params,
1667 result_formats,
1668 state_revision,
1669 ) {
1670 return self
1671 .send_error_and_get_state(err.into_response(Severity::Error))
1672 .await;
1673 }
1674
1675 self.send(BackendMessage::BindComplete).await?;
1676 Ok(State::Ready)
1677 }
1678
1679 fn execute(
1682 &mut self,
1683 portal_name: String,
1684 max_rows: ExecuteCount,
1685 get_response: GetResponse,
1686 fetch_portal_name: Option<String>,
1687 timeout: ExecuteTimeout,
1688 outer_ctx_extra: Option<ExecuteContextGuard>,
1689 received: Option<EpochMillis>,
1690 ) -> BoxFuture<'_, Result<State, io::Error>> {
1691 async move {
1692 let aborted_txn = self.is_aborted_txn();
1693
1694 let portal = match self
1696 .adapter_client
1697 .session()
1698 .get_portal_unverified_mut(&portal_name)
1699 {
1700 Some(portal) => portal,
1701 None => {
1702 let msg = format!("portal {} does not exist", portal_name.quoted());
1703 if let Some(outer_ctx_extra) = outer_ctx_extra {
1704 self.adapter_client.retire_execute(
1705 outer_ctx_extra,
1706 StatementEndedExecutionReason::Errored { error: msg.clone() },
1707 );
1708 }
1709 return self
1710 .send_error_and_get_state(ErrorResponse::error(
1711 SqlState::INVALID_CURSOR_NAME,
1712 msg,
1713 ))
1714 .await;
1715 }
1716 };
1717
1718 *portal.lifecycle_timestamps = received.map(LifecycleTimestamps::new);
1719
1720 let txn_exit_stmt = is_txn_exit_stmt(portal.stmt.as_deref());
1722 if aborted_txn && !txn_exit_stmt {
1723 if let Some(outer_ctx_extra) = outer_ctx_extra {
1724 self.adapter_client.retire_execute(
1725 outer_ctx_extra,
1726 StatementEndedExecutionReason::Errored {
1727 error: ABORTED_TXN_MSG.to_string(),
1728 },
1729 );
1730 }
1731 return self.aborted_txn_error().await;
1732 }
1733
1734 let row_desc = portal.desc.relation_desc.clone();
1735 match portal.state {
1736 PortalState::NotStarted => {
1737 self.ensure_transaction(1, "execute").await?;
1739 match self
1740 .adapter_client
1741 .execute(
1742 portal_name.clone(),
1743 self.conn.wait_closed(),
1744 outer_ctx_extra,
1745 )
1746 .await
1747 {
1748 Ok((response, execute_started)) => {
1749 self.send_pending_notices().await?;
1750 self.send_execute_response(
1751 response,
1752 row_desc,
1753 portal_name,
1754 max_rows,
1755 get_response,
1756 fetch_portal_name,
1757 timeout,
1758 execute_started,
1759 )
1760 .await
1761 }
1762 Err(e) => {
1763 self.send_pending_notices().await?;
1764 self.send_error_and_get_state(e.into_response(Severity::Error))
1765 .await
1766 }
1767 }
1768 }
1769 PortalState::InProgress(rows) => {
1770 let rows = rows.take().expect("InProgress rows must be populated");
1771 let (result, statement_ended_execution_reason) = match self
1772 .send_rows(
1773 row_desc.expect("portal missing row desc on resumption"),
1774 portal_name,
1775 rows,
1776 max_rows,
1777 get_response,
1778 fetch_portal_name,
1779 timeout,
1780 )
1781 .await
1782 {
1783 Err(e) => {
1784 (Err(e), StatementEndedExecutionReason::Canceled)
1787 }
1788 Ok((ok, SendRowsEndedReason::Canceled)) => {
1789 (Ok(ok), StatementEndedExecutionReason::Canceled)
1790 }
1791 Ok((
1804 ok,
1805 SendRowsEndedReason::Success {
1806 result_size: _,
1807 rows_returned: _,
1808 },
1809 )) => (
1810 Ok(ok),
1811 StatementEndedExecutionReason::Success {
1812 result_size: None,
1813 rows_returned: None,
1814 execution_strategy: None,
1815 },
1816 ),
1817 Ok((ok, SendRowsEndedReason::Errored { error })) => {
1818 (Ok(ok), StatementEndedExecutionReason::Errored { error })
1819 }
1820 };
1821 if let Some(outer_ctx_extra) = outer_ctx_extra {
1822 self.adapter_client
1823 .retire_execute(outer_ctx_extra, statement_ended_execution_reason);
1824 }
1825 result
1826 }
1827 PortalState::Completed(Some(tag)) => {
1834 let tag = tag.to_string();
1835 if let Some(outer_ctx_extra) = outer_ctx_extra {
1836 self.adapter_client.retire_execute(
1837 outer_ctx_extra,
1838 StatementEndedExecutionReason::Success {
1839 result_size: None,
1840 rows_returned: None,
1841 execution_strategy: None,
1842 },
1843 );
1844 }
1845 self.send(BackendMessage::CommandComplete { tag }).await?;
1846 Ok(State::Ready)
1847 }
1848 PortalState::Completed(None) => {
1849 let error = format!(
1850 "portal {} cannot be run",
1851 Ident::new_unchecked(portal_name).to_ast_string_stable()
1852 );
1853 if let Some(outer_ctx_extra) = outer_ctx_extra {
1854 self.adapter_client.retire_execute(
1855 outer_ctx_extra,
1856 StatementEndedExecutionReason::Errored {
1857 error: error.clone(),
1858 },
1859 );
1860 }
1861 self.send_error_and_get_state(ErrorResponse::error(
1862 SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE,
1863 error,
1864 ))
1865 .await
1866 }
1867 }
1868 }
1869 .instrument(debug_span!("execute"))
1870 .boxed()
1871 }
1872
1873 #[instrument(level = "debug")]
1874 async fn describe_statement(&mut self, name: &str) -> Result<State, io::Error> {
1875 self.ensure_transaction(1, "describe_statement").await?;
1877
1878 let stmt = match self.adapter_client.get_prepared_statement(name).await {
1879 Ok(stmt) => stmt,
1880 Err(err) => {
1881 return self
1882 .send_error_and_get_state(err.into_response(Severity::Error))
1883 .await;
1884 }
1885 };
1886 let parameter_desc = BackendMessage::ParameterDescription(
1888 stmt.desc()
1889 .param_types
1890 .iter()
1891 .map(mz_pgrepr::Type::from)
1892 .collect(),
1893 );
1894 let formats = vec![Format::Text; stmt.desc().arity()];
1898 let row_desc = describe_rows(stmt.desc(), &formats);
1899 self.send_all([parameter_desc, row_desc]).await?;
1900 Ok(State::Ready)
1901 }
1902
1903 #[instrument(level = "debug")]
1904 async fn describe_portal(&mut self, name: &str) -> Result<State, io::Error> {
1905 self.ensure_transaction(1, "describe_portal").await?;
1907
1908 let session = self.adapter_client.session();
1909 let row_desc = session
1910 .get_portal_unverified(name)
1911 .map(|portal| describe_rows(&portal.desc, &portal.result_formats));
1912 match row_desc {
1913 Some(row_desc) => {
1914 self.send(row_desc).await?;
1915 Ok(State::Ready)
1916 }
1917 None => {
1918 self.send_error_and_get_state(ErrorResponse::error(
1919 SqlState::INVALID_CURSOR_NAME,
1920 format!("portal {} does not exist", name.quoted()),
1921 ))
1922 .await
1923 }
1924 }
1925 }
1926
1927 #[instrument(level = "debug")]
1928 async fn close_statement(&mut self, name: String) -> Result<State, io::Error> {
1929 self.adapter_client
1930 .session()
1931 .remove_prepared_statement(&name);
1932 self.send(BackendMessage::CloseComplete).await?;
1933 Ok(State::Ready)
1934 }
1935
1936 #[instrument(level = "debug")]
1937 async fn close_portal(&mut self, name: String) -> Result<State, io::Error> {
1938 self.adapter_client.session().remove_portal(&name);
1939 self.send(BackendMessage::CloseComplete).await?;
1940 Ok(State::Ready)
1941 }
1942
1943 fn complete_portal(&mut self, name: &str) {
1944 let portal = self
1945 .adapter_client
1946 .session()
1947 .get_portal_unverified_mut(name)
1948 .expect("portal should exist");
1949 *portal.state = PortalState::Completed(None);
1950 }
1951
1952 async fn fetch(
1953 &mut self,
1954 name: String,
1955 count: Option<FetchDirection>,
1956 max_rows: ExecuteCount,
1957 fetch_portal_name: Option<String>,
1958 timeout: ExecuteTimeout,
1959 ctx_extra: ExecuteContextGuard,
1960 ) -> Result<State, io::Error> {
1961 let count = count.unwrap_or(FetchDirection::ForwardCount(1));
1964
1965 let count = match (max_rows, count) {
1978 (ExecuteCount::Count(max_rows), FetchDirection::ForwardCount(count)) => {
1979 let count = usize::cast_from(count);
1980 if max_rows < count {
1981 let msg = "Execute with max_rows < a FETCH's count is not supported";
1982 self.adapter_client.retire_execute(
1983 ctx_extra,
1984 StatementEndedExecutionReason::Errored {
1985 error: msg.to_string(),
1986 },
1987 );
1988 return self
1989 .send_error_and_get_state(ErrorResponse::error(
1990 SqlState::FEATURE_NOT_SUPPORTED,
1991 msg,
1992 ))
1993 .await;
1994 }
1995 ExecuteCount::Count(count)
1996 }
1997 (ExecuteCount::Count(_), FetchDirection::ForwardAll) => {
1998 let msg = "Execute with max_rows of a FETCH ALL is not supported";
1999 self.adapter_client.retire_execute(
2000 ctx_extra,
2001 StatementEndedExecutionReason::Errored {
2002 error: msg.to_string(),
2003 },
2004 );
2005 return self
2006 .send_error_and_get_state(ErrorResponse::error(
2007 SqlState::FEATURE_NOT_SUPPORTED,
2008 msg,
2009 ))
2010 .await;
2011 }
2012 (ExecuteCount::All, FetchDirection::ForwardAll) => ExecuteCount::All,
2013 (ExecuteCount::All, FetchDirection::ForwardCount(count)) => {
2014 ExecuteCount::Count(usize::cast_from(count))
2015 }
2016 };
2017 let cursor_name = name.to_string();
2018 self.execute(
2019 cursor_name,
2020 count,
2021 fetch_message,
2022 fetch_portal_name,
2023 timeout,
2024 Some(ctx_extra),
2025 None,
2026 )
2027 .await
2028 }
2029
2030 async fn flush(&mut self) -> Result<State, io::Error> {
2031 self.conn.flush().await?;
2032 Ok(State::Ready)
2033 }
2034
2035 #[instrument(level = "debug")]
2040 async fn send<M>(&mut self, message: M) -> Result<(), io::Error>
2041 where
2042 M: Into<BackendMessage>,
2043 {
2044 let message: BackendMessage = message.into();
2045 let is_error =
2046 matches!(&message, BackendMessage::ErrorResponse(e) if e.severity.is_error());
2047
2048 self.conn.send(message).await?;
2049
2050 if is_error {
2057 self.conn.flush().await?;
2058 }
2059
2060 Ok(())
2061 }
2062
2063 #[instrument(level = "debug")]
2064 pub async fn send_all(
2065 &mut self,
2066 messages: impl IntoIterator<Item = BackendMessage>,
2067 ) -> Result<(), io::Error> {
2068 for m in messages {
2069 self.send(m).await?;
2070 }
2071 Ok(())
2072 }
2073
2074 #[instrument(level = "debug")]
2075 async fn sync(&mut self) -> Result<State, io::Error> {
2076 if self.adapter_client.session().transaction().is_implicit() {
2078 self.commit_transaction().await?;
2079 }
2080 self.ready().await
2081 }
2082
2083 #[instrument(level = "debug")]
2084 async fn ready(&mut self) -> Result<State, io::Error> {
2085 let txn_state = self.adapter_client.session().transaction().into();
2086 self.send(BackendMessage::ReadyForQuery(txn_state)).await?;
2087 self.flush().await
2088 }
2089
2090 #[allow(clippy::too_many_arguments)]
2091 #[instrument(level = "debug")]
2092 async fn send_execute_response(
2093 &mut self,
2094 response: ExecuteResponse,
2095 row_desc: Option<RelationDesc>,
2096 portal_name: String,
2097 max_rows: ExecuteCount,
2098 get_response: GetResponse,
2099 fetch_portal_name: Option<String>,
2100 timeout: ExecuteTimeout,
2101 execute_started: Instant,
2102 ) -> Result<State, io::Error> {
2103 let mut tag = response.tag();
2104
2105 macro_rules! command_complete {
2106 () => {{
2107 self.send(BackendMessage::CommandComplete {
2108 tag: tag
2109 .take()
2110 .expect("command_complete only called on tag-generating results"),
2111 })
2112 .await?;
2113 Ok(State::Ready)
2114 }};
2115 }
2116
2117 let r = match response {
2118 ExecuteResponse::ClosedCursor => {
2119 self.complete_portal(&portal_name);
2120 command_complete!()
2121 }
2122 ExecuteResponse::DeclaredCursor => {
2123 self.complete_portal(&portal_name);
2124 command_complete!()
2125 }
2126 ExecuteResponse::EmptyQuery => {
2127 self.send(BackendMessage::EmptyQueryResponse).await?;
2128 Ok(State::Ready)
2129 }
2130 ExecuteResponse::Fetch {
2131 name,
2132 count,
2133 timeout,
2134 ctx_extra,
2135 } => {
2136 self.fetch(
2137 name,
2138 count,
2139 max_rows,
2140 Some(portal_name.to_string()),
2141 timeout,
2142 ctx_extra,
2143 )
2144 .await
2145 }
2146 ExecuteResponse::SendingRowsStreaming {
2147 rows,
2148 instance_id,
2149 strategy,
2150 } => {
2151 let row_desc = row_desc
2152 .expect("missing row description for ExecuteResponse::SendingRowsStreaming");
2153
2154 let span = tracing::debug_span!("sending_rows_streaming");
2155
2156 self.send_rows(
2157 row_desc,
2158 portal_name,
2159 InProgressRows::new(RecordFirstRowStream::new(
2160 Box::new(rows),
2161 execute_started,
2162 &self.adapter_client,
2163 Some(instance_id),
2164 Some(strategy),
2165 )),
2166 max_rows,
2167 get_response,
2168 fetch_portal_name,
2169 timeout,
2170 )
2171 .instrument(span)
2172 .await
2173 .map(|(state, _)| state)
2174 }
2175 ExecuteResponse::SendingRowsImmediate { rows } => {
2176 let row_desc = row_desc
2177 .expect("missing row description for ExecuteResponse::SendingRowsImmediate");
2178
2179 let span = tracing::debug_span!("sending_rows_immediate");
2180
2181 let stream =
2182 futures::stream::once(futures::future::ready(PeekResponseUnary::Rows(rows)));
2183 self.send_rows(
2184 row_desc,
2185 portal_name,
2186 InProgressRows::new(RecordFirstRowStream::new(
2187 Box::new(stream),
2188 execute_started,
2189 &self.adapter_client,
2190 None,
2191 Some(StatementExecutionStrategy::Constant),
2192 )),
2193 max_rows,
2194 get_response,
2195 fetch_portal_name,
2196 timeout,
2197 )
2198 .instrument(span)
2199 .await
2200 .map(|(state, _)| state)
2201 }
2202 ExecuteResponse::SetVariable { name, .. } => {
2203 let qn = name.to_string();
2206 let msg = if let Some(var) = self
2207 .adapter_client
2208 .session()
2209 .vars_mut()
2210 .notify_set()
2211 .find(|v| v.name() == qn)
2212 {
2213 Some(BackendMessage::ParameterStatus(var.name(), var.value()))
2214 } else {
2215 None
2216 };
2217 if let Some(msg) = msg {
2218 self.send(msg).await?;
2219 }
2220 command_complete!()
2221 }
2222 ExecuteResponse::Subscribing {
2223 rx,
2224 ctx_extra,
2225 instance_id,
2226 } => {
2227 if fetch_portal_name.is_none() {
2228 let mut msg = ErrorResponse::notice(
2229 SqlState::WARNING,
2230 "streaming SUBSCRIBE rows directly requires a client that does not buffer output",
2231 );
2232 if self.adapter_client.session().vars().application_name() == "psql" {
2233 msg.hint = Some(
2234 "Wrap your SUBSCRIBE statement in `COPY (SUBSCRIBE ...) TO STDOUT`."
2235 .into(),
2236 )
2237 }
2238 self.send(msg).await?;
2239 self.conn.flush().await?;
2240 }
2241 let row_desc =
2242 row_desc.expect("missing row description for ExecuteResponse::Subscribing");
2243 let (result, statement_ended_execution_reason) = match self
2244 .send_rows(
2245 row_desc,
2246 portal_name,
2247 InProgressRows::new(RecordFirstRowStream::new(
2248 Box::new(UnboundedReceiverStream::new(rx)),
2249 execute_started,
2250 &self.adapter_client,
2251 Some(instance_id),
2252 None,
2253 )),
2254 max_rows,
2255 get_response,
2256 fetch_portal_name,
2257 timeout,
2258 )
2259 .await
2260 {
2261 Err(e) => {
2262 (Err(e), StatementEndedExecutionReason::Canceled)
2265 }
2266 Ok((ok, SendRowsEndedReason::Canceled)) => {
2267 (Ok(ok), StatementEndedExecutionReason::Canceled)
2268 }
2269 Ok((
2270 ok,
2271 SendRowsEndedReason::Success {
2272 result_size,
2273 rows_returned,
2274 },
2275 )) => (
2276 Ok(ok),
2277 StatementEndedExecutionReason::Success {
2278 result_size: Some(result_size),
2279 rows_returned: Some(rows_returned),
2280 execution_strategy: None,
2281 },
2282 ),
2283 Ok((ok, SendRowsEndedReason::Errored { error })) => {
2284 (Ok(ok), StatementEndedExecutionReason::Errored { error })
2285 }
2286 };
2287 self.adapter_client
2288 .retire_execute(ctx_extra, statement_ended_execution_reason);
2289 return result;
2290 }
2291 ExecuteResponse::CopyTo { format, resp } => {
2292 let row_desc =
2293 row_desc.expect("missing row description for ExecuteResponse::CopyTo");
2294 match *resp {
2295 ExecuteResponse::Subscribing {
2296 rx,
2297 ctx_extra,
2298 instance_id,
2299 } => {
2300 let (result, statement_ended_execution_reason) = match self
2301 .copy_rows(
2302 format,
2303 row_desc,
2304 RecordFirstRowStream::new(
2305 Box::new(UnboundedReceiverStream::new(rx)),
2306 execute_started,
2307 &self.adapter_client,
2308 Some(instance_id),
2309 None,
2310 ),
2311 )
2312 .await
2313 {
2314 Err(e) => {
2315 (Err(e), StatementEndedExecutionReason::Canceled)
2318 }
2319 Ok((
2320 state,
2321 SendRowsEndedReason::Success {
2322 result_size,
2323 rows_returned,
2324 },
2325 )) => (
2326 Ok(state),
2327 StatementEndedExecutionReason::Success {
2328 result_size: Some(result_size),
2329 rows_returned: Some(rows_returned),
2330 execution_strategy: None,
2331 },
2332 ),
2333 Ok((state, SendRowsEndedReason::Errored { error })) => {
2334 (Ok(state), StatementEndedExecutionReason::Errored { error })
2335 }
2336 Ok((state, SendRowsEndedReason::Canceled)) => {
2337 (Ok(state), StatementEndedExecutionReason::Canceled)
2338 }
2339 };
2340 self.adapter_client
2341 .retire_execute(ctx_extra, statement_ended_execution_reason);
2342 return result;
2343 }
2344 ExecuteResponse::SendingRowsStreaming {
2345 rows,
2346 instance_id,
2347 strategy,
2348 } => {
2349 return self
2354 .copy_rows(
2355 format,
2356 row_desc,
2357 RecordFirstRowStream::new(
2358 Box::new(rows),
2359 execute_started,
2360 &self.adapter_client,
2361 Some(instance_id),
2362 Some(strategy),
2363 ),
2364 )
2365 .await
2366 .map(|(state, _)| state);
2367 }
2368 ExecuteResponse::SendingRowsImmediate { rows } => {
2369 let span = tracing::debug_span!("sending_rows_immediate");
2370
2371 let rows = futures::stream::once(futures::future::ready(
2372 PeekResponseUnary::Rows(rows),
2373 ));
2374 return self
2379 .copy_rows(
2380 format,
2381 row_desc,
2382 RecordFirstRowStream::new(
2383 Box::new(rows),
2384 execute_started,
2385 &self.adapter_client,
2386 None,
2387 Some(StatementExecutionStrategy::Constant),
2388 ),
2389 )
2390 .instrument(span)
2391 .await
2392 .map(|(state, _)| state);
2393 }
2394 _ => {
2395 return self
2396 .send_error_and_get_state(ErrorResponse::error(
2397 SqlState::INTERNAL_ERROR,
2398 "unsupported COPY response type".to_string(),
2399 ))
2400 .await;
2401 }
2402 };
2403 }
2404 ExecuteResponse::CopyFrom {
2405 target_id,
2406 target_name,
2407 columns,
2408 params,
2409 ctx_extra,
2410 } => {
2411 let row_desc =
2412 row_desc.expect("missing row description for ExecuteResponse::CopyFrom");
2413 self.copy_from(target_id, target_name, columns, params, row_desc, ctx_extra)
2414 .await
2415 }
2416 ExecuteResponse::TransactionCommitted { params }
2417 | ExecuteResponse::TransactionRolledBack { params } => {
2418 self.send_parameter_statuses(params).await?;
2419 command_complete!()
2420 }
2421
2422 ExecuteResponse::AlteredDefaultPrivileges
2423 | ExecuteResponse::AlteredObject(..)
2424 | ExecuteResponse::AlteredRole
2425 | ExecuteResponse::AlteredSystemConfiguration
2426 | ExecuteResponse::CreatedCluster { .. }
2427 | ExecuteResponse::CreatedClusterReplica { .. }
2428 | ExecuteResponse::CreatedConnection { .. }
2429 | ExecuteResponse::CreatedDatabase { .. }
2430 | ExecuteResponse::CreatedIndex { .. }
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}