This method inlines expressions with a single use. This method only inlines expressions; it does not delete expressions that are no longer referenced. The `remove_undemanded()` method does that, and should likely be used after this method. Inlining replaces column references when the referred-to item is either another column reference, or the only referrer of its referent. This is most common af
(&mut self)
| 1253 | /// ); |
| 1254 | /// ``` |
| 1255 | pub fn inline_expressions(&mut self) { |
| 1256 | // Local copy of input_arity to avoid borrowing `self` in closures. |
| 1257 | let input_arity = self.input_arity; |
| 1258 | // Reference counts track the number of places that a reference occurs. |
| 1259 | let mut reference_count = vec![0; input_arity + self.expressions.len()]; |
| 1260 | // Increment reference counts for each use |
| 1261 | for expr in self.expressions.iter() { |
| 1262 | expr.visit_pre(&mut |e| { |
| 1263 | if let Some(i) = e.as_column() { |
| 1264 | reference_count[i] += 1; |
| 1265 | } |
| 1266 | }); |
| 1267 | } |
| 1268 | for (_, pred) in self.predicates.iter() { |
| 1269 | pred.visit_pre(&mut |e| { |
| 1270 | if let Some(i) = e.as_column() { |
| 1271 | reference_count[i] += 1; |
| 1272 | } |
| 1273 | }); |
| 1274 | } |
| 1275 | for proj in self.projection.iter() { |
| 1276 | reference_count[*proj] += 1; |
| 1277 | } |
| 1278 | |
| 1279 | // Determine which expressions should be inlined because they reference temporal expressions. |
| 1280 | let mut is_temporal = vec![false; input_arity]; |
| 1281 | for expr in self.expressions.iter() { |
| 1282 | // An express may contain a temporal expression, or reference a column containing such. |
| 1283 | is_temporal.push( |
| 1284 | OptimizableExpr::contains_temporal(expr) |
| 1285 | || expr.support().into_iter().any(|col| is_temporal[col]), |
| 1286 | ); |
| 1287 | } |
| 1288 | |
| 1289 | // Inline only those columns that 1. are expressions not inputs, and |
| 1290 | // 2a. are column references or literals or 2b. have a refcount of 1, |
| 1291 | // or 2c. reference temporal expressions (which cannot be evaluated). |
| 1292 | let mut should_inline = vec![false; reference_count.len()]; |
| 1293 | for i in (input_arity..reference_count.len()).rev() { |
| 1294 | if let Some(c) = self.expressions[i - input_arity].as_column() { |
| 1295 | should_inline[i] = true; |
| 1296 | // The reference count of the referenced column should be |
| 1297 | // incremented with the number of references |
| 1298 | // `self.expressions[i - input_arity]` has. |
| 1299 | // Subtract 1 because `self.expressions[i - input_arity]` is |
| 1300 | // itself a reference. |
| 1301 | reference_count[c] += reference_count[i] - 1; |
| 1302 | } else { |
| 1303 | should_inline[i] = reference_count[i] == 1 || is_temporal[i]; |
| 1304 | } |
| 1305 | } |
| 1306 | // Inline expressions per `should_inline`. |
| 1307 | self.perform_inlining(should_inline); |
| 1308 | // We can only inline column references in `self.projection`, but we should. |
| 1309 | for proj in self.projection.iter_mut() { |
| 1310 | if *proj >= self.input_arity { |
| 1311 | if let Some(i) = self.expressions[*proj - self.input_arity].as_column() { |
| 1312 | // TODO(mgree) !!! propagate name information to projection |