Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent infinite loop in recursive query in Postgresql

Sorry - this is kind of vague...

Here: (To find infinite recursive loop in CTE) is a discussion how to prevent an infinite loop in a recursive query. There the recursion is prevented on the "query level" - at least in an answer about Postgresql.

Is there a way in Postgresql (10) to implement some kind of safety net to prevent infinite recursions? Is it a feasible way to use statement_timeout for this or is there any other widely accepted way?

like image 542
madflow Avatar asked Jun 25 '18 14:06

madflow


People also ask

How do you stop infinite recursion?

To prevent infinite recursion, you need at least one branch (i.e. of an if/else statement) that does not make a recursive call. Branches without recursive calls are called base cases; branches with recursive calls are called recursive cases. Functions can also be mutually recursive.

Can recursion causes infinite loop?

Iteration and recursion can occur infinitely: An infinite loop occurs with iteration if the loop-continuation test never becomes false; infinite recursion occurs if the recursion step does not reduce the problem in a manner that converges on the base case.

How recursive query works in PostgreSQL?

A recursive query is a query in PostgreSQL, referred to as recursive common table expressions; it is used in multiple situations such as querying hierarchical data like organisation structure. The common table expression in PostgreSQL is the same as temporary tables, which was used during running the query.


1 Answers

In my development environment, I always use two fuses for recursive queries or functions. My client automatically sets on startup

set statement_timeout to '10s'

It is very rare that I need more and quite often it saves me from a dead loop.

When I write a recursive query from scratch I always use an additional column that limits the number of levels involved, something like this:

with recursive cte (root, parent, depth) as (
    select id, parent_id, 1
    from ...
union all
    select c.id, t.parent_id, depth+ 1
    from ...
    where depth < 10
)
select * 
from cte;

In production both these ways may be problematic. Instead, you can adjust the value of the configuration parameter max_stack_depth (integer) to the anticipated needs and capabilities of the operating system and/or hardware.

The method described by a_horse_with_no_name is obviously very effective, also in the production environment, but it can not always be used (or it is too expensive).

like image 138
klin Avatar answered Sep 22 '22 13:09

klin