In any given query scope, reading clauses (MATCH, UNWIND, and InQueryCall) * cannot follow updating clauses (CREATE, MERGE, DELETE, SET, REMOVE, FOREACH). * https://s3.amazonaws.com/artifacts.opencypher.org/railroad/SinglePartQuery.html * Additionally, a MATCH clause cannot follow an OPTIONAL MATCH clause. */
| 1928 | * https://s3.amazonaws.com/artifacts.opencypher.org/railroad/SinglePartQuery.html |
| 1929 | * Additionally, a MATCH clause cannot follow an OPTIONAL MATCH clause. */ |
| 1930 | static AST_Validation _ValidateClauseOrder |
| 1931 | ( |
| 1932 | const AST *ast // ast |
| 1933 | ) { |
| 1934 | uint clause_count = cypher_ast_query_nclauses(ast->root); |
| 1935 | |
| 1936 | bool encountered_optional_match = false; |
| 1937 | bool encountered_updating_clause = false; |
| 1938 | for(uint i = 0; i < clause_count; i ++) { |
| 1939 | const cypher_astnode_t *clause = cypher_ast_query_get_clause(ast->root, i); |
| 1940 | cypher_astnode_type_t type = cypher_astnode_type(clause); |
| 1941 | if(encountered_updating_clause && (type == CYPHER_AST_MATCH || |
| 1942 | type == CYPHER_AST_UNWIND || |
| 1943 | type == CYPHER_AST_CALL || |
| 1944 | type == CYPHER_AST_CALL_SUBQUERY)) { |
| 1945 | ErrorCtx_SetError("A WITH clause is required to introduce %s after an updating clause.", |
| 1946 | cypher_astnode_typestr(type)); |
| 1947 | return AST_INVALID; |
| 1948 | } |
| 1949 | if(type == CYPHER_AST_UNION) { |
| 1950 | encountered_optional_match = false; |
| 1951 | encountered_updating_clause = false; |
| 1952 | continue; |
| 1953 | } |
| 1954 | encountered_updating_clause = (encountered_updating_clause || |
| 1955 | _is_updating_clause(clause)); |
| 1956 | |
| 1957 | if(type == CYPHER_AST_MATCH) { |
| 1958 | // Check whether this match is optional |
| 1959 | bool current_clause_is_optional = cypher_ast_match_is_optional(clause); |
| 1960 | // If the current clause is non-optional but we have already |
| 1961 | // encountered an optional match, emit an error |
| 1962 | if(!current_clause_is_optional && encountered_optional_match) { |
| 1963 | ErrorCtx_SetError("A WITH clause is required to introduce a \ |
| 1964 | MATCH clause after an OPTIONAL MATCH."); |
| 1965 | return AST_INVALID; |
| 1966 | } |
| 1967 | encountered_optional_match |= current_clause_is_optional; |
| 1968 | } |
| 1969 | |
| 1970 | if(type == CYPHER_AST_WITH) { |
| 1971 | encountered_optional_match = false; |
| 1972 | encountered_updating_clause = false; |
| 1973 | } |
| 1974 | |
| 1975 | if(type == CYPHER_AST_CALL_SUBQUERY) { |
| 1976 | AST subquery_ast = { |
| 1977 | .root = cypher_ast_call_subquery_get_query(clause) |
| 1978 | }; |
| 1979 | if(_ValidateClauseOrder(&subquery_ast) != AST_VALID) { |
| 1980 | return AST_INVALID; |
| 1981 | } |
| 1982 | } |
| 1983 | } |
| 1984 | |
| 1985 | return AST_VALID; |
| 1986 | } |
| 1987 |
no test coverage detected