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