normalize_lets.slt 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. # Copyright Materialize, Inc. and contributors. All rights reserved.
  2. #
  3. # Use of this software is governed by the Business Source License
  4. # included in the LICENSE file at the root of this repository.
  5. #
  6. # As of the Change Date specified in that file, in accordance with
  7. # the Business Source License, use of this software will be governed
  8. # by the Apache License, Version 2.0.
  9. mode cockroach
  10. ## Test a plausibly correct recursive query.
  11. query T multiline
  12. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE
  13. foo (a int, b int) AS (SELECT 1, 2 UNION SELECT a, 7 FROM bar),
  14. bar (a int) as (SELECT a FROM foo)
  15. SELECT * FROM bar;
  16. ----
  17. Explained Query:
  18. With Mutually Recursive
  19. cte l0 =
  20. Project (#1)
  21. Map (1)
  22. Distinct project=[#0] monotonic
  23. Union
  24. Project (#1)
  25. Map (7)
  26. Get l0
  27. Constant
  28. - (2)
  29. Return
  30. Get l0
  31. Target cluster: mz_catalog_server
  32. EOF
  33. ## Test a nested recursive query.
  34. # With materialize#27389 this stopped testing a thing; see issue database-issues#8294.
  35. query T multiline
  36. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE
  37. foo (a int8) AS (
  38. WITH MUTUALLY RECURSIVE
  39. bar (b int8) AS (
  40. SELECT * FROM (SELECT * FROM foo UNION ALL SELECT * FROM bar)
  41. )
  42. SELECT * FROM (SELECT * FROM foo EXCEPT ALL SELECT * FROM bar)
  43. )
  44. SELECT * FROM foo;
  45. ----
  46. Explained Query (fast path):
  47. Constant <empty>
  48. Target cluster: mz_catalog_server
  49. EOF
  50. ## Test inlining at an inner nesting level. (database-issues#5581)
  51. ## `bar` is used only in `baz`, so it should be inlined. The inner WMR should have only one cte.
  52. # With materialize#27389 this stopped testing a thing; see issue database-issues#8294.
  53. query T multiline
  54. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE
  55. foo (a int8) AS (
  56. WITH MUTUALLY RECURSIVE
  57. bar (b int8) AS (
  58. SELECT * FROM (SELECT * FROM foo UNION ALL SELECT * FROM baz)
  59. ),
  60. baz (b int8) AS (
  61. SELECT b + 3 FROM bar WHERE b > -5
  62. )
  63. SELECT * FROM (SELECT * FROM foo EXCEPT ALL SELECT * FROM baz)
  64. )
  65. SELECT * FROM foo;
  66. ----
  67. Explained Query (fast path):
  68. Constant <empty>
  69. Target cluster: mz_catalog_server
  70. EOF
  71. statement ok
  72. CREATE TABLE t1(f0 int);
  73. ## Test inlining a cte from a `Let` into a `LetRec`.
  74. query T multiline
  75. EXPLAIN OPTIMIZED PLAN WITH(raw, humanized expressions) AS VERBOSE TEXT FOR
  76. WITH
  77. cte0 AS (
  78. SELECT * from t1 where f0 < 27
  79. )
  80. SELECT * FROM
  81. (
  82. WITH MUTUALLY RECURSIVE
  83. cnt (i int) AS (
  84. (SELECT f0 AS i FROM cte0)
  85. UNION
  86. SELECT i+1 FROM cnt)
  87. SELECT * FROM cnt
  88. );
  89. ----
  90. Explained Query:
  91. With Mutually Recursive
  92. cte l0 =
  93. Reduce group_by=[#0]
  94. Union
  95. Filter (#0{f0} < 27)
  96. ReadStorage materialize.public.t1
  97. Project (#1)
  98. Map ((#0{i} + 1))
  99. Get l0
  100. Return
  101. Get l0
  102. Source materialize.public.t1
  103. filter=((#0{f0} < 27))
  104. Target cluster: quickstart
  105. EOF
  106. ## Test consolidation of not-really nested recursive query.
  107. # With materialize#27389 this stopped testing a thing; see issue database-issues#8294.
  108. query T multiline
  109. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE
  110. foo (a int8) AS (
  111. WITH MUTUALLY RECURSIVE
  112. bar (b int8) AS (
  113. SELECT * FROM foo
  114. )
  115. SELECT * FROM (SELECT * FROM foo UNION ALL SELECT * FROM bar)
  116. )
  117. SELECT * FROM foo;
  118. ----
  119. Explained Query (fast path):
  120. Constant <empty>
  121. Target cluster: mz_catalog_server
  122. EOF
  123. ## Test consolidation of independent recursive query blocks.
  124. # With materialize#27389 this stopped testing a thing; see issue database-issues#8294.
  125. query T multiline
  126. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR SELECT * FROM (
  127. WITH MUTUALLY RECURSIVE
  128. foo (a int8) AS (SELECT DISTINCT a FROM foo)
  129. SELECT * FROM foo
  130. )
  131. UNION ALL
  132. SELECT * FROM (
  133. WITH MUTUALLY RECURSIVE
  134. bar (a int8) AS (SELECT DISTINCT a FROM bar)
  135. SELECT * FROM bar
  136. );
  137. ----
  138. Explained Query (fast path):
  139. Constant <empty>
  140. Target cluster: mz_catalog_server
  141. EOF
  142. statement ok
  143. CREATE TABLE edges (src int, dst int);
  144. ## Complex inlining and other things
  145. query T multiline
  146. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE
  147. label (node int, comp int) AS (
  148. SELECT dst, MIN(comp)
  149. FROM (
  150. SELECT dst, dst AS comp FROM edges
  151. UNION ALL
  152. SELECT edges.dst, label.comp
  153. FROM edges, label
  154. WHERE edges.src = label.node
  155. )
  156. GROUP BY dst
  157. )
  158. SELECT round, COUNT(*) FROM (
  159. WITH MUTUALLY RECURSIVE
  160. relabel (node int, comp int, round int) AS (
  161. SELECT DISTINCT ON(node) node, comp, round
  162. FROM (
  163. SELECT node, comp, 0 as round FROM label
  164. UNION ALL
  165. SELECT edges.dst, relabel.comp, relabel.round + 1
  166. FROM edges, relabel
  167. WHERE edges.src = relabel.node
  168. )
  169. ORDER BY node, comp
  170. )
  171. SELECT round FROM relabel
  172. )
  173. GROUP BY round;
  174. ----
  175. Explained Query:
  176. With Mutually Recursive
  177. cte l0 =
  178. Reduce group_by=[#0{dst}] aggregates=[min(#1{dst})]
  179. Union
  180. Project (#1{dst}, #1{dst})
  181. ReadStorage materialize.public.edges
  182. Project (#1{dst}, #3)
  183. Join on=(#0{src} = #2{node}) type=differential
  184. ArrangeBy keys=[[#0{src}]]
  185. Filter (#0{src}) IS NOT NULL
  186. ReadStorage materialize.public.edges
  187. ArrangeBy keys=[[#0{node}]]
  188. Filter (#0{dst}) IS NOT NULL
  189. Get l0
  190. Return
  191. With Mutually Recursive
  192. cte l1 =
  193. TopK group_by=[#0{dst}] order_by=[#1{min_dst} asc nulls_last] limit=1
  194. Union
  195. Map (0)
  196. Get l0
  197. Project (#1{dst}, #3, #5)
  198. Map ((#4{round} + 1))
  199. Join on=(#0{src} = #2{node}) type=differential
  200. ArrangeBy keys=[[#0{src}]]
  201. Filter (#0{src}) IS NOT NULL
  202. ReadStorage materialize.public.edges
  203. ArrangeBy keys=[[#0{node}]]
  204. Filter (#0{dst}) IS NOT NULL
  205. Get l1
  206. Return
  207. Reduce group_by=[#0] aggregates=[count(*)]
  208. Project (#2)
  209. Get l1
  210. Source materialize.public.edges
  211. Target cluster: quickstart
  212. EOF
  213. #### Tests for RECURSION LIMIT
  214. ## RECURSION LIMIT -- Simple test
  215. query T multiline
  216. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE (RECURSION LIMIT 10)
  217. cnt (i int) AS (
  218. SELECT 1 AS i
  219. UNION
  220. SELECT i+1 FROM cnt)
  221. SELECT * FROM cnt;
  222. ----
  223. Explained Query:
  224. With Mutually Recursive [recursion_limit=10]
  225. cte l0 =
  226. Distinct project=[#0] monotonic
  227. Union
  228. Project (#1)
  229. Map ((#0{i} + 1))
  230. Get l0
  231. Constant
  232. - (1)
  233. Return
  234. Get l0
  235. Target cluster: mz_catalog_server
  236. EOF
  237. ## RECURSION LIMIT -- RETURN AT RECURSION LIMIT
  238. query T multiline
  239. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE (RETURN AT RECURSION LIMIT 10)
  240. cnt (i int) AS (
  241. SELECT 1 AS i
  242. UNION
  243. SELECT i+1 FROM cnt)
  244. SELECT * FROM cnt;
  245. ----
  246. Explained Query:
  247. With Mutually Recursive [recursion_limit=10, return_at_limit]
  248. cte l0 =
  249. Distinct project=[#0] monotonic
  250. Union
  251. Project (#1)
  252. Map ((#0{i} + 1))
  253. Get l0
  254. Constant
  255. - (1)
  256. Return
  257. Get l0
  258. Target cluster: mz_catalog_server
  259. EOF
  260. ## RECURSION LIMIT -- ERROR AT RECURSION LIMIT
  261. query T multiline
  262. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE (ERROR AT RECURSION LIMIT 10)
  263. cnt (i int) AS (
  264. SELECT 1 AS i
  265. UNION
  266. SELECT i+1 FROM cnt)
  267. SELECT * FROM cnt;
  268. ----
  269. Explained Query:
  270. With Mutually Recursive [recursion_limit=10]
  271. cte l0 =
  272. Distinct project=[#0] monotonic
  273. Union
  274. Project (#1)
  275. Map ((#0{i} + 1))
  276. Get l0
  277. Constant
  278. - (1)
  279. Return
  280. Get l0
  281. Target cluster: mz_catalog_server
  282. EOF
  283. ## RECURSION LIMIT -- consolidation of independent recursive query blocks with different RECURSION LIMIT
  284. # With materialize#27389 this stopped testing a thing; see issue database-issues#8294.
  285. query T multiline
  286. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR SELECT * FROM (
  287. WITH MUTUALLY RECURSIVE (RECURSION LIMIT 5)
  288. foo (a int8) AS (SELECT DISTINCT a FROM foo)
  289. SELECT * FROM foo
  290. )
  291. UNION ALL
  292. SELECT * FROM (
  293. WITH MUTUALLY RECURSIVE (RECURSION LIMIT 7)
  294. bar (a int8) AS (SELECT DISTINCT a - 2 FROM bar)
  295. SELECT * FROM bar
  296. );
  297. ----
  298. Explained Query (fast path):
  299. Constant <empty>
  300. Target cluster: mz_catalog_server
  301. EOF
  302. ## RECURSION LIMIT -- consolidation of independent recursive query blocks with equal RECURSION LIMIT.
  303. ## We want to see RECURSION LIMIT printed at the block level rather than on each cte.
  304. # With materialize#27389 this stopped testing a thing; see issue database-issues#8294.
  305. query T multiline
  306. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR SELECT * FROM (
  307. WITH MUTUALLY RECURSIVE (RECURSION LIMIT 27)
  308. foo (a int8) AS (SELECT DISTINCT a FROM foo)
  309. SELECT * FROM foo
  310. )
  311. UNION ALL
  312. SELECT * FROM (
  313. WITH MUTUALLY RECURSIVE (RECURSION LIMIT 27)
  314. bar (a int8) AS (SELECT DISTINCT a - 2 FROM bar)
  315. SELECT * FROM bar
  316. );
  317. ----
  318. Explained Query (fast path):
  319. Constant <empty>
  320. Target cluster: mz_catalog_server
  321. EOF
  322. ## ITERATION RECURSION -- consolidation of not-really nested recursive query.
  323. ## Here, the ITERATION RECURSION of the inner WMR is irrelevant, because it's not recursive.
  324. # With materialize#27389 this stopped testing a thing; see issue database-issues#8294.
  325. query T multiline
  326. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE (RECURSION LIMIT 9)
  327. foo (a int8) AS (
  328. WITH MUTUALLY RECURSIVE (RECURSION LIMIT 3)
  329. bar (b int8) AS (
  330. SELECT * FROM foo
  331. )
  332. SELECT * FROM (SELECT * FROM foo UNION ALL SELECT * FROM bar)
  333. )
  334. SELECT * FROM foo;
  335. ----
  336. Explained Query (fast path):
  337. Constant <empty>
  338. Target cluster: mz_catalog_server
  339. EOF
  340. # ITERATION RECURSION -- a nested recursive query.
  341. # With materialize#27389 this stopped testing a thing; see issue database-issues#8294.
  342. query T multiline
  343. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE (RECURSION LIMIT 17)
  344. foo (a int8) AS (
  345. WITH MUTUALLY RECURSIVE (RECURSION LIMIT 11)
  346. bar (b int8) AS (
  347. SELECT * FROM (SELECT * FROM foo UNION ALL SELECT * FROM bar)
  348. )
  349. SELECT * FROM (SELECT * FROM foo EXCEPT ALL SELECT * FROM bar)
  350. )
  351. SELECT * FROM foo;
  352. ----
  353. Explained Query (fast path):
  354. Constant <empty>
  355. Target cluster: mz_catalog_server
  356. EOF
  357. ## ITERATION RECURSION -- Complex inlining and other things.
  358. query T multiline
  359. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE (RECURSION LIMIT 21)
  360. label (node int, comp int) AS (
  361. SELECT dst, MIN(comp)
  362. FROM (
  363. SELECT dst, dst AS comp FROM edges
  364. UNION ALL
  365. SELECT edges.dst, label.comp
  366. FROM edges, label
  367. WHERE edges.src = label.node
  368. )
  369. GROUP BY dst
  370. )
  371. SELECT round, COUNT(*) FROM (
  372. WITH MUTUALLY RECURSIVE (RECURSION LIMIT 23)
  373. relabel (node int, comp int, round int) AS (
  374. SELECT DISTINCT ON(node) node, comp, round
  375. FROM (
  376. SELECT node, comp, 0 as round FROM label
  377. UNION ALL
  378. SELECT edges.dst, relabel.comp, relabel.round + 1
  379. FROM edges, relabel
  380. WHERE edges.src = relabel.node
  381. )
  382. ORDER BY node, comp
  383. )
  384. SELECT round FROM relabel
  385. )
  386. GROUP BY round;
  387. ----
  388. Explained Query:
  389. With Mutually Recursive [recursion_limit=21]
  390. cte l0 =
  391. Reduce group_by=[#0{dst}] aggregates=[min(#1{dst})]
  392. Union
  393. Project (#1{dst}, #1{dst})
  394. ReadStorage materialize.public.edges
  395. Project (#1{dst}, #3)
  396. Join on=(#0{src} = #2{node}) type=differential
  397. ArrangeBy keys=[[#0{src}]]
  398. Filter (#0{src}) IS NOT NULL
  399. ReadStorage materialize.public.edges
  400. ArrangeBy keys=[[#0{node}]]
  401. Filter (#0{dst}) IS NOT NULL
  402. Get l0
  403. Return
  404. With Mutually Recursive [recursion_limit=23]
  405. cte l1 =
  406. TopK group_by=[#0{dst}] order_by=[#1{min_dst} asc nulls_last] limit=1
  407. Union
  408. Map (0)
  409. Get l0
  410. Project (#1{dst}, #3, #5)
  411. Map ((#4{round} + 1))
  412. Join on=(#0{src} = #2{node}) type=differential
  413. ArrangeBy keys=[[#0{src}]]
  414. Filter (#0{src}) IS NOT NULL
  415. ReadStorage materialize.public.edges
  416. ArrangeBy keys=[[#0{node}]]
  417. Filter (#0{dst}) IS NOT NULL
  418. Get l1
  419. Return
  420. Reduce group_by=[#0] aggregates=[count(*)]
  421. Project (#2)
  422. Get l1
  423. Source materialize.public.edges
  424. Target cluster: quickstart
  425. EOF
  426. ## Make sure that we run `NormalizeLets` just before `CollectIndexRequests`.
  427. ## Regression test for https://github.com/MaterializeInc/database-issues/issues/6371
  428. statement ok
  429. CREATE TABLE t (a int2, b int4, c int8, d uint2, e uint4, f uint8, g text);
  430. statement ok
  431. SET cluster_replica = r1
  432. statement ok
  433. EXPLAIN OPTIMIZED PLAN WITH (humanized expressions) AS VERBOSE TEXT FOR
  434. select
  435. subq_0."c2" as c0,
  436. ((select "attlen" from pg_catalog.pg_attribute limit 1 offset 4)
  437. ) # ((pg_catalog.abs(
  438. CAST((select "a" from public.t limit 1 offset 1)
  439. as int2))) # (case when ((cast(null as oid)) < (cast(null as oid)))
  440. or (((subq_0."c2" is not NULL)
  441. and ((numrange(0,0)) <= (numrange(0,0))))
  442. and ((((select "write_frontier" from mz_internal.mz_frontiers limit 1 offset 1)
  443. ) <> ((select pg_catalog.max("time") from mz_introspection.mz_compute_import_frontiers_per_worker)
  444. ))
  445. or (false))) then pg_catalog.abs(
  446. CAST((select "tgtype" from pg_catalog.pg_trigger limit 1 offset 6)
  447. as int2)) else pg_catalog.abs(
  448. CAST((select "tgtype" from pg_catalog.pg_trigger limit 1 offset 6)
  449. as int2)) end
  450. )) as c1,
  451. subq_0."c0" as c2
  452. from
  453. (select
  454. ref_0."credits_per_hour" as c0,
  455. ref_0."credits_per_hour" as c1,
  456. ref_0."replica_id" as c2,
  457. ref_0."cluster_name" as c3,
  458. (select "id" from mz_introspection.mz_scheduling_elapsed_raw limit 1 offset 57)
  459. as c4
  460. from
  461. mz_internal.mz_cluster_replica_history as ref_0
  462. where ref_0."replica_id" is NULL
  463. limit 102) as subq_0
  464. where (~ (select "replication_factor" from mz_catalog.mz_clusters limit 1 offset 5)
  465. ) <= (~ case when (case when (((((select "details" from mz_internal.mz_sink_statuses limit 1 offset 4)
  466. ) >= ((select pg_catalog.jsonb_agg("id") from mz_introspection.mz_dataflow_operators)
  467. ))
  468. or ((cast(0 as name)) >= (cast(null as name))))
  469. or (subq_0."c1" is NULL))
  470. and (((select pg_catalog.min("tgtype") from pg_catalog.pg_trigger)
  471. is not NULL)
  472. and (true)) then (select "d" from public.t limit 1 offset 4)
  473. else (select "d" from public.t limit 1 offset 4)
  474. end
  475. ) <> (pg_catalog.mod(
  476. CAST(cast(coalesce((select pg_catalog.max("d") from public.t)
  477. ,
  478. (select "d" from public.t limit 1 offset 2)
  479. ) as uint2) as uint2),
  480. CAST((select "d" from public.t limit 1 offset 3)
  481. as uint2))) then (select "replication_factor" from mz_catalog.mz_clusters limit 1 offset 2)
  482. else (select "replication_factor" from mz_catalog.mz_clusters limit 1 offset 2)
  483. end
  484. )
  485. limit 117;
  486. ## Ensure that we hoist WMR-invariant Let bindings, to avoid a `raw` modifier on arrangements
  487. ## that can be accessed through keys (and which do not otherwise require linear work).
  488. statement ok
  489. create table potato (a TEXT, b TEXT);
  490. statement ok
  491. create index on potato(a);
  492. ## The only thing that needs to stay true about what follows is that `potato` is used only
  493. ## as indexed access, and has `raw = false` to avoid decanting its contents.
  494. query T multiline
  495. EXPLAIN PHYSICAL PLAN AS VERBOSE TEXT FOR WITH MUTUALLY RECURSIVE
  496. walk(a TEXT, b TEXT) AS (
  497. SELECT a, b
  498. FROM potato
  499. WHERE a = 'russet'
  500. UNION
  501. SELECT potato.a, potato.b
  502. FROM potato
  503. INNER JOIN walk
  504. ON potato.a = walk.b
  505. )
  506. select * from walk;
  507. ----
  508. Explained Query:
  509. With
  510. cte l0 =
  511. Get::PassArrangements materialize.public.potato
  512. raw=false
  513. arrangements[0]={ key=[#0{a}], permutation=id, thinning=(#1) }
  514. types=[text?, text?]
  515. Return
  516. With Mutually Recursive
  517. cte l1 =
  518. ArrangeBy
  519. input_key=[#0, #1]
  520. raw=true
  521. Reduce::Distinct
  522. val_plan
  523. project=()
  524. key_plan=id
  525. Union
  526. Join::Linear
  527. linear_stage[0]
  528. lookup={ relation=0, key=[#0{a}] }
  529. stream={ key=[#0], thinning=() }
  530. source={ relation=1, key=[#0] }
  531. Get::PassArrangements l0
  532. raw=false
  533. arrangements[0]={ key=[#0{a}], permutation=id, thinning=(#1) }
  534. types=[text?, text?]
  535. ArrangeBy
  536. raw=true
  537. arrangements[0]={ key=[#0], permutation=id, thinning=() }
  538. types=[text]
  539. Constant
  540. - ("russet")
  541. Join::Linear
  542. linear_stage[0]
  543. lookup={ relation=1, key=[#0{b}] }
  544. stream={ key=[#0{a}], thinning=(#1) }
  545. source={ relation=0, key=[#0{a}] }
  546. Get::PassArrangements l0
  547. raw=false
  548. arrangements[0]={ key=[#0{a}], permutation=id, thinning=(#1) }
  549. types=[text?, text?]
  550. ArrangeBy
  551. raw=true
  552. arrangements[0]={ key=[#0{b}], permutation=id, thinning=() }
  553. types=[text]
  554. Get::Collection l1
  555. project=(#1)
  556. filter=((#1{b}) IS NOT NULL)
  557. raw=true
  558. Return
  559. Get::PassArrangements l1
  560. raw=true
  561. Used Indexes:
  562. - materialize.public.potato_a_idx (differential join, lookup)
  563. Target cluster: quickstart
  564. EOF