* Tree walker function to detect invalid self-references in a recursive query. */
| 946 | * Tree walker function to detect invalid self-references in a recursive query. |
| 947 | */ |
| 948 | static bool |
| 949 | checkWellFormedRecursionWalker(Node *node, CteState *cstate) |
| 950 | { |
| 951 | RecursionContext save_context = cstate->context; |
| 952 | |
| 953 | if (node == NULL) |
| 954 | return false; |
| 955 | if (IsA(node, RangeVar)) |
| 956 | { |
| 957 | RangeVar *rv = (RangeVar *) node; |
| 958 | |
| 959 | /* If unqualified name, might be a CTE reference */ |
| 960 | if (!rv->schemaname) |
| 961 | { |
| 962 | ListCell *lc; |
| 963 | CommonTableExpr *mycte; |
| 964 | |
| 965 | /* ... but first see if it's captured by an inner WITH */ |
| 966 | foreach(lc, cstate->innerwiths) |
| 967 | { |
| 968 | List *withlist = (List *) lfirst(lc); |
| 969 | ListCell *lc2; |
| 970 | |
| 971 | foreach(lc2, withlist) |
| 972 | { |
| 973 | CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2); |
| 974 | |
| 975 | if (strcmp(rv->relname, cte->ctename) == 0) |
| 976 | return false; /* yes, so bail out */ |
| 977 | } |
| 978 | } |
| 979 | |
| 980 | /* No, could be a reference to the query level we are working on */ |
| 981 | mycte = cstate->items[cstate->curitem].cte; |
| 982 | if (strcmp(rv->relname, mycte->ctename) == 0) |
| 983 | { |
| 984 | /* Found a recursive reference to the active query */ |
| 985 | if (cstate->context != RECURSION_OK) |
| 986 | ereport(ERROR, |
| 987 | (errcode(ERRCODE_INVALID_RECURSION), |
| 988 | errmsg(recursion_errormsgs[cstate->context], |
| 989 | mycte->ctename), |
| 990 | parser_errposition(cstate->pstate, |
| 991 | rv->location))); |
| 992 | /* Count references */ |
| 993 | if (++(cstate->selfrefcount) > 1) |
| 994 | ereport(ERROR, |
| 995 | (errcode(ERRCODE_INVALID_RECURSION), |
| 996 | errmsg("recursive reference to query \"%s\" must not appear more than once", |
| 997 | mycte->ctename), |
| 998 | parser_errposition(cstate->pstate, |
| 999 | rv->location))); |
| 1000 | } |
| 1001 | } |
| 1002 | return false; |
| 1003 | } |
| 1004 | if (IsA(node, SelectStmt)) |
| 1005 | { |
no test coverage detected