Bulk update: scan documents matching filters, apply field updates. When `returning` is `None`, returns affected row count as JSON: `{"affected": N}`. When `returning` is `Some(spec)`, returns a `RowsPayload` with the post-update documents projected per spec. If 0 rows match, returns an empty `RowsPayload`.
(
&mut self,
task: &ExecutionTask,
tid: u64,
params: BulkUpdateParams<'_>,
)
| 101 | /// post-update documents projected per spec. If 0 rows match, returns |
| 102 | /// an empty `RowsPayload`. |
| 103 | pub(in crate::data::executor) fn execute_bulk_update( |
| 104 | &mut self, |
| 105 | task: &ExecutionTask, |
| 106 | tid: u64, |
| 107 | params: BulkUpdateParams<'_>, |
| 108 | ) -> Response { |
| 109 | let BulkUpdateParams { |
| 110 | collection, |
| 111 | filter_bytes, |
| 112 | updates, |
| 113 | returning, |
| 114 | ollp_predicted_surrogates, |
| 115 | } = params; |
| 116 | debug!(core = self.core_id, %collection, has_returning = returning.is_some(), "bulk update"); |
| 117 | |
| 118 | // Reject direct updates to generated columns. |
| 119 | let config_key = (crate::types::TenantId::new(tid), collection.to_string()); |
| 120 | if let Some(config) = self.doc_configs.get(&config_key) |
| 121 | && let Err(e) = super::generated::check_generated_readonly( |
| 122 | updates, |
| 123 | &config.enforcement.generated_columns, |
| 124 | ) |
| 125 | { |
| 126 | return self.response_error(task, e); |
| 127 | } |
| 128 | |
| 129 | // Empty `filter_bytes` means "no WHERE clause" — match every row. |
| 130 | let filters: Vec<ScanFilter> = if filter_bytes.is_empty() { |
| 131 | Vec::new() |
| 132 | } else { |
| 133 | match zerompk::from_msgpack(filter_bytes) { |
| 134 | Ok(f) => f, |
| 135 | Err(e) => { |
| 136 | return self.response_error( |
| 137 | task, |
| 138 | ErrorCode::Internal { |
| 139 | detail: format!("deserialize filters: {e}"), |
| 140 | }, |
| 141 | ); |
| 142 | } |
| 143 | } |
| 144 | }; |
| 145 | |
| 146 | let matching_ids = match self.scan_matching_documents(tid, collection, &filters) { |
| 147 | Ok(ids) => ids, |
| 148 | Err(e) => { |
| 149 | return self.response_error( |
| 150 | task, |
| 151 | ErrorCode::Internal { |
| 152 | detail: e.to_string(), |
| 153 | }, |
| 154 | ); |
| 155 | } |
| 156 | }; |
| 157 | |
| 158 | // OLLP verification: when predicted surrogates are provided, compare |
| 159 | // against the actual matching set. On mismatch return OllpRetryRequired |
| 160 | // WITHOUT writing. The set comparison is deterministic: both sides are |
no test coverage detected