Skip to content

Commit cd6db20

Browse files
committed
fix prunning in CTEs on PostgreSQL 9.5
1 parent 1b3dbb9 commit cd6db20

File tree

4 files changed

+193
-27
lines changed

4 files changed

+193
-27
lines changed

expected/pathman_upd_del.out

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,55 @@ WITH q AS (DELETE FROM test.tmp t
404404
RETURNING *)
405405
DELETE FROM test.tmp USING q;
406406
ROLLBACK;
407+
/* Test special rule for CTE; Nested CTEs (PostgreSQL 9.5) */
408+
EXPLAIN (COSTS OFF)
409+
WITH q AS (WITH n AS (SELECT id FROM test.tmp2 WHERE id = 2)
410+
DELETE FROM test.tmp t
411+
USING n
412+
WHERE t.id = n.id
413+
RETURNING *)
414+
DELETE FROM test.tmp USING q;
415+
QUERY PLAN
416+
--------------------------------------------
417+
Delete on tmp
418+
CTE q
419+
-> Delete on tmp t
420+
CTE n
421+
-> Append
422+
-> Seq Scan on tmp2_2
423+
Filter: (id = 2)
424+
-> Nested Loop
425+
Join Filter: (t.id = n.id)
426+
-> Seq Scan on tmp t
427+
-> CTE Scan on n
428+
-> Nested Loop
429+
-> Seq Scan on tmp
430+
-> CTE Scan on q
431+
(14 rows)
432+
433+
/* Test special rule for CTE; CTE in quals (PostgreSQL 9.5) */
434+
EXPLAIN (COSTS OFF)
435+
WITH q AS (SELECT id FROM test.tmp2
436+
WHERE id < 3)
437+
DELETE FROM test.tmp t WHERE t.id in (SELECT id FROM q);
438+
QUERY PLAN
439+
------------------------------------
440+
Delete on tmp t
441+
CTE q
442+
-> Append
443+
-> Seq Scan on tmp2_1
444+
-> Seq Scan on tmp2_2
445+
-> Nested Loop Semi Join
446+
Join Filter: (t.id = q.id)
447+
-> Seq Scan on tmp t
448+
-> CTE Scan on q
449+
(9 rows)
450+
451+
BEGIN;
452+
WITH q AS (SELECT id FROM test.tmp2
453+
WHERE id < 3)
454+
DELETE FROM test.tmp t WHERE t.id in (SELECT id FROM q);
455+
ROLLBACK;
407456
DROP SCHEMA test CASCADE;
408457
NOTICE: drop cascades to 27 other objects
409458
DROP EXTENSION pg_pathman CASCADE;

expected/pathman_upd_del_1.out

Lines changed: 83 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -229,23 +229,41 @@ USING (SELECT *
229229
JOIN test.tmp2 a2
230230
USING(id)) t
231231
WHERE t.id = r.id;
232-
QUERY PLAN
233-
---------------------------------------------
232+
QUERY PLAN
233+
---------------------------------------------------------
234234
Delete on tmp r
235-
-> Merge Join
236-
Merge Cond: (a1.id = a2.id)
237-
-> Merge Join
238-
Merge Cond: (r.id = a1.id)
239-
-> Sort
240-
Sort Key: r.id
241-
-> Seq Scan on tmp r
242-
-> Sort
243-
Sort Key: a1.id
244-
-> Seq Scan on tmp2 a1
245-
-> Sort
246-
Sort Key: a2.id
247-
-> Seq Scan on tmp2 a2
248-
(14 rows)
235+
-> Nested Loop
236+
Join Filter: (a1.id = a2.id)
237+
-> Nested Loop
238+
Join Filter: (r.id = a1.id)
239+
-> Seq Scan on tmp r
240+
-> Materialize
241+
-> Append
242+
-> Seq Scan on tmp2 a1
243+
-> Seq Scan on tmp2_1 a1_1
244+
-> Seq Scan on tmp2_2 a1_2
245+
-> Seq Scan on tmp2_3 a1_3
246+
-> Seq Scan on tmp2_4 a1_4
247+
-> Seq Scan on tmp2_5 a1_5
248+
-> Seq Scan on tmp2_6 a1_6
249+
-> Seq Scan on tmp2_7 a1_7
250+
-> Seq Scan on tmp2_8 a1_8
251+
-> Seq Scan on tmp2_9 a1_9
252+
-> Seq Scan on tmp2_10 a1_10
253+
-> Materialize
254+
-> Append
255+
-> Seq Scan on tmp2 a2
256+
-> Seq Scan on tmp2_1 a2_1
257+
-> Seq Scan on tmp2_2 a2_2
258+
-> Seq Scan on tmp2_3 a2_3
259+
-> Seq Scan on tmp2_4 a2_4
260+
-> Seq Scan on tmp2_5 a2_5
261+
-> Seq Scan on tmp2_6 a2_6
262+
-> Seq Scan on tmp2_7 a2_7
263+
-> Seq Scan on tmp2_8 a2_8
264+
-> Seq Scan on tmp2_9 a2_9
265+
-> Seq Scan on tmp2_10 a2_10
266+
(32 rows)
249267

250268
BEGIN;
251269
DELETE FROM test.tmp r
@@ -386,6 +404,55 @@ WITH q AS (DELETE FROM test.tmp t
386404
RETURNING *)
387405
DELETE FROM test.tmp USING q;
388406
ROLLBACK;
407+
/* Test special rule for CTE; Nested CTEs (PostgreSQL 9.5) */
408+
EXPLAIN (COSTS OFF)
409+
WITH q AS (WITH n AS (SELECT id FROM test.tmp2 WHERE id = 2)
410+
DELETE FROM test.tmp t
411+
USING n
412+
WHERE t.id = n.id
413+
RETURNING *)
414+
DELETE FROM test.tmp USING q;
415+
QUERY PLAN
416+
--------------------------------------------
417+
Delete on tmp
418+
CTE q
419+
-> Delete on tmp t
420+
CTE n
421+
-> Append
422+
-> Seq Scan on tmp2_2
423+
Filter: (id = 2)
424+
-> Nested Loop
425+
Join Filter: (t.id = n.id)
426+
-> Seq Scan on tmp t
427+
-> CTE Scan on n
428+
-> Nested Loop
429+
-> Seq Scan on tmp
430+
-> CTE Scan on q
431+
(14 rows)
432+
433+
/* Test special rule for CTE; CTE in quals (PostgreSQL 9.5) */
434+
EXPLAIN (COSTS OFF)
435+
WITH q AS (SELECT id FROM test.tmp2
436+
WHERE id < 3)
437+
DELETE FROM test.tmp t WHERE t.id in (SELECT id FROM q);
438+
QUERY PLAN
439+
------------------------------------
440+
Delete on tmp t
441+
CTE q
442+
-> Append
443+
-> Seq Scan on tmp2_1
444+
-> Seq Scan on tmp2_2
445+
-> Nested Loop Semi Join
446+
Join Filter: (t.id = q.id)
447+
-> Seq Scan on tmp t
448+
-> CTE Scan on q
449+
(9 rows)
450+
451+
BEGIN;
452+
WITH q AS (SELECT id FROM test.tmp2
453+
WHERE id < 3)
454+
DELETE FROM test.tmp t WHERE t.id in (SELECT id FROM q);
455+
ROLLBACK;
389456
DROP SCHEMA test CASCADE;
390457
NOTICE: drop cascades to 27 other objects
391458
DROP EXTENSION pg_pathman CASCADE;

sql/pathman_upd_del.sql

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,29 @@ DELETE FROM test.tmp USING q;
243243
ROLLBACK;
244244

245245

246+
/* Test special rule for CTE; Nested CTEs (PostgreSQL 9.5) */
247+
EXPLAIN (COSTS OFF)
248+
WITH q AS (WITH n AS (SELECT id FROM test.tmp2 WHERE id = 2)
249+
DELETE FROM test.tmp t
250+
USING n
251+
WHERE t.id = n.id
252+
RETURNING *)
253+
DELETE FROM test.tmp USING q;
254+
255+
256+
/* Test special rule for CTE; CTE in quals (PostgreSQL 9.5) */
257+
EXPLAIN (COSTS OFF)
258+
WITH q AS (SELECT id FROM test.tmp2
259+
WHERE id < 3)
260+
DELETE FROM test.tmp t WHERE t.id in (SELECT id FROM q);
261+
262+
BEGIN;
263+
WITH q AS (SELECT id FROM test.tmp2
264+
WHERE id < 3)
265+
DELETE FROM test.tmp t WHERE t.id in (SELECT id FROM q);
266+
ROLLBACK;
267+
268+
246269

247270
DROP SCHEMA test CASCADE;
248271
DROP EXTENSION pg_pathman CASCADE;

src/planner_tree_modification.c

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,36 @@
6262
(context)->TRANSFORM_CONTEXT_FIELD(command_type) = true; \
6363
break; \
6464

65+
#define TRANSFORM_CONTEXT_QUERY_IS_CTE_CTE(context, query) \
66+
( (context)->parent_cte && \
67+
(context)->parent_cte->ctequery == (Node *) (query) )
68+
69+
#define TRANSFORM_CONTEXT_QUERY_IS_CTE_SL(context, query) \
70+
( (context)->parent_sublink && \
71+
(context)->parent_sublink->subselect == (Node *) (query) && \
72+
(context)->parent_sublink->subLinkType == CTE_SUBLINK )
73+
74+
/* Check if 'query' is CTE according to 'context' */
75+
#define TRANSFORM_CONTEXT_QUERY_IS_CTE(context, query) \
76+
( TRANSFORM_CONTEXT_QUERY_IS_CTE_CTE((context), (query)) || \
77+
TRANSFORM_CONTEXT_QUERY_IS_CTE_SL ((context), (query)) )
78+
6579
typedef struct
6680
{
6781
/* Do we have a parent CmdType query? */
68-
bool TRANSFORM_CONTEXT_FIELD(SELECT),
69-
TRANSFORM_CONTEXT_FIELD(INSERT),
70-
TRANSFORM_CONTEXT_FIELD(UPDATE),
71-
TRANSFORM_CONTEXT_FIELD(DELETE);
82+
bool TRANSFORM_CONTEXT_FIELD(SELECT),
83+
TRANSFORM_CONTEXT_FIELD(INSERT),
84+
TRANSFORM_CONTEXT_FIELD(UPDATE),
85+
TRANSFORM_CONTEXT_FIELD(DELETE);
7286

7387
/* Parameters for handle_modification_query() */
74-
ParamListInfo query_params;
88+
ParamListInfo query_params;
7589

7690
/* SubLink that might contain an examined query */
77-
SubLink *parent_sublink;
91+
SubLink *parent_sublink;
92+
93+
/* CommonTableExpr that might containt an examined query */
94+
CommonTableExpr *parent_cte;
7895
} transform_query_cxt;
7996

8097

@@ -208,14 +225,24 @@ pathman_transform_query_walker(Node *node, void *context)
208225
if (node == NULL)
209226
return false;
210227

211-
else if (IsA(node, SubLink))
228+
else if (IsA(node, SubLink) || IsA(node, CommonTableExpr))
212229
{
213230
transform_query_cxt *current_context = context,
214231
next_context;
215232

216233
/* Initialize next context for bottom subqueries */
217234
next_context = *current_context;
218-
next_context.parent_sublink = (SubLink *) node;
235+
236+
if (IsA(node, SubLink))
237+
{
238+
next_context.parent_sublink = (SubLink *) node;
239+
next_context.parent_cte = NULL;
240+
}
241+
else
242+
{
243+
next_context.parent_sublink = NULL;
244+
next_context.parent_cte = (CommonTableExpr *) node;
245+
}
219246

220247
/* Handle expression subtree */
221248
return expression_tree_walker(node,
@@ -241,6 +268,8 @@ pathman_transform_query_walker(Node *node, void *context)
241268
default:
242269
break;
243270
}
271+
next_context.parent_sublink = NULL;
272+
next_context.parent_cte = NULL;
244273

245274
/* Assign Query a 'queryId' */
246275
assign_query_id(query);
@@ -284,9 +313,7 @@ disable_standard_inheritance(Query *parse, transform_query_cxt *context)
284313
/* Don't process queries under UPDATE or DELETE (except for CTEs) */
285314
if ((TRANSFORM_CONTEXT_HAS_PARENT(context, UPDATE) ||
286315
TRANSFORM_CONTEXT_HAS_PARENT(context, DELETE)) &&
287-
(context->parent_sublink &&
288-
context->parent_sublink->subselect == (Node *) parse &&
289-
context->parent_sublink->subLinkType != CTE_SUBLINK))
316+
!TRANSFORM_CONTEXT_QUERY_IS_CTE(context, parse))
290317
return;
291318
#endif
292319

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy