MCPcopy Create free account
hub / github.com/MaterializeInc/materialize / unroll_sql_execute

Method unroll_sql_execute

src/adapter/src/client.rs:846–977  ·  view source on GitHub ↗

If the named portal binds a SQL `EXECUTE `, resolve the prepared statement, install a fresh portal for the inner statement (carrying the EXECUTE's actual parameter values), and return that portal's name so the caller can run `try_frontend_peek` against it. Only ever unrolls one level: the parser rejects `PREPARE foo AS EXECUTE bar` (matching Postgres), so the inner statement is guarante

(
        &mut self,
        portal_name: String,
        outer_ctx_extra: &mut Option<ExecuteContextGuard>,
    )

Source from the content-addressed store, hash-verified

844 /// the caller can thread it into `try_frontend_peek`, which reuses it
845 /// instead of taking its own.
846 async fn unroll_sql_execute(
847 &mut self,
848 portal_name: String,
849 outer_ctx_extra: &mut Option<ExecuteContextGuard>,
850 ) -> Result<(String, Option<Arc<Catalog>>), AdapterError> {
851 let (stmt, params, outer_logging, outer_lifecycle_timestamps) = {
852 let session = self.session.as_ref().expect("SessionClient invariant");
853 let portal = match session.get_portal_unverified(&portal_name) {
854 Some(p) => p,
855 // No portal: let `try_frontend_peek` surface the
856 // standard "missing portal" error.
857 None => return Ok((portal_name, None)),
858 };
859 match &portal.stmt {
860 Some(stmt) => (
861 Arc::clone(stmt),
862 portal.parameters.clone(),
863 Arc::clone(&portal.logging),
864 portal.lifecycle_timestamps.clone(),
865 ),
866 None => return Ok((portal_name, None)),
867 }
868 };
869
870 // Only EXECUTE statements need unrolling. Bail out before taking a
871 // catalog snapshot in the (overwhelmingly common) non-EXECUTE case.
872 if !matches!(&*stmt, Statement::Execute(_)) {
873 return Ok((portal_name, None));
874 }
875
876 let catalog = self.catalog_snapshot("unroll_sql_execute").await;
877
878 // Validate the outer EXECUTE portal against the (possibly newer)
879 // catalog: ensures the recorded portal description still matches
880 // what describing the EXECUTE would produce now.
881 {
882 let session = self.session.as_mut().expect("SessionClient invariant");
883 Coordinator::verify_portal(&catalog, session, &portal_name)?;
884 }
885
886 // Bump query_total for the outer EXECUTE itself. The inner
887 // statement gets its own increment inside `try_frontend_peek_inner`
888 // (or, on bailout, in the coordinator's `handle_execute`).
889 {
890 let session = self.session.as_ref().expect("SessionClient invariant");
891 session
892 .metrics()
893 .query_total(&[
894 metrics::session_type_label_value(session.user()),
895 metrics::statement_type_label_value(&stmt),
896 ])
897 .inc();
898 }
899
900 // Begin EXECUTE-level statement logging up front, so that planning
901 // errors below produce an `Errored` end-event in
902 // `mz_statement_execution_history` rather than no entry at all.
903 //

Callers 1

executeMethod · 0.80

Calls 15

cloneFunction · 0.85
session_type_label_valueFunction · 0.85
expectMethod · 0.80
get_portal_unverifiedMethod · 0.80
query_totalMethod · 0.80
is_noneMethod · 0.80
log_began_executionMethod · 0.80
log_ended_executionMethod · 0.80
as_refMethod · 0.45
cloneMethod · 0.45

Tested by

no test coverage detected