1use std::collections::BTreeMap;
11use std::net::{IpAddr, SocketAddr};
12use std::pin::pin;
13use std::sync::Arc;
14use std::time::Duration;
15
16use anyhow::anyhow;
17use async_trait::async_trait;
18use axum::extract::connect_info::ConnectInfo;
19use axum::extract::ws::{CloseFrame, Message, Utf8Bytes, WebSocket};
20use axum::extract::{State, WebSocketUpgrade};
21use axum::response::IntoResponse;
22use axum::{Extension, Json};
23use futures::Future;
24use futures::future::BoxFuture;
25
26use http::StatusCode;
27use itertools::Itertools;
28use mz_adapter::client::{RecordFirstRowStream, redact_sql_for_logging};
29use mz_adapter::session::{EndTransactionAction, TransactionStatus};
30use mz_adapter::statement_logging::{StatementEndedExecutionReason, StatementExecutionStrategy};
31use mz_adapter::{
32 AdapterError, AdapterNotice, ExecuteContextGuard, ExecuteResponse, ExecuteResponseKind,
33 PeekResponseUnary, SessionClient, verify_datum_desc,
34};
35use mz_auth::password::Password;
36use mz_catalog::memory::objects::{Cluster, ClusterReplica};
37use mz_interchange::encode::TypedDatum;
38use mz_interchange::json::{JsonNumberPolicy, ToJson};
39use mz_ore::cast::CastFrom;
40use mz_ore::metrics::{MakeCollectorOpts, MetricsRegistry};
41use mz_ore::result::ResultExt;
42use mz_ore::sql::Sql;
43use mz_repr::{Datum, RelationDesc, RowArena, RowIterator};
44use mz_sql::ast::display::AstDisplay;
45use mz_sql::ast::{CopyDirection, CopyStatement, CopyTarget, Raw, Statement, StatementKind};
46use mz_sql::parse::StatementParseResult;
47use mz_sql::plan::Plan;
48use mz_sql::session::metadata::SessionMetadata;
49use prometheus::Opts;
50use prometheus::core::{AtomicF64, GenericGaugeVec};
51use serde::{Deserialize, Serialize};
52use tokio::{select, time};
53use tokio_postgres::error::SqlState;
54use tower_sessions::Session as TowerSession;
55use tracing::{debug, info};
56use tungstenite::protocol::frame::coding::CloseCode;
57
58use crate::http::prometheus::PrometheusSqlQuery;
59use crate::http::{
60 AuthError, AuthedClient, AuthedUser, MAX_REQUEST_SIZE, WsState, ensure_session_unexpired,
61 init_ws, maybe_get_authenticated_session,
62};
63
64#[derive(Debug, thiserror::Error)]
65pub enum Error {
66 #[error(transparent)]
67 Adapter(#[from] AdapterError),
68 #[error(transparent)]
69 Json(#[from] serde_json::Error),
70 #[error(transparent)]
71 Axum(#[from] axum::Error),
72 #[error("SUBSCRIBE only supported over websocket")]
73 SubscribeOnlyOverWs,
74 #[error("current transaction is aborted, commands ignored until end of transaction block")]
75 AbortedTransaction,
76 #[error("unsupported via this API: {0}")]
77 Unsupported(String),
78 #[error("{0}")]
79 Unstructured(anyhow::Error),
80}
81
82impl Error {
83 pub fn detail(&self) -> Option<String> {
84 match self {
85 Error::Adapter(err) => err.detail(),
86 _ => None,
87 }
88 }
89
90 pub fn hint(&self) -> Option<String> {
91 match self {
92 Error::Adapter(err) => err.hint(),
93 _ => None,
94 }
95 }
96
97 pub fn position(&self) -> Option<usize> {
98 match self {
99 Error::Adapter(err) => err.position(),
100 _ => None,
101 }
102 }
103
104 pub fn code(&self) -> SqlState {
105 match self {
106 Error::Adapter(err) => err.code(),
107 Error::AbortedTransaction => SqlState::IN_FAILED_SQL_TRANSACTION,
108 _ => SqlState::INTERNAL_ERROR,
109 }
110 }
111}
112
113static PER_REPLICA_LABELS: &[&str] = &["replica_full_name", "instance_id", "replica_id"];
114
115async fn execute_promsql_query(
116 client: &mut AuthedClient,
117 query: &PrometheusSqlQuery<'_>,
118 metrics_registry: &MetricsRegistry,
119 metrics_by_name: &mut BTreeMap<String, GenericGaugeVec<AtomicF64>>,
120 cluster: Option<(&Cluster, &ClusterReplica)>,
121) {
122 assert_eq!(query.per_replica, cluster.is_some());
123
124 let mut res = SqlResponse {
125 results: Vec::new(),
126 };
127
128 execute_request(client, query.to_sql_request(cluster), &mut res)
129 .await
130 .expect("valid SQL query");
131
132 let result = match res.results.as_slice() {
133 [
136 SqlResult::Ok { .. },
137 SqlResult::Ok { .. },
138 SqlResult::Ok { .. },
139 result,
140 ] => result,
141 _ => {
145 info!(
146 "error executing prometheus query {}: {:?}",
147 query.metric_name, res
148 );
149 return;
150 }
151 };
152
153 let SqlResult::Rows { desc, rows, .. } = result else {
154 info!(
155 "did not receive rows for SQL query for prometheus metric {}: {:?}, {:?}",
156 query.metric_name, result, cluster
157 );
158 return;
159 };
160
161 let gauge_vec = metrics_by_name
162 .entry(query.metric_name.to_string())
163 .or_insert_with(|| {
164 let mut label_names: Vec<String> = desc
165 .columns
166 .iter()
167 .filter(|col| col.name != query.value_column_name)
168 .map(|col| col.name.clone())
169 .collect();
170
171 if query.per_replica {
172 label_names.extend(PER_REPLICA_LABELS.iter().map(|label| label.to_string()));
173 }
174
175 metrics_registry.register::<GenericGaugeVec<AtomicF64>>(MakeCollectorOpts {
176 opts: Opts::new(query.metric_name, query.help).variable_labels(label_names),
177 buckets: None,
178 })
179 });
180
181 for row in rows {
182 let row: Vec<serde_json::Value> =
186 serde_json::from_str(row.get()).expect("row is a valid JSON array");
187
188 let mut label_values = desc
194 .columns
195 .iter()
196 .zip_eq(&row)
197 .filter(|(col, _)| col.name != query.value_column_name)
198 .map(|(_, val)| val.as_str().unwrap_or(""))
199 .collect::<Vec<_>>();
200
201 let value = desc
202 .columns
203 .iter()
204 .zip_eq(&row)
205 .find(|(col, _)| col.name == query.value_column_name)
206 .map(|(_, val)| val.as_str().unwrap_or("0").parse::<f64>().unwrap_or(0.0))
207 .unwrap_or(0.0);
208
209 match cluster {
210 Some((cluster, replica)) => {
211 let replica_full_name = format!("{}.{}", cluster.name, replica.name);
212 let cluster_id = cluster.id.to_string();
213 let replica_id = replica.replica_id.to_string();
214
215 label_values.push(&replica_full_name);
216 label_values.push(&cluster_id);
217 label_values.push(&replica_id);
218
219 gauge_vec
220 .get_metric_with_label_values(&label_values)
221 .expect("valid labels")
222 .set(value);
223 }
224 None => {
225 gauge_vec
226 .get_metric_with_label_values(&label_values)
227 .expect("valid labels")
228 .set(value);
229 }
230 }
231 }
232}
233
234async fn handle_promsql_query(
235 client: &mut AuthedClient,
236 query: &PrometheusSqlQuery<'_>,
237 metrics_registry: &MetricsRegistry,
238 metrics_by_name: &mut BTreeMap<String, GenericGaugeVec<AtomicF64>>,
239) {
240 if !query.per_replica {
241 execute_promsql_query(client, query, metrics_registry, metrics_by_name, None).await;
242 return;
243 }
244
245 let catalog = client.client.catalog_snapshot("handle_promsql_query").await;
246 let clusters: Vec<&Cluster> = catalog.clusters().collect();
247
248 for cluster in clusters {
249 for replica in cluster.replicas() {
250 execute_promsql_query(
251 client,
252 query,
253 metrics_registry,
254 metrics_by_name,
255 Some((cluster, replica)),
256 )
257 .await;
258 }
259 }
260}
261
262pub async fn handle_promsql(
263 mut client: AuthedClient,
264 queries: &[PrometheusSqlQuery<'_>],
265) -> MetricsRegistry {
266 let metrics_registry = MetricsRegistry::new();
267 let mut metrics_by_name = BTreeMap::new();
268
269 for query in queries {
270 handle_promsql_query(&mut client, query, &metrics_registry, &mut metrics_by_name).await;
271 }
272
273 metrics_registry
274}
275
276pub async fn handle_sql(
277 mut client: AuthedClient,
278 Json(request): Json<SqlRequest>,
279) -> impl IntoResponse {
280 let mut res = SqlResponse {
281 results: Vec::new(),
282 };
283 match execute_request(&mut client, request, &mut res).await {
286 Ok(()) => Ok(Json(res)),
287 Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
288 }
289}
290
291#[derive(Debug)]
292pub enum ExistingUser {
293 XMaterializeUserHeader(AuthedUser),
296 Session(AuthedUser),
299}
300
301pub(crate) async fn handle_sql_ws(
302 State(state): State<WsState>,
303 existing_user: Option<Extension<AuthedUser>>,
304 ws: WebSocketUpgrade,
305 ConnectInfo(addr): ConnectInfo<SocketAddr>,
306 tower_session: Option<Extension<TowerSession>>,
307) -> Result<impl IntoResponse, AuthError> {
308 let session = tower_session.map(|Extension(session)| session);
309 let user = match existing_user {
311 Some(Extension(user)) => Some(ExistingUser::XMaterializeUserHeader(user)),
312 None => {
313 let session = maybe_get_authenticated_session(session.as_ref()).await;
314 if let Some((session, session_data)) = session {
315 let user = ensure_session_unexpired(session, session_data).await?;
316 Some(ExistingUser::Session(user))
317 } else {
318 None
319 }
320 }
321 };
322
323 let addr = Box::new(addr.ip());
324 Ok(ws
325 .max_message_size(MAX_REQUEST_SIZE)
326 .on_upgrade(|ws| async move { run_ws(state, user, *addr, ws).await }))
327}
328
329#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
330#[serde(untagged)]
331pub enum WebSocketAuth {
332 Basic {
333 user: String,
334 password: Password,
335 #[serde(default)]
336 options: BTreeMap<String, String>,
337 },
338 Bearer {
339 token: String,
340 #[serde(default)]
341 options: BTreeMap<String, String>,
342 },
343 OptionsOnly {
344 #[serde(default)]
345 options: BTreeMap<String, String>,
346 },
347}
348
349async fn run_ws(state: WsState, user: Option<ExistingUser>, peer_addr: IpAddr, mut ws: WebSocket) {
350 let mut client = match init_ws(state, user, peer_addr, &mut ws).await {
351 Ok(client) => client,
352 Err(e) => {
353 debug!("WS request failed init: {}", e);
357 let reason: Utf8Bytes = match e.downcast_ref::<AdapterError>() {
358 Some(error) => error.to_string().into(),
359 None => "unauthorized".to_string().into(),
360 };
361 let _ = ws
362 .send(Message::Close(Some(CloseFrame {
363 code: CloseCode::Protocol.into(),
364 reason,
365 })))
366 .await;
367 return;
368 }
369 };
370
371 let mut msgs = Vec::new();
373 let session = client.client.session();
374 for var in session.vars().notify_set() {
375 msgs.push(WebSocketResponse::ParameterStatus(ParameterStatus {
376 name: var.name().to_string(),
377 value: var.value(),
378 }));
379 }
380 msgs.push(WebSocketResponse::BackendKeyData(BackendKeyData {
381 conn_id: session.conn_id().unhandled(),
382 secret_key: session.secret_key(),
383 }));
384 msgs.push(WebSocketResponse::ReadyForQuery(
385 session.transaction_code().into(),
386 ));
387 for msg in msgs {
388 let _ = ws
389 .send(Message::Text(
390 serde_json::to_string(&msg).expect("must serialize").into(),
391 ))
392 .await;
393 }
394
395 let notices = session.drain_notices();
397 if let Err(err) = forward_notices(&mut ws, notices).await {
398 debug!("failed to forward notices to WebSocket, {err:?}");
399 return;
400 }
401
402 loop {
403 let msg = select! {
405 biased;
406
407 Some(timeout) = client.client.recv_timeout() => {
409 client.client.terminate().await;
410 let _ = ws.recv().await;
414 let err = Error::from(AdapterError::from(timeout));
415 let _ = send_ws_response(&mut ws, WebSocketResponse::Error(err.into())).await;
416 return;
417 },
418 message = ws.recv() => message,
419 };
420
421 client.client.remove_idle_in_transaction_session_timeout();
422
423 let msg = match msg {
424 Some(Ok(msg)) => msg,
425 _ => {
426 return;
428 }
429 };
430
431 let req: Result<SqlRequest, Error> = match msg {
432 Message::Text(data) => serde_json::from_str(&data).err_into(),
433 Message::Binary(data) => serde_json::from_slice(&data).err_into(),
434 Message::Ping(_) => {
436 continue;
437 }
438 Message::Pong(_) => {
439 continue;
440 }
441 Message::Close(_) => {
442 return;
443 }
444 };
445
446 let err = match run_ws_request(req, &mut client, &mut ws).await {
448 Ok(()) => None,
449 Err(err) => Some(WebSocketResponse::Error(err.into())),
450 };
451
452 let ws_response = || async {
459 if let Some(e_resp) = err {
461 send_ws_response(&mut ws, e_resp).await?;
462 }
463
464 let notices = client.client.session().drain_notices();
466 forward_notices(&mut ws, notices).await?;
467
468 let ready =
470 WebSocketResponse::ReadyForQuery(client.client.session().transaction_code().into());
471 send_ws_response(&mut ws, ready).await?;
472
473 Ok::<_, Error>(())
474 };
475
476 if let Err(err) = ws_response().await {
477 debug!("failed to send response over WebSocket, {err:?}");
478 return;
479 }
480 }
481}
482
483async fn run_ws_request(
484 req: Result<SqlRequest, Error>,
485 client: &mut AuthedClient,
486 ws: &mut WebSocket,
487) -> Result<(), Error> {
488 let req = req?;
489 execute_request(client, req, ws).await
490}
491
492async fn send_ws_response(ws: &mut WebSocket, resp: WebSocketResponse) -> Result<(), Error> {
494 let msg = serde_json::to_string(&resp).unwrap();
495 let msg = Message::Text(msg.into());
496 ws.send(msg).await?;
497
498 Ok(())
499}
500
501async fn forward_notices(
503 ws: &mut WebSocket,
504 notices: impl IntoIterator<Item = AdapterNotice>,
505) -> Result<(), Error> {
506 let ws_notices = notices.into_iter().map(|notice| {
507 WebSocketResponse::Notice(Notice {
508 message: notice.to_string(),
509 code: notice.code().code().to_string(),
510 severity: notice.severity().as_str().to_lowercase(),
511 detail: notice.detail(),
512 hint: notice.hint(),
513 })
514 });
515
516 for notice in ws_notices {
517 send_ws_response(ws, notice).await?;
518 }
519
520 Ok(())
521}
522
523#[derive(Serialize, Deserialize, Debug)]
525#[serde(untagged)]
526pub enum SqlRequest {
527 Simple {
529 query: Sql,
532 },
533 Extended {
535 queries: Vec<ExtendedRequest>,
537 },
538}
539
540#[derive(Serialize, Deserialize, Debug)]
542pub struct ExtendedRequest {
543 query: String,
545 #[serde(default)]
547 params: Vec<Option<String>>,
548}
549
550#[derive(Debug, Serialize, Deserialize)]
552pub struct SqlResponse {
553 pub(in crate::http) results: Vec<SqlResult>,
555}
556
557impl SqlResponse {
558 pub(in crate::http) fn new() -> Self {
560 Self {
561 results: Vec::new(),
562 }
563 }
564}
565
566pub(in crate::http) enum StatementResult {
567 SqlResult(SqlResult),
568 Rows {
573 desc: RelationDesc,
574 rows_stream: RecordFirstRowStream,
575 max_result_size: usize,
576 },
577 Subscribe {
578 desc: RelationDesc,
579 tag: String,
580 rx: RecordFirstRowStream,
581 ctx_extra: ExecuteContextGuard,
582 },
583}
584
585impl From<SqlResult> for StatementResult {
586 fn from(inner: SqlResult) -> Self {
587 Self::SqlResult(inner)
588 }
589}
590
591#[derive(Debug, Serialize, Deserialize)]
593#[serde(untagged)]
594pub enum SqlResult {
595 Rows {
597 tag: String,
599 rows: Vec<Box<serde_json::value::RawValue>>,
608 desc: Description,
610 notices: Vec<Notice>,
612 },
613 Ok {
615 ok: String,
617 notices: Vec<Notice>,
619 #[serde(skip_serializing_if = "Vec::is_empty")]
623 parameters: Vec<ParameterStatus>,
624 },
625 Err {
627 error: SqlError,
628 notices: Vec<Notice>,
630 },
631}
632
633impl SqlResult {
634 async fn rows<S>(
645 sender: &mut S,
646 client: &mut SessionClient,
647 mut rows_stream: RecordFirstRowStream,
648 max_query_result_size: usize,
649 desc: &RelationDesc,
650 ) -> Result<SqlResult, Error>
651 where
652 S: ResultSender,
653 {
654 let mut rows: Vec<Box<serde_json::value::RawValue>> = vec![];
655 let mut datum_vec = mz_repr::DatumVec::new();
656 let types = &desc.typ().column_types;
657
658 let mut query_result_size: usize = 0;
659
660 loop {
661 let peek_response = tokio::select! {
662 notice = client.session().recv_notice(), if S::SUPPORTS_STREAMING_NOTICES => {
663 sender.emit_streaming_notices(vec![notice]).await?;
664 continue;
665 }
666 e = sender.connection_error() => return Err(e),
667 r = rows_stream.recv() => {
668 match r {
669 Some(r) => r,
670 None => break,
671 }
672 },
673 };
674
675 let mut sql_rows = match peek_response {
676 PeekResponseUnary::Rows(rows) => rows,
677 PeekResponseUnary::Error(e) => {
678 return Ok(SqlResult::err(client, Error::Unstructured(anyhow!(e))));
679 }
680 PeekResponseUnary::DependencyDropped(dep) => {
681 return Ok(SqlResult::err(client, dep.to_concurrent_dependency_drop()));
682 }
683 PeekResponseUnary::Canceled => {
684 return Ok(SqlResult::err(client, AdapterError::Canceled));
685 }
686 };
687
688 if let Err(err) = verify_datum_desc(desc, &mut sql_rows) {
689 return Ok(SqlResult::Err {
690 error: err.into(),
691 notices: make_notices(client),
692 });
693 }
694
695 while let Some(row) = sql_rows.next() {
696 query_result_size = query_result_size.saturating_add(row.byte_len());
700 if query_result_size > max_query_result_size {
701 use bytesize::ByteSize;
702 return Ok(SqlResult::err(
703 client,
704 AdapterError::ResultSize(format!(
705 "result exceeds max size of {}",
706 ByteSize::b(u64::cast_from(max_query_result_size))
707 )),
708 ));
709 }
710 let datums = datum_vec.borrow_with(row);
711 let json_row: Vec<serde_json::Value> = datums
712 .iter()
713 .enumerate()
714 .map(|(i, d)| {
715 TypedDatum::new(*d, &types[i])
716 .json(&JsonNumberPolicy::ConvertNumberToString)
717 })
718 .collect();
719 let raw = serde_json::value::to_raw_value(&json_row)
723 .expect("row of JSON values always serializes");
724 rows.push(raw);
725 }
726 }
727
728 let tag = format!("SELECT {}", rows.len());
729 Ok(SqlResult::Rows {
730 tag,
731 rows,
732 desc: Description::from(desc),
733 notices: make_notices(client),
734 })
735 }
736
737 fn err(client: &mut SessionClient, error: impl Into<SqlError>) -> SqlResult {
738 SqlResult::Err {
739 error: error.into(),
740 notices: make_notices(client),
741 }
742 }
743
744 fn ok(client: &mut SessionClient, tag: String, params: Vec<ParameterStatus>) -> SqlResult {
745 SqlResult::Ok {
746 ok: tag,
747 parameters: params,
748 notices: make_notices(client),
749 }
750 }
751}
752
753#[derive(Debug, Deserialize, Serialize)]
754pub struct SqlError {
755 pub message: String,
756 pub code: String,
757 #[serde(skip_serializing_if = "Option::is_none")]
758 pub detail: Option<String>,
759 #[serde(skip_serializing_if = "Option::is_none")]
760 pub hint: Option<String>,
761 #[serde(skip_serializing_if = "Option::is_none")]
762 pub position: Option<usize>,
763}
764
765impl From<Error> for SqlError {
766 fn from(err: Error) -> Self {
767 SqlError {
768 message: err.to_string(),
769 code: err.code().code().to_string(),
770 detail: err.detail(),
771 hint: err.hint(),
772 position: err.position(),
773 }
774 }
775}
776
777impl From<AdapterError> for SqlError {
778 fn from(value: AdapterError) -> Self {
779 Error::from(value).into()
780 }
781}
782
783#[derive(Debug, Deserialize, Serialize)]
784#[serde(tag = "type", content = "payload")]
785pub enum WebSocketResponse {
786 ReadyForQuery(String),
787 Notice(Notice),
788 Rows(Description),
789 Row(Vec<serde_json::Value>),
790 CommandStarting(CommandStarting),
791 CommandComplete(String),
792 Error(SqlError),
793 ParameterStatus(ParameterStatus),
794 BackendKeyData(BackendKeyData),
795}
796
797#[derive(Debug, Serialize, Deserialize)]
798pub struct Notice {
799 message: String,
800 code: String,
801 severity: String,
802 #[serde(skip_serializing_if = "Option::is_none")]
803 pub detail: Option<String>,
804 #[serde(skip_serializing_if = "Option::is_none")]
805 pub hint: Option<String>,
806}
807
808impl Notice {
809 pub fn message(&self) -> &str {
810 &self.message
811 }
812}
813
814#[derive(Debug, Serialize, Deserialize)]
815pub struct Description {
816 pub columns: Vec<Column>,
817}
818
819impl From<&RelationDesc> for Description {
820 fn from(desc: &RelationDesc) -> Self {
821 let columns = desc
822 .iter()
823 .map(|(name, typ)| {
824 let pg_type = mz_pgrepr::Type::from(&typ.scalar_type);
825 Column {
826 name: name.to_string(),
827 type_oid: pg_type.oid(),
828 type_len: pg_type.typlen(),
829 type_mod: pg_type.typmod(),
830 }
831 })
832 .collect();
833 Description { columns }
834 }
835}
836
837#[derive(Debug, Serialize, Deserialize)]
838pub struct Column {
839 pub name: String,
840 pub type_oid: u32,
841 pub type_len: i16,
842 pub type_mod: i32,
843}
844
845#[derive(Debug, Serialize, Deserialize)]
846pub struct ParameterStatus {
847 name: String,
848 value: String,
849}
850
851#[derive(Debug, Serialize, Deserialize)]
852pub struct BackendKeyData {
853 conn_id: u32,
854 secret_key: u32,
855}
856
857#[derive(Debug, Serialize, Deserialize)]
858pub struct CommandStarting {
859 has_rows: bool,
860 is_streaming: bool,
861}
862
863#[async_trait]
867pub(in crate::http) trait ResultSender: Send {
868 const SUPPORTS_STREAMING_NOTICES: bool = false;
869
870 async fn add_result(
878 &mut self,
879 client: &mut SessionClient,
880 res: StatementResult,
881 ) -> (
882 Result<Result<(), ()>, Error>,
883 Option<(StatementEndedExecutionReason, ExecuteContextGuard)>,
884 );
885
886 fn connection_error(&mut self) -> BoxFuture<'_, Error>;
888 fn allow_subscribe(&self) -> bool;
890
891 async fn emit_streaming_notices(&mut self, _: Vec<AdapterNotice>) -> Result<(), Error> {
895 unreachable!("streaming notices marked as unsupported")
896 }
897}
898
899#[async_trait]
900impl ResultSender for SqlResponse {
901 async fn add_result(
909 &mut self,
910 client: &mut SessionClient,
911 res: StatementResult,
912 ) -> (
913 Result<Result<(), ()>, Error>,
914 Option<(StatementEndedExecutionReason, ExecuteContextGuard)>,
915 ) {
916 let (res, stmt_logging) = match res {
917 StatementResult::SqlResult(res) => {
918 let is_err = matches!(res, SqlResult::Err { .. });
919 self.results.push(res);
920 let res = if is_err { Err(()) } else { Ok(()) };
921 (res, None)
922 }
923 StatementResult::Rows {
924 desc,
925 rows_stream,
926 max_result_size,
927 } => {
928 let res = match SqlResult::rows(self, client, rows_stream, max_result_size, &desc)
932 .await
933 {
934 Ok(res) => res,
935 Err(e) => return (Err(e), None),
936 };
937 let is_err = matches!(res, SqlResult::Err { .. });
938 self.results.push(res);
939 let res = if is_err { Err(()) } else { Ok(()) };
940 (res, None)
941 }
942 StatementResult::Subscribe { ctx_extra, .. } => {
943 let message = "SUBSCRIBE only supported over websocket";
944 self.results.push(SqlResult::Err {
945 error: Error::SubscribeOnlyOverWs.into(),
946 notices: Vec::new(),
947 });
948 (
949 Err(()),
950 Some((
951 StatementEndedExecutionReason::Errored {
952 error: message.into(),
953 },
954 ctx_extra,
955 )),
956 )
957 }
958 };
959 (Ok(res), stmt_logging)
960 }
961
962 fn connection_error(&mut self) -> BoxFuture<'_, Error> {
963 Box::pin(futures::future::pending())
964 }
965
966 fn allow_subscribe(&self) -> bool {
967 false
968 }
969}
970
971#[async_trait]
972impl ResultSender for WebSocket {
973 const SUPPORTS_STREAMING_NOTICES: bool = true;
974
975 async fn add_result(
981 &mut self,
982 client: &mut SessionClient,
983 res: StatementResult,
984 ) -> (
985 Result<Result<(), ()>, Error>,
986 Option<(StatementEndedExecutionReason, ExecuteContextGuard)>,
987 ) {
988 let (has_rows, is_streaming) = match res {
989 StatementResult::SqlResult(SqlResult::Err { .. }) => (false, false),
990 StatementResult::SqlResult(SqlResult::Ok { .. }) => (false, false),
991 StatementResult::SqlResult(SqlResult::Rows { .. }) => (true, false),
992 StatementResult::Rows { .. } => (true, false),
993 StatementResult::Subscribe { .. } => (true, true),
994 };
995 if let Err(e) = send_ws_response(
996 self,
997 WebSocketResponse::CommandStarting(CommandStarting {
998 has_rows,
999 is_streaming,
1000 }),
1001 )
1002 .await
1003 {
1004 return (Err(e), None);
1005 }
1006
1007 let (is_err, msgs, stmt_logging) = match res {
1008 StatementResult::SqlResult(SqlResult::Rows { .. }) => {
1009 unreachable!("WebSocket streams peek rows via StatementResult::Rows")
1014 }
1015 StatementResult::Rows {
1016 ref desc,
1017 mut rows_stream,
1018 max_result_size,
1019 } => match stream_ws_peek_rows(self, client, desc, &mut rows_stream, max_result_size)
1020 .await
1021 {
1022 Ok(result) => result,
1023 Err(e) => return (Err(e), None),
1026 },
1027 StatementResult::SqlResult(SqlResult::Ok {
1028 ok,
1029 parameters,
1030 notices,
1031 }) => {
1032 let mut msgs = vec![WebSocketResponse::CommandComplete(ok)];
1033 msgs.extend(notices.into_iter().map(WebSocketResponse::Notice));
1034 msgs.extend(
1035 parameters
1036 .into_iter()
1037 .map(WebSocketResponse::ParameterStatus),
1038 );
1039 (false, msgs, None)
1040 }
1041 StatementResult::SqlResult(SqlResult::Err { error, notices }) => {
1042 let mut msgs = vec![WebSocketResponse::Error(error)];
1043 msgs.extend(notices.into_iter().map(WebSocketResponse::Notice));
1044 (true, msgs, None)
1045 }
1046 StatementResult::Subscribe {
1047 ref desc,
1048 tag,
1049 mut rx,
1050 ctx_extra,
1051 } => {
1052 if let Err(e) = send_ws_response(self, WebSocketResponse::Rows(desc.into())).await {
1053 return (
1056 Err(e),
1057 Some((StatementEndedExecutionReason::Canceled, ctx_extra)),
1058 );
1059 }
1060
1061 let mut datum_vec = mz_repr::DatumVec::new();
1062 let mut result_size: usize = 0;
1063 let mut rows_returned = 0;
1064 loop {
1065 let res = match await_rows(self, client, rx.recv()).await {
1066 Ok(res) => res,
1067 Err(e) => {
1068 return (
1071 Err(e),
1072 Some((StatementEndedExecutionReason::Canceled, ctx_extra)),
1073 );
1074 }
1075 };
1076 match res {
1077 Some(PeekResponseUnary::Rows(mut rows)) => {
1078 if let Err(err) = verify_datum_desc(desc, &mut rows) {
1079 let error = err.to_string();
1080 break (
1081 true,
1082 vec![WebSocketResponse::Error(err.into())],
1083 Some((
1084 StatementEndedExecutionReason::Errored { error },
1085 ctx_extra,
1086 )),
1087 );
1088 }
1089
1090 rows_returned += rows.count();
1091 while let Some(row) = rows.next() {
1092 result_size = result_size.saturating_add(row.byte_len());
1093 let datums = datum_vec.borrow_with(row);
1094 let types = &desc.typ().column_types;
1095 if let Err(e) = send_ws_response(
1096 self,
1097 WebSocketResponse::Row(
1098 datums
1099 .iter()
1100 .enumerate()
1101 .map(|(i, d)| {
1102 TypedDatum::new(*d, &types[i])
1103 .json(&JsonNumberPolicy::ConvertNumberToString)
1104 })
1105 .collect(),
1106 ),
1107 )
1108 .await
1109 {
1110 return (
1113 Err(e),
1114 Some((StatementEndedExecutionReason::Canceled, ctx_extra)),
1115 );
1116 }
1117 }
1118 }
1119 Some(PeekResponseUnary::Error(error)) => {
1120 break (
1121 true,
1122 vec![WebSocketResponse::Error(
1123 Error::Unstructured(anyhow!(error.clone())).into(),
1124 )],
1125 Some((StatementEndedExecutionReason::Errored { error }, ctx_extra)),
1126 );
1127 }
1128 Some(PeekResponseUnary::DependencyDropped(dep)) => {
1129 let err = dep.to_concurrent_dependency_drop();
1130 let error = err.to_string();
1131 break (
1132 true,
1133 vec![WebSocketResponse::Error(err.into())],
1134 Some((StatementEndedExecutionReason::Errored { error }, ctx_extra)),
1135 );
1136 }
1137 Some(PeekResponseUnary::Canceled) => {
1138 break (
1139 true,
1140 vec![WebSocketResponse::Error(AdapterError::Canceled.into())],
1141 Some((StatementEndedExecutionReason::Canceled, ctx_extra)),
1142 );
1143 }
1144 None => {
1145 break (
1146 false,
1147 vec![WebSocketResponse::CommandComplete(tag)],
1148 Some((
1149 StatementEndedExecutionReason::Success {
1150 result_size: Some(u64::cast_from(result_size)),
1151 rows_returned: Some(u64::cast_from(rows_returned)),
1152 execution_strategy: Some(
1153 StatementExecutionStrategy::Standard,
1154 ),
1155 },
1156 ctx_extra,
1157 )),
1158 );
1159 }
1160 }
1161 }
1162 }
1163 };
1164 for msg in msgs {
1165 if let Err(e) = send_ws_response(self, msg).await {
1166 return (
1167 Err(e),
1168 stmt_logging.map(|(_old_reason, ctx_extra)| {
1169 (StatementEndedExecutionReason::Canceled, ctx_extra)
1170 }),
1171 );
1172 }
1173 }
1174 (Ok(if is_err { Err(()) } else { Ok(()) }), stmt_logging)
1175 }
1176
1177 fn connection_error(&mut self) -> BoxFuture<'_, Error> {
1180 Box::pin(async {
1181 let mut tick = time::interval(Duration::from_secs(1));
1182 tick.tick().await;
1183 loop {
1184 tick.tick().await;
1185 if let Err(err) = self.send(Message::Ping(Vec::new().into())).await {
1186 return err.into();
1187 }
1188 }
1189 })
1190 }
1191
1192 fn allow_subscribe(&self) -> bool {
1193 true
1194 }
1195
1196 async fn emit_streaming_notices(&mut self, notices: Vec<AdapterNotice>) -> Result<(), Error> {
1197 forward_notices(self, notices).await
1198 }
1199}
1200
1201async fn await_rows<S, F, R>(sender: &mut S, client: &mut SessionClient, f: F) -> Result<R, Error>
1202where
1203 S: ResultSender,
1204 F: Future<Output = R> + Send,
1205{
1206 let mut f = pin!(f);
1207 loop {
1208 tokio::select! {
1209 notice = client.session().recv_notice(), if S::SUPPORTS_STREAMING_NOTICES => {
1210 sender.emit_streaming_notices(vec![notice]).await?;
1211 }
1212 e = sender.connection_error() => return Err(e),
1213 r = &mut f => return Ok(r),
1214 }
1215 }
1216}
1217
1218async fn stream_ws_peek_rows(
1233 ws: &mut WebSocket,
1234 client: &mut SessionClient,
1235 desc: &RelationDesc,
1236 rows_stream: &mut RecordFirstRowStream,
1237 max_result_size: usize,
1238) -> Result<
1239 (
1240 bool,
1241 Vec<WebSocketResponse>,
1242 Option<(StatementEndedExecutionReason, ExecuteContextGuard)>,
1243 ),
1244 Error,
1245> {
1246 let mut datum_vec = mz_repr::DatumVec::new();
1247 let mut result_size: usize = 0;
1248 let mut rows_returned: usize = 0;
1249 let mut sent_rows_desc = false;
1250 loop {
1251 let res = await_rows(ws, client, rows_stream.recv()).await?;
1254 match res {
1255 Some(PeekResponseUnary::Rows(mut rows)) => {
1256 if let Err(err) = verify_datum_desc(desc, &mut rows) {
1257 return Ok(ws_peek_result(
1258 client,
1259 true,
1260 vec![WebSocketResponse::Error(err.into())],
1261 ));
1262 }
1263 if !sent_rows_desc {
1268 send_ws_response(ws, WebSocketResponse::Rows(desc.into())).await?;
1269 sent_rows_desc = true;
1270 }
1271 let types = &desc.typ().column_types;
1272 while let Some(row) = rows.next() {
1273 result_size = result_size.saturating_add(row.byte_len());
1274 if result_size > max_result_size {
1275 use bytesize::ByteSize;
1276 return Ok(ws_peek_result(
1277 client,
1278 true,
1279 vec![WebSocketResponse::Error(
1280 AdapterError::ResultSize(format!(
1281 "result exceeds max size of {}",
1282 ByteSize::b(u64::cast_from(max_result_size))
1283 ))
1284 .into(),
1285 )],
1286 ));
1287 }
1288 let datums = datum_vec.borrow_with(row);
1289 send_ws_response(
1290 ws,
1291 WebSocketResponse::Row(
1292 datums
1293 .iter()
1294 .enumerate()
1295 .map(|(i, d)| {
1296 TypedDatum::new(*d, &types[i])
1297 .json(&JsonNumberPolicy::ConvertNumberToString)
1298 })
1299 .collect(),
1300 ),
1301 )
1302 .await?;
1303 rows_returned += 1;
1304 }
1305 }
1306 Some(PeekResponseUnary::Error(error)) => {
1307 return Ok(ws_peek_result(
1308 client,
1309 true,
1310 vec![WebSocketResponse::Error(
1311 Error::Unstructured(anyhow!(error)).into(),
1312 )],
1313 ));
1314 }
1315 Some(PeekResponseUnary::DependencyDropped(dep)) => {
1316 return Ok(ws_peek_result(
1317 client,
1318 true,
1319 vec![WebSocketResponse::Error(
1320 dep.to_concurrent_dependency_drop().into(),
1321 )],
1322 ));
1323 }
1324 Some(PeekResponseUnary::Canceled) => {
1325 return Ok(ws_peek_result(
1326 client,
1327 true,
1328 vec![WebSocketResponse::Error(AdapterError::Canceled.into())],
1329 ));
1330 }
1331 None => {
1332 if !sent_rows_desc {
1335 send_ws_response(ws, WebSocketResponse::Rows(desc.into())).await?;
1336 }
1337 return Ok(ws_peek_result(
1338 client,
1339 false,
1340 vec![WebSocketResponse::CommandComplete(format!(
1341 "SELECT {rows_returned}"
1342 ))],
1343 ));
1344 }
1345 }
1346 }
1347}
1348
1349fn ws_peek_result(
1357 client: &mut SessionClient,
1358 is_err: bool,
1359 mut msgs: Vec<WebSocketResponse>,
1360) -> (
1361 bool,
1362 Vec<WebSocketResponse>,
1363 Option<(StatementEndedExecutionReason, ExecuteContextGuard)>,
1364) {
1365 msgs.extend(
1366 make_notices(client)
1367 .into_iter()
1368 .map(WebSocketResponse::Notice),
1369 );
1370 (is_err, msgs, None)
1371}
1372
1373async fn send_and_retire<S: ResultSender>(
1374 res: StatementResult,
1375 client: &mut SessionClient,
1376 sender: &mut S,
1377) -> Result<Result<(), ()>, Error> {
1378 let (res, stmt_logging) = sender.add_result(client, res).await;
1379 if let Some((reason, ctx_extra)) = stmt_logging {
1380 client.retire_execute(ctx_extra, reason);
1381 }
1382 res
1383}
1384
1385async fn execute_stmt_group<S: ResultSender>(
1387 client: &mut SessionClient,
1388 sender: &mut S,
1389 stmt_group: Vec<(Statement<Raw>, String, Vec<Option<String>>)>,
1390) -> Result<Result<(), ()>, Error> {
1391 let num_stmts = stmt_group.len();
1392 for (stmt, sql, params) in stmt_group {
1393 assert!(
1394 num_stmts <= 1 || params.is_empty(),
1395 "statement groups contain more than 1 statement iff Simple request, which does not support parameters"
1396 );
1397
1398 let is_aborted_txn = matches!(client.session().transaction(), TransactionStatus::Failed(_));
1399 if is_aborted_txn && !is_txn_exit_stmt(&stmt) {
1400 let err = SqlResult::err(client, Error::AbortedTransaction);
1401 let _ = send_and_retire(err.into(), client, sender).await?;
1402 return Ok(Err(()));
1403 }
1404
1405 if let Err(e) = client.start_transaction(Some(num_stmts)) {
1408 let err = SqlResult::err(client, e);
1409 let _ = send_and_retire(err.into(), client, sender).await?;
1410 return Ok(Err(()));
1411 }
1412 let res = execute_stmt(client, sender, stmt, sql, params).await?;
1413 let is_err = send_and_retire(res, client, sender).await?;
1414
1415 if is_err.is_err() {
1416 let txn = client.session().transaction();
1419 match txn {
1420 TransactionStatus::Default | TransactionStatus::Failed(_) => {}
1423 TransactionStatus::Started(_) | TransactionStatus::InTransactionImplicit(_) => {
1425 if let Err(err) = client.end_transaction(EndTransactionAction::Rollback).await {
1426 let err = SqlResult::err(client, err);
1427 let _ = send_and_retire(err.into(), client, sender).await?;
1428 }
1429 }
1430 TransactionStatus::InTransaction(_) => {
1432 client.fail_transaction();
1433 }
1434 }
1435 return Ok(Err(()));
1436 }
1437 }
1438 Ok(Ok(()))
1439}
1440
1441pub(in crate::http) async fn execute_request<S: ResultSender>(
1450 client: &mut AuthedClient,
1451 request: SqlRequest,
1452 sender: &mut S,
1453) -> Result<(), Error> {
1454 let client = &mut client.client;
1455
1456 if client.statement_arrival_logging_enabled().await {
1457 let session = client.session();
1458 let conn_id = session.conn_id();
1459 let session_uuid = session.uuid();
1460 match &request {
1461 SqlRequest::Simple { query } => {
1462 info!(
1463 %conn_id, %session_uuid, kind = "http_simple",
1464 sql = %redact_sql_for_logging(query.as_str()),
1465 "statement arrival"
1466 );
1467 }
1468 SqlRequest::Extended { queries } => {
1469 for ExtendedRequest { query, params } in queries {
1470 info!(
1473 %conn_id, %session_uuid, kind = "http_extended",
1474 sql = %redact_sql_for_logging(query), num_params = params.len(),
1475 "statement arrival"
1476 );
1477 }
1478 }
1479 }
1480 }
1481
1482 fn check_prohibited_stmts<S: ResultSender>(
1485 sender: &S,
1486 stmt: &Statement<Raw>,
1487 ) -> Result<(), Error> {
1488 let kind: StatementKind = stmt.into();
1489 let execute_responses = Plan::generated_from(&kind)
1490 .into_iter()
1491 .map(ExecuteResponse::generated_from)
1492 .flatten()
1493 .collect::<Vec<_>>();
1494
1495 let is_valid_copy = matches!(
1499 stmt,
1500 Statement::Copy(CopyStatement {
1501 direction: CopyDirection::To,
1502 target: CopyTarget::Expr(_),
1503 ..
1504 }) | Statement::Copy(CopyStatement {
1505 direction: CopyDirection::From,
1506 target: CopyTarget::Expr(_),
1507 ..
1508 })
1509 );
1510
1511 if !is_valid_copy
1512 && execute_responses.iter().any(|execute_response| {
1513 match execute_response {
1515 ExecuteResponseKind::Subscribing if sender.allow_subscribe() => false,
1516 ExecuteResponseKind::Fetch
1517 | ExecuteResponseKind::Subscribing
1518 | ExecuteResponseKind::CopyFrom
1519 | ExecuteResponseKind::DeclaredCursor
1520 | ExecuteResponseKind::ClosedCursor => true,
1521 ExecuteResponseKind::CopyTo if matches!(kind, StatementKind::Copy) => true,
1526 _ => false,
1527 }
1528 })
1529 {
1530 return Err(Error::Unsupported(stmt.to_ast_string_simple()));
1531 }
1532 Ok(())
1533 }
1534
1535 fn parse<'a>(
1536 client: &SessionClient,
1537 query: &'a str,
1538 ) -> Result<Vec<StatementParseResult<'a>>, Error> {
1539 let result = client
1540 .parse(query)
1541 .map_err(|e| Error::Unstructured(anyhow!(e)))?;
1542 result.map_err(|e| AdapterError::from(e).into())
1543 }
1544
1545 let mut stmt_groups = vec![];
1546
1547 match request {
1548 SqlRequest::Simple { query } => match parse(client, query.as_str()) {
1549 Ok(stmts) => {
1550 let mut stmt_group = Vec::with_capacity(stmts.len());
1551 let mut stmt_err = None;
1552 for StatementParseResult { ast: stmt, sql } in stmts {
1553 if let Err(err) = check_prohibited_stmts(sender, &stmt) {
1554 stmt_err = Some(err);
1555 break;
1556 }
1557 stmt_group.push((stmt, sql.to_string(), vec![]));
1558 }
1559 stmt_groups.push(stmt_err.map(Err).unwrap_or_else(|| Ok(stmt_group)));
1560 }
1561 Err(e) => stmt_groups.push(Err(e)),
1562 },
1563 SqlRequest::Extended { queries } => {
1564 for ExtendedRequest { query, params } in queries {
1565 match parse(client, &query) {
1566 Ok(mut stmts) => {
1567 if stmts.len() != 1 {
1568 return Err(Error::Unstructured(anyhow!(
1569 "each query must contain exactly 1 statement, but \"{}\" contains {}",
1570 query,
1571 stmts.len()
1572 )));
1573 }
1574
1575 let StatementParseResult { ast: stmt, sql } = stmts.pop().unwrap();
1576 stmt_groups.push(
1577 check_prohibited_stmts(sender, &stmt)
1578 .map(|_| vec![(stmt, sql.to_string(), params)]),
1579 );
1580 }
1581 Err(e) => stmt_groups.push(Err(e)),
1582 };
1583 }
1584 }
1585 }
1586
1587 for stmt_group_res in stmt_groups {
1588 let executed = match stmt_group_res {
1589 Ok(stmt_group) => execute_stmt_group(client, sender, stmt_group).await,
1590 Err(e) => {
1591 let err = SqlResult::err(client, e);
1592 let _ = send_and_retire(err.into(), client, sender).await?;
1593 Ok(Err(()))
1594 }
1595 };
1596 if client.session().transaction().is_implicit() {
1599 let ended = client.end_transaction(EndTransactionAction::Commit).await;
1600 if let Err(err) = ended {
1601 let err = SqlResult::err(client, err);
1602 let _ = send_and_retire(StatementResult::SqlResult(err), client, sender).await?;
1603 }
1604 }
1605 if executed?.is_err() {
1606 break;
1607 }
1608 }
1609
1610 Ok(())
1611}
1612
1613async fn execute_stmt<S: ResultSender>(
1615 client: &mut SessionClient,
1616 sender: &mut S,
1617 stmt: Statement<Raw>,
1618 sql: String,
1619 raw_params: Vec<Option<String>>,
1620) -> Result<StatementResult, Error> {
1621 const EMPTY_PORTAL: &str = "";
1622 if let Err(e) = client
1623 .prepare(EMPTY_PORTAL.into(), Some(stmt.clone()), sql, vec![])
1624 .await
1625 {
1626 return Ok(SqlResult::err(client, e).into());
1627 }
1628
1629 let prep_stmt = match client.get_prepared_statement(EMPTY_PORTAL).await {
1630 Ok(stmt) => stmt,
1631 Err(err) => {
1632 return Ok(SqlResult::err(client, err).into());
1633 }
1634 };
1635
1636 let param_types = &prep_stmt.desc().param_types;
1637 if param_types.len() != raw_params.len() {
1638 let message = anyhow!(
1639 "request supplied {actual} parameters, \
1640 but {statement} requires {expected}",
1641 statement = stmt.to_ast_string_simple(),
1642 actual = raw_params.len(),
1643 expected = param_types.len()
1644 );
1645 return Ok(SqlResult::err(client, Error::Unstructured(message)).into());
1646 }
1647
1648 let buf = RowArena::new();
1649 let mut params = vec![];
1650 for (raw_param, mz_typ) in raw_params.into_iter().zip_eq(param_types) {
1651 let pg_typ = mz_pgrepr::Type::from(mz_typ);
1652 let datum = match raw_param {
1653 None => Datum::Null,
1654 Some(raw_param) => {
1655 match mz_pgrepr::Value::decode(
1656 mz_pgwire_common::Format::Text,
1657 &pg_typ,
1658 raw_param.as_bytes(),
1659 ) {
1660 Ok(param) => match param.into_datum_decode_error(&buf, &pg_typ, "parameter") {
1661 Ok(datum) => datum,
1662 Err(msg) => {
1663 return Ok(
1664 SqlResult::err(client, Error::Unstructured(anyhow!(msg))).into()
1665 );
1666 }
1667 },
1668 Err(err) => {
1669 let msg = anyhow!("unable to decode parameter: {}", err);
1670 return Ok(SqlResult::err(client, Error::Unstructured(msg)).into());
1671 }
1672 }
1673 }
1674 };
1675 params.push((datum, mz_typ.clone()))
1676 }
1677
1678 let result_formats = vec![
1679 mz_pgwire_common::Format::Text;
1680 prep_stmt
1681 .desc()
1682 .relation_desc
1683 .clone()
1684 .map(|desc| desc.typ().column_types.len())
1685 .unwrap_or(0)
1686 ];
1687
1688 let desc = prep_stmt.desc().clone();
1689 let logging = Arc::clone(prep_stmt.logging());
1690 let stmt_ast = prep_stmt.stmt().cloned();
1691 let state_revision = prep_stmt.state_revision;
1692 if let Err(err) = client.session().set_portal(
1693 EMPTY_PORTAL.into(),
1694 desc,
1695 stmt_ast,
1696 logging,
1697 params,
1698 result_formats,
1699 state_revision,
1700 ) {
1701 return Ok(SqlResult::err(client, err).into());
1702 }
1703
1704 let desc = client
1705 .session()
1706 .get_portal_unverified(EMPTY_PORTAL)
1708 .map(|portal| portal.desc.clone())
1709 .expect("unnamed portal should be present");
1710
1711 let res = client
1712 .execute(EMPTY_PORTAL.into(), futures::future::pending(), None)
1713 .await;
1714
1715 if S::SUPPORTS_STREAMING_NOTICES {
1716 sender
1717 .emit_streaming_notices(client.session().drain_notices())
1718 .await?;
1719 }
1720
1721 let (res, execute_started) = match res {
1722 Ok(res) => res,
1723 Err(e) => {
1724 return Ok(SqlResult::err(client, e).into());
1725 }
1726 };
1727 let tag = res.tag();
1728
1729 Ok(match res {
1730 ExecuteResponse::CreatedConnection { .. }
1731 | ExecuteResponse::CreatedDatabase { .. }
1732 | ExecuteResponse::CreatedSchema { .. }
1733 | ExecuteResponse::CreatedRole
1734 | ExecuteResponse::CreatedCluster { .. }
1735 | ExecuteResponse::CreatedClusterReplica { .. }
1736 | ExecuteResponse::CreatedTable { .. }
1737 | ExecuteResponse::CreatedIndex { .. }
1738 | ExecuteResponse::CreatedMetricSink { .. }
1739 | ExecuteResponse::CreatedIntrospectionSubscribe
1740 | ExecuteResponse::CreatedSecret { .. }
1741 | ExecuteResponse::CreatedSource { .. }
1742 | ExecuteResponse::CreatedSink { .. }
1743 | ExecuteResponse::CreatedView { .. }
1744 | ExecuteResponse::CreatedViews { .. }
1745 | ExecuteResponse::CreatedMaterializedView { .. }
1746 | ExecuteResponse::CreatedType
1747 | ExecuteResponse::CreatedNetworkPolicy
1748 | ExecuteResponse::Comment
1749 | ExecuteResponse::Deleted(_)
1750 | ExecuteResponse::DiscardedTemp
1751 | ExecuteResponse::DiscardedAll
1752 | ExecuteResponse::DroppedObject(_)
1753 | ExecuteResponse::DroppedOwned
1754 | ExecuteResponse::EmptyQuery
1755 | ExecuteResponse::GrantedPrivilege
1756 | ExecuteResponse::GrantedRole
1757 | ExecuteResponse::Inserted(_)
1758 | ExecuteResponse::Copied(_)
1759 | ExecuteResponse::Raised
1760 | ExecuteResponse::ReassignOwned
1761 | ExecuteResponse::RevokedPrivilege
1762 | ExecuteResponse::AlteredDefaultPrivileges
1763 | ExecuteResponse::RevokedRole
1764 | ExecuteResponse::StartedTransaction { .. }
1765 | ExecuteResponse::Updated(_)
1766 | ExecuteResponse::AlteredObject(_)
1767 | ExecuteResponse::AlteredRole
1768 | ExecuteResponse::AlteredSystemConfiguration
1769 | ExecuteResponse::Deallocate { .. }
1770 | ExecuteResponse::ValidatedConnection
1771 | ExecuteResponse::Prepare => SqlResult::ok(
1772 client,
1773 tag.expect("ok only called on tag-generating results"),
1774 Vec::default(),
1775 )
1776 .into(),
1777 ExecuteResponse::TransactionCommitted { params }
1778 | ExecuteResponse::TransactionRolledBack { params } => {
1779 let notify_set: mz_ore::collections::HashSet<_> = client
1780 .session()
1781 .vars()
1782 .notify_set()
1783 .map(|v| v.name().to_string())
1784 .collect();
1785 let params = params
1786 .into_iter()
1787 .filter(|(name, _value)| notify_set.contains(*name))
1788 .map(|(name, value)| ParameterStatus {
1789 name: name.to_string(),
1790 value,
1791 })
1792 .collect();
1793 SqlResult::ok(
1794 client,
1795 tag.expect("ok only called on tag-generating results"),
1796 params,
1797 )
1798 .into()
1799 }
1800 ExecuteResponse::SetVariable { name, .. } => {
1801 let mut params = Vec::with_capacity(1);
1802 if let Some(var) = client
1803 .session()
1804 .vars()
1805 .notify_set()
1806 .find(|v| v.name() == &name)
1807 {
1808 params.push(ParameterStatus {
1809 name,
1810 value: var.value(),
1811 });
1812 };
1813 SqlResult::ok(
1814 client,
1815 tag.expect("ok only called on tag-generating results"),
1816 params,
1817 )
1818 .into()
1819 }
1820 ExecuteResponse::SendingRowsStreaming {
1821 rows,
1822 instance_id,
1823 strategy,
1824 } => {
1825 let max_result_size =
1826 usize::cast_from(client.get_system_vars().await.max_result_size());
1827
1828 let rows_stream = RecordFirstRowStream::new(
1829 Box::new(rows),
1830 execute_started,
1831 client,
1832 Some(instance_id),
1833 Some(strategy),
1834 );
1835
1836 StatementResult::Rows {
1837 desc: desc.relation_desc.expect("RelationDesc must exist"),
1838 rows_stream,
1839 max_result_size,
1840 }
1841 }
1842 ExecuteResponse::SendingRowsImmediate { rows } => {
1843 let max_result_size =
1844 usize::cast_from(client.get_system_vars().await.max_result_size());
1845
1846 let rows = futures::stream::once(futures::future::ready(PeekResponseUnary::Rows(rows)));
1847 let rows_stream =
1848 RecordFirstRowStream::new(Box::new(rows), execute_started, client, None, None);
1849
1850 StatementResult::Rows {
1851 desc: desc.relation_desc.expect("RelationDesc must exist"),
1852 rows_stream,
1853 max_result_size,
1854 }
1855 }
1856 ExecuteResponse::Subscribing {
1857 rx,
1858 ctx_extra,
1859 instance_id,
1860 } => StatementResult::Subscribe {
1861 tag: "SUBSCRIBE".into(),
1862 desc: desc.relation_desc.unwrap(),
1863 rx: RecordFirstRowStream::new(rx, execute_started, client, Some(instance_id), None),
1864 ctx_extra,
1865 },
1866 res @ (ExecuteResponse::Fetch { .. }
1867 | ExecuteResponse::CopyTo { .. }
1868 | ExecuteResponse::CopyFrom { .. }
1869 | ExecuteResponse::DeclaredCursor
1870 | ExecuteResponse::ClosedCursor) => SqlResult::err(
1871 client,
1872 Error::Unstructured(anyhow!(
1873 "internal error: encountered prohibited ExecuteResponse {:?}.\n\n
1874 This is a bug. Can you please file an bug report letting us know?\n
1875 https://github.com/MaterializeInc/materialize/discussions/new?category=bug-reports",
1876 ExecuteResponseKind::from(res)
1877 )),
1878 )
1879 .into(),
1880 })
1881}
1882
1883fn make_notices(client: &mut SessionClient) -> Vec<Notice> {
1884 client
1885 .session()
1886 .drain_notices()
1887 .into_iter()
1888 .map(|notice| Notice {
1889 message: notice.to_string(),
1890 code: notice.code().code().to_string(),
1891 severity: notice.severity().as_str().to_lowercase(),
1892 detail: notice.detail(),
1893 hint: notice.hint(),
1894 })
1895 .collect()
1896}
1897
1898fn is_txn_exit_stmt(stmt: &Statement<Raw>) -> bool {
1901 matches!(
1902 stmt,
1903 Statement::Commit(_) | Statement::Rollback(_) | Statement::Prepare(_)
1904 )
1905}
1906
1907#[cfg(test)]
1908mod tests {
1909 use std::collections::BTreeMap;
1910
1911 use super::{Password, WebSocketAuth};
1912
1913 #[mz_ore::test]
1914 fn smoke_test_websocket_auth_parse() {
1915 struct TestCase {
1916 json: &'static str,
1917 expected: WebSocketAuth,
1918 }
1919
1920 let test_cases = vec![
1921 TestCase {
1922 json: r#"{ "user": "mz", "password": "1234" }"#,
1923 expected: WebSocketAuth::Basic {
1924 user: "mz".to_string(),
1925 password: Password("1234".to_string()),
1926 options: BTreeMap::default(),
1927 },
1928 },
1929 TestCase {
1930 json: r#"{ "user": "mz", "password": "1234", "options": {} }"#,
1931 expected: WebSocketAuth::Basic {
1932 user: "mz".to_string(),
1933 password: Password("1234".to_string()),
1934 options: BTreeMap::default(),
1935 },
1936 },
1937 TestCase {
1938 json: r#"{ "token": "i_am_a_token" }"#,
1939 expected: WebSocketAuth::Bearer {
1940 token: "i_am_a_token".to_string(),
1941 options: BTreeMap::default(),
1942 },
1943 },
1944 TestCase {
1945 json: r#"{ "token": "i_am_a_token", "options": { "foo": "bar" } }"#,
1946 expected: WebSocketAuth::Bearer {
1947 token: "i_am_a_token".to_string(),
1948 options: BTreeMap::from([("foo".to_string(), "bar".to_string())]),
1949 },
1950 },
1951 ];
1952
1953 fn assert_parse(json: &'static str, expected: WebSocketAuth) {
1954 let parsed: WebSocketAuth = serde_json::from_str(json).unwrap();
1955 assert_eq!(parsed, expected);
1956 }
1957
1958 for TestCase { json, expected } in test_cases {
1959 assert_parse(json, expected)
1960 }
1961 }
1962}