Introduces a specific input and keys to the order, along with its characteristics. This method places a next element in the order, and updates the associated state about other candidates, including which columns are now bound and which potential keys are available to consider (both arranged, and unarranged).
(&mut self, input: usize)
| 1263 | /// about other candidates, including which columns are now bound and which potential |
| 1264 | /// keys are available to consider (both arranged, and unarranged). |
| 1265 | fn order_input(&mut self, input: usize) { |
| 1266 | self.placed[input] = true; |
| 1267 | for (equivalence, expr_index) in self.reverse_equivalences[input].iter() { |
| 1268 | if !self.equivalences_active[*equivalence] { |
| 1269 | // Placing `input` *may* activate the equivalence. Each of its columns |
| 1270 | // come in to scope, which may result in an expression in `equivalence` |
| 1271 | // becoming fully defined (when its support is contained in placed inputs) |
| 1272 | let fully_supported = self |
| 1273 | .input_mapper |
| 1274 | .lookup_inputs(&self.equivalences[*equivalence][*expr_index]) |
| 1275 | .all(|i| self.placed[i]); |
| 1276 | if fully_supported { |
| 1277 | self.equivalences_active[*equivalence] = true; |
| 1278 | for expr in self.equivalences[*equivalence].iter() { |
| 1279 | // find the relations that columns in the expression belong to |
| 1280 | let mut rels = self.input_mapper.lookup_inputs(expr); |
| 1281 | // Skip the expression if |
| 1282 | // * the expression is a literal -> this would translate |
| 1283 | // to `rels` being empty |
| 1284 | // * the expression has columns belonging to more than |
| 1285 | // one relation -> TODO: see how we can plan better in |
| 1286 | // this case. Arguably, if this happens, it would |
| 1287 | // not be unreasonable to ask the user to write the |
| 1288 | // query better. |
| 1289 | if let Some(rel) = rels.next() { |
| 1290 | if rels.next().is_none() { |
| 1291 | let expr = self.input_mapper.map_expr_to_local(expr.clone()); |
| 1292 | |
| 1293 | // Update bound columns. |
| 1294 | self.bound[rel].push(expr); |
| 1295 | self.bound[rel].sort(); |
| 1296 | |
| 1297 | // Reconsider all available arrangements. |
| 1298 | for (pos, key) in self.arrangements[rel].iter().enumerate() { |
| 1299 | if !self.arrangement_active[rel].contains(&pos) { |
| 1300 | // TODO: support the restoration of the |
| 1301 | // following original lines, which have been |
| 1302 | // commented out because Materialize may |
| 1303 | // panic otherwise. The original line and comments |
| 1304 | // here are: |
| 1305 | // Determine if the arrangement is viable, which happens when the |
| 1306 | // support of its key is all bound. |
| 1307 | // if key.iter().all(|k| k.support().iter().all(|c| self.bound[*rel].contains(&ScalarExpr::Column(*c))) { |
| 1308 | |
| 1309 | // Determine if the arrangement is viable, |
| 1310 | // which happens when all its key components are bound. |
| 1311 | if key.iter().all(|k| self.bound[rel].contains(k)) { |
| 1312 | self.arrangement_active[rel].push(pos); |
| 1313 | // TODO: This could be pre-computed, as it is independent of the order. |
| 1314 | let is_unique = self.unique_arrangement[rel][pos]; |
| 1315 | self.priority_queue.push(( |
| 1316 | JoinInputCharacteristics::new( |
| 1317 | is_unique, |
| 1318 | key.len(), |
| 1319 | true, |
| 1320 | self.cardinalities[rel], |
| 1321 | self.filters[rel].clone(), |
| 1322 | rel, |
no test coverage detected