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

Method handle_execute_inner

src/adapter/src/coord/command_handler.rs:1169–1626  ·  view source on GitHub ↗
(
        &mut self,
        stmt: Arc<Statement<Raw>>,
        params: Params,
        mut ctx: ExecuteContext,
    )

Source from the content-addressed store, hash-verified

1167
1168 #[instrument(name = "coord::handle_execute_inner", fields(stmt = stmt.to_ast_string_redacted()))]
1169 pub(crate) async fn handle_execute_inner(
1170 &mut self,
1171 stmt: Arc<Statement<Raw>>,
1172 params: Params,
1173 mut ctx: ExecuteContext,
1174 ) {
1175 // This comment describes the various ways DDL can execute (the ordered operations: name
1176 // resolve, purify, plan, sequence), all of which are managed by this function. DDL has
1177 // three notable properties that all partially interact.
1178 //
1179 // 1. Most DDL statements (and a few others) support single-statement transaction delayed
1180 // execution. This occurs when a session executes `BEGIN`, a single DDL, then `COMMIT`.
1181 // We announce success of the single DDL when it is executed, but do not attempt to plan
1182 // or sequence it until `COMMIT`, which is able to error if needed while sequencing the
1183 // DDL (this behavior is Postgres-compatible). The purpose of this is because some
1184 // drivers or tools wrap all statements in `BEGIN` and `COMMIT` and we would like them to
1185 // work. When the single DDL is announced as successful we also put the session's
1186 // transaction ops into `SingleStatement` which will produce an error if any other
1187 // statement is run in the transaction except `COMMIT`. Additionally, this will cause
1188 // `handle_execute_inner` to stop further processing (no planning, etc.) of the
1189 // statement.
1190 // 2. A few other DDL statements (`ALTER .. RENAME/SWAP`) enter the `DDL` ops which allows
1191 // any number of only these DDL statements to be executed in a transaction. During
1192 // sequencing we run an incremental catalog dry run against in-memory transaction state
1193 // and store the resulting `CatalogState` in `TransactionOps::DDL`, but nothing is yet
1194 // committed to the durable catalog. At `COMMIT`, all accumulated ops are applied in one
1195 // catalog transaction. The purpose of this is to allow multiple, atomic renames in the
1196 // same transaction.
1197 // 3. Some DDLs do off-thread work during purification or sequencing that is expensive or
1198 // makes network calls (interfacing with secrets, optimization of views/indexes, source
1199 // purification). These must guarantee correctness when they return to the main
1200 // coordinator thread because the catalog state could have changed while they were doing
1201 // the off-thread work. Previously we would use `PlanValidity::Checks` to specify a bunch
1202 // of IDs that we needed to exist. We discovered the way we were doing that was not
1203 // always correct. Instead of attempting to get that completely right, we have opted to
1204 // serialize DDL. Getting this right is difficult because catalog changes can affect name
1205 // resolution, planning, sequencing, and optimization. Correctly writing logic that is
1206 // aware of all possible catalog changes that would affect any of those parts is not
1207 // something our current code has been designed to be helpful at. Even if a DDL statement
1208 // is doing off-thread work, another DDL must not yet execute at all. Executing these
1209 // serially will guarantee that no off-thread work has affected the state of the catalog.
1210 // This is done by adding a VecDeque of deferred statements and a lock to the
1211 // Coordinator. When a DDL is run in `handle_execute_inner` (after applying whatever
1212 // transaction ops are needed to the session as described above), it attempts to own the
1213 // lock (a tokio Mutex). If acquired, it stashes the lock in the connection`s `ConnMeta`
1214 // struct in `active_conns` and proceeds. The lock is dropped at transaction end in
1215 // `clear_transaction` and a message sent to the Coordinator to execute the next queued
1216 // DDL. If the lock could not be acquired, the DDL is put into the VecDeque where it
1217 // awaits dequeuing caused by the lock being released.
1218
1219 // Verify that this statement type can be executed in the current
1220 // transaction state.
1221 match ctx.session().transaction() {
1222 // By this point we should be in a running transaction.
1223 TransactionStatus::Default => unreachable!(),
1224
1225 // Failed transactions have already been checked in pgwire for a safe statement
1226 // (COMMIT, ROLLBACK, etc.) and can proceed.

Calls 15

cloneFunction · 0.85
resolveFunction · 0.85
spawnFunction · 0.85
check_usageFunction · 0.85
purify_statementFunction · 0.85
transient_revisionMethod · 0.80
transaction_mutMethod · 0.80
add_opsMethod · 0.80
try_lock_ownedMethod · 0.80
expectMethod · 0.80
is_someMethod · 0.80

Tested by

no test coverage detected