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)