Add some recursion and looping defenses in prepjointree.c.

Andrey Lepikhov demonstrated a case where we spend an unreasonable
amount of time in pull_up_subqueries().  Not only is that recursing
with no explicit check for stack overrun, but the code seems not
interruptable by control-C.  Let's stick a CHECK_FOR_INTERRUPTS
there, along with sprinkling some stack depth checks.

An actual fix for the excessive time consumption seems a bit
risky to back-patch; but this isn't, so let's do so.

Discussion: https://postgr.es/m/703c09a2-08f3-d2ec-b33d-dbecd62428b8@postgrespro.ru
This commit is contained in:
Tom Lane 2022-12-22 10:35:02 -05:00
parent f489b480f4
commit 97431d6739
1 changed files with 12 additions and 0 deletions

View File

@ -27,6 +27,7 @@
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
@ -235,6 +236,9 @@ static Node *
pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode,
Relids *relids)
{
/* Since this function recurses, it could be driven to stack overflow. */
check_stack_depth();
if (jtnode == NULL)
{
*relids = NULL;
@ -732,6 +736,11 @@ pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode,
JoinExpr *lowest_nulling_outer_join,
AppendRelInfo *containing_appendrel)
{
/* Since this function recurses, it could be driven to stack overflow. */
check_stack_depth();
/* Also, since it's a bit expensive, let's check for query cancel. */
CHECK_FOR_INTERRUPTS();
Assert(jtnode != NULL);
if (IsA(jtnode, RangeTblRef))
{
@ -1854,6 +1863,9 @@ is_simple_union_all(Query *subquery)
static bool
is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
{
/* Since this function recurses, it could be driven to stack overflow. */
check_stack_depth();
if (IsA(setOp, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) setOp;