(
pipeline: Vec<pq::SqlTransform>,
ctx: &mut Context,
)
| 265 | } |
| 266 | |
| 267 | fn compile_loop( |
| 268 | pipeline: Vec<pq::SqlTransform>, |
| 269 | ctx: &mut Context, |
| 270 | ) -> Result<Vec<pq::SqlTransform>> { |
| 271 | // split the pipeline |
| 272 | let (mut initial, mut following) = |
| 273 | pipeline.break_up(|t| matches!(t, pq::SqlTransform::Super(rq::Transform::Loop(_)))); |
| 274 | let loop_ = following.remove(0); |
| 275 | let step = loop_.into_super_and(|t| t.into_loop()).unwrap(); |
| 276 | let step = preprocess::preprocess(step, ctx)?; |
| 277 | |
| 278 | // determine columns of the initial table |
| 279 | let recursive_columns = ctx.anchor.determine_select_columns(&initial); |
| 280 | |
| 281 | // do the same thing we do when splitting a pipeline |
| 282 | // (defining new columns, redirecting cids) |
| 283 | let recursive_columns = pq::SqlTransform::Super(rq::Transform::Select(recursive_columns)); |
| 284 | initial.push(recursive_columns.clone()); |
| 285 | let step = anchor_split(&mut ctx.anchor, initial, step); |
| 286 | let from = step.first().unwrap().as_from().unwrap(); |
| 287 | let from = ctx.anchor.relation_instances.get(from).unwrap(); |
| 288 | let initial_tid = from.table_ref.source; |
| 289 | |
| 290 | let initial = ctx.anchor.table_decls.get_mut(&initial_tid).unwrap(); |
| 291 | |
| 292 | // compile initial |
| 293 | let initial = if let RelationStatus::NotYetDefined(rel) = initial.relation.take_to_define() { |
| 294 | compile_relation(rel, ctx)? |
| 295 | } else { |
| 296 | unreachable!() |
| 297 | }; |
| 298 | |
| 299 | // compile step (without producing CTEs) |
| 300 | ctx.push_query(); |
| 301 | ctx.query.allow_ctes = false; |
| 302 | |
| 303 | let step = compile_pipeline(step, ctx)?; |
| 304 | |
| 305 | ctx.pop_query(); |
| 306 | |
| 307 | // create a split between the loop SELECT statement and the following pipeline |
| 308 | let mut following = anchor_split(&mut ctx.anchor, vec![recursive_columns], following); |
| 309 | |
| 310 | let from = following.first_mut().unwrap(); |
| 311 | let from = from.as_from().unwrap(); |
| 312 | let from = ctx.anchor.relation_instances.get(from).unwrap(); |
| 313 | let from = &from.table_ref; |
| 314 | |
| 315 | // this will be table decl that references the whole loop expression |
| 316 | let loop_decl = ctx.anchor.table_decls.get_mut(&from.source).unwrap(); |
| 317 | |
| 318 | loop_decl.redirect_to = Some(initial_tid); |
| 319 | loop_decl.relation = RelationStatus::Defined; |
| 320 | |
| 321 | // push the whole thing into WITH of the main query |
| 322 | ctx.ctes.push(pq::Cte { |
| 323 | tid: from.source, |
| 324 | kind: pq::CteKind::Loop { initial, step }, |
no test coverage detected