1use std::any::Any;
16use std::collections::HashMap;
17use std::io::ErrorKind;
18use std::panic::AssertUnwindSafe;
19use std::pin::Pin;
20use std::str::Utf8Error;
21use std::sync::{Arc, LazyLock, Weak};
22use std::time::{Duration, Instant};
23use std::{io, str};
24
25use bytes::{Bytes, BytesMut};
26use futures::FutureExt;
27use futures::stream::StreamExt;
28use itertools::Itertools;
29use openssl::ssl::{SslAcceptor, SslContext, SslContextRef, SslMethod};
30use risingwave_common::types::DataType;
31use risingwave_common::util::deployment::Deployment;
32use risingwave_common::util::env_var::env_var_is_true;
33use risingwave_common::util::panic::FutureCatchUnwindExt;
34use risingwave_common::util::query_log::*;
35use risingwave_common::{PG_VERSION, SERVER_ENCODING, STANDARD_CONFORMING_STRINGS};
36use risingwave_sqlparser::ast::{RedactSqlOptionKeywordsRef, Statement};
37use risingwave_sqlparser::parser::Parser;
38use thiserror_ext::AsReport;
39use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
40use tokio::sync::Mutex;
41use tokio_openssl::SslStream;
42use tracing::Instrument;
43
44use crate::error::{PsqlError, PsqlResult};
45use crate::error_or_notice::Severity;
46use crate::memory_manager::{MessageMemoryGuard, MessageMemoryManagerRef};
47use crate::net::AddressRef;
48use crate::pg_extended::ResultCache;
49use crate::pg_message::{
50 BeCommandCompleteMessage, BeMessage, BeParameterStatusMessage, FeBindMessage, FeCancelMessage,
51 FeCloseMessage, FeDescribeMessage, FeExecuteMessage, FeMessage, FeMessageHeader,
52 FeParseMessage, FePasswordMessage, FeStartupMessage, ServerThrottleReason, TransactionStatus,
53};
54use crate::pg_server::{Session, SessionManager, UserAuthenticator};
55use crate::types::Format;
56
57static RW_QUERY_LOG_TRUNCATE_LEN: LazyLock<usize> =
60 LazyLock::new(|| match std::env::var("RW_QUERY_LOG_TRUNCATE_LEN") {
61 Ok(len) if len.parse::<usize>().is_ok() => len.parse::<usize>().unwrap(),
62 _ => 65536,
63 });
64
65tokio::task_local! {
66 pub static CURRENT_SESSION: Weak<dyn Any + Send + Sync>
68}
69
70pub struct PgProtocol<S, SM>
73where
74 SM: SessionManager,
75{
76 stream: PgStream<S>,
78 state: PgProtocolState,
80 is_terminate: bool,
82
83 session_mgr: Arc<SM>,
84 session: Option<Arc<SM::Session>>,
85
86 result_cache: HashMap<String, ResultCache<<SM::Session as Session>::ValuesStream>>,
87 unnamed_prepare_statement:
88 Option<PreparedStatementData<<SM::Session as Session>::PreparedStatement>>,
89 prepare_statement_store:
90 HashMap<String, PreparedStatementData<<SM::Session as Session>::PreparedStatement>>,
91 unnamed_portal: Option<PortalData<<SM::Session as Session>::Portal>>,
92 portal_store: HashMap<String, PortalData<<SM::Session as Session>::Portal>>,
93 statement_portal_dependency: HashMap<String, Vec<String>>,
96
97 tls_context: Option<SslContext>,
100
101 tls_config: Option<TlsConfig>,
103
104 ignore_util_sync: bool,
107
108 peer_addr: AddressRef,
110
111 redact_sql_option_keywords: Option<RedactSqlOptionKeywordsRef>,
112 message_memory_manager: MessageMemoryManagerRef,
113}
114
115#[derive(Debug, Clone)]
117pub struct TlsConfig {
118 pub cert: String,
120 pub key: String,
122 pub enforce_ssl: bool,
124}
125
126impl TlsConfig {
127 pub fn new_default() -> anyhow::Result<Option<Self>> {
128 let cert = std::env::var("RW_SSL_CERT").ok();
129 let key = std::env::var("RW_SSL_KEY").ok();
130 let enforce_ssl = env_var_is_true("RW_SSL_ENFORCE");
131
132 if cert.is_some() ^ key.is_some() {
133 return Err(anyhow::anyhow!(
134 "RW_SSL_CERT and RW_SSL_KEY must be set together"
135 ));
136 }
137
138 if enforce_ssl && cert.is_none() {
139 return Err(anyhow::anyhow!(
140 "RW_SSL_ENFORCE requires RW_SSL_CERT and RW_SSL_KEY to be set"
141 ));
142 }
143
144 let (Some(cert), Some(key)) = (cert, key) else {
145 return Ok(None);
146 };
147
148 tracing::info!(
149 "RW_SSL_CERT={}, RW_SSL_KEY={}, RW_SSL_ENFORCE={}",
150 cert,
151 key,
152 enforce_ssl
153 );
154 Ok(Some(Self {
155 cert,
156 key,
157 enforce_ssl,
158 }))
159 }
160}
161
162impl<S, SM> Drop for PgProtocol<S, SM>
163where
164 SM: SessionManager,
165{
166 fn drop(&mut self) {
167 if let Some(session) = &self.session {
168 self.session_mgr.end_session(session);
170 }
171 }
172}
173
174#[derive(PartialEq, Eq)]
176enum PgProtocolState {
177 Startup,
178 Authentication,
179 Regular,
180}
181
182#[derive(Clone)]
183struct PreparedStatementData<S> {
184 statement: S,
185 sql: Arc<str>,
186}
187
188#[derive(Clone)]
189struct PortalData<P> {
190 portal: P,
191 sql: Arc<str>,
192}
193
194pub fn cstr_to_str(b: &Bytes) -> Result<&str, Utf8Error> {
198 let without_null = if b.last() == Some(&0) {
199 &b[..b.len() - 1]
200 } else {
201 &b[..]
202 };
203 std::str::from_utf8(without_null)
204}
205
206fn get_redacted_and_truncated_sql(
207 sql: &str,
208 redact_sql_option_keywords: Option<RedactSqlOptionKeywordsRef>,
209) -> String {
210 let redacted_sql = if let Some(keywords) = redact_sql_option_keywords
211 && !keywords.is_empty()
212 {
213 redact_sql(sql, keywords)
214 } else {
215 sql.to_owned()
216 };
217 let truncated = truncated_fmt::TruncatedFmt(&redacted_sql, *RW_QUERY_LOG_TRUNCATE_LEN);
218 truncated.to_string()
219}
220
221fn record_sql_in_span(
223 sql: &str,
224 redact_sql_option_keywords: Option<RedactSqlOptionKeywordsRef>,
225 span: &mut tracing::Span,
226) {
227 let redacted_and_truncated_sql =
228 get_redacted_and_truncated_sql(sql, redact_sql_option_keywords);
229 span.record("sql", tracing::field::display(&redacted_and_truncated_sql));
230}
231
232fn record_user_in_span(user: &str, span: &mut tracing::Span) {
233 span.record("user", tracing::field::display(user));
234}
235
236fn redact_sql(sql: &str, keywords: RedactSqlOptionKeywordsRef) -> String {
238 match Parser::parse_sql(sql) {
239 Ok(sqls) => sqls
240 .into_iter()
241 .map(|sql| sql.to_redacted_string(keywords.clone()))
242 .join(";"),
243 Err(_) => sql.to_owned(),
244 }
245}
246
247#[derive(Clone)]
248pub struct ConnectionContext {
249 pub tls_config: Option<TlsConfig>,
250 pub redact_sql_option_keywords: Option<RedactSqlOptionKeywordsRef>,
251 pub message_memory_manager: MessageMemoryManagerRef,
252 pub stream_flush_threshold_bytes: usize,
253}
254
255impl<S, SM> PgProtocol<S, SM>
256where
257 S: PgByteStream,
258 SM: SessionManager,
259{
260 pub fn new(
261 stream: S,
262 session_mgr: Arc<SM>,
263 peer_addr: AddressRef,
264 context: ConnectionContext,
265 ) -> Self {
266 let ConnectionContext {
267 tls_config,
268 redact_sql_option_keywords,
269 message_memory_manager,
270 stream_flush_threshold_bytes,
271 } = context;
272 Self {
273 stream: PgStream::new(stream, stream_flush_threshold_bytes),
274 is_terminate: false,
275 state: PgProtocolState::Startup,
276 session_mgr,
277 session: None,
278 tls_context: tls_config
279 .as_ref()
280 .and_then(|e| build_ssl_ctx_from_config(e).ok()),
281 tls_config,
282 result_cache: Default::default(),
283 unnamed_prepare_statement: Default::default(),
284 prepare_statement_store: Default::default(),
285 unnamed_portal: Default::default(),
286 portal_store: Default::default(),
287 statement_portal_dependency: Default::default(),
288 ignore_util_sync: false,
289 peer_addr,
290 redact_sql_option_keywords,
291 message_memory_manager,
292 }
293 }
294
295 pub async fn run(&mut self) {
297 let mut notice_fut = None;
298
299 loop {
300 if notice_fut.is_none()
302 && let Some(session) = self.session.clone()
303 {
304 let mut stream = self.stream.clone();
305 notice_fut = Some(Box::pin(async move {
306 loop {
307 let notice = session.next_notice().await;
308 if let Err(e) = stream.write(BeMessage::NoticeResponse(¬ice)).await {
309 tracing::error!(error = %e.as_report(), notice, "failed to send notice");
310 }
311 }
312 }));
313 }
314
315 let process = std::pin::pin!(async {
317 let (msg, _memory_guard) = match self.read_message().await {
318 Ok(msg) => msg,
319 Err(e) => {
320 tracing::error!(error = %e.as_report(), "error when reading message");
321 return true; }
323 };
324 tracing::trace!(?msg, "received message");
325 self.process(msg).await
326 });
327
328 let terminated = if let Some(notice_fut) = notice_fut.as_mut() {
329 tokio::select! {
330 _ = notice_fut => unreachable!(),
331 terminated = process => terminated,
332 }
333 } else {
334 process.await
335 };
336
337 if terminated {
338 break;
339 }
340 }
341 }
342
343 pub async fn process(&mut self, msg: FeMessage) -> bool {
345 self.do_process(msg).await.is_none() || self.is_terminate
346 }
347
348 fn root_span_for_msg(&self, msg: &FeMessage) -> tracing::Span {
356 let Some(session_id) = self.session.as_ref().map(|s| s.id().0) else {
357 return tracing::Span::none();
358 };
359
360 let mode = match msg {
361 FeMessage::Query(_) => "simple query",
362 FeMessage::Parse(_) => "extended query parse",
363 FeMessage::Execute(_) => "extended query execute",
364 _ => return tracing::Span::none(),
365 };
366
367 let mut span = tracing::info_span!(
368 target: PGWIRE_ROOT_SPAN_TARGET,
369 "handle_query",
370 mode,
371 session_id,
372 sql = tracing::field::Empty,
373 user = tracing::field::Empty,
374 );
375 match msg {
376 FeMessage::Execute(execute_msg) => {
377 if let Ok(portal_name) = cstr_to_str(&execute_msg.portal_name)
378 && let Ok(sql) = self.get_portal_sql(portal_name)
379 {
380 record_sql_in_span(&sql, self.redact_sql_option_keywords.clone(), &mut span);
381 }
382 }
383 _ => {
384 if let Ok(sql) = msg.get_sql()
385 && let Some(sql) = sql
386 {
387 record_sql_in_span(sql, self.redact_sql_option_keywords.clone(), &mut span);
388 }
389 }
390 }
391 if let Some(current_session) = self.session.as_ref() {
392 record_user_in_span(¤t_session.user(), &mut span);
393 }
394 span
395 }
396
397 async fn do_process(&mut self, msg: FeMessage) -> Option<()> {
401 let span = self.root_span_for_msg(&msg);
402 let weak_session = self
403 .session
404 .as_ref()
405 .map(|s| Arc::downgrade(s) as Weak<dyn Any + Send + Sync>);
406
407 let fut = Box::pin(self.do_process_inner(msg));
412
413 let fut = async move {
415 if let Some(session) = weak_session {
416 CURRENT_SESSION.scope(session, fut).await
417 } else {
418 fut.await
419 }
420 };
421
422 let fut = async move {
424 AssertUnwindSafe(fut)
425 .rw_catch_unwind()
426 .await
427 .unwrap_or_else(|payload| {
428 Err(PsqlError::Panic(
429 panic_message::panic_message(&payload).to_owned(),
430 ))
431 })
432 };
433
434 let fut = async move {
436 let period = *SLOW_QUERY_LOG_PERIOD;
437 let mut fut = std::pin::pin!(fut);
438 let mut elapsed = Duration::ZERO;
439
440 loop {
442 match tokio::time::timeout(period, &mut fut).await {
443 Ok(result) => break result,
444 Err(_) => {
445 elapsed += period;
446 tracing::info!(
447 target: PGWIRE_SLOW_QUERY_LOG,
448 elapsed = %format_args!("{}ms", elapsed.as_millis()),
449 "slow query"
450 );
451 }
452 }
453 }
454 };
455
456 let fut = async move {
458 if !tracing::Span::current().is_none() {
459 tracing::info!(
460 target: PGWIRE_QUERY_LOG,
461 status = "started",
462 );
463 }
464
465 let start = Instant::now();
466 let result = fut.await;
467 let elapsed = start.elapsed();
468
469 if let Err(error) = &result {
473 if cfg!(debug_assertions) && !Deployment::current().is_ci() {
474 tracing::error!(error = ?error.as_report(), "error when process message");
480 } else {
481 tracing::error!(error = %error.as_report(), "error when process message");
482 }
483 }
484
485 if !tracing::Span::current().is_none() {
488 tracing::info!(
489 target: PGWIRE_QUERY_LOG,
490 status = if result.is_ok() { "ok" } else { "err" },
491 time = %format_args!("{}ms", elapsed.as_millis()),
492 );
493 }
494
495 result
496 };
497
498 let fut = fut.instrument(span);
500
501 match fut.await {
503 Ok(()) => Some(()),
504 Err(e) => {
505 match e {
506 PsqlError::IoError(io_err) => {
507 if io_err.kind() == std::io::ErrorKind::UnexpectedEof {
508 return None;
509 }
510 }
511
512 PsqlError::SslError(_) => {
513 return None;
516 }
517
518 PsqlError::StartupError(_)
519 | PsqlError::PasswordError
520 | PsqlError::ProtocolError(_) => {
521 self.stream
522 .write_no_flush(BeMessage::ErrorResponse {
523 error: &e,
524 pretty: false,
527 severity: Some(Severity::Fatal),
528 })
529 .ok()?;
530 let _ = self.stream.flush().await;
531 return None;
532 }
533
534 PsqlError::SimpleQueryError(_) | PsqlError::ServerThrottle(_) => {
535 self.stream
536 .write_no_flush(BeMessage::ErrorResponse {
537 error: &e,
538 pretty: true,
539 severity: None,
540 })
541 .ok()?;
542 self.ready_for_query().ok()?;
543 }
544
545 PsqlError::IdleInTxnTimeout | PsqlError::Panic(_) => {
546 self.stream
547 .write_no_flush(BeMessage::ErrorResponse {
548 error: &e,
549 pretty: true,
550 severity: None,
551 })
552 .ok()?;
553 let _ = self.stream.flush().await;
554
555 return None;
560 }
561
562 PsqlError::Uncategorized(_)
563 | PsqlError::ExtendedPrepareError(_)
564 | PsqlError::ExtendedExecuteError(_) => {
565 self.stream
566 .write_no_flush(BeMessage::ErrorResponse {
567 error: &e,
568 pretty: true,
569 severity: None,
570 })
571 .ok()?;
572 }
573 }
574 let _ = self.stream.flush().await;
575 Some(())
576 }
577 }
578 }
579
580 async fn do_process_inner(&mut self, msg: FeMessage) -> PsqlResult<()> {
581 if self.state == PgProtocolState::Authentication && !matches!(&msg, FeMessage::Password(_))
582 {
583 return Err(PsqlError::protocol_error(
584 "expected PasswordMessage during authentication",
585 ));
586 }
587
588 if self.ignore_util_sync {
590 if let FeMessage::Sync = msg {
591 } else {
592 tracing::trace!("ignore message {:?} until sync.", msg);
593 return Ok(());
594 }
595 }
596
597 match msg {
598 FeMessage::Gss => self.process_gss_msg().await?,
599 FeMessage::Ssl => self.process_ssl_msg().await?,
600 FeMessage::Startup(msg) => self.process_startup_msg(msg).await?,
601 FeMessage::Password(msg) => self.process_password_msg(msg).await?,
602 FeMessage::Query(query_msg) => {
603 let sql = Arc::from(query_msg.get_sql()?);
604 drop(query_msg);
606 self.process_query_msg(sql).await?
607 }
608 FeMessage::CancelQuery(m) => self.process_cancel_msg(m)?,
609 FeMessage::Terminate => self.process_terminate(),
610 FeMessage::Parse(m) => {
611 if let Err(err) = self.process_parse_msg(m).await {
612 self.ignore_util_sync = true;
613 return Err(err);
614 }
615 }
616 FeMessage::Bind(m) => {
617 if let Err(err) = self.process_bind_msg(m) {
618 self.ignore_util_sync = true;
619 return Err(err);
620 }
621 }
622 FeMessage::Execute(m) => {
623 if let Err(err) = self.process_execute_msg(m).await {
624 self.ignore_util_sync = true;
625 return Err(err);
626 }
627 }
628 FeMessage::Describe(m) => {
629 if let Err(err) = self.process_describe_msg(m) {
630 self.ignore_util_sync = true;
631 return Err(err);
632 }
633 }
634 FeMessage::Sync => {
635 self.ignore_util_sync = false;
636 self.ready_for_query()?
637 }
638 FeMessage::Close(m) => {
639 if let Err(err) = self.process_close_msg(m) {
640 self.ignore_util_sync = true;
641 return Err(err);
642 }
643 }
644 FeMessage::Flush => {
645 if let Err(err) = self.stream.flush().await {
646 self.ignore_util_sync = true;
647 return Err(err.into());
648 }
649 }
650 FeMessage::HealthCheck => self.process_health_check(),
651 FeMessage::ServerThrottle(reason) => match reason {
652 ServerThrottleReason::TooLargeMessage => {
653 return Err(PsqlError::ServerThrottle(format!(
654 "max_single_query_size_bytes {} has been exceeded, please either reduce the query size or increase the limit",
655 self.message_memory_manager.max_filter_bytes
656 )));
657 }
658 ServerThrottleReason::TooManyMemoryUsage => {
659 return Err(PsqlError::ServerThrottle(format!(
660 "max_total_query_size_bytes {} has been exceeded, please either retry or increase the limit",
661 self.message_memory_manager.max_running_bytes
662 )));
663 }
664 },
665 }
666 self.stream.flush().await?;
667 Ok(())
668 }
669
670 pub async fn read_message(&mut self) -> io::Result<(FeMessage, Option<MessageMemoryGuard>)> {
671 match self.state {
672 PgProtocolState::Startup => self
673 .stream
674 .read_startup()
675 .await
676 .map(|message: FeMessage| (message, None)),
677 PgProtocolState::Authentication | PgProtocolState::Regular => {
678 self.stream.read_header().await?;
679 let guard = if let Some(ref header) = self.stream.read_header {
680 let payload_len = std::cmp::max(header.payload_len, 0) as u64;
681 let (reason, guard) = self.message_memory_manager.add(payload_len);
682 if let Some(reason) = reason {
683 drop(guard);
685 self.stream.skip_body().await?;
686 return Ok((FeMessage::ServerThrottle(reason), None));
687 }
688 guard
689 } else {
690 None
691 };
692 let message = self.stream.read_body().await?;
693 Ok((message, guard))
694 }
695 }
696 }
697
698 fn ready_for_query(&mut self) -> io::Result<()> {
700 self.stream.write_no_flush(BeMessage::ReadyForQuery(
701 self.session
702 .as_ref()
703 .map(|s| s.transaction_status())
704 .unwrap_or(TransactionStatus::Idle),
705 ))
706 }
707
708 async fn process_gss_msg(&mut self) -> PsqlResult<()> {
709 self.stream.write(BeMessage::EncryptionResponseNo).await?;
711 Ok(())
712 }
713
714 async fn process_ssl_msg(&mut self) -> PsqlResult<()> {
715 if let Some(context) = self.tls_context.as_ref() {
716 self.stream.write(BeMessage::EncryptionResponseSsl).await?;
719 self.stream.upgrade_to_ssl(context).await?;
720 } else {
721 self.stream.write(BeMessage::EncryptionResponseNo).await?;
723 }
724
725 Ok(())
726 }
727
728 async fn process_startup_msg(&mut self, msg: FeStartupMessage) -> PsqlResult<()> {
729 if let Some(ref tls_config) = self.tls_config
731 && tls_config.enforce_ssl
732 && !self.stream.is_ssl_connection().await
733 {
734 return Err(PsqlError::StartupError(
735 "SSL connection is required but not established".into(),
736 ));
737 }
738
739 let db_name = msg
740 .config
741 .get("database")
742 .cloned()
743 .unwrap_or_else(|| "dev".to_owned());
744 let user_name = msg
745 .config
746 .get("user")
747 .cloned()
748 .unwrap_or_else(|| "root".to_owned());
749
750 let session = self
751 .session_mgr
752 .connect(&db_name, &user_name, self.peer_addr.clone())
753 .map_err(|e| PsqlError::StartupError(e.into()))?;
754
755 if let Some(options) = msg.config.get("options") {
756 for (key, value) in parse_options(options)? {
757 session
758 .set_config(&key, value)
759 .map_err(|e| PsqlError::StartupError(e.into()))?;
760 }
761 }
762 let application_name = msg.config.get("application_name");
764 if let Some(application_name) = application_name {
765 session
766 .set_config("application_name", application_name.clone())
767 .map_err(|e| PsqlError::StartupError(e.into()))?;
768 }
769
770 self.state = match session.user_authenticator() {
771 UserAuthenticator::None => {
772 self.stream.write_no_flush(BeMessage::AuthenticationOk)?;
773
774 self.stream
777 .write_no_flush(BeMessage::BackendKeyData(session.id()))?;
778
779 self.stream.write_no_flush(BeMessage::ParameterStatus(
780 BeParameterStatusMessage::TimeZone(
781 &session
782 .get_config("timezone")
783 .map_err(|e| PsqlError::StartupError(e.into()))?,
784 ),
785 ))?;
786 self.stream
787 .write_parameter_status_msg_no_flush(&ParameterStatus {
788 application_name: application_name.cloned(),
789 })?;
790 self.ready_for_query()?;
791 PgProtocolState::Regular
792 }
793 UserAuthenticator::ClearText(_)
794 | UserAuthenticator::OAuth { .. }
795 | UserAuthenticator::Ldap(..) => {
796 self.stream
797 .write_no_flush(BeMessage::AuthenticationCleartextPassword)?;
798 PgProtocolState::Authentication
799 }
800 UserAuthenticator::Md5WithSalt { salt, .. } => {
801 self.stream
802 .write_no_flush(BeMessage::AuthenticationMd5Password(salt))?;
803 PgProtocolState::Authentication
804 }
805 };
806
807 self.session = Some(session);
808 Ok(())
809 }
810
811 async fn process_password_msg(&mut self, msg: FePasswordMessage) -> PsqlResult<()> {
812 let session = self.session.as_ref().unwrap();
813 let authenticator = session.user_authenticator();
814 authenticator.authenticate(&msg.password).await?;
815 self.stream.write_no_flush(BeMessage::AuthenticationOk)?;
816 let timezone = session
817 .get_config("timezone")
818 .map_err(|e| PsqlError::StartupError(e.into()))?;
819 self.stream.write_no_flush(BeMessage::ParameterStatus(
820 BeParameterStatusMessage::TimeZone(&timezone),
821 ))?;
822 self.stream
823 .write_parameter_status_msg_no_flush(&ParameterStatus::default())?;
824 self.ready_for_query()?;
825 self.state = PgProtocolState::Regular;
826 Ok(())
827 }
828
829 fn process_cancel_msg(&mut self, m: FeCancelMessage) -> PsqlResult<()> {
830 let session_id = (m.target_process_id, m.target_secret_key);
831 tracing::trace!("cancel query in session: {:?}", session_id);
832 self.session_mgr.cancel_queries_in_session(session_id);
833 self.session_mgr.cancel_creating_jobs_in_session(session_id);
834 self.is_terminate = true;
835 Ok(())
836 }
837
838 async fn process_query_msg(&mut self, sql: Arc<str>) -> PsqlResult<()> {
839 let truncated_sql =
840 get_redacted_and_truncated_sql(&sql, self.redact_sql_option_keywords.clone());
841 let session = self.session.clone().unwrap();
842
843 session.check_idle_in_transaction_timeout()?;
844 let _exec_context_guard = session.init_exec_context(truncated_sql.into());
846 self.inner_process_query_msg(sql, session.clone()).await
847 }
848
849 async fn inner_process_query_msg(
850 &mut self,
851 sql: Arc<str>,
852 session: Arc<SM::Session>,
853 ) -> PsqlResult<()> {
854 let stmts =
856 Parser::parse_sql(&sql).map_err(|err| PsqlError::SimpleQueryError(err.into()))?;
857 drop(sql);
859 if stmts.is_empty() {
860 self.stream.write_no_flush(BeMessage::EmptyQueryResponse)?;
861 }
862
863 for stmt in stmts {
865 self.inner_process_query_msg_one_stmt(stmt, session.clone())
866 .await?;
867 }
868 self.ready_for_query()?;
871 Ok(())
872 }
873
874 async fn inner_process_query_msg_one_stmt(
875 &mut self,
876 stmt: Statement,
877 session: Arc<SM::Session>,
878 ) -> PsqlResult<()> {
879 let session = session.clone();
880
881 let res = session.clone().run_one_query(stmt, Format::Text).await;
883
884 while let Some(notice) = session.next_notice().now_or_never() {
886 self.stream
887 .write_no_flush(BeMessage::NoticeResponse(¬ice))?;
888 }
889
890 let mut res = res.map_err(|e| PsqlError::SimpleQueryError(e.into()))?;
891
892 for notice in res.notices() {
893 self.stream
894 .write_no_flush(BeMessage::NoticeResponse(notice))?;
895 }
896
897 let status = res.status();
898 if let Some(ref application_name) = status.application_name {
899 self.stream.write_no_flush(BeMessage::ParameterStatus(
900 BeParameterStatusMessage::ApplicationName(application_name),
901 ))?;
902 }
903
904 if res.is_copy_query_to_stdout() {
905 self.stream
906 .write_no_flush(BeMessage::CopyOutResponse(res.row_desc().len()))?;
907 let mut count = 0;
908 while let Some(row_set) = res.values_stream().next().await {
909 let row_set = row_set.map_err(PsqlError::SimpleQueryError)?;
910 for row in row_set {
911 self.stream
912 .write_streaming(BeMessage::CopyData(&row))
913 .await?;
914 count += 1;
915 }
916 }
917
918 self.stream.write_no_flush(BeMessage::CopyDone)?;
919
920 res.run_callback().await?;
922
923 self.stream
924 .write_no_flush(BeMessage::CommandComplete(BeCommandCompleteMessage {
925 stmt_type: res.stmt_type(),
926 rows_cnt: count,
927 }))?;
928 } else if res.is_query() {
929 self.stream
930 .write_no_flush(BeMessage::RowDescription(res.row_desc()))?;
931
932 let mut rows_cnt = 0;
933
934 while let Some(row_set) = res.values_stream().next().await {
935 let row_set = row_set.map_err(PsqlError::SimpleQueryError)?;
936 for row in row_set {
937 self.stream
938 .write_streaming(BeMessage::DataRow(&row))
939 .await?;
940 rows_cnt += 1;
941 }
942 }
943
944 res.run_callback().await?;
946
947 self.stream
948 .write_no_flush(BeMessage::CommandComplete(BeCommandCompleteMessage {
949 stmt_type: res.stmt_type(),
950 rows_cnt,
951 }))?;
952 } else if res.stmt_type().is_dml() && !res.stmt_type().is_returning() {
953 let first_row_set = res.values_stream().next().await;
954 let first_row_set = match first_row_set {
955 None => {
956 return Err(PsqlError::Uncategorized(
957 anyhow::anyhow!("no affected rows in output").into(),
958 ));
959 }
960 Some(row) => row.map_err(PsqlError::SimpleQueryError)?,
961 };
962 let affected_rows_str = first_row_set[0].values()[0]
963 .as_ref()
964 .expect("compute node should return affected rows in output");
965
966 assert!(matches!(res.row_cnt_format(), Some(Format::Text)));
967 let affected_rows_cnt = String::from_utf8(affected_rows_str.to_vec())
968 .unwrap()
969 .parse()
970 .unwrap_or_default();
971
972 res.run_callback().await?;
974
975 self.stream
976 .write_no_flush(BeMessage::CommandComplete(BeCommandCompleteMessage {
977 stmt_type: res.stmt_type(),
978 rows_cnt: affected_rows_cnt,
979 }))?;
980 } else {
981 res.run_callback().await?;
983
984 self.stream
985 .write_no_flush(BeMessage::CommandComplete(BeCommandCompleteMessage {
986 stmt_type: res.stmt_type(),
987 rows_cnt: 0,
988 }))?;
989 }
990
991 Ok(())
992 }
993
994 fn process_terminate(&mut self) {
995 self.is_terminate = true;
996 }
997
998 fn process_health_check(&mut self) {
999 tracing::debug!("health check");
1000 self.is_terminate = true;
1001 }
1002
1003 async fn process_parse_msg(&mut self, mut msg: FeParseMessage) -> PsqlResult<()> {
1004 let sql = Arc::from(cstr_to_str(&msg.sql_bytes).unwrap());
1005 let session = self.session.clone().unwrap();
1006 let statement_name = cstr_to_str(&msg.statement_name).unwrap().to_owned();
1007 let type_ids = std::mem::take(&mut msg.type_ids);
1008 drop(msg);
1010 self.inner_process_parse_msg(session, sql, statement_name, type_ids)
1011 .await?;
1012 Ok(())
1013 }
1014
1015 async fn inner_process_parse_msg(
1016 &mut self,
1017 session: Arc<SM::Session>,
1018 sql: Arc<str>,
1019 statement_name: String,
1020 type_ids: Vec<i32>,
1021 ) -> PsqlResult<()> {
1022 if statement_name.is_empty() {
1023 self.unnamed_prepare_statement.take();
1026 } else if self.prepare_statement_store.contains_key(&statement_name) {
1027 return Err(PsqlError::ExtendedPrepareError(
1028 "Duplicated statement name".into(),
1029 ));
1030 }
1031
1032 let stmt = {
1033 let stmts = Parser::parse_sql(&sql)
1034 .map_err(|err| PsqlError::ExtendedPrepareError(err.into()))?;
1035 if stmts.len() > 1 {
1036 return Err(PsqlError::ExtendedPrepareError(
1037 "Only one statement is allowed in extended query mode".into(),
1038 ));
1039 }
1040
1041 stmts.into_iter().next()
1042 };
1043
1044 let param_types: Vec<Option<DataType>> = type_ids
1045 .iter()
1046 .map(|&id| {
1047 if id == 0 {
1050 Ok(None)
1051 } else {
1052 DataType::from_oid(id)
1053 .map(Some)
1054 .map_err(|e| PsqlError::ExtendedPrepareError(e.into()))
1055 }
1056 })
1057 .try_collect()?;
1058
1059 let prepare_statement = session
1060 .parse(stmt, param_types)
1061 .await
1062 .map_err(|e| PsqlError::ExtendedPrepareError(e.into()))?;
1063 let prepare_statement = PreparedStatementData {
1064 statement: prepare_statement,
1065 sql,
1066 };
1067
1068 if statement_name.is_empty() {
1069 self.unnamed_prepare_statement.replace(prepare_statement);
1070 } else {
1071 self.prepare_statement_store
1072 .insert(statement_name.clone(), prepare_statement);
1073 }
1074
1075 self.statement_portal_dependency
1076 .entry(statement_name)
1077 .or_default()
1078 .clear();
1079
1080 self.stream.write_no_flush(BeMessage::ParseComplete)?;
1081 Ok(())
1082 }
1083
1084 fn process_bind_msg(&mut self, msg: FeBindMessage) -> PsqlResult<()> {
1085 let statement_name = cstr_to_str(&msg.statement_name).unwrap().to_owned();
1086 let portal_name = cstr_to_str(&msg.portal_name).unwrap().to_owned();
1087 let session = self.session.clone().unwrap();
1088
1089 if self.portal_store.contains_key(&portal_name) {
1090 return Err(PsqlError::Uncategorized("Duplicated portal name".into()));
1091 }
1092
1093 let prepare_statement = self.get_statement_data(&statement_name)?.clone();
1094
1095 let result_formats = msg
1096 .result_format_codes
1097 .iter()
1098 .map(|&format_code| Format::from_i16(format_code))
1099 .try_collect()?;
1100 let param_formats = msg
1101 .param_format_codes
1102 .iter()
1103 .map(|&format_code| Format::from_i16(format_code))
1104 .try_collect()?;
1105
1106 let portal = session
1107 .bind(
1108 prepare_statement.statement,
1109 msg.params,
1110 param_formats,
1111 result_formats,
1112 )
1113 .map_err(|e| PsqlError::Uncategorized(e.into()))?;
1114 let portal = PortalData {
1115 portal,
1116 sql: prepare_statement.sql,
1117 };
1118
1119 if portal_name.is_empty() {
1120 self.result_cache.remove(&portal_name);
1121 self.unnamed_portal.replace(portal);
1122 } else {
1123 assert!(
1124 !self.result_cache.contains_key(&portal_name),
1125 "Named portal never can be overridden."
1126 );
1127 self.portal_store.insert(portal_name.clone(), portal);
1128 }
1129
1130 self.statement_portal_dependency
1131 .get_mut(&statement_name)
1132 .unwrap()
1133 .push(portal_name);
1134
1135 self.stream.write_no_flush(BeMessage::BindComplete)?;
1136 Ok(())
1137 }
1138
1139 async fn process_execute_msg(&mut self, msg: FeExecuteMessage) -> PsqlResult<()> {
1140 let portal_name = cstr_to_str(&msg.portal_name).unwrap().to_owned();
1141 let row_max = msg.max_rows as usize;
1142 drop(msg);
1143 let session = self.session.clone().unwrap();
1144
1145 match self.result_cache.remove(&portal_name) {
1146 Some(mut result_cache) => {
1147 assert!(self.portal_store.contains_key(&portal_name));
1148
1149 let is_consume_completed =
1150 result_cache.consume::<S>(row_max, &mut self.stream).await?;
1151
1152 if !is_consume_completed {
1153 self.result_cache.insert(portal_name, result_cache);
1154 }
1155 }
1156 _ => {
1157 let portal = self.get_portal_data(&portal_name)?.clone();
1158 let sql = format!("{}", portal.portal);
1159 let truncated_sql =
1160 get_redacted_and_truncated_sql(&sql, self.redact_sql_option_keywords.clone());
1161 drop(sql);
1162
1163 session.check_idle_in_transaction_timeout()?;
1164 let _exec_context_guard = session.init_exec_context(truncated_sql.into());
1166 let result = session.clone().execute(portal.portal).await;
1167
1168 let pg_response = result.map_err(|e| PsqlError::ExtendedExecuteError(e.into()))?;
1169 let mut result_cache = ResultCache::new(pg_response);
1170 let is_consume_completed =
1171 result_cache.consume::<S>(row_max, &mut self.stream).await?;
1172 if !is_consume_completed {
1173 self.result_cache.insert(portal_name, result_cache);
1174 }
1175 }
1176 }
1177
1178 Ok(())
1179 }
1180
1181 fn process_describe_msg(&mut self, msg: FeDescribeMessage) -> PsqlResult<()> {
1182 let name = cstr_to_str(&msg.name).unwrap().to_owned();
1183 let session = self.session.clone().unwrap();
1184 assert!(msg.kind == b'S' || msg.kind == b'P');
1188 if msg.kind == b'S' {
1189 let prepare_statement = self.get_statement(&name)?;
1190
1191 let (param_types, row_descriptions) = self
1192 .session
1193 .clone()
1194 .unwrap()
1195 .describe_statement(prepare_statement)
1196 .map_err(|e| PsqlError::Uncategorized(e.into()))?;
1197 self.stream.write_no_flush(BeMessage::ParameterDescription(
1198 ¶m_types.iter().map(|t| t.to_oid()).collect_vec(),
1199 ))?;
1200
1201 if row_descriptions.is_empty() {
1202 self.stream.write_no_flush(BeMessage::NoData)?;
1205 } else {
1206 self.stream
1207 .write_no_flush(BeMessage::RowDescription(&row_descriptions))?;
1208 }
1209 } else if msg.kind == b'P' {
1210 let portal = self.get_portal(&name)?;
1211
1212 let row_descriptions = session
1213 .describe_portal(portal)
1214 .map_err(|e| PsqlError::Uncategorized(e.into()))?;
1215
1216 if row_descriptions.is_empty() {
1217 self.stream.write_no_flush(BeMessage::NoData)?;
1220 } else {
1221 self.stream
1222 .write_no_flush(BeMessage::RowDescription(&row_descriptions))?;
1223 }
1224 }
1225 Ok(())
1226 }
1227
1228 fn process_close_msg(&mut self, msg: FeCloseMessage) -> PsqlResult<()> {
1229 let name = cstr_to_str(&msg.name).unwrap().to_owned();
1230 assert!(msg.kind == b'S' || msg.kind == b'P');
1231 if msg.kind == b'S' {
1232 if name.is_empty() {
1233 self.unnamed_prepare_statement = None;
1234 } else {
1235 self.prepare_statement_store.remove(&name);
1236 }
1237 for portal_name in self
1238 .statement_portal_dependency
1239 .remove(&name)
1240 .unwrap_or_default()
1241 {
1242 self.remove_portal(&portal_name);
1243 }
1244 } else if msg.kind == b'P' {
1245 self.remove_portal(&name);
1246 }
1247 self.stream.write_no_flush(BeMessage::CloseComplete)?;
1248 Ok(())
1249 }
1250
1251 fn remove_portal(&mut self, portal_name: &str) {
1252 if portal_name.is_empty() {
1253 self.unnamed_portal = None;
1254 } else {
1255 self.portal_store.remove(portal_name);
1256 }
1257 self.result_cache.remove(portal_name);
1258 }
1259
1260 fn get_portal(&self, portal_name: &str) -> PsqlResult<<SM::Session as Session>::Portal> {
1261 Ok(self.get_portal_data(portal_name)?.portal.clone())
1262 }
1263
1264 fn get_portal_data(
1265 &self,
1266 portal_name: &str,
1267 ) -> PsqlResult<&PortalData<<SM::Session as Session>::Portal>> {
1268 if portal_name.is_empty() {
1269 self.unnamed_portal
1270 .as_ref()
1271 .ok_or_else(|| PsqlError::Uncategorized("unnamed portal not found".into()))
1272 } else {
1273 self.portal_store.get(portal_name).ok_or_else(|| {
1274 PsqlError::Uncategorized(format!("Portal {} not found", portal_name).into())
1275 })
1276 }
1277 }
1278
1279 fn get_statement(
1280 &self,
1281 statement_name: &str,
1282 ) -> PsqlResult<<SM::Session as Session>::PreparedStatement> {
1283 Ok(self.get_statement_data(statement_name)?.statement.clone())
1284 }
1285
1286 fn get_statement_data(
1287 &self,
1288 statement_name: &str,
1289 ) -> PsqlResult<&PreparedStatementData<<SM::Session as Session>::PreparedStatement>> {
1290 if statement_name.is_empty() {
1291 self.unnamed_prepare_statement.as_ref().ok_or_else(|| {
1292 PsqlError::Uncategorized("unnamed prepare statement not found".into())
1293 })
1294 } else {
1295 self.prepare_statement_store
1296 .get(statement_name)
1297 .ok_or_else(|| {
1298 PsqlError::Uncategorized(
1299 format!("Prepare statement {} not found", statement_name).into(),
1300 )
1301 })
1302 }
1303 }
1304
1305 fn get_portal_sql(&self, portal_name: &str) -> PsqlResult<Arc<str>> {
1306 Ok(self.get_portal_data(portal_name)?.sql.clone())
1307 }
1308}
1309
1310enum PgStreamInner<S> {
1311 Placeholder,
1313 Unencrypted(S),
1315 Ssl(SslStream<S>),
1317}
1318
1319pub trait PgByteStream: AsyncWrite + AsyncRead + Unpin + Send + 'static {}
1321impl<S> PgByteStream for S where S: AsyncWrite + AsyncRead + Unpin + Send + 'static {}
1322
1323pub struct PgStream<S> {
1328 stream: Arc<Mutex<PgStreamInner<S>>>,
1330 write_buf: BytesMut,
1332 stream_flush_threshold_bytes: usize,
1333 read_header: Option<FeMessageHeader>,
1334}
1335
1336impl<S> PgStream<S> {
1337 pub fn new(stream: S, stream_flush_threshold_bytes: usize) -> Self {
1339 const DEFAULT_WRITE_BUF_CAPACITY: usize = 10 * 1024;
1340
1341 Self {
1342 stream: Arc::new(Mutex::new(PgStreamInner::Unencrypted(stream))),
1343 write_buf: BytesMut::with_capacity(DEFAULT_WRITE_BUF_CAPACITY),
1344 stream_flush_threshold_bytes,
1345 read_header: None,
1346 }
1347 }
1348
1349 async fn is_ssl_connection(&self) -> bool {
1351 let stream = self.stream.lock().await;
1352 matches!(*stream, PgStreamInner::Ssl(_))
1353 }
1354}
1355
1356impl<S> Clone for PgStream<S> {
1357 fn clone(&self) -> Self {
1358 Self {
1359 stream: Arc::clone(&self.stream),
1360 write_buf: BytesMut::with_capacity(self.write_buf.capacity()),
1361 stream_flush_threshold_bytes: self.stream_flush_threshold_bytes,
1362 read_header: self.read_header.clone(),
1363 }
1364 }
1365}
1366
1367#[derive(Debug, Default, Clone)]
1384pub struct ParameterStatus {
1385 pub application_name: Option<String>,
1386}
1387
1388impl<S> PgStream<S>
1389where
1390 S: PgByteStream,
1391{
1392 async fn read_startup(&mut self) -> io::Result<FeMessage> {
1393 let mut stream = self.stream.lock().await;
1394 match &mut *stream {
1395 PgStreamInner::Placeholder => unreachable!(),
1396 PgStreamInner::Unencrypted(stream) => FeStartupMessage::read(stream).await,
1397 PgStreamInner::Ssl(ssl_stream) => FeStartupMessage::read(ssl_stream).await,
1398 }
1399 }
1400
1401 async fn read_header(&mut self) -> io::Result<()> {
1402 let mut stream = self.stream.lock().await;
1403 match &mut *stream {
1404 PgStreamInner::Placeholder => unreachable!(),
1405 PgStreamInner::Unencrypted(stream) => {
1406 self.read_header = Some(FeMessage::read_header(stream).await?);
1407 Ok(())
1408 }
1409 PgStreamInner::Ssl(ssl_stream) => {
1410 self.read_header = Some(FeMessage::read_header(ssl_stream).await?);
1411 Ok(())
1412 }
1413 }
1414 }
1415
1416 async fn read_body(&mut self) -> io::Result<FeMessage> {
1417 let mut stream = self.stream.lock().await;
1418 let header = self
1419 .read_header
1420 .take()
1421 .ok_or_else(|| std::io::Error::new(ErrorKind::InvalidInput, "header not found"))?;
1422 match &mut *stream {
1423 PgStreamInner::Placeholder => unreachable!(),
1424 PgStreamInner::Unencrypted(stream) => FeMessage::read_body(stream, header).await,
1425 PgStreamInner::Ssl(ssl_stream) => FeMessage::read_body(ssl_stream, header).await,
1426 }
1427 }
1428
1429 async fn skip_body(&mut self) -> io::Result<()> {
1430 let mut stream = self.stream.lock().await;
1431 let header = self
1432 .read_header
1433 .take()
1434 .ok_or_else(|| std::io::Error::new(ErrorKind::InvalidInput, "header not found"))?;
1435 match &mut *stream {
1436 PgStreamInner::Placeholder => unreachable!(),
1437 PgStreamInner::Unencrypted(stream) => FeMessage::skip_body(stream, header).await,
1438 PgStreamInner::Ssl(ssl_stream) => FeMessage::skip_body(ssl_stream, header).await,
1439 }
1440 }
1441
1442 fn write_parameter_status_msg_no_flush(&mut self, status: &ParameterStatus) -> io::Result<()> {
1443 self.write_no_flush(BeMessage::ParameterStatus(
1444 BeParameterStatusMessage::ClientEncoding(SERVER_ENCODING),
1445 ))?;
1446 self.write_no_flush(BeMessage::ParameterStatus(
1447 BeParameterStatusMessage::StandardConformingString(STANDARD_CONFORMING_STRINGS),
1448 ))?;
1449 self.write_no_flush(BeMessage::ParameterStatus(
1450 BeParameterStatusMessage::ServerVersion(PG_VERSION),
1451 ))?;
1452 if let Some(application_name) = &status.application_name {
1453 self.write_no_flush(BeMessage::ParameterStatus(
1454 BeParameterStatusMessage::ApplicationName(application_name),
1455 ))?;
1456 }
1457 Ok(())
1458 }
1459
1460 pub fn write_no_flush(&mut self, message: BeMessage<'_>) -> io::Result<()> {
1461 BeMessage::write(&mut self.write_buf, message)
1462 }
1463
1464 pub(crate) async fn write_streaming(&mut self, message: BeMessage<'_>) -> io::Result<()> {
1467 self.write_no_flush(message)?;
1468 if self.write_buf.len() >= self.stream_flush_threshold_bytes {
1469 self.flush().await?;
1470 }
1471 Ok(())
1472 }
1473
1474 async fn write(&mut self, message: BeMessage<'_>) -> io::Result<()> {
1475 self.write_no_flush(message)?;
1476 self.flush().await?;
1477 Ok(())
1478 }
1479
1480 async fn flush(&mut self) -> io::Result<()> {
1481 let mut stream = self.stream.lock().await;
1482 match &mut *stream {
1483 PgStreamInner::Placeholder => unreachable!(),
1484 PgStreamInner::Unencrypted(stream) => {
1485 stream.write_all(&self.write_buf).await?;
1486 stream.flush().await?;
1487 }
1488 PgStreamInner::Ssl(ssl_stream) => {
1489 ssl_stream.write_all(&self.write_buf).await?;
1490 ssl_stream.flush().await?;
1491 }
1492 }
1493 self.write_buf.clear();
1494 Ok(())
1495 }
1496}
1497
1498impl<S> PgStream<S>
1499where
1500 S: PgByteStream,
1501{
1502 async fn upgrade_to_ssl(&mut self, ssl_ctx: &SslContextRef) -> PsqlResult<()> {
1504 let mut stream = self.stream.lock().await;
1505
1506 match std::mem::replace(&mut *stream, PgStreamInner::Placeholder) {
1507 PgStreamInner::Unencrypted(unencrypted_stream) => {
1508 let ssl = openssl::ssl::Ssl::new(ssl_ctx).unwrap();
1509 let mut ssl_stream =
1510 tokio_openssl::SslStream::new(ssl, unencrypted_stream).unwrap();
1511
1512 if let Err(e) = Pin::new(&mut ssl_stream).accept().await {
1513 tracing::warn!(error = %e.as_report(), "Unable to set up an ssl connection");
1514 let _ = ssl_stream.shutdown().await;
1515 return Err(e.into());
1516 }
1517
1518 *stream = PgStreamInner::Ssl(ssl_stream);
1519 }
1520 PgStreamInner::Ssl(_) => panic!("the stream is already ssl"),
1521 PgStreamInner::Placeholder => unreachable!(),
1522 }
1523
1524 Ok(())
1525 }
1526}
1527
1528fn build_ssl_ctx_from_config(tls_config: &TlsConfig) -> PsqlResult<SslContext> {
1529 let mut acceptor = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls()).unwrap();
1530
1531 let key_path = &tls_config.key;
1532 let cert_path = &tls_config.cert;
1533
1534 acceptor
1537 .set_private_key_file(key_path, openssl::ssl::SslFiletype::PEM)
1538 .map_err(|e| PsqlError::Uncategorized(e.into()))?;
1539 acceptor
1540 .set_ca_file(cert_path)
1541 .map_err(|e| PsqlError::Uncategorized(e.into()))?;
1542 acceptor
1543 .set_certificate_chain_file(cert_path)
1544 .map_err(|e| PsqlError::Uncategorized(e.into()))?;
1545 let acceptor = acceptor.build();
1546
1547 Ok(acceptor.into_context())
1548}
1549
1550pub mod truncated_fmt {
1551 use std::fmt::*;
1552
1553 struct TruncatedFormatter<'a, 'b> {
1554 remaining: usize,
1555 finished: bool,
1556 f: &'a mut Formatter<'b>,
1557 }
1558 impl Write for TruncatedFormatter<'_, '_> {
1559 fn write_str(&mut self, s: &str) -> Result {
1560 if self.finished {
1561 return Ok(());
1562 }
1563
1564 if self.remaining < s.len() {
1565 let actual = s.floor_char_boundary(self.remaining);
1566 self.f.write_str(&s[0..actual])?;
1567 self.remaining -= actual;
1568 self.f.write_str(&format!("...(truncated,{})", s.len()))?;
1569 self.finished = true; } else {
1571 self.f.write_str(s)?;
1572 self.remaining -= s.len();
1573 }
1574 Ok(())
1575 }
1576 }
1577
1578 pub struct TruncatedFmt<'a, T>(pub &'a T, pub usize);
1579
1580 impl<T> Debug for TruncatedFmt<'_, T>
1581 where
1582 T: Debug,
1583 {
1584 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1585 TruncatedFormatter {
1586 remaining: self.1,
1587 finished: false,
1588 f,
1589 }
1590 .write_fmt(format_args!("{:?}", self.0))
1591 }
1592 }
1593
1594 impl<T> Display for TruncatedFmt<'_, T>
1595 where
1596 T: Display,
1597 {
1598 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1599 TruncatedFormatter {
1600 remaining: self.1,
1601 finished: false,
1602 f,
1603 }
1604 .write_fmt(format_args!("{}", self.0))
1605 }
1606 }
1607
1608 #[cfg(test)]
1609 mod tests {
1610 use super::*;
1611
1612 #[test]
1613 fn test_trunc_utf8() {
1614 assert_eq!(
1615 format!("{}", TruncatedFmt(&"select '🌊';", 10)),
1616 "select '...(truncated,14)",
1617 );
1618 }
1619 }
1620}
1621
1622fn parse_options(options: &str) -> PsqlResult<Vec<(String, String)>> {
1635 let mut args = Vec::new();
1636 let mut current_arg = String::new();
1637 let mut chars = options.chars().peekable();
1638
1639 while let Some(c) = chars.next() {
1640 if c == '\\' {
1641 if let Some(next_c) = chars.next() {
1642 current_arg.push(next_c);
1643 }
1644 } else if c.is_ascii_whitespace() {
1645 if !current_arg.is_empty() {
1646 args.push(std::mem::take(&mut current_arg));
1647 }
1648 } else {
1649 current_arg.push(c);
1650 }
1651 }
1652 if !current_arg.is_empty() {
1653 args.push(current_arg);
1654 }
1655
1656 let mut args_iter = args.into_iter();
1657 let mut config = Vec::new();
1658
1659 while let Some(arg) = args_iter.next() {
1660 if arg == "-c" {
1661 if let Some(config_str) = args_iter.next() {
1662 if let Some((key, value)) = config_str.split_once('=') {
1663 let key = key.replace("-", "_");
1664 config.push((key, value.to_owned()));
1665 } else {
1666 return Err(PsqlError::StartupError(
1667 format!("invalid config format: {}", config_str).into(),
1668 ));
1669 }
1670 } else {
1671 return Err(PsqlError::StartupError("missing argument for -c".into()));
1672 }
1673 } else if let Some(config_str) = arg.strip_prefix("--") {
1674 if let Some((key, value)) = config_str.split_once('=') {
1675 let key = key.replace("-", "_");
1676 config.push((key, value.to_owned()));
1677 } else {
1678 return Err(PsqlError::StartupError(
1679 format!("invalid config format: {}", config_str).into(),
1680 ));
1681 }
1682 } else {
1683 tracing::warn!(
1684 arg,
1685 "ignoring unrecognized option for backward compatibility"
1686 );
1687 }
1688 }
1689 Ok(config)
1690}
1691
1692#[cfg(test)]
1693mod tests {
1694 use std::collections::HashSet;
1695
1696 use tokio::io::AsyncReadExt;
1697
1698 use super::*;
1699 use crate::types::Row;
1700
1701 #[tokio::test]
1702 async fn test_streaming_write_flushes_at_threshold() {
1703 const STREAM_FLUSH_THRESHOLD: usize = 64 * 1024;
1704
1705 let (server, mut client) = tokio::io::duplex(STREAM_FLUSH_THRESHOLD * 2);
1706 let mut stream = PgStream::new(server, STREAM_FLUSH_THRESHOLD);
1707
1708 let small_row = Row::new(vec![Some(Bytes::from_static(b"small"))]);
1709 stream
1710 .write_streaming(BeMessage::DataRow(&small_row))
1711 .await
1712 .unwrap();
1713 assert!(!stream.write_buf.is_empty());
1714
1715 let large_row = Row::new(vec![Some(Bytes::from(vec![0; STREAM_FLUSH_THRESHOLD]))]);
1716 stream
1717 .write_streaming(BeMessage::DataRow(&large_row))
1718 .await
1719 .unwrap();
1720 assert!(stream.write_buf.is_empty());
1721
1722 let mut message_tag = [0];
1723 client.read_exact(&mut message_tag).await.unwrap();
1724 assert_eq!(message_tag[0], b'D');
1725 }
1726
1727 #[test]
1728 fn test_redact_parsable_sql() {
1729 let keywords = Arc::new(HashSet::from(["v2".into(), "v4".into(), "b".into()]));
1730 let sql = r"
1731 create source temp (k bigint, v varchar) with (
1732 connector = 'datagen',
1733 v1 = 123,
1734 v2 = 'with',
1735 v3 = false,
1736 v4 = '',
1737 ) FORMAT plain ENCODE json (a='1',b='2')
1738 ";
1739 assert_eq!(
1740 redact_sql(sql, keywords),
1741 "CREATE SOURCE temp (k BIGINT, v CHARACTER VARYING) WITH (connector = 'datagen', v1 = 123, v2 = [REDACTED], v3 = false, v4 = [REDACTED]) FORMAT PLAIN ENCODE JSON (a = '1', b = [REDACTED])"
1742 );
1743 }
1744
1745 #[test]
1746 fn test_redact_user_password_sql() {
1747 let keywords = Arc::new(HashSet::from(["password".into()]));
1748
1749 assert_eq!(
1750 redact_sql("ALTER USER WITH PASSWORD 'rw_password_2'", keywords.clone()),
1751 "ALTER USER WITH PASSWORD [REDACTED]"
1752 );
1753 assert_eq!(
1754 redact_sql(
1755 "ALTER USER foo WITH ENCRYPTED PASSWORD 'md5827ccb0eea8a706c4c34a16891f84e7b'",
1756 keywords.clone(),
1757 ),
1758 "ALTER USER foo WITH ENCRYPTED PASSWORD [REDACTED]"
1759 );
1760 assert_eq!(
1761 redact_sql("CREATE USER foo WITH PASSWORD 'rw_password_2'", keywords),
1762 "CREATE USER foo WITH PASSWORD [REDACTED]"
1763 );
1764 }
1765
1766 #[test]
1767 fn test_parse_options() {
1768 assert_eq!(parse_options("").unwrap(), vec![]);
1769 assert_eq!(
1770 parse_options("-c a=1 -c b=2").unwrap(),
1771 vec![("a".into(), "1".into()), ("b".into(), "2".into())]
1772 );
1773 assert_eq!(
1774 parse_options("-c key=value").unwrap(),
1775 vec![("key".into(), "value".into())]
1776 );
1777 assert_eq!(
1779 parse_options("-c key='value'").unwrap(),
1780 vec![("key".into(), "'value'".into())]
1781 );
1782
1783 assert_eq!(
1785 parse_options(r#"-c key=value\ with\ spaces"#).unwrap(),
1786 vec![("key".into(), "value with spaces".into())]
1787 );
1788 assert_eq!(
1789 parse_options(r#"-c search_path=my\ schema"#).unwrap(),
1790 vec![("search_path".into(), "my schema".into())]
1791 );
1792
1793 assert!(parse_options("-c").is_err());
1794 assert!(parse_options("-c foo").is_err()); assert!(parse_options("--foo").is_err()); assert_eq!(
1798 parse_options("--foo=bar").unwrap(),
1799 vec![("foo".into(), "bar".into())]
1800 );
1801 assert_eq!(
1802 parse_options(r#"--foo=bar\ baz"#).unwrap(),
1803 vec![("foo".into(), "bar baz".into())]
1804 );
1805 assert_eq!(
1806 parse_options("-c a=1 --b=2").unwrap(),
1807 vec![("a".into(), "1".into()), ("b".into(), "2".into())]
1808 );
1809 assert_eq!(
1811 parse_options(r#"-c a=b\"#).unwrap(),
1812 vec![("a".into(), "b".into())]
1813 );
1814 }
1815}