| 225 | } |
| 226 | |
| 227 | static ExecutionPlan *_tie_segments |
| 228 | ( |
| 229 | ExecutionPlan **segments, |
| 230 | uint segment_count |
| 231 | ) { |
| 232 | FT_FilterNode *ft = NULL; // filters following WITH |
| 233 | OpBase *connecting_op = NULL; // op connecting one segment to another |
| 234 | OpBase *prev_connecting_op = NULL; // root of previous segment |
| 235 | ExecutionPlan *prev_segment = NULL; |
| 236 | ExecutionPlan *current_segment = NULL; |
| 237 | AST *master_ast = QueryCtx_GetAST(); // top-level AST of plan |
| 238 | |
| 239 | //-------------------------------------------------------------------------- |
| 240 | // merge segments |
| 241 | //-------------------------------------------------------------------------- |
| 242 | |
| 243 | for(int i = 0; i < segment_count; i++) { |
| 244 | ExecutionPlan *segment = segments[i]; |
| 245 | AST *ast = segment->ast_segment; |
| 246 | |
| 247 | // find the first non-argument op with no children in this segment |
| 248 | prev_connecting_op = connecting_op; |
| 249 | // in the case of a single segment with FOREACH as its root, there is no |
| 250 | // tap (of the current definition) |
| 251 | // for instance: FOREACH(i in [i] | CREATE (n:N)) |
| 252 | // in any other case, there must be a tap |
| 253 | |
| 254 | ASSERT(_ExecutionPlan_HasLocateTaps(segment->root) == true); |
| 255 | |
| 256 | connecting_op = segment->root; |
| 257 | while(connecting_op->childCount > 0) { |
| 258 | connecting_op = connecting_op->children[0]; |
| 259 | } |
| 260 | |
| 261 | // tie the current segment's tap to the previous segment's root op |
| 262 | if(prev_segment != NULL) { |
| 263 | // validate the connecting operation |
| 264 | // the connecting operation may already have children |
| 265 | // if it's been attached to a previous scope |
| 266 | ASSERT(connecting_op->type == OPType_PROJECT || |
| 267 | connecting_op->type == OPType_AGGREGATE); |
| 268 | |
| 269 | ExecutionPlan_AddOp(connecting_op, prev_segment->root); |
| 270 | } |
| 271 | |
| 272 | //---------------------------------------------------------------------- |
| 273 | // build pattern comprehension ops |
| 274 | //---------------------------------------------------------------------- |
| 275 | |
| 276 | // WITH projections |
| 277 | if(prev_segment != NULL) { |
| 278 | const cypher_astnode_t *opening_clause = cypher_ast_query_get_clause(ast->root, 0); |
| 279 | ASSERT(cypher_astnode_type(opening_clause) == CYPHER_AST_WITH); |
| 280 | uint projections = cypher_ast_with_nprojections(opening_clause); |
| 281 | for (uint j = 0; j < projections; j++) { |
| 282 | const cypher_astnode_t *projection = cypher_ast_with_get_projection(opening_clause, j); |
| 283 | buildPatternComprehensionOps(prev_segment, connecting_op, projection); |
| 284 | buildPatternPathOps(prev_segment, connecting_op, projection); |
no test coverage detected