1use std::collections::BTreeMap;
11use std::net::{IpAddr, SocketAddr};
12use std::pin::pin;
13use std::sync::Arc;
14use std::time::{Duration, Instant};
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 ExecutionTime, 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
507 .into_iter()
508 .map(|notice| WebSocketResponse::Notice(Notice::from(notice)));
509
510 for notice in ws_notices {
511 send_ws_response(ws, notice).await?;
512 }
513
514 Ok(())
515}
516
517#[derive(Serialize, Deserialize, Debug)]
520#[serde(untagged)]
521pub enum SqlRequest {
522 Simple { query: Sql },
526 Extended { queries: Vec<ExtendedRequest> },
530}
531
532#[derive(Serialize, Deserialize, Debug)]
534pub struct ExtendedRequest {
535 query: String,
537 #[serde(default)]
539 params: Vec<Option<String>>,
540}
541
542#[derive(Debug, Serialize, Deserialize)]
544pub struct SqlResponse {
545 pub(in crate::http) results: Vec<SqlResult>,
547}
548
549impl SqlResponse {
550 pub(in crate::http) fn new() -> Self {
552 Self {
553 results: Vec::new(),
554 }
555 }
556}
557
558pub(in crate::http) enum StatementResult {
559 SqlResult(SqlResult),
561 Rows {
567 desc: RelationDesc,
568 rows_stream: RecordFirstRowStream,
569 max_result_size: usize,
570 ends_group: bool,
573 },
574 Subscribe {
575 desc: RelationDesc,
576 tag: String,
577 rx: RecordFirstRowStream,
578 ctx_extra: ExecuteContextGuard,
579 },
580}
581
582impl From<SqlResult> for StatementResult {
583 fn from(inner: SqlResult) -> Self {
584 Self::SqlResult(inner)
585 }
586}
587
588#[derive(Debug, Serialize, Deserialize)]
590#[serde(untagged)]
591pub enum SqlResult {
592 Rows {
594 tag: String,
596 rows: Vec<Box<serde_json::value::RawValue>>,
605 desc: Description,
607 notices: Vec<Notice>,
609 },
610 Ok {
612 ok: String,
614 notices: Vec<Notice>,
616 #[serde(skip_serializing_if = "Vec::is_empty")]
620 parameters: Vec<ParameterStatus>,
621 #[serde(skip)]
624 execution_time: Option<Notice>,
625 },
626 Err {
628 error: SqlError,
629 notices: Vec<Notice>,
631 },
632}
633
634impl SqlResult {
635 async fn rows<S>(
648 sender: &mut S,
649 client: &mut SessionClient,
650 mut rows_stream: RecordFirstRowStream,
651 max_query_result_size: usize,
652 desc: &RelationDesc,
653 ends_group: bool,
654 ) -> Result<SqlResult, Error>
655 where
656 S: ResultSender,
657 {
658 let mut rows: Vec<Box<serde_json::value::RawValue>> = vec![];
659 let mut datum_vec = mz_repr::DatumVec::new();
660 let types = &desc.typ().column_types;
661
662 let mut query_result_size: usize = 0;
663
664 loop {
665 let peek_response = tokio::select! {
666 notice = client.session().recv_notice(), if S::SUPPORTS_STREAMING_NOTICES => {
667 sender.emit_streaming_notices(vec![notice]).await?;
668 continue;
669 }
670 e = sender.connection_error() => return Err(e),
671 r = rows_stream.recv() => {
672 match r {
673 Some(r) => r,
674 None => break,
675 }
676 },
677 };
678
679 let mut sql_rows = match peek_response {
680 PeekResponseUnary::Rows(rows) => rows,
681 PeekResponseUnary::Error(e) => {
682 return Ok(SqlResult::err(client, e));
683 }
684 PeekResponseUnary::DependencyDropped(dep) => {
685 return Ok(SqlResult::err(client, dep.to_concurrent_dependency_drop()));
686 }
687 PeekResponseUnary::Canceled => {
688 return Ok(SqlResult::err(client, AdapterError::Canceled));
689 }
690 };
691
692 if let Err(err) = verify_datum_desc(desc, &mut sql_rows) {
693 return Ok(SqlResult::Err {
694 error: err.into(),
695 notices: make_notices(client),
696 });
697 }
698
699 while let Some(row) = sql_rows.next() {
700 query_result_size = query_result_size.saturating_add(row.byte_len());
704 if query_result_size > max_query_result_size {
705 use bytesize::ByteSize;
706 return Ok(SqlResult::err(
707 client,
708 AdapterError::ResultSize(format!(
709 "result exceeds max size of {}",
710 ByteSize::b(u64::cast_from(max_query_result_size))
711 )),
712 ));
713 }
714 let datums = datum_vec.borrow_with(row);
715 let json_row: Vec<serde_json::Value> = datums
716 .iter()
717 .enumerate()
718 .map(|(i, d)| {
719 TypedDatum::new(*d, &types[i])
720 .json(&JsonNumberPolicy::ConvertNumberToString)
721 })
722 .collect();
723 let raw = serde_json::value::to_raw_value(&json_row)
727 .expect("row of JSON values always serializes");
728 rows.push(raw);
729 }
730 }
731
732 let execution_time = rows_stream
733 .take_execution_time()
734 .map(|time| client.session().maybe_mark_staged(time));
735 if let Err(err) = client.settle_statement(ends_group).await {
738 return Ok(SqlResult::err(client, err));
739 }
740 let mut notices = make_notices(client);
741 notices.extend(
742 execution_time
743 .and_then(|time| client.session().execution_time_notice(time))
744 .map(Notice::from),
745 );
746 let tag = format!("SELECT {}", rows.len());
747 Ok(SqlResult::Rows {
748 tag,
749 rows,
750 desc: Description::from(desc),
751 notices,
752 })
753 }
754
755 fn err(client: &mut SessionClient, error: impl Into<SqlError>) -> SqlResult {
756 SqlResult::Err {
757 error: error.into(),
758 notices: make_notices(client),
759 }
760 }
761
762 async fn ok(
766 client: &mut SessionClient,
767 tag: String,
768 mut params: Vec<ParameterStatus>,
769 ends_group: bool,
770 execution_time: ExecutionTime,
771 ) -> SqlResult {
772 match client.settle_statement(ends_group).await {
773 Ok(settled) => {
774 params.extend(notify_params(client, settled.reverted));
775 SqlResult::Ok {
776 ok: tag,
777 parameters: params,
778 notices: make_notices(client),
779 execution_time: client
780 .session()
781 .execution_time_notice(execution_time)
782 .map(Notice::from),
783 }
784 }
785 Err(err) => SqlResult::err(client, err),
786 }
787 }
788}
789
790#[derive(Debug, Deserialize, Serialize)]
791pub struct SqlError {
792 pub message: String,
793 pub code: String,
794 #[serde(skip_serializing_if = "Option::is_none")]
795 pub detail: Option<String>,
796 #[serde(skip_serializing_if = "Option::is_none")]
797 pub hint: Option<String>,
798 #[serde(skip_serializing_if = "Option::is_none")]
799 pub position: Option<usize>,
800}
801
802impl From<Error> for SqlError {
803 fn from(err: Error) -> Self {
804 SqlError {
805 message: err.to_string(),
806 code: err.code().code().to_string(),
807 detail: err.detail(),
808 hint: err.hint(),
809 position: err.position(),
810 }
811 }
812}
813
814impl From<AdapterError> for SqlError {
815 fn from(value: AdapterError) -> Self {
816 Error::from(value).into()
817 }
818}
819
820#[derive(Debug, Deserialize, Serialize)]
821#[serde(tag = "type", content = "payload")]
822pub enum WebSocketResponse {
823 ReadyForQuery(String),
824 Notice(Notice),
825 Rows(Description),
826 Row(Vec<serde_json::Value>),
827 CommandStarting(CommandStarting),
828 CommandComplete(String),
829 Error(SqlError),
830 ParameterStatus(ParameterStatus),
831 BackendKeyData(BackendKeyData),
832}
833
834#[derive(Debug, Serialize, Deserialize)]
835pub struct Notice {
836 message: String,
837 code: String,
838 severity: String,
839 #[serde(skip_serializing_if = "Option::is_none")]
840 pub detail: Option<String>,
841 #[serde(skip_serializing_if = "Option::is_none")]
842 pub hint: Option<String>,
843}
844
845impl Notice {
846 pub fn message(&self) -> &str {
847 &self.message
848 }
849}
850
851#[derive(Debug, Serialize, Deserialize)]
852pub struct Description {
853 pub columns: Vec<Column>,
854}
855
856impl From<&RelationDesc> for Description {
857 fn from(desc: &RelationDesc) -> Self {
858 let columns = desc
859 .iter()
860 .map(|(name, typ)| {
861 let pg_type = mz_pgrepr::Type::from(&typ.scalar_type);
862 Column {
863 name: name.to_string(),
864 type_oid: pg_type.oid(),
865 type_len: pg_type.typlen(),
866 type_mod: pg_type.typmod(),
867 }
868 })
869 .collect();
870 Description { columns }
871 }
872}
873
874#[derive(Debug, Serialize, Deserialize)]
875pub struct Column {
876 pub name: String,
877 pub type_oid: u32,
878 pub type_len: i16,
879 pub type_mod: i32,
880}
881
882#[derive(Debug, Serialize, Deserialize)]
883pub struct ParameterStatus {
884 name: String,
885 value: String,
886}
887
888#[derive(Debug, Serialize, Deserialize)]
889pub struct BackendKeyData {
890 conn_id: u32,
891 secret_key: u32,
892}
893
894#[derive(Debug, Serialize, Deserialize)]
895pub struct CommandStarting {
896 has_rows: bool,
897 is_streaming: bool,
898}
899
900#[async_trait]
904pub(in crate::http) trait ResultSender: Send {
905 const SUPPORTS_STREAMING_NOTICES: bool = false;
906
907 async fn add_result(
915 &mut self,
916 client: &mut SessionClient,
917 res: StatementResult,
918 ) -> (
919 Result<Result<(), ()>, Error>,
920 Option<(StatementEndedExecutionReason, ExecuteContextGuard)>,
921 );
922
923 fn connection_error(&mut self) -> BoxFuture<'_, Error>;
925 fn allow_subscribe(&self) -> bool;
927
928 async fn emit_streaming_notices(&mut self, _: Vec<AdapterNotice>) -> Result<(), Error> {
932 unreachable!("streaming notices marked as unsupported")
933 }
934}
935
936#[async_trait]
937impl ResultSender for SqlResponse {
938 async fn add_result(
946 &mut self,
947 client: &mut SessionClient,
948 res: StatementResult,
949 ) -> (
950 Result<Result<(), ()>, Error>,
951 Option<(StatementEndedExecutionReason, ExecuteContextGuard)>,
952 ) {
953 let (res, stmt_logging) = match res {
954 StatementResult::SqlResult(mut res) => {
955 if let SqlResult::Ok {
956 notices,
957 execution_time,
958 ..
959 } = &mut res
960 {
961 notices.extend(execution_time.take());
962 }
963 let is_err = matches!(res, SqlResult::Err { .. });
964 self.results.push(res);
965 let res = if is_err { Err(()) } else { Ok(()) };
966 (res, None)
967 }
968 StatementResult::Rows {
969 desc,
970 rows_stream,
971 max_result_size,
972 ends_group,
973 } => {
974 let res = match SqlResult::rows(
978 self,
979 client,
980 rows_stream,
981 max_result_size,
982 &desc,
983 ends_group,
984 )
985 .await
986 {
987 Ok(res) => res,
988 Err(e) => return (Err(e), None),
989 };
990 let is_err = matches!(res, SqlResult::Err { .. });
991 self.results.push(res);
992 let res = if is_err { Err(()) } else { Ok(()) };
993 (res, None)
994 }
995 StatementResult::Subscribe { ctx_extra, .. } => {
996 let message = "SUBSCRIBE only supported over websocket";
997 self.results.push(SqlResult::Err {
998 error: Error::SubscribeOnlyOverWs.into(),
999 notices: Vec::new(),
1000 });
1001 (
1002 Err(()),
1003 Some((
1004 StatementEndedExecutionReason::Errored {
1005 error: message.into(),
1006 },
1007 ctx_extra,
1008 )),
1009 )
1010 }
1011 };
1012 (Ok(res), stmt_logging)
1013 }
1014
1015 fn connection_error(&mut self) -> BoxFuture<'_, Error> {
1016 Box::pin(futures::future::pending())
1017 }
1018
1019 fn allow_subscribe(&self) -> bool {
1020 false
1021 }
1022}
1023
1024#[async_trait]
1025impl ResultSender for WebSocket {
1026 const SUPPORTS_STREAMING_NOTICES: bool = true;
1027
1028 async fn add_result(
1034 &mut self,
1035 client: &mut SessionClient,
1036 res: StatementResult,
1037 ) -> (
1038 Result<Result<(), ()>, Error>,
1039 Option<(StatementEndedExecutionReason, ExecuteContextGuard)>,
1040 ) {
1041 let (has_rows, is_streaming) = match res {
1042 StatementResult::SqlResult(SqlResult::Err { .. }) => (false, false),
1043 StatementResult::SqlResult(SqlResult::Ok { .. }) => (false, false),
1044 StatementResult::SqlResult(SqlResult::Rows { .. }) => (true, false),
1045 StatementResult::Rows { .. } => (true, false),
1046 StatementResult::Subscribe { .. } => (true, true),
1047 };
1048 if let Err(e) = send_ws_response(
1049 self,
1050 WebSocketResponse::CommandStarting(CommandStarting {
1051 has_rows,
1052 is_streaming,
1053 }),
1054 )
1055 .await
1056 {
1057 return (Err(e), None);
1058 }
1059
1060 let (is_err, msgs, stmt_logging) = match res {
1061 StatementResult::SqlResult(SqlResult::Rows { .. }) => {
1062 unreachable!("WebSocket streams peek rows via StatementResult::Rows")
1067 }
1068 StatementResult::Rows {
1069 ref desc,
1070 mut rows_stream,
1071 max_result_size,
1072 ends_group,
1073 } => match stream_ws_peek_rows(
1074 self,
1075 client,
1076 desc,
1077 &mut rows_stream,
1078 max_result_size,
1079 ends_group,
1080 )
1081 .await
1082 {
1083 Ok(result) => result,
1084 Err(e) => return (Err(e), None),
1087 },
1088 StatementResult::SqlResult(SqlResult::Ok {
1089 ok,
1090 parameters,
1091 notices,
1092 execution_time,
1093 }) => {
1094 let mut msgs: Vec<_> = execution_time
1097 .into_iter()
1098 .map(WebSocketResponse::Notice)
1099 .collect();
1100 msgs.push(WebSocketResponse::CommandComplete(ok));
1101 msgs.extend(notices.into_iter().map(WebSocketResponse::Notice));
1102 msgs.extend(
1103 parameters
1104 .into_iter()
1105 .map(WebSocketResponse::ParameterStatus),
1106 );
1107 (false, msgs, None)
1108 }
1109 StatementResult::SqlResult(SqlResult::Err { error, notices }) => {
1110 let mut msgs = vec![WebSocketResponse::Error(error)];
1111 msgs.extend(notices.into_iter().map(WebSocketResponse::Notice));
1112 (true, msgs, None)
1113 }
1114 StatementResult::Subscribe {
1115 ref desc,
1116 tag,
1117 mut rx,
1118 ctx_extra,
1119 } => {
1120 if let Err(e) = send_ws_response(self, WebSocketResponse::Rows(desc.into())).await {
1121 return (
1124 Err(e),
1125 Some((StatementEndedExecutionReason::Canceled, ctx_extra)),
1126 );
1127 }
1128
1129 let mut datum_vec = mz_repr::DatumVec::new();
1130 let mut result_size: usize = 0;
1131 let mut rows_returned = 0;
1132 loop {
1133 let res = match await_rows(self, client, rx.recv()).await {
1134 Ok(res) => res,
1135 Err(e) => {
1136 return (
1139 Err(e),
1140 Some((StatementEndedExecutionReason::Canceled, ctx_extra)),
1141 );
1142 }
1143 };
1144 match res {
1145 Some(PeekResponseUnary::Rows(mut rows)) => {
1146 if let Err(err) = verify_datum_desc(desc, &mut rows) {
1147 let error = err.to_string();
1148 break (
1149 true,
1150 vec![WebSocketResponse::Error(err.into())],
1151 Some((
1152 StatementEndedExecutionReason::Errored { error },
1153 ctx_extra,
1154 )),
1155 );
1156 }
1157
1158 rows_returned += rows.count();
1159 while let Some(row) = rows.next() {
1160 result_size = result_size.saturating_add(row.byte_len());
1161 let datums = datum_vec.borrow_with(row);
1162 let types = &desc.typ().column_types;
1163 if let Err(e) = send_ws_response(
1164 self,
1165 WebSocketResponse::Row(
1166 datums
1167 .iter()
1168 .enumerate()
1169 .map(|(i, d)| {
1170 TypedDatum::new(*d, &types[i])
1171 .json(&JsonNumberPolicy::ConvertNumberToString)
1172 })
1173 .collect(),
1174 ),
1175 )
1176 .await
1177 {
1178 return (
1181 Err(e),
1182 Some((StatementEndedExecutionReason::Canceled, ctx_extra)),
1183 );
1184 }
1185 }
1186 }
1187 Some(PeekResponseUnary::Error(err)) => {
1188 let error = err.to_string();
1189 break (
1190 true,
1191 vec![WebSocketResponse::Error(err.into())],
1192 Some((StatementEndedExecutionReason::Errored { error }, ctx_extra)),
1193 );
1194 }
1195 Some(PeekResponseUnary::DependencyDropped(dep)) => {
1196 let err = dep.to_concurrent_dependency_drop();
1197 let error = err.to_string();
1198 break (
1199 true,
1200 vec![WebSocketResponse::Error(err.into())],
1201 Some((StatementEndedExecutionReason::Errored { error }, ctx_extra)),
1202 );
1203 }
1204 Some(PeekResponseUnary::Canceled) => {
1205 break (
1206 true,
1207 vec![WebSocketResponse::Error(AdapterError::Canceled.into())],
1208 Some((StatementEndedExecutionReason::Canceled, ctx_extra)),
1209 );
1210 }
1211 None => {
1212 break (
1213 false,
1214 vec![WebSocketResponse::CommandComplete(tag)],
1215 Some((
1216 StatementEndedExecutionReason::Success {
1217 result_size: Some(u64::cast_from(result_size)),
1218 rows_returned: Some(u64::cast_from(rows_returned)),
1219 execution_strategy: Some(
1220 StatementExecutionStrategy::Standard,
1221 ),
1222 },
1223 ctx_extra,
1224 )),
1225 );
1226 }
1227 }
1228 }
1229 }
1230 };
1231 for msg in msgs {
1232 if let Err(e) = send_ws_response(self, msg).await {
1233 return (
1234 Err(e),
1235 stmt_logging.map(|(_old_reason, ctx_extra)| {
1236 (StatementEndedExecutionReason::Canceled, ctx_extra)
1237 }),
1238 );
1239 }
1240 }
1241 (Ok(if is_err { Err(()) } else { Ok(()) }), stmt_logging)
1242 }
1243
1244 fn connection_error(&mut self) -> BoxFuture<'_, Error> {
1247 Box::pin(async {
1248 let mut tick = time::interval(Duration::from_secs(1));
1249 tick.tick().await;
1250 loop {
1251 tick.tick().await;
1252 if let Err(err) = self.send(Message::Ping(Vec::new().into())).await {
1253 return err.into();
1254 }
1255 }
1256 })
1257 }
1258
1259 fn allow_subscribe(&self) -> bool {
1260 true
1261 }
1262
1263 async fn emit_streaming_notices(&mut self, notices: Vec<AdapterNotice>) -> Result<(), Error> {
1264 forward_notices(self, notices).await
1265 }
1266}
1267
1268async fn await_rows<S, F, R>(sender: &mut S, client: &mut SessionClient, f: F) -> Result<R, Error>
1269where
1270 S: ResultSender,
1271 F: Future<Output = R> + Send,
1272{
1273 let mut f = pin!(f);
1274 loop {
1275 tokio::select! {
1276 notice = client.session().recv_notice(), if S::SUPPORTS_STREAMING_NOTICES => {
1277 sender.emit_streaming_notices(vec![notice]).await?;
1278 }
1279 e = sender.connection_error() => return Err(e),
1280 r = &mut f => return Ok(r),
1281 }
1282 }
1283}
1284
1285async fn stream_ws_peek_rows(
1300 ws: &mut WebSocket,
1301 client: &mut SessionClient,
1302 desc: &RelationDesc,
1303 rows_stream: &mut RecordFirstRowStream,
1304 max_result_size: usize,
1305 ends_group: bool,
1306) -> Result<
1307 (
1308 bool,
1309 Vec<WebSocketResponse>,
1310 Option<(StatementEndedExecutionReason, ExecuteContextGuard)>,
1311 ),
1312 Error,
1313> {
1314 let mut datum_vec = mz_repr::DatumVec::new();
1315 let mut result_size: usize = 0;
1316 let mut rows_returned: usize = 0;
1317 let mut sent_rows_desc = false;
1318 loop {
1319 let res = await_rows(ws, client, rows_stream.recv()).await?;
1322 match res {
1323 Some(PeekResponseUnary::Rows(mut rows)) => {
1324 if let Err(err) = verify_datum_desc(desc, &mut rows) {
1325 return Ok(ws_peek_result(
1326 client,
1327 true,
1328 vec![WebSocketResponse::Error(err.into())],
1329 ));
1330 }
1331 if !sent_rows_desc {
1336 send_ws_response(ws, WebSocketResponse::Rows(desc.into())).await?;
1337 sent_rows_desc = true;
1338 }
1339 let types = &desc.typ().column_types;
1340 while let Some(row) = rows.next() {
1341 result_size = result_size.saturating_add(row.byte_len());
1342 if result_size > max_result_size {
1343 use bytesize::ByteSize;
1344 return Ok(ws_peek_result(
1345 client,
1346 true,
1347 vec![WebSocketResponse::Error(
1348 AdapterError::ResultSize(format!(
1349 "result exceeds max size of {}",
1350 ByteSize::b(u64::cast_from(max_result_size))
1351 ))
1352 .into(),
1353 )],
1354 ));
1355 }
1356 let datums = datum_vec.borrow_with(row);
1357 send_ws_response(
1358 ws,
1359 WebSocketResponse::Row(
1360 datums
1361 .iter()
1362 .enumerate()
1363 .map(|(i, d)| {
1364 TypedDatum::new(*d, &types[i])
1365 .json(&JsonNumberPolicy::ConvertNumberToString)
1366 })
1367 .collect(),
1368 ),
1369 )
1370 .await?;
1371 rows_returned += 1;
1372 }
1373 }
1374 Some(PeekResponseUnary::Error(error)) => {
1375 return Ok(ws_peek_result(
1376 client,
1377 true,
1378 vec![WebSocketResponse::Error(error.into())],
1379 ));
1380 }
1381 Some(PeekResponseUnary::DependencyDropped(dep)) => {
1382 return Ok(ws_peek_result(
1383 client,
1384 true,
1385 vec![WebSocketResponse::Error(
1386 dep.to_concurrent_dependency_drop().into(),
1387 )],
1388 ));
1389 }
1390 Some(PeekResponseUnary::Canceled) => {
1391 return Ok(ws_peek_result(
1392 client,
1393 true,
1394 vec![WebSocketResponse::Error(AdapterError::Canceled.into())],
1395 ));
1396 }
1397 None => {
1398 let execution_time = rows_stream
1399 .take_execution_time()
1400 .map(|time| client.session().maybe_mark_staged(time));
1401 let settled = match client.settle_statement(ends_group).await {
1402 Ok(settled) => settled,
1403 Err(err) => {
1404 return Ok(ws_peek_result(
1405 client,
1406 true,
1407 vec![WebSocketResponse::Error(err.into())],
1408 ));
1409 }
1410 };
1411 if !sent_rows_desc {
1414 send_ws_response(ws, WebSocketResponse::Rows(desc.into())).await?;
1415 }
1416 let command_complete =
1417 WebSocketResponse::CommandComplete(format!("SELECT {rows_returned}"));
1418 let msgs = execution_time
1419 .and_then(|time| client.session().execution_time_notice(time))
1420 .map(|notice| WebSocketResponse::Notice(Notice::from(notice)))
1421 .into_iter()
1422 .chain([command_complete])
1423 .collect();
1424 let (is_err, mut msgs, stmt_logging) = ws_peek_result(client, false, msgs);
1425 let reverted = notify_params(client, settled.reverted);
1426 msgs.extend(reverted.into_iter().map(WebSocketResponse::ParameterStatus));
1427 return Ok((is_err, msgs, stmt_logging));
1428 }
1429 }
1430 }
1431}
1432
1433fn ws_peek_result(
1441 client: &mut SessionClient,
1442 is_err: bool,
1443 mut msgs: Vec<WebSocketResponse>,
1444) -> (
1445 bool,
1446 Vec<WebSocketResponse>,
1447 Option<(StatementEndedExecutionReason, ExecuteContextGuard)>,
1448) {
1449 msgs.extend(
1450 make_notices(client)
1451 .into_iter()
1452 .map(WebSocketResponse::Notice),
1453 );
1454 (is_err, msgs, None)
1455}
1456
1457async fn send_and_retire<S: ResultSender>(
1458 res: StatementResult,
1459 client: &mut SessionClient,
1460 sender: &mut S,
1461) -> Result<Result<(), ()>, Error> {
1462 let (res, stmt_logging) = sender.add_result(client, res).await;
1463 if let Some((reason, ctx_extra)) = stmt_logging {
1464 client.retire_execute(ctx_extra, reason);
1465 }
1466 res
1467}
1468
1469async fn execute_stmt_group<S: ResultSender>(
1471 client: &mut SessionClient,
1472 sender: &mut S,
1473 stmt_group: Vec<(Statement<Raw>, String, Vec<Option<String>>)>,
1474) -> Result<Result<(), ()>, Error> {
1475 let num_stmts = stmt_group.len();
1476 for (idx, (stmt, sql, params)) in stmt_group.into_iter().enumerate() {
1477 assert!(
1478 num_stmts <= 1 || params.is_empty(),
1479 "statement groups contain more than 1 statement iff Simple request, which does not support parameters"
1480 );
1481
1482 let is_aborted_txn = matches!(client.session().transaction(), TransactionStatus::Failed(_));
1483 if is_aborted_txn && !is_txn_exit_stmt(&stmt) {
1484 let err = SqlResult::err(client, Error::AbortedTransaction);
1485 let _ = send_and_retire(err.into(), client, sender).await?;
1486 return Ok(Err(()));
1487 }
1488
1489 if let Err(e) = client.start_transaction(Some(num_stmts)) {
1492 let err = SqlResult::err(client, e);
1493 let _ = send_and_retire(err.into(), client, sender).await?;
1494 return Ok(Err(()));
1495 }
1496 let ends_group = idx + 1 == num_stmts;
1497 let res = execute_stmt(client, sender, stmt, sql, params, ends_group).await?;
1498 let is_err = send_and_retire(res, client, sender).await?;
1499
1500 if is_err.is_err() {
1501 let txn = client.session().transaction();
1504 match txn {
1505 TransactionStatus::Default | TransactionStatus::Failed(_) => {}
1508 TransactionStatus::Started(_) | TransactionStatus::InTransactionImplicit(_) => {
1510 if let Err(err) = client.end_transaction(EndTransactionAction::Rollback).await {
1511 let err = SqlResult::err(client, err);
1512 let _ = send_and_retire(err.into(), client, sender).await?;
1513 }
1514 }
1515 TransactionStatus::InTransaction(_) => {
1517 client.fail_transaction();
1518 }
1519 }
1520 return Ok(Err(()));
1521 }
1522 }
1523 Ok(Ok(()))
1524}
1525
1526pub(in crate::http) async fn execute_request<S: ResultSender>(
1535 client: &mut AuthedClient,
1536 request: SqlRequest,
1537 sender: &mut S,
1538) -> Result<(), Error> {
1539 let client = &mut client.client;
1540
1541 if client.statement_arrival_logging_enabled().await {
1542 let session = client.session();
1543 let conn_id = session.conn_id();
1544 let session_uuid = session.uuid();
1545 match &request {
1546 SqlRequest::Simple { query } => {
1547 info!(
1548 %conn_id, %session_uuid, kind = "http_simple",
1549 sql = %redact_sql_for_logging(query.as_str()),
1550 "statement arrival"
1551 );
1552 }
1553 SqlRequest::Extended { queries } => {
1554 for ExtendedRequest { query, params } in queries {
1555 info!(
1558 %conn_id, %session_uuid, kind = "http_extended",
1559 sql = %redact_sql_for_logging(query), num_params = params.len(),
1560 "statement arrival"
1561 );
1562 }
1563 }
1564 }
1565 }
1566
1567 fn check_prohibited_stmts<S: ResultSender>(
1570 sender: &S,
1571 stmt: &Statement<Raw>,
1572 ) -> Result<(), Error> {
1573 let kind: StatementKind = stmt.into();
1574 let execute_responses = Plan::generated_from(&kind)
1575 .into_iter()
1576 .map(ExecuteResponse::generated_from)
1577 .flatten()
1578 .collect::<Vec<_>>();
1579
1580 let is_valid_copy = matches!(
1584 stmt,
1585 Statement::Copy(CopyStatement {
1586 direction: CopyDirection::To,
1587 target: CopyTarget::Expr(_),
1588 ..
1589 }) | Statement::Copy(CopyStatement {
1590 direction: CopyDirection::From,
1591 target: CopyTarget::Expr(_),
1592 ..
1593 })
1594 );
1595
1596 if !is_valid_copy
1597 && execute_responses.iter().any(|execute_response| {
1598 match execute_response {
1600 ExecuteResponseKind::Subscribing if sender.allow_subscribe() => false,
1601 ExecuteResponseKind::Fetch
1602 | ExecuteResponseKind::Subscribing
1603 | ExecuteResponseKind::CopyFrom
1604 | ExecuteResponseKind::DeclaredCursor
1605 | ExecuteResponseKind::ClosedCursor => true,
1606 ExecuteResponseKind::CopyTo if matches!(kind, StatementKind::Copy) => true,
1611 _ => false,
1612 }
1613 })
1614 {
1615 return Err(Error::Unsupported(stmt.to_ast_string_simple()));
1616 }
1617 Ok(())
1618 }
1619
1620 fn parse<'a>(
1621 client: &SessionClient,
1622 query: &'a str,
1623 ) -> Result<Vec<StatementParseResult<'a>>, Error> {
1624 let result = client
1625 .parse(query)
1626 .map_err(|e| Error::Unstructured(anyhow!(e)))?;
1627 result.map_err(|e| AdapterError::from(e).into())
1628 }
1629
1630 let mut stmt_groups = vec![];
1631
1632 match request {
1633 SqlRequest::Simple { query } => match parse(client, query.as_str()) {
1634 Ok(stmts) => {
1635 let mut stmt_group = Vec::with_capacity(stmts.len());
1636 let mut stmt_err = None;
1637 for StatementParseResult { ast: stmt, sql } in stmts {
1638 if let Err(err) = check_prohibited_stmts(sender, &stmt) {
1639 stmt_err = Some(err);
1640 break;
1641 }
1642 stmt_group.push((stmt, sql.to_string(), vec![]));
1643 }
1644 stmt_groups.push(stmt_err.map(Err).unwrap_or_else(|| Ok(stmt_group)));
1645 }
1646 Err(e) => stmt_groups.push(Err(e)),
1647 },
1648 SqlRequest::Extended { queries } => {
1649 for ExtendedRequest { query, params } in queries {
1650 match parse(client, &query) {
1651 Ok(mut stmts) => {
1652 if stmts.len() != 1 {
1653 return Err(Error::Unstructured(anyhow!(
1654 "each query must contain exactly 1 statement, but \"{}\" contains {}",
1655 query,
1656 stmts.len()
1657 )));
1658 }
1659
1660 let StatementParseResult { ast: stmt, sql } = stmts.pop().unwrap();
1661 stmt_groups.push(
1662 check_prohibited_stmts(sender, &stmt)
1663 .map(|_| vec![(stmt, sql.to_string(), params)]),
1664 );
1665 }
1666 Err(e) => stmt_groups.push(Err(e)),
1667 };
1668 }
1669 }
1670 }
1671
1672 for stmt_group_res in stmt_groups {
1673 let executed = match stmt_group_res {
1674 Ok(stmt_group) => execute_stmt_group(client, sender, stmt_group).await,
1675 Err(e) => {
1676 let err = SqlResult::err(client, e);
1677 let _ = send_and_retire(err.into(), client, sender).await?;
1678 Ok(Err(()))
1679 }
1680 };
1681 let mut commit_failed = false;
1684 if client.session().transaction().is_implicit() {
1685 let ended = client.end_transaction(EndTransactionAction::Commit).await;
1686 if let Err(err) = ended {
1687 let err = SqlResult::err(client, err);
1688 let _ = send_and_retire(StatementResult::SqlResult(err), client, sender).await?;
1689 commit_failed = true;
1690 }
1691 }
1692 if executed?.is_err() || commit_failed {
1693 break;
1694 }
1695 }
1696
1697 Ok(())
1698}
1699
1700async fn execute_stmt<S: ResultSender>(
1702 client: &mut SessionClient,
1703 sender: &mut S,
1704 stmt: Statement<Raw>,
1705 sql: String,
1706 raw_params: Vec<Option<String>>,
1707 ends_group: bool,
1708) -> Result<StatementResult, Error> {
1709 const EMPTY_PORTAL: &str = "";
1710 if let Err(e) = client
1711 .prepare(EMPTY_PORTAL.into(), Some(stmt.clone()), sql, vec![])
1712 .await
1713 {
1714 return Ok(SqlResult::err(client, e).into());
1715 }
1716
1717 let prep_stmt = match client.get_prepared_statement(EMPTY_PORTAL).await {
1718 Ok(stmt) => stmt,
1719 Err(err) => {
1720 return Ok(SqlResult::err(client, err).into());
1721 }
1722 };
1723
1724 let param_types = &prep_stmt.desc().param_types;
1725 if param_types.len() != raw_params.len() {
1726 let message = anyhow!(
1727 "request supplied {actual} parameters, \
1728 but {statement} requires {expected}",
1729 statement = stmt.to_ast_string_simple(),
1730 actual = raw_params.len(),
1731 expected = param_types.len()
1732 );
1733 return Ok(SqlResult::err(client, Error::Unstructured(message)).into());
1734 }
1735
1736 let buf = RowArena::new();
1737 let mut params = vec![];
1738 for (raw_param, mz_typ) in raw_params.into_iter().zip_eq(param_types) {
1739 let pg_typ = mz_pgrepr::Type::from(mz_typ);
1740 let datum = match raw_param {
1741 None => Datum::Null,
1742 Some(raw_param) => {
1743 match mz_pgrepr::Value::decode(
1744 mz_pgwire_common::Format::Text,
1745 &pg_typ,
1746 raw_param.as_bytes(),
1747 ) {
1748 Ok(param) => match param.into_datum_decode_error(&buf, &pg_typ, "parameter") {
1749 Ok(datum) => datum,
1750 Err(msg) => {
1751 return Ok(
1752 SqlResult::err(client, Error::Unstructured(anyhow!(msg))).into()
1753 );
1754 }
1755 },
1756 Err(err) => {
1757 let msg = anyhow!("unable to decode parameter: {}", err);
1758 return Ok(SqlResult::err(client, Error::Unstructured(msg)).into());
1759 }
1760 }
1761 }
1762 };
1763 params.push((datum, mz_typ.clone()))
1764 }
1765
1766 let result_formats = vec![
1767 mz_pgwire_common::Format::Text;
1768 prep_stmt
1769 .desc()
1770 .relation_desc
1771 .clone()
1772 .map(|desc| desc.typ().column_types.len())
1773 .unwrap_or(0)
1774 ];
1775
1776 let desc = prep_stmt.desc().clone();
1777 let logging = Arc::clone(prep_stmt.logging());
1778 let stmt_ast = prep_stmt.stmt().cloned();
1779 let state_revision = prep_stmt.state_revision;
1780 if let Err(err) = client.session().set_portal(
1781 EMPTY_PORTAL.into(),
1782 desc,
1783 stmt_ast,
1784 logging,
1785 params,
1786 result_formats,
1787 state_revision,
1788 ) {
1789 return Ok(SqlResult::err(client, err).into());
1790 }
1791
1792 let desc = client
1793 .session()
1794 .get_portal_unverified(EMPTY_PORTAL)
1796 .map(|portal| portal.desc.clone())
1797 .expect("unnamed portal should be present");
1798
1799 let res = client
1800 .execute(EMPTY_PORTAL.into(), futures::future::pending(), None)
1801 .await;
1802 let executed = Instant::now();
1805
1806 if S::SUPPORTS_STREAMING_NOTICES {
1807 sender
1808 .emit_streaming_notices(client.session().drain_notices())
1809 .await?;
1810 }
1811
1812 let (res, execute_started) = match res {
1813 Ok(res) => res,
1814 Err(e) => {
1815 return Ok(SqlResult::err(client, e).into());
1816 }
1817 };
1818 let execution_time = client.session().maybe_mark_staged(ExecutionTime::completed(
1819 executed.duration_since(execute_started),
1820 ));
1821 let tag = res.tag();
1822
1823 Ok(match res {
1824 ExecuteResponse::CreatedConnection { .. }
1825 | ExecuteResponse::CreatedDatabase { .. }
1826 | ExecuteResponse::CreatedSchema { .. }
1827 | ExecuteResponse::CreatedRole
1828 | ExecuteResponse::CreatedCluster { .. }
1829 | ExecuteResponse::CreatedClusterReplica { .. }
1830 | ExecuteResponse::CreatedTable { .. }
1831 | ExecuteResponse::CreatedIndex { .. }
1832 | ExecuteResponse::CreatedMetricSink { .. }
1833 | ExecuteResponse::CreatedIntrospectionSubscribe
1834 | ExecuteResponse::CreatedSecret { .. }
1835 | ExecuteResponse::CreatedSource { .. }
1836 | ExecuteResponse::CreatedSink { .. }
1837 | ExecuteResponse::CreatedView { .. }
1838 | ExecuteResponse::CreatedViews { .. }
1839 | ExecuteResponse::CreatedMaterializedView { .. }
1840 | ExecuteResponse::CreatedType
1841 | ExecuteResponse::CreatedNetworkPolicy
1842 | ExecuteResponse::Comment
1843 | ExecuteResponse::Deleted(_)
1844 | ExecuteResponse::DiscardedTemp
1845 | ExecuteResponse::DroppedObject(_)
1846 | ExecuteResponse::DroppedOwned
1847 | ExecuteResponse::EmptyQuery
1848 | ExecuteResponse::GrantedPrivilege
1849 | ExecuteResponse::GrantedRole
1850 | ExecuteResponse::Inserted(_)
1851 | ExecuteResponse::Copied(_)
1852 | ExecuteResponse::Raised
1853 | ExecuteResponse::ReassignOwned
1854 | ExecuteResponse::RevokedPrivilege
1855 | ExecuteResponse::AlteredDefaultPrivileges
1856 | ExecuteResponse::RevokedRole
1857 | ExecuteResponse::StartedTransaction { .. }
1858 | ExecuteResponse::Updated(_)
1859 | ExecuteResponse::AlteredObject(_)
1860 | ExecuteResponse::AlteredRole
1861 | ExecuteResponse::AlteredSystemConfiguration
1862 | ExecuteResponse::Deallocate { .. }
1863 | ExecuteResponse::ValidatedConnection
1864 | ExecuteResponse::Prepare => SqlResult::ok(
1865 client,
1866 tag.expect("ok only called on tag-generating results"),
1867 Vec::default(),
1868 ends_group,
1869 execution_time,
1870 )
1871 .await
1872 .into(),
1873 ExecuteResponse::TransactionCommitted { params }
1874 | ExecuteResponse::TransactionRolledBack { params }
1875 | ExecuteResponse::DiscardedAll { params } => {
1876 let params = notify_params(client, params);
1877 SqlResult::ok(
1878 client,
1879 tag.expect("ok only called on tag-generating results"),
1880 params,
1881 ends_group,
1882 execution_time,
1883 )
1884 .await
1885 .into()
1886 }
1887 ExecuteResponse::SetVariable { name, .. } => {
1888 let mut params = Vec::with_capacity(1);
1889 if let Some(var) = client
1890 .session()
1891 .vars()
1892 .notify_set()
1893 .find(|v| v.name() == &name)
1894 {
1895 params.push(ParameterStatus {
1896 name,
1897 value: var.value(),
1898 });
1899 };
1900 SqlResult::ok(
1901 client,
1902 tag.expect("ok only called on tag-generating results"),
1903 params,
1904 ends_group,
1905 execution_time,
1906 )
1907 .await
1908 .into()
1909 }
1910 ExecuteResponse::SendingRowsStreaming {
1911 rows,
1912 instance_id,
1913 strategy,
1914 } => {
1915 let max_result_size = max_result_size(client).await;
1916
1917 let rows_stream = RecordFirstRowStream::new(
1918 Box::new(rows),
1919 execute_started,
1920 client,
1921 Some(instance_id),
1922 Some(strategy),
1923 );
1924
1925 StatementResult::Rows {
1926 desc: desc.relation_desc.expect("RelationDesc must exist"),
1927 rows_stream,
1928 max_result_size,
1929 ends_group,
1930 }
1931 }
1932 ExecuteResponse::SendingRowsImmediate { rows } => {
1933 let max_result_size = max_result_size(client).await;
1934
1935 let rows = futures::stream::once(futures::future::ready(PeekResponseUnary::Rows(rows)));
1936 let rows_stream = RecordFirstRowStream::new(
1937 Box::new(rows),
1938 execute_started,
1939 client,
1940 None,
1941 Some(StatementExecutionStrategy::Constant),
1942 );
1943
1944 StatementResult::Rows {
1945 desc: desc.relation_desc.expect("RelationDesc must exist"),
1946 rows_stream,
1947 max_result_size,
1948 ends_group,
1949 }
1950 }
1951 ExecuteResponse::Subscribing {
1952 rx,
1953 ctx_extra,
1954 instance_id,
1955 } => StatementResult::Subscribe {
1956 tag: "SUBSCRIBE".into(),
1957 desc: desc.relation_desc.unwrap(),
1958 rx: RecordFirstRowStream::new(rx, execute_started, client, Some(instance_id), None)
1959 .without_execution_time(),
1960 ctx_extra,
1961 },
1962 res @ (ExecuteResponse::Fetch { .. }
1963 | ExecuteResponse::CopyTo { .. }
1964 | ExecuteResponse::CopyFrom { .. }
1965 | ExecuteResponse::DeclaredCursor
1966 | ExecuteResponse::ClosedCursor) => SqlResult::err(
1967 client,
1968 Error::Unstructured(anyhow!(
1969 "internal error: encountered prohibited ExecuteResponse {:?}.\n\n
1970 This is a bug. Can you please file an bug report letting us know?\n
1971 https://github.com/MaterializeInc/materialize/discussions/new?category=bug-reports",
1972 ExecuteResponseKind::from(res)
1973 )),
1974 )
1975 .into(),
1976 })
1977}
1978
1979async fn max_result_size(client: &mut SessionClient) -> usize {
1983 let catalog = client.catalog_snapshot("http_max_result_size").await;
1984 usize::cast_from(catalog.system_config().max_result_size())
1985}
1986
1987fn notify_params(
1989 client: &mut SessionClient,
1990 params: BTreeMap<&'static str, String>,
1991) -> Vec<ParameterStatus> {
1992 let notify_set: mz_ore::collections::HashSet<_> = client
1993 .session()
1994 .vars()
1995 .notify_set()
1996 .map(|v| v.name().to_string())
1997 .collect();
1998 params
1999 .into_iter()
2000 .filter(|(name, _value)| notify_set.contains(*name))
2001 .map(|(name, value)| ParameterStatus {
2002 name: name.to_string(),
2003 value,
2004 })
2005 .collect()
2006}
2007
2008fn make_notices(client: &mut SessionClient) -> Vec<Notice> {
2009 client
2010 .session()
2011 .drain_notices()
2012 .into_iter()
2013 .map(Notice::from)
2014 .collect()
2015}
2016
2017impl From<AdapterNotice> for Notice {
2018 fn from(notice: AdapterNotice) -> Self {
2019 Notice {
2020 message: notice.to_string(),
2021 code: notice.code().code().to_string(),
2022 severity: notice.severity().as_str().to_lowercase(),
2023 detail: notice.detail(),
2024 hint: notice.hint(),
2025 }
2026 }
2027}
2028
2029fn is_txn_exit_stmt(stmt: &Statement<Raw>) -> bool {
2032 matches!(
2033 stmt,
2034 Statement::Commit(_) | Statement::Rollback(_) | Statement::Prepare(_)
2035 )
2036}
2037
2038#[cfg(test)]
2039mod tests {
2040 use std::collections::BTreeMap;
2041
2042 use super::{Password, WebSocketAuth};
2043
2044 #[mz_ore::test]
2045 fn smoke_test_websocket_auth_parse() {
2046 struct TestCase {
2047 json: &'static str,
2048 expected: WebSocketAuth,
2049 }
2050
2051 let test_cases = vec![
2052 TestCase {
2053 json: r#"{ "user": "mz", "password": "1234" }"#,
2054 expected: WebSocketAuth::Basic {
2055 user: "mz".to_string(),
2056 password: Password("1234".to_string()),
2057 options: BTreeMap::default(),
2058 },
2059 },
2060 TestCase {
2061 json: r#"{ "user": "mz", "password": "1234", "options": {} }"#,
2062 expected: WebSocketAuth::Basic {
2063 user: "mz".to_string(),
2064 password: Password("1234".to_string()),
2065 options: BTreeMap::default(),
2066 },
2067 },
2068 TestCase {
2069 json: r#"{ "token": "i_am_a_token" }"#,
2070 expected: WebSocketAuth::Bearer {
2071 token: "i_am_a_token".to_string(),
2072 options: BTreeMap::default(),
2073 },
2074 },
2075 TestCase {
2076 json: r#"{ "token": "i_am_a_token", "options": { "foo": "bar" } }"#,
2077 expected: WebSocketAuth::Bearer {
2078 token: "i_am_a_token".to_string(),
2079 options: BTreeMap::from([("foo".to_string(), "bar".to_string())]),
2080 },
2081 },
2082 ];
2083
2084 fn assert_parse(json: &'static str, expected: WebSocketAuth) {
2085 let parsed: WebSocketAuth = serde_json::from_str(json).unwrap();
2086 assert_eq!(parsed, expected);
2087 }
2088
2089 for TestCase { json, expected } in test_cases {
2090 assert_parse(json, expected)
2091 }
2092 }
2093}