@@ -156,6 +156,70 @@ defmodule Ecto.Adapters.PostgresTest do
156156 ~s{ INNER JOIN "tree" AS t1 ON t1."id" = s0."category_id"}
157157 end
158158
159+ test "materialized CTE" do
160+ initial_query =
161+ "categories"
162+ |> where ( [ c ] , is_nil ( c . parent_id ) )
163+ |> select ( [ c ] , % { id: c . id , depth: fragment ( "1" ) } )
164+
165+ iteration_query =
166+ "categories"
167+ |> join ( :inner , [ c ] , t in "tree" , on: t . id == c . parent_id )
168+ |> select ( [ c , t ] , % { id: c . id , depth: fragment ( "? + 1" , t . depth ) } )
169+
170+ cte_query = initial_query |> union_all ( ^ iteration_query )
171+
172+ query =
173+ Schema
174+ |> recursive_ctes ( true )
175+ |> with_cte ( "tree" , as: ^ cte_query , materialized: true )
176+ |> join ( :inner , [ r ] , t in "tree" , on: t . id == r . category_id )
177+ |> select ( [ r , t ] , % { x: r . x , category_id: t . id , depth: type ( t . depth , :integer ) } )
178+ |> plan ( )
179+
180+ assert all ( query ) ==
181+ ~s{ WITH RECURSIVE "tree" AS MATERIALIZED} <>
182+ ~s{ (SELECT sc0."id" AS "id", 1 AS "depth" FROM "categories" AS sc0 WHERE (sc0."parent_id" IS NULL) } <>
183+ ~s{ UNION ALL } <>
184+ ~s{ (SELECT c0."id", t1."depth" + 1 FROM "categories" AS c0 } <>
185+ ~s{ INNER JOIN "tree" AS t1 ON t1."id" = c0."parent_id")) } <>
186+ ~s{ SELECT s0."x", t1."id", t1."depth"::bigint } <>
187+ ~s{ FROM "schema" AS s0 } <>
188+ ~s{ INNER JOIN "tree" AS t1 ON t1."id" = s0."category_id"}
189+ end
190+
191+ test "not materialized CTE" do
192+ initial_query =
193+ "categories"
194+ |> where ( [ c ] , is_nil ( c . parent_id ) )
195+ |> select ( [ c ] , % { id: c . id , depth: fragment ( "1" ) } )
196+
197+ iteration_query =
198+ "categories"
199+ |> join ( :inner , [ c ] , t in "tree" , on: t . id == c . parent_id )
200+ |> select ( [ c , t ] , % { id: c . id , depth: fragment ( "? + 1" , t . depth ) } )
201+
202+ cte_query = initial_query |> union_all ( ^ iteration_query )
203+
204+ query =
205+ Schema
206+ |> recursive_ctes ( true )
207+ |> with_cte ( "tree" , as: ^ cte_query , materialized: false )
208+ |> join ( :inner , [ r ] , t in "tree" , on: t . id == r . category_id )
209+ |> select ( [ r , t ] , % { x: r . x , category_id: t . id , depth: type ( t . depth , :integer ) } )
210+ |> plan ( )
211+
212+ assert all ( query ) ==
213+ ~s{ WITH RECURSIVE "tree" AS NOT MATERIALIZED} <>
214+ ~s{ (SELECT sc0."id" AS "id", 1 AS "depth" FROM "categories" AS sc0 WHERE (sc0."parent_id" IS NULL) } <>
215+ ~s{ UNION ALL } <>
216+ ~s{ (SELECT c0."id", t1."depth" + 1 FROM "categories" AS c0 } <>
217+ ~s{ INNER JOIN "tree" AS t1 ON t1."id" = c0."parent_id")) } <>
218+ ~s{ SELECT s0."x", t1."id", t1."depth"::bigint } <>
219+ ~s{ FROM "schema" AS s0 } <>
220+ ~s{ INNER JOIN "tree" AS t1 ON t1."id" = s0."category_id"}
221+ end
222+
159223 @ raw_sql_cte """
160224 SELECT * FROM categories WHERE c.parent_id IS NULL
161225 UNION ALL
0 commit comments