validate reduce
| 604 | |
| 605 | // validate reduce |
| 606 | static VISITOR_STRATEGY _Validate_reduce |
| 607 | ( |
| 608 | const cypher_astnode_t *n, // ast-node |
| 609 | bool start, // first traversal |
| 610 | ast_visitor *visitor // visitor |
| 611 | ) { |
| 612 | validations_ctx *vctx = AST_Visitor_GetContext(visitor); |
| 613 | if(!start) { |
| 614 | return VISITOR_CONTINUE; |
| 615 | } |
| 616 | |
| 617 | cypher_astnode_type_t orig_clause = vctx->clause; |
| 618 | // change clause type of vctx so that function-validation will work properly |
| 619 | // (include-aggregations should be set to false) |
| 620 | vctx->clause = CYPHER_AST_REDUCE; |
| 621 | |
| 622 | // A reduce call has an accumulator and a local list variable that should |
| 623 | // only be accessed within its scope; |
| 624 | // do not leave them in the identifiers map |
| 625 | // example: reduce(sum=0, n in [1,2] | sum+n) |
| 626 | // the reduce function is composed of 5 components: |
| 627 | // 1. accumulator `sum` |
| 628 | // 2. accumulator init expression `0` |
| 629 | // 3. list expression `[1,2,3]` |
| 630 | // 4. variable `n` |
| 631 | // 5. eval expression `sum + n` |
| 632 | |
| 633 | // make sure that the init expression is a known var or valid exp. |
| 634 | const cypher_astnode_t *init_node = cypher_ast_reduce_get_init(n); |
| 635 | if(cypher_astnode_type(init_node) == CYPHER_AST_IDENTIFIER) { |
| 636 | // check if the variable has already been introduced |
| 637 | const char *var_str = cypher_ast_identifier_get_name(init_node); |
| 638 | if(raxFind(vctx->defined_identifiers, (unsigned char *)var_str, strlen(var_str)) == raxNotFound) { |
| 639 | ErrorCtx_SetError("%s not defined.", var_str); |
| 640 | return VISITOR_BREAK; |
| 641 | } |
| 642 | } |
| 643 | else { |
| 644 | AST_Visitor_visit(init_node, visitor); |
| 645 | if(ErrorCtx_EncounteredError()) { |
| 646 | return VISITOR_BREAK; |
| 647 | } |
| 648 | } |
| 649 | |
| 650 | // make sure that the list expression is a list (or list comprehension) or an |
| 651 | // alias of an existing one. |
| 652 | const cypher_astnode_t *list_var = cypher_ast_reduce_get_expression(n); |
| 653 | if(cypher_astnode_type(list_var) == CYPHER_AST_IDENTIFIER) { |
| 654 | const char *list_var_str = cypher_ast_identifier_get_name(list_var); |
| 655 | if(raxFind(vctx->defined_identifiers, (unsigned char *) list_var_str, strlen(list_var_str)) == raxNotFound) { |
| 656 | ErrorCtx_SetError("%s not defined", list_var_str); |
| 657 | return VISITOR_BREAK; |
| 658 | } |
| 659 | } |
| 660 | |
| 661 | // Visit the list expression (no need to introduce local vars) |
| 662 | AST_Visitor_visit(list_var, visitor); |
| 663 | if(ErrorCtx_EncounteredError()) { |
nothing calls this directly
no test coverage detected