(
&mut self,
mut ctx: ExecuteContext,
plan: plan::InsertPlan,
)
| 2567 | |
| 2568 | #[instrument] |
| 2569 | pub(super) async fn sequence_insert( |
| 2570 | &mut self, |
| 2571 | mut ctx: ExecuteContext, |
| 2572 | plan: plan::InsertPlan, |
| 2573 | ) { |
| 2574 | // Normally, this would get checked when trying to add "write ops" to |
| 2575 | // the transaction but we go down diverging paths below, based on |
| 2576 | // whether the INSERT is only constant values or not. |
| 2577 | // |
| 2578 | // For the non-constant case we sequence an implicit read-then-write, |
| 2579 | // which messes with the transaction ops and would allow an implicit |
| 2580 | // read-then-write to sneak into a read-only transaction. |
| 2581 | if !ctx.session_mut().transaction().allows_writes() { |
| 2582 | ctx.retire(Err(AdapterError::ReadOnlyTransaction)); |
| 2583 | return; |
| 2584 | } |
| 2585 | if ctx |
| 2586 | .session() |
| 2587 | .vars() |
| 2588 | .transaction_isolation() |
| 2589 | .is_bounded_staleness() |
| 2590 | { |
| 2591 | ctx.retire(Err(AdapterError::BoundedStalenessReadOnly)); |
| 2592 | return; |
| 2593 | } |
| 2594 | |
| 2595 | // The structure of this code originates from a time where |
| 2596 | // `ReadThenWritePlan` was carrying an `MirRelationExpr` instead of an |
| 2597 | // optimized `MirRelationExpr`. |
| 2598 | // |
| 2599 | // Ideally, we would like to make the `selection.as_const().is_some()` |
| 2600 | // check on `plan.values` instead. However, `VALUES (1), (3)` statements |
| 2601 | // are planned as a Wrap($n, $vals) call, so until we can reduce |
| 2602 | // HirRelationExpr this will always returns false. |
| 2603 | // |
| 2604 | // Unfortunately, hitting the default path of the match below also |
| 2605 | // causes a lot of tests to fail, so we opted to go with the extra |
| 2606 | // `plan.values.clone()` statements when producing the `optimized_mir` |
| 2607 | // and re-optimize the values in the `sequence_read_then_write` call. |
| 2608 | let optimized_mir = if let Some(..) = &plan.values.as_const() { |
| 2609 | // We don't perform any optimizations on an expression that is already |
| 2610 | // a constant for writes, as we want to maximize bulk-insert throughput. |
| 2611 | let expr = return_if_err!( |
| 2612 | plan.values |
| 2613 | .clone() |
| 2614 | .lower(self.catalog().system_config(), None), |
| 2615 | ctx |
| 2616 | ); |
| 2617 | OptimizedMirRelationExpr(expr) |
| 2618 | } else { |
| 2619 | // Collect optimizer parameters. |
| 2620 | let optimizer_config = optimize::OptimizerConfig::from(self.catalog().system_config()); |
| 2621 | |
| 2622 | // (`optimize::view::Optimizer` has a special case for constant queries.) |
| 2623 | let mut optimizer = optimize::view::Optimizer::new(optimizer_config, None); |
| 2624 | |
| 2625 | // HIR ⇒ MIR lowering and MIR ⇒ MIR optimization (local) |
| 2626 | return_if_err!(optimizer.optimize(plan.values.clone()), ctx) |
no test coverage detected