Skip to main content

mz_adapter/
command.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10use std::collections::{BTreeMap, BTreeSet};
11use std::net::IpAddr;
12use std::pin::Pin;
13use std::sync::Arc;
14use std::time::Duration;
15
16use chrono::{DateTime, Utc};
17use derivative::Derivative;
18use enum_kinds::EnumKind;
19use futures::Stream;
20use mz_adapter_types::connection::{ConnectionId, ConnectionIdType};
21use mz_auth::password::Password;
22use mz_cluster_client::ReplicaId;
23use mz_compute_types::ComputeInstanceId;
24use mz_compute_types::dataflows::DataflowDescription;
25use mz_controller_types::ClusterId;
26use mz_expr::RowSetFinishing;
27use mz_ore::collections::CollectionExt;
28use mz_ore::soft_assert_no_log;
29use mz_ore::tracing::OpenTelemetryContext;
30use mz_persist_client::PersistClient;
31use mz_pgcopy::CopyFormatParams;
32use mz_repr::global_id::TransientIdGen;
33use mz_repr::role_id::RoleId;
34use mz_repr::{CatalogItemId, ColumnIndex, GlobalId, RowIterator, SqlRelationType};
35use mz_sql::ast::{FetchDirection, Raw, Statement};
36use mz_sql::catalog::ObjectType;
37use mz_sql::optimizer_metrics::OptimizerMetrics;
38use mz_sql::plan;
39use mz_sql::plan::{ExecuteTimeout, Plan, PlanKind, SideEffectingFunc};
40use mz_sql::session::user::User;
41use mz_sql::session::vars::{OwnedVarInput, SystemVars};
42use mz_sql_parser::ast::{AlterObjectRenameStatement, AlterOwnerStatement, DropObjectsStatement};
43use mz_storage_types::sources::Timeline;
44use mz_timestamp_oracle::TimestampOracle;
45use tokio::sync::{mpsc, oneshot};
46use uuid::Uuid;
47
48use crate::catalog::Catalog;
49use crate::config::{ScopedParameters, ScopedParametersScope, SystemParameterFrontend};
50use crate::coord::appends::BuiltinTableAppendNotify;
51use crate::coord::consistency::CoordinatorInconsistencies;
52use crate::coord::peek::{PeekDataflowPlan, PeekResponseUnary};
53use crate::coord::timestamp_selection::TimestampDetermination;
54use crate::coord::{ExecuteContextExtra, ExecuteContextGuard};
55use crate::error::AdapterError;
56use crate::session::{EndTransactionAction, RowBatchStream, Session};
57use crate::statement_logging::{
58    FrontendStatementLoggingEvent, StatementEndedExecutionReason, StatementExecutionStrategy,
59    StatementLoggingFrontend,
60};
61use crate::statement_logging::{StatementLoggingId, WatchSetCreation};
62use crate::util::Transmittable;
63use crate::webhook::AppendWebhookResponse;
64use crate::{
65    AdapterNotice, AppendWebhookError, CollectionIdBundle, ReadHolds, TimestampExplanation,
66};
67
68/// A handle for pgwire to stream raw byte chunks to the coordinator's
69/// parallel background batch builder tasks during COPY FROM STDIN.
70#[derive(Debug)]
71pub struct CopyFromStdinWriter {
72    /// Channels for distributing raw byte chunks (split at row boundaries)
73    /// across parallel worker tasks. pgwire round-robins chunks across these.
74    pub batch_txs: Vec<mpsc::Sender<Vec<u8>>>,
75    /// Receives the final result (`Vec<ProtoBatch>` + total row count, or error)
76    /// from the collector task. pgwire uses this to commit the batches.
77    pub completion_rx: oneshot::Receiver<
78        Result<(Vec<mz_persist_client::batch::ProtoBatch>, u64), crate::AdapterError>,
79    >,
80}
81
82#[derive(Debug)]
83pub struct CatalogSnapshot {
84    pub catalog: Arc<Catalog>,
85}
86
87#[derive(Debug)]
88pub enum Command {
89    CatalogSnapshot {
90        tx: oneshot::Sender<CatalogSnapshot>,
91    },
92
93    Startup {
94        tx: oneshot::Sender<Result<StartupResponse, AdapterError>>,
95        user: User,
96        conn_id: ConnectionId,
97        client_ip: Option<IpAddr>,
98        secret_key: u32,
99        uuid: Uuid,
100        application_name: String,
101        notice_tx: mpsc::UnboundedSender<AdapterNotice>,
102    },
103
104    AuthenticatePassword {
105        tx: oneshot::Sender<Result<(), AdapterError>>,
106        role_name: String,
107        password: Option<Password>,
108    },
109
110    AuthenticateGetSASLChallenge {
111        tx: oneshot::Sender<Result<SASLChallengeResponse, AdapterError>>,
112        role_name: String,
113        nonce: String,
114    },
115
116    AuthenticateVerifySASLProof {
117        tx: oneshot::Sender<Result<SASLVerifyProofResponse, AdapterError>>,
118        role_name: String,
119        proof: String,
120        auth_message: String,
121        mock_hash: String,
122    },
123
124    CheckRoleCanLogin {
125        tx: oneshot::Sender<Result<(), AdapterError>>,
126        role_name: String,
127    },
128
129    Execute {
130        portal_name: String,
131        session: Session,
132        tx: oneshot::Sender<Response<ExecuteResponse>>,
133        outer_ctx_extra: Option<ExecuteContextGuard>,
134    },
135
136    /// Attempts to commit or abort the session's transaction. Guarantees that the Coordinator's
137    /// transaction state has been cleared, even if the commit or abort fails. (A failure can
138    /// happen, for example, if the session's role id has been dropped which will prevent
139    /// sequence_end_transaction from running.)
140    Commit {
141        action: EndTransactionAction,
142        session: Session,
143        tx: oneshot::Sender<Response<ExecuteResponse>>,
144    },
145
146    CancelRequest {
147        conn_id: ConnectionIdType,
148        secret_key: u32,
149    },
150
151    PrivilegedCancelRequest {
152        conn_id: ConnectionId,
153    },
154
155    GetWebhook {
156        database: String,
157        schema: String,
158        name: String,
159        tx: oneshot::Sender<Result<AppendWebhookResponse, AppendWebhookError>>,
160    },
161
162    GetSystemVars {
163        tx: oneshot::Sender<SystemVars>,
164    },
165
166    SetSystemVars {
167        vars: BTreeMap<String, String>,
168        conn_id: ConnectionId,
169        tx: oneshot::Sender<Result<(), AdapterError>>,
170    },
171
172    /// Replace the scoped feature-flag overrides (the complete desired state).
173    /// Computed by the system-parameter sync loop from continuous LaunchDarkly
174    /// evaluation. The coordinator stores this working copy and reconciles it
175    /// into the per-scope resolution boundaries (the compute controller's
176    /// per-replica dyncfg layer for `replica`-scoped parameters). See the
177    /// scoped feature flags design.
178    UpdateScopedSystemParameters {
179        overrides: ScopedParameters,
180        /// Bounds which objects' durable rows the reconcile may prune. See
181        /// [`crate::catalog::Op::UpdateScopedSystemParameters`].
182        prune_scope: Option<ScopedParametersScope>,
183        tx: oneshot::Sender<()>,
184    },
185
186    /// Install (or replace) the shared system-parameter frontend on the
187    /// coordinator, so the create-cluster / create-replica paths can resolve a
188    /// new object's scoped overrides synchronously, before the controller
189    /// installs it or its first dataflow is planned, rather than waiting for
190    /// the next sync tick. Sent by the sync loop whenever it (re)initializes the
191    /// frontend. See the scoped feature flags design.
192    InstallScopedSystemParameterFrontend {
193        frontend: Arc<SystemParameterFrontend>,
194    },
195
196    InjectAuditEvents {
197        events: Vec<crate::catalog::InjectedAuditEvent>,
198        conn_id: ConnectionId,
199        tx: oneshot::Sender<Result<(), AdapterError>>,
200    },
201
202    Terminate {
203        conn_id: ConnectionId,
204        tx: Option<oneshot::Sender<Result<(), AdapterError>>>,
205    },
206
207    /// Sets up a streaming COPY FROM STDIN operation. The coordinator
208    /// creates parallel background batch builder tasks and returns a
209    /// [`CopyFromStdinWriter`] that pgwire uses to stream raw byte chunks.
210    StartCopyFromStdin {
211        target_id: CatalogItemId,
212        target_name: String,
213        columns: Vec<ColumnIndex>,
214        /// The row description for the target table (used for constraint checks).
215        row_desc: mz_repr::RelationDesc,
216        /// Copy format parameters (text/csv/binary) for decoding raw bytes.
217        params: mz_pgcopy::CopyFormatParams<'static>,
218        session: Session,
219        tx: oneshot::Sender<Response<CopyFromStdinWriter>>,
220    },
221
222    /// Performs any cleanup and logging actions necessary for
223    /// finalizing a statement execution.
224    ///
225    /// Only used for cases that terminate in the protocol layer and
226    /// otherwise have no reason to hand control back to the coordinator.
227    /// In other cases, we piggy-back on another command.
228    RetireExecute {
229        data: ExecuteContextExtra,
230        reason: StatementEndedExecutionReason,
231    },
232
233    CheckConsistency {
234        tx: oneshot::Sender<Result<(), CoordinatorInconsistencies>>,
235    },
236
237    Dump {
238        tx: oneshot::Sender<Result<serde_json::Value, anyhow::Error>>,
239    },
240
241    GetComputeInstanceClient {
242        instance_id: ComputeInstanceId,
243        tx: oneshot::Sender<
244            Result<
245                mz_compute_client::controller::instance_client::InstanceClient,
246                mz_compute_client::controller::error::InstanceMissing,
247            >,
248        >,
249    },
250
251    GetOracle {
252        timeline: Timeline,
253        tx: oneshot::Sender<
254            Result<Arc<dyn TimestampOracle<mz_repr::Timestamp> + Send + Sync>, AdapterError>,
255        >,
256    },
257
258    DetermineRealTimeRecentTimestamp {
259        source_ids: BTreeSet<GlobalId>,
260        real_time_recency_timeout: Duration,
261        tx: oneshot::Sender<Result<Option<mz_repr::Timestamp>, AdapterError>>,
262    },
263
264    GetTransactionReadHoldsBundle {
265        conn_id: ConnectionId,
266        tx: oneshot::Sender<Option<ReadHolds>>,
267    },
268
269    /// _Merges_ the given read holds into the given connection's stored transaction read holds.
270    StoreTransactionReadHolds {
271        conn_id: ConnectionId,
272        read_holds: ReadHolds,
273        tx: oneshot::Sender<()>,
274    },
275
276    ExecuteSlowPathPeek {
277        dataflow_plan: Box<PeekDataflowPlan>,
278        determination: TimestampDetermination,
279        finishing: RowSetFinishing,
280        compute_instance: ComputeInstanceId,
281        target_replica: Option<ReplicaId>,
282        intermediate_result_type: SqlRelationType,
283        source_ids: BTreeSet<GlobalId>,
284        conn_id: ConnectionId,
285        max_result_size: u64,
286        max_query_result_size: Option<u64>,
287        /// If statement logging is enabled, contains all info needed for installing watch sets
288        /// and logging the statement execution.
289        watch_set: Option<WatchSetCreation>,
290        tx: oneshot::Sender<Result<ExecuteResponse, AdapterError>>,
291    },
292
293    ExecuteSubscribe {
294        df_desc: DataflowDescription<mz_compute_types::plan::LirRelationExpr>,
295        dependency_ids: BTreeSet<GlobalId>,
296        cluster_id: ComputeInstanceId,
297        replica_id: Option<ReplicaId>,
298        conn_id: ConnectionId,
299        session_uuid: Uuid,
300        read_holds: ReadHolds,
301        plan: plan::SubscribePlan,
302        statement_logging_id: Option<StatementLoggingId>,
303        tx: oneshot::Sender<Result<ExecuteResponse, AdapterError>>,
304    },
305
306    /// Preflight check for COPY TO S3 operation. This runs the slow S3 operations
307    /// (loading SDK config, checking bucket path, verifying permissions, uploading sentinel)
308    /// in a background task to avoid blocking the coordinator.
309    CopyToPreflight {
310        /// The S3 connection info needed for preflight checks.
311        s3_sink_connection: mz_compute_types::sinks::CopyToS3OneshotSinkConnection,
312        /// The sink ID for logging and S3 key management.
313        sink_id: GlobalId,
314        /// Response channel for the preflight result.
315        tx: oneshot::Sender<Result<(), AdapterError>>,
316    },
317
318    ExecuteCopyTo {
319        df_desc: Box<DataflowDescription<mz_compute_types::plan::LirRelationExpr>>,
320        compute_instance: ComputeInstanceId,
321        target_replica: Option<ReplicaId>,
322        source_ids: BTreeSet<GlobalId>,
323        conn_id: ConnectionId,
324        /// If statement logging is enabled, contains all info needed for installing watch sets
325        /// and logging the statement execution.
326        watch_set: Option<WatchSetCreation>,
327        tx: oneshot::Sender<Result<ExecuteResponse, AdapterError>>,
328    },
329
330    /// Execute a side-effecting function from the frontend peek path.
331    ExecuteSideEffectingFunc {
332        plan: SideEffectingFunc,
333        conn_id: ConnectionId,
334        tx: oneshot::Sender<Result<ExecuteResponse, AdapterError>>,
335    },
336
337    /// Look up an active connection by its raw connection ID, returning its
338    /// `ConnectionId` handle and authenticated role, or `None` if there is no
339    /// such connection.
340    ///
341    /// While the caller holds the returned `ConnectionId` handle, the raw
342    /// connection ID cannot be reused by a new connection. Frontend peek
343    /// sequencing relies on this to ensure that the connection it performs an
344    /// RBAC check against is the same one that a subsequent
345    /// `ExecuteSideEffectingFunc` acts on.
346    LookupConnection {
347        connection_id: u32,
348        tx: oneshot::Sender<Option<(ConnectionId, RoleId)>>,
349    },
350
351    /// Register a pending peek initiated by frontend sequencing. This is needed for:
352    /// - statement logging
353    /// - query cancellation
354    RegisterFrontendPeek {
355        uuid: Uuid,
356        conn_id: ConnectionId,
357        cluster_id: mz_controller_types::ClusterId,
358        depends_on: BTreeSet<GlobalId>,
359        is_fast_path: bool,
360        /// If statement logging is enabled, contains all info needed for installing watch sets
361        /// and logging the statement execution.
362        watch_set: Option<WatchSetCreation>,
363        tx: oneshot::Sender<Result<(), AdapterError>>,
364    },
365
366    /// Unregister and retire a pending peek that was registered but then
367    /// failed to issue, ending its statement-logging execution with the given
368    /// reason.
369    ///
370    /// Registration handed ownership of end-of-execution logging to the
371    /// coordinator, so the frontend must not log the end itself. If a
372    /// concurrent teardown (e.g. a `DROP CLUSTER`) already retired the peek
373    /// and logged its end, this is a no-op.
374    UnregisterFrontendPeek {
375        uuid: Uuid,
376        reason: StatementEndedExecutionReason,
377        tx: oneshot::Sender<()>,
378    },
379
380    /// Generate a timestamp explanation.
381    /// This is used when `emit_timestamp_notice` is enabled.
382    ExplainTimestamp {
383        conn_id: ConnectionId,
384        session_wall_time: DateTime<Utc>,
385        cluster_id: ClusterId,
386        id_bundle: CollectionIdBundle,
387        determination: TimestampDetermination,
388        tx: oneshot::Sender<TimestampExplanation>,
389    },
390
391    /// Statement logging event from frontend peek sequencing.
392    /// No response channel needed - this is fire-and-forget.
393    FrontendStatementLogging(FrontendStatementLoggingEvent),
394}
395
396impl Command {
397    pub fn session(&self) -> Option<&Session> {
398        match self {
399            Command::Execute { session, .. }
400            | Command::Commit { session, .. }
401            | Command::StartCopyFromStdin { session, .. } => Some(session),
402            Command::CancelRequest { .. }
403            | Command::Startup { .. }
404            | Command::AuthenticatePassword { .. }
405            | Command::AuthenticateGetSASLChallenge { .. }
406            | Command::AuthenticateVerifySASLProof { .. }
407            | Command::CheckRoleCanLogin { .. }
408            | Command::CatalogSnapshot { .. }
409            | Command::PrivilegedCancelRequest { .. }
410            | Command::GetWebhook { .. }
411            | Command::Terminate { .. }
412            | Command::GetSystemVars { .. }
413            | Command::SetSystemVars { .. }
414            | Command::UpdateScopedSystemParameters { .. }
415            | Command::InstallScopedSystemParameterFrontend { .. }
416            | Command::RetireExecute { .. }
417            | Command::CheckConsistency { .. }
418            | Command::Dump { .. }
419            | Command::GetComputeInstanceClient { .. }
420            | Command::GetOracle { .. }
421            | Command::DetermineRealTimeRecentTimestamp { .. }
422            | Command::GetTransactionReadHoldsBundle { .. }
423            | Command::StoreTransactionReadHolds { .. }
424            | Command::ExecuteSlowPathPeek { .. }
425            | Command::ExecuteSubscribe { .. }
426            | Command::CopyToPreflight { .. }
427            | Command::ExecuteCopyTo { .. }
428            | Command::ExecuteSideEffectingFunc { .. }
429            | Command::LookupConnection { .. }
430            | Command::RegisterFrontendPeek { .. }
431            | Command::UnregisterFrontendPeek { .. }
432            | Command::ExplainTimestamp { .. }
433            | Command::FrontendStatementLogging(..)
434            | Command::InjectAuditEvents { .. } => None,
435        }
436    }
437
438    pub fn session_mut(&mut self) -> Option<&mut Session> {
439        match self {
440            Command::Execute { session, .. }
441            | Command::Commit { session, .. }
442            | Command::StartCopyFromStdin { session, .. } => Some(session),
443            Command::CancelRequest { .. }
444            | Command::Startup { .. }
445            | Command::AuthenticatePassword { .. }
446            | Command::AuthenticateGetSASLChallenge { .. }
447            | Command::AuthenticateVerifySASLProof { .. }
448            | Command::CheckRoleCanLogin { .. }
449            | Command::CatalogSnapshot { .. }
450            | Command::PrivilegedCancelRequest { .. }
451            | Command::GetWebhook { .. }
452            | Command::Terminate { .. }
453            | Command::GetSystemVars { .. }
454            | Command::SetSystemVars { .. }
455            | Command::UpdateScopedSystemParameters { .. }
456            | Command::InstallScopedSystemParameterFrontend { .. }
457            | Command::RetireExecute { .. }
458            | Command::CheckConsistency { .. }
459            | Command::Dump { .. }
460            | Command::GetComputeInstanceClient { .. }
461            | Command::GetOracle { .. }
462            | Command::DetermineRealTimeRecentTimestamp { .. }
463            | Command::GetTransactionReadHoldsBundle { .. }
464            | Command::StoreTransactionReadHolds { .. }
465            | Command::ExecuteSlowPathPeek { .. }
466            | Command::ExecuteSubscribe { .. }
467            | Command::CopyToPreflight { .. }
468            | Command::ExecuteCopyTo { .. }
469            | Command::ExecuteSideEffectingFunc { .. }
470            | Command::LookupConnection { .. }
471            | Command::RegisterFrontendPeek { .. }
472            | Command::UnregisterFrontendPeek { .. }
473            | Command::ExplainTimestamp { .. }
474            | Command::FrontendStatementLogging(..)
475            | Command::InjectAuditEvents { .. } => None,
476        }
477    }
478}
479
480#[derive(Debug)]
481pub struct Response<T> {
482    pub result: Result<T, AdapterError>,
483    pub session: Session,
484    pub otel_ctx: OpenTelemetryContext,
485}
486
487#[derive(Debug, Clone, Copy)]
488pub struct SuperuserAttribute(pub Option<bool>);
489
490/// The response to [`Client::startup`](crate::Client::startup).
491#[derive(Derivative)]
492#[derivative(Debug)]
493pub struct StartupResponse {
494    /// RoleId for the user.
495    pub role_id: RoleId,
496    /// The role's superuser attribute in the Catalog.
497    /// This attribute is None for Cloud. Cloud is able
498    /// to derive the role's superuser status from
499    /// external_metadata_rx.
500    pub superuser_attribute: SuperuserAttribute,
501    /// A future that completes when all necessary Builtin Table writes have completed.
502    #[derivative(Debug = "ignore")]
503    pub write_notify: BuiltinTableAppendNotify,
504    /// Map of (name, VarInput::Flat) tuples of session default variables that should be set.
505    pub session_defaults: BTreeMap<String, OwnedVarInput>,
506    pub catalog: Arc<Catalog>,
507    pub storage_collections:
508        Arc<dyn mz_storage_client::storage_collections::StorageCollections + Send + Sync>,
509    pub transient_id_gen: Arc<TransientIdGen>,
510    pub optimizer_metrics: OptimizerMetrics,
511    pub persist_client: PersistClient,
512    pub statement_logging_frontend: StatementLoggingFrontend,
513}
514
515#[derive(Derivative)]
516#[derivative(Debug)]
517pub struct SASLChallengeResponse {
518    pub iteration_count: usize,
519    /// Base64-encoded salt for the SASL challenge.
520    pub salt: String,
521    pub nonce: String,
522}
523
524#[derive(Derivative)]
525#[derivative(Debug)]
526pub struct SASLVerifyProofResponse {
527    pub verifier: String,
528}
529
530// Facile implementation for `StartupResponse`, which does not use the `allowed`
531// feature of `ClientTransmitter`.
532impl Transmittable for StartupResponse {
533    type Allowed = bool;
534    fn to_allowed(&self) -> Self::Allowed {
535        true
536    }
537}
538
539/// The response to [`SessionClient::dump_catalog`](crate::SessionClient::dump_catalog).
540#[derive(Debug, Clone)]
541pub struct CatalogDump(String);
542
543impl CatalogDump {
544    pub fn new(raw: String) -> Self {
545        CatalogDump(raw)
546    }
547
548    pub fn into_string(self) -> String {
549        self.0
550    }
551}
552
553impl Transmittable for CatalogDump {
554    type Allowed = bool;
555    fn to_allowed(&self) -> Self::Allowed {
556        true
557    }
558}
559
560impl Transmittable for SystemVars {
561    type Allowed = bool;
562    fn to_allowed(&self) -> Self::Allowed {
563        true
564    }
565}
566
567/// The response to [`SessionClient::execute`](crate::SessionClient::execute).
568#[derive(EnumKind, Derivative)]
569#[derivative(Debug)]
570#[enum_kind(ExecuteResponseKind, derive(PartialOrd, Ord))]
571pub enum ExecuteResponse {
572    /// The default privileges were altered.
573    AlteredDefaultPrivileges,
574    /// The requested object was altered.
575    AlteredObject(ObjectType),
576    /// The role was altered.
577    AlteredRole,
578    /// The system configuration was altered.
579    AlteredSystemConfiguration,
580    /// The requested cursor was closed.
581    ClosedCursor,
582    /// The provided comment was created.
583    Comment,
584    /// The specified number of rows were copied into the requested output.
585    Copied(usize),
586    /// The response for a COPY TO STDOUT query.
587    CopyTo {
588        format: mz_sql::plan::CopyFormat,
589        resp: Box<ExecuteResponse>,
590    },
591    CopyFrom {
592        /// Table we're copying into.
593        target_id: CatalogItemId,
594        /// Human-readable full name of the target table.
595        target_name: String,
596        columns: Vec<ColumnIndex>,
597        params: CopyFormatParams<'static>,
598        ctx_extra: ExecuteContextGuard,
599    },
600    /// The requested connection was created.
601    CreatedConnection,
602    /// The requested database was created.
603    CreatedDatabase,
604    /// The requested schema was created.
605    CreatedSchema,
606    /// The requested role was created.
607    CreatedRole,
608    /// The requested cluster was created.
609    CreatedCluster,
610    /// The requested cluster replica was created.
611    CreatedClusterReplica,
612    /// The requested index was created.
613    CreatedIndex,
614    /// The requested introspection subscribe was created.
615    CreatedIntrospectionSubscribe,
616    /// The requested secret was created.
617    CreatedSecret,
618    /// The requested sink was created.
619    CreatedSink,
620    /// The requested source was created.
621    CreatedSource,
622    /// The requested table was created.
623    CreatedTable,
624    /// The requested view was created.
625    CreatedView,
626    /// The requested views were created.
627    CreatedViews,
628    /// The requested materialized view was created.
629    CreatedMaterializedView,
630    /// The requested type was created.
631    CreatedType,
632    /// The requested network policy was created.
633    CreatedNetworkPolicy,
634    /// The requested prepared statement was removed.
635    Deallocate { all: bool },
636    /// The requested cursor was declared.
637    DeclaredCursor,
638    /// The specified number of rows were deleted from the requested table.
639    Deleted(usize),
640    /// The temporary objects associated with the session have been discarded.
641    DiscardedTemp,
642    /// All state associated with the session has been discarded.
643    DiscardedAll,
644    /// The requested object was dropped.
645    DroppedObject(ObjectType),
646    /// The requested objects were dropped.
647    DroppedOwned,
648    /// The provided query was empty.
649    EmptyQuery,
650    /// Fetch results from a cursor.
651    Fetch {
652        /// The name of the cursor from which to fetch results.
653        name: String,
654        /// The number of results to fetch.
655        count: Option<FetchDirection>,
656        /// How long to wait for results to arrive.
657        timeout: ExecuteTimeout,
658        ctx_extra: ExecuteContextGuard,
659    },
660    /// The requested privilege was granted.
661    GrantedPrivilege,
662    /// The requested role was granted.
663    GrantedRole,
664    /// The specified number of rows were inserted into the requested table.
665    Inserted(usize),
666    /// The specified prepared statement was created.
667    Prepare,
668    /// A user-requested warning was raised.
669    Raised,
670    /// The requested objects were reassigned.
671    ReassignOwned,
672    /// The requested privilege was revoked.
673    RevokedPrivilege,
674    /// The requested role was revoked.
675    RevokedRole,
676    /// Rows will be delivered via the specified stream.
677    SendingRowsStreaming {
678        #[derivative(Debug = "ignore")]
679        rows: Pin<Box<dyn Stream<Item = PeekResponseUnary> + Send + Sync>>,
680        instance_id: ComputeInstanceId,
681        strategy: StatementExecutionStrategy,
682    },
683    /// Rows are known to be available immediately, and thus the execution is
684    /// considered ended in the coordinator.
685    SendingRowsImmediate {
686        #[derivative(Debug = "ignore")]
687        rows: Box<dyn RowIterator + Send + Sync>,
688    },
689    /// The specified variable was set to a new value.
690    SetVariable {
691        name: String,
692        /// Whether the operation was a `RESET` rather than a set.
693        reset: bool,
694    },
695    /// A new transaction was started.
696    StartedTransaction,
697    /// Updates to the requested source or view will be streamed to the
698    /// contained receiver.
699    Subscribing {
700        rx: RowBatchStream,
701        ctx_extra: ExecuteContextGuard,
702        instance_id: ComputeInstanceId,
703    },
704    /// The active transaction committed.
705    TransactionCommitted {
706        /// Session parameters that changed because the transaction ended.
707        params: BTreeMap<&'static str, String>,
708    },
709    /// The active transaction rolled back.
710    TransactionRolledBack {
711        /// Session parameters that changed because the transaction ended.
712        params: BTreeMap<&'static str, String>,
713    },
714    /// The specified number of rows were updated in the requested table.
715    Updated(usize),
716    /// A connection was validated.
717    ValidatedConnection,
718}
719
720impl TryFrom<&Statement<Raw>> for ExecuteResponse {
721    type Error = ();
722
723    /// Returns Ok if this Statement always produces a single, trivial ExecuteResponse.
724    fn try_from(stmt: &Statement<Raw>) -> Result<Self, Self::Error> {
725        let resp_kinds = Plan::generated_from(&stmt.into())
726            .iter()
727            .map(ExecuteResponse::generated_from)
728            .flatten()
729            .cloned()
730            .collect::<BTreeSet<ExecuteResponseKind>>();
731        let resps = resp_kinds
732            .iter()
733            .map(|r| (*r).try_into())
734            .collect::<Result<Vec<ExecuteResponse>, _>>();
735        // Check if this statement's possible plans yield exactly one possible ExecuteResponse.
736        if let Ok(resps) = resps {
737            if resps.len() == 1 {
738                return Ok(resps.into_element());
739            }
740        }
741        let resp = match stmt {
742            Statement::DropObjects(DropObjectsStatement { object_type, .. }) => {
743                ExecuteResponse::DroppedObject((*object_type).into())
744            }
745            Statement::AlterObjectRename(AlterObjectRenameStatement { object_type, .. })
746            | Statement::AlterOwner(AlterOwnerStatement { object_type, .. }) => {
747                ExecuteResponse::AlteredObject((*object_type).into())
748            }
749            _ => return Err(()),
750        };
751        // Ensure that if the planner ever adds possible plans we complain here.
752        soft_assert_no_log!(
753            resp_kinds.len() == 1
754                && resp_kinds.first().expect("must exist") == &ExecuteResponseKind::from(&resp),
755            "ExecuteResponses out of sync with planner"
756        );
757        Ok(resp)
758    }
759}
760
761impl TryInto<ExecuteResponse> for ExecuteResponseKind {
762    type Error = ();
763
764    /// Attempts to convert into an ExecuteResponse. Returns an error if not possible without
765    /// actually executing a statement.
766    fn try_into(self) -> Result<ExecuteResponse, Self::Error> {
767        match self {
768            ExecuteResponseKind::AlteredDefaultPrivileges => {
769                Ok(ExecuteResponse::AlteredDefaultPrivileges)
770            }
771            ExecuteResponseKind::AlteredObject => Err(()),
772            ExecuteResponseKind::AlteredRole => Ok(ExecuteResponse::AlteredRole),
773            ExecuteResponseKind::AlteredSystemConfiguration => {
774                Ok(ExecuteResponse::AlteredSystemConfiguration)
775            }
776            ExecuteResponseKind::ClosedCursor => Ok(ExecuteResponse::ClosedCursor),
777            ExecuteResponseKind::Comment => Ok(ExecuteResponse::Comment),
778            ExecuteResponseKind::Copied => Err(()),
779            ExecuteResponseKind::CopyTo => Err(()),
780            ExecuteResponseKind::CopyFrom => Err(()),
781            ExecuteResponseKind::CreatedConnection => Ok(ExecuteResponse::CreatedConnection),
782            ExecuteResponseKind::CreatedDatabase => Ok(ExecuteResponse::CreatedDatabase),
783            ExecuteResponseKind::CreatedSchema => Ok(ExecuteResponse::CreatedSchema),
784            ExecuteResponseKind::CreatedRole => Ok(ExecuteResponse::CreatedRole),
785            ExecuteResponseKind::CreatedCluster => Ok(ExecuteResponse::CreatedCluster),
786            ExecuteResponseKind::CreatedClusterReplica => {
787                Ok(ExecuteResponse::CreatedClusterReplica)
788            }
789            ExecuteResponseKind::CreatedIndex => Ok(ExecuteResponse::CreatedIndex),
790            ExecuteResponseKind::CreatedSecret => Ok(ExecuteResponse::CreatedSecret),
791            ExecuteResponseKind::CreatedSink => Ok(ExecuteResponse::CreatedSink),
792            ExecuteResponseKind::CreatedSource => Ok(ExecuteResponse::CreatedSource),
793            ExecuteResponseKind::CreatedTable => Ok(ExecuteResponse::CreatedTable),
794            ExecuteResponseKind::CreatedView => Ok(ExecuteResponse::CreatedView),
795            ExecuteResponseKind::CreatedViews => Ok(ExecuteResponse::CreatedViews),
796            ExecuteResponseKind::CreatedMaterializedView => {
797                Ok(ExecuteResponse::CreatedMaterializedView)
798            }
799            ExecuteResponseKind::CreatedNetworkPolicy => Ok(ExecuteResponse::CreatedNetworkPolicy),
800            ExecuteResponseKind::CreatedType => Ok(ExecuteResponse::CreatedType),
801            ExecuteResponseKind::Deallocate => Err(()),
802            ExecuteResponseKind::DeclaredCursor => Ok(ExecuteResponse::DeclaredCursor),
803            ExecuteResponseKind::Deleted => Err(()),
804            ExecuteResponseKind::DiscardedTemp => Ok(ExecuteResponse::DiscardedTemp),
805            ExecuteResponseKind::DiscardedAll => Ok(ExecuteResponse::DiscardedAll),
806            ExecuteResponseKind::DroppedObject => Err(()),
807            ExecuteResponseKind::DroppedOwned => Ok(ExecuteResponse::DroppedOwned),
808            ExecuteResponseKind::EmptyQuery => Ok(ExecuteResponse::EmptyQuery),
809            ExecuteResponseKind::Fetch => Err(()),
810            ExecuteResponseKind::GrantedPrivilege => Ok(ExecuteResponse::GrantedPrivilege),
811            ExecuteResponseKind::GrantedRole => Ok(ExecuteResponse::GrantedRole),
812            ExecuteResponseKind::Inserted => Err(()),
813            ExecuteResponseKind::Prepare => Ok(ExecuteResponse::Prepare),
814            ExecuteResponseKind::Raised => Ok(ExecuteResponse::Raised),
815            ExecuteResponseKind::ReassignOwned => Ok(ExecuteResponse::ReassignOwned),
816            ExecuteResponseKind::RevokedPrivilege => Ok(ExecuteResponse::RevokedPrivilege),
817            ExecuteResponseKind::RevokedRole => Ok(ExecuteResponse::RevokedRole),
818            ExecuteResponseKind::SetVariable => Err(()),
819            ExecuteResponseKind::StartedTransaction => Ok(ExecuteResponse::StartedTransaction),
820            ExecuteResponseKind::Subscribing => Err(()),
821            ExecuteResponseKind::TransactionCommitted => Err(()),
822            ExecuteResponseKind::TransactionRolledBack => Err(()),
823            ExecuteResponseKind::Updated => Err(()),
824            ExecuteResponseKind::ValidatedConnection => Ok(ExecuteResponse::ValidatedConnection),
825            ExecuteResponseKind::SendingRowsStreaming => Err(()),
826            ExecuteResponseKind::SendingRowsImmediate => Err(()),
827            ExecuteResponseKind::CreatedIntrospectionSubscribe => {
828                Ok(ExecuteResponse::CreatedIntrospectionSubscribe)
829            }
830        }
831    }
832}
833
834impl ExecuteResponse {
835    pub fn tag(&self) -> Option<String> {
836        use ExecuteResponse::*;
837        match self {
838            AlteredDefaultPrivileges => Some("ALTER DEFAULT PRIVILEGES".into()),
839            AlteredObject(o) => Some(format!("ALTER {}", o)),
840            AlteredRole => Some("ALTER ROLE".into()),
841            AlteredSystemConfiguration => Some("ALTER SYSTEM".into()),
842            ClosedCursor => Some("CLOSE CURSOR".into()),
843            Comment => Some("COMMENT".into()),
844            Copied(n) => Some(format!("COPY {}", n)),
845            CopyTo { .. } => None,
846            CopyFrom { .. } => None,
847            CreatedConnection { .. } => Some("CREATE CONNECTION".into()),
848            CreatedDatabase { .. } => Some("CREATE DATABASE".into()),
849            CreatedSchema { .. } => Some("CREATE SCHEMA".into()),
850            CreatedRole => Some("CREATE ROLE".into()),
851            CreatedCluster { .. } => Some("CREATE CLUSTER".into()),
852            CreatedClusterReplica { .. } => Some("CREATE CLUSTER REPLICA".into()),
853            CreatedIndex { .. } => Some("CREATE INDEX".into()),
854            CreatedSecret { .. } => Some("CREATE SECRET".into()),
855            CreatedSink { .. } => Some("CREATE SINK".into()),
856            CreatedSource { .. } => Some("CREATE SOURCE".into()),
857            CreatedTable { .. } => Some("CREATE TABLE".into()),
858            CreatedView { .. } => Some("CREATE VIEW".into()),
859            CreatedViews { .. } => Some("CREATE VIEWS".into()),
860            CreatedMaterializedView { .. } => Some("CREATE MATERIALIZED VIEW".into()),
861            CreatedType => Some("CREATE TYPE".into()),
862            CreatedNetworkPolicy => Some("CREATE NETWORKPOLICY".into()),
863            Deallocate { all } => Some(format!("DEALLOCATE{}", if *all { " ALL" } else { "" })),
864            DeclaredCursor => Some("DECLARE CURSOR".into()),
865            Deleted(n) => Some(format!("DELETE {}", n)),
866            DiscardedTemp => Some("DISCARD TEMP".into()),
867            DiscardedAll => Some("DISCARD ALL".into()),
868            DroppedObject(o) => Some(format!("DROP {o}")),
869            DroppedOwned => Some("DROP OWNED".into()),
870            EmptyQuery => None,
871            Fetch { .. } => None,
872            GrantedPrivilege => Some("GRANT".into()),
873            GrantedRole => Some("GRANT ROLE".into()),
874            Inserted(n) => {
875                // "On successful completion, an INSERT command returns a
876                // command tag of the form `INSERT <oid> <count>`."
877                //     -- https://www.postgresql.org/docs/11/sql-insert.html
878                //
879                // OIDs are a PostgreSQL-specific historical quirk, but we
880                // can return a 0 OID to indicate that the table does not
881                // have OIDs.
882                Some(format!("INSERT 0 {}", n))
883            }
884            Prepare => Some("PREPARE".into()),
885            Raised => Some("RAISE".into()),
886            ReassignOwned => Some("REASSIGN OWNED".into()),
887            RevokedPrivilege => Some("REVOKE".into()),
888            RevokedRole => Some("REVOKE ROLE".into()),
889            SendingRowsStreaming { .. } | SendingRowsImmediate { .. } => None,
890            SetVariable { reset: true, .. } => Some("RESET".into()),
891            SetVariable { reset: false, .. } => Some("SET".into()),
892            StartedTransaction { .. } => Some("BEGIN".into()),
893            Subscribing { .. } => None,
894            TransactionCommitted { .. } => Some("COMMIT".into()),
895            TransactionRolledBack { .. } => Some("ROLLBACK".into()),
896            Updated(n) => Some(format!("UPDATE {}", n)),
897            ValidatedConnection => Some("VALIDATE CONNECTION".into()),
898            CreatedIntrospectionSubscribe => Some("CREATE INTROSPECTION SUBSCRIBE".into()),
899        }
900    }
901
902    /// Expresses which [`PlanKind`] generate which set of [`ExecuteResponseKind`].
903    /// `ExecuteResponseKind::Canceled` could be generated at any point as well, but that is
904    /// excluded from this function.
905    pub fn generated_from(plan: &PlanKind) -> &'static [ExecuteResponseKind] {
906        use ExecuteResponseKind::*;
907        use PlanKind::*;
908
909        match plan {
910            AbortTransaction => &[TransactionRolledBack],
911            AlterClusterRename
912            | AlterClusterSwap
913            | AlterCluster
914            | AlterClusterReplicaRename
915            | AlterOwner
916            | AlterItemRename
917            | AlterRetainHistory
918            | AlterSourceTimestampInterval
919            | AlterNoop
920            | AlterSchemaRename
921            | AlterSchemaSwap
922            | AlterSecret
923            | AlterConnection
924            | AlterSource
925            | AlterSink
926            | AlterTableAddColumn
927            | AlterMaterializedViewApplyReplacement
928            | AlterNetworkPolicy => &[AlteredObject],
929            AlterDefaultPrivileges => &[AlteredDefaultPrivileges],
930            AlterSetCluster => &[AlteredObject],
931            AlterRole => &[AlteredRole],
932            AlterSystemSet | AlterSystemReset | AlterSystemResetAll => {
933                &[AlteredSystemConfiguration]
934            }
935            Close => &[ClosedCursor],
936            PlanKind::CopyFrom => &[ExecuteResponseKind::CopyFrom, ExecuteResponseKind::Copied],
937            PlanKind::CopyTo => &[ExecuteResponseKind::Copied],
938            PlanKind::Comment => &[ExecuteResponseKind::Comment],
939            CommitTransaction => &[TransactionCommitted, TransactionRolledBack],
940            CreateConnection => &[CreatedConnection],
941            CreateDatabase => &[CreatedDatabase],
942            CreateSchema => &[CreatedSchema],
943            CreateRole => &[CreatedRole],
944            CreateCluster => &[CreatedCluster],
945            CreateClusterReplica => &[CreatedClusterReplica],
946            CreateSource | CreateSources => &[CreatedSource],
947            CreateSecret => &[CreatedSecret],
948            CreateSink => &[CreatedSink],
949            CreateTable => &[CreatedTable],
950            CreateView => &[CreatedView],
951            CreateMaterializedView => &[CreatedMaterializedView],
952            CreateIndex => &[CreatedIndex],
953            CreateType => &[CreatedType],
954            PlanKind::Deallocate => &[ExecuteResponseKind::Deallocate],
955            CreateNetworkPolicy => &[CreatedNetworkPolicy],
956            Declare => &[DeclaredCursor],
957            DiscardTemp => &[DiscardedTemp],
958            DiscardAll => &[DiscardedAll],
959            DropObjects => &[DroppedObject],
960            DropOwned => &[DroppedOwned],
961            PlanKind::EmptyQuery => &[ExecuteResponseKind::EmptyQuery],
962            ExplainPlan | ExplainPushdown | ExplainTimestamp | Select | ShowAllVariables
963            | ShowCreate | ShowColumns | ShowVariable | InspectShard | ExplainSinkSchema => &[
964                ExecuteResponseKind::CopyTo,
965                SendingRowsStreaming,
966                SendingRowsImmediate,
967            ],
968            Execute | ReadThenWrite => &[
969                Deleted,
970                Inserted,
971                SendingRowsStreaming,
972                SendingRowsImmediate,
973                Updated,
974            ],
975            PlanKind::Fetch => &[ExecuteResponseKind::Fetch],
976            GrantPrivileges => &[GrantedPrivilege],
977            GrantRole => &[GrantedRole],
978            Insert => &[Inserted, SendingRowsImmediate],
979            PlanKind::Prepare => &[ExecuteResponseKind::Prepare],
980            PlanKind::Raise => &[ExecuteResponseKind::Raised],
981            PlanKind::ReassignOwned => &[ExecuteResponseKind::ReassignOwned],
982            RevokePrivileges => &[RevokedPrivilege],
983            RevokeRole => &[RevokedRole],
984            PlanKind::SetVariable | ResetVariable | PlanKind::SetTransaction => {
985                &[ExecuteResponseKind::SetVariable]
986            }
987            PlanKind::Subscribe => &[Subscribing, ExecuteResponseKind::CopyTo],
988            StartTransaction => &[StartedTransaction],
989            SideEffectingFunc => &[SendingRowsStreaming, SendingRowsImmediate],
990            ValidateConnection => &[ExecuteResponseKind::ValidatedConnection],
991        }
992    }
993}
994
995/// This implementation is meant to ensure that we maintain updated information
996/// about which types of `ExecuteResponse`s are permitted to be sent, which will
997/// be a function of which plan we're executing.
998impl Transmittable for ExecuteResponse {
999    type Allowed = ExecuteResponseKind;
1000    fn to_allowed(&self) -> Self::Allowed {
1001        ExecuteResponseKind::from(self)
1002    }
1003}