try to replace given Conditional Traverse operation and a set of Filter operations with a single Index Scan operation
| 422 | // try to replace given Conditional Traverse operation and a set of Filter operations with |
| 423 | // a single Index Scan operation |
| 424 | void reduce_cond_op(ExecutionPlan *plan, OpCondTraverse *cond) { |
| 425 | // make sure there's an index for scanned label |
| 426 | const char *edge = AlgebraicExpression_Edge(cond->ae); |
| 427 | if(!edge) return; |
| 428 | |
| 429 | QGEdge *e = QueryGraph_GetEdgeByAlias(cond->op.plan->query_graph, edge); |
| 430 | if(QGEdge_RelationCount(e) != 1) return; |
| 431 | |
| 432 | const char *label = QGEdge_Relation(e, 0); |
| 433 | GraphContext *gc = QueryCtx_GetGraphCtx(); |
| 434 | Index idx = GraphContext_GetIndex(gc, label, NULL, 0, IDX_EXACT_MATCH, |
| 435 | SCHEMA_EDGE); |
| 436 | if(idx == NULL) return; |
| 437 | |
| 438 | // get all applicable filter for index |
| 439 | OpFilter **filters = _applicableFilters((OpBase *)cond, edge, idx); |
| 440 | |
| 441 | // no filters, return |
| 442 | uint filters_count = array_len(filters); |
| 443 | if(filters_count == 0) goto cleanup; |
| 444 | |
| 445 | RSIndex *rs_idx = Index_RSIndex(idx); |
| 446 | FT_FilterNode *root = _Concat_Filters(filters); |
| 447 | OpBase *indexOp = NewEdgeIndexScanOp(cond->op.plan, cond->graph, e, rs_idx, |
| 448 | root); |
| 449 | |
| 450 | // The OPType_ALL_NODE_SCAN operation is redundant |
| 451 | // because OPType_EDGE_BY_INDEX_SCAN will resolve source nodes |
| 452 | if(cond->op.children[0]->type == OPType_ALL_NODE_SCAN) { |
| 453 | OpBase *allNodeScan = cond->op.children[0]; |
| 454 | // remove all node scan op |
| 455 | ExecutionPlan_RemoveOp(plan, allNodeScan); |
| 456 | OpBase_Free(allNodeScan); |
| 457 | } |
| 458 | |
| 459 | |
| 460 | const char *other_alias = AlgebraicExpression_Dest(cond->ae); |
| 461 | QGNode *other_node = QueryGraph_GetNodeByAlias(cond->op.plan->query_graph, other_alias); |
| 462 | ASSERT(other_node != NULL); |
| 463 | uint other_label_count = QGNode_LabelCount(other_node); |
| 464 | if(other_label_count > 0) { |
| 465 | // create func expression |
| 466 | const char *func_name = "hasLabels"; |
| 467 | AR_ExpNode *op = AR_EXP_NewOpNode(func_name, true, 2); |
| 468 | |
| 469 | // create node expression |
| 470 | AR_ExpNode *node_exp = AR_EXP_NewVariableOperandNode(other_alias); |
| 471 | |
| 472 | // create labels expression |
| 473 | SIValue labels = SI_Array(other_label_count); |
| 474 | for (uint i = 0; i < other_label_count; i++) { |
| 475 | SIArray_Append(&labels, SI_ConstStringVal((char *)other_node->labels[i])); |
| 476 | } |
| 477 | AR_ExpNode *labels_exp = AR_EXP_NewConstOperandNode(labels); |
| 478 | |
| 479 | // set function arguments |
| 480 | op->op.children[0] = node_exp; |
| 481 | op->op.children[1] = labels_exp; |
no test coverage detected