cte_lowering.slt 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  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. # Test that correlated CTE are lowered properly
  10. mode cockroach
  11. statement ok
  12. CREATE TABLE x (a int)
  13. statement ok
  14. INSERT INTO x VALUES (1), (2), (3)
  15. statement ok
  16. CREATE TABLE y (a int)
  17. statement ok
  18. INSERT INTO y VALUES (2), (3), (4)
  19. # Check that CTEs aren't inlined during planning
  20. query T multiline
  21. EXPLAIN RAW PLAN FOR
  22. WITH t AS (SELECT * FROM y WHERE a < 3)
  23. SELECT * FROM t NATURAL JOIN t a;
  24. ----
  25. Project (#0)
  26. With
  27. cte [l0 as t] =
  28. Filter (#0{a} < 3)
  29. Get materialize.public.y
  30. Return
  31. InnerJoin (#0{a} = #1{a})
  32. Get l0
  33. Get l0
  34. Target cluster: quickstart
  35. EOF
  36. # Check that CTE defined in outer context is explained properly
  37. query T multiline
  38. EXPLAIN RAW PLAN FOR
  39. WITH t AS (SELECT * FROM y WHERE a < 3)
  40. SELECT * FROM y WHERE (select a from t) < a;
  41. ----
  42. With
  43. cte [l0 as t] =
  44. Filter (#0{a} < 3)
  45. Get materialize.public.y
  46. Return
  47. Filter (select(Get l0) < #0{a})
  48. Get materialize.public.y
  49. Target cluster: quickstart
  50. EOF
  51. # Check the body of a CTE is only lowered once
  52. query T multiline
  53. EXPLAIN DECORRELATED PLAN WITH(arity) FOR
  54. WITH t AS (SELECT * FROM y WHERE a < 3)
  55. SELECT * FROM t NATURAL JOIN t a;
  56. ----
  57. With
  58. cte l0 =
  59. Filter (#0{a} < 3) // { arity: 1 }
  60. CrossJoin // { arity: 1 }
  61. Constant // { arity: 0 }
  62. - ()
  63. Get materialize.public.y // { arity: 1 }
  64. Return // { arity: 1 }
  65. Project (#0) // { arity: 1 }
  66. Filter (#0{a} = #1{a}) // { arity: 2 }
  67. Project (#0, #1) // { arity: 2 }
  68. CrossJoin // { arity: 2 }
  69. Get l0 // { arity: 1 }
  70. Get l0 // { arity: 1 }
  71. Target cluster: quickstart
  72. EOF
  73. # Correlated CTE inside a LATERAL join operand
  74. query T multiline
  75. EXPLAIN DECORRELATED PLAN WITH(arity) FOR
  76. SELECT *
  77. FROM x,
  78. LATERAL(WITH a(m) AS (SELECT max(y.a) FROM y WHERE y.a < x.a)
  79. SELECT * FROM a);
  80. ----
  81. With
  82. cte l0 =
  83. CrossJoin // { arity: 1 }
  84. Constant // { arity: 0 }
  85. - ()
  86. Get materialize.public.x // { arity: 1 }
  87. cte l1 =
  88. Distinct project=[#0] // { arity: 1 }
  89. Get l0 // { arity: 1 }
  90. cte l2 =
  91. Reduce group_by=[#0] aggregates=[max(#1{a})] // { arity: 2 }
  92. Filter (#1{a} < #0{a}) // { arity: 2 }
  93. CrossJoin // { arity: 2 }
  94. Get l1 // { arity: 1 }
  95. Get materialize.public.y // { arity: 1 }
  96. Return // { arity: 2 }
  97. Project (#0, #2) // { arity: 2 }
  98. Join on=(#0 = #1) // { arity: 3 }
  99. Get l0 // { arity: 1 }
  100. Union // { arity: 2 }
  101. Get l2 // { arity: 2 }
  102. CrossJoin // { arity: 2 }
  103. Project (#0) // { arity: 1 }
  104. Join on=(#0 = #1) // { arity: 2 }
  105. Union // { arity: 1 }
  106. Negate // { arity: 1 }
  107. Distinct project=[#0] // { arity: 1 }
  108. Get l2 // { arity: 2 }
  109. Distinct project=[#0] // { arity: 1 }
  110. Get l1 // { arity: 1 }
  111. Get l1 // { arity: 1 }
  112. Constant // { arity: 1 }
  113. - (null)
  114. Target cluster: quickstart
  115. EOF
  116. query II rowsort
  117. SELECT *
  118. FROM x,
  119. LATERAL(WITH a(m) AS (SELECT max(y.a) FROM y WHERE y.a < x.a)
  120. SELECT * FROM a);
  121. ----
  122. 1 NULL
  123. 2 NULL
  124. 3 2
  125. # Reference of a correlated CTE applied to an outer relation that has the same cardinality as
  126. # the one the CTE was applied to.
  127. # When the CTE is lowered, the outer relation is `Get x`. But then, the reference of the CTE
  128. # is applied to `Distinct(Join(Get x, Get y), x.*)` which has the same cardinality as `Get x`.
  129. query T multiline
  130. EXPLAIN DECORRELATED PLAN WITH(arity) FOR
  131. SELECT *
  132. FROM x,
  133. LATERAL(WITH a(m) as (SELECT max(y.a) FROM y WHERE y.a < x.a)
  134. SELECT (SELECT m FROM a) FROM y) b;
  135. ----
  136. With
  137. cte l0 =
  138. CrossJoin // { arity: 1 }
  139. Constant // { arity: 0 }
  140. - ()
  141. Get materialize.public.x // { arity: 1 }
  142. cte l1 =
  143. Distinct project=[#0] // { arity: 1 }
  144. Get l0 // { arity: 1 }
  145. cte l2 =
  146. Reduce group_by=[#0] aggregates=[max(#1{a})] // { arity: 2 }
  147. Filter (#1{a} < #0{a}) // { arity: 2 }
  148. CrossJoin // { arity: 2 }
  149. Get l1 // { arity: 1 }
  150. Get materialize.public.y // { arity: 1 }
  151. cte l3 =
  152. CrossJoin // { arity: 2 }
  153. Get l1 // { arity: 1 }
  154. Get materialize.public.y // { arity: 1 }
  155. cte l4 =
  156. Distinct project=[#0, #1] // { arity: 2 }
  157. Get l3 // { arity: 2 }
  158. cte l5 =
  159. Distinct project=[#0] // { arity: 1 }
  160. Get l4 // { arity: 2 }
  161. cte l6 =
  162. Project (#0, #2) // { arity: 2 }
  163. Join on=(#0 = #1) // { arity: 3 }
  164. Get l5 // { arity: 1 }
  165. Union // { arity: 2 }
  166. Get l2 // { arity: 2 }
  167. CrossJoin // { arity: 2 }
  168. Project (#0) // { arity: 1 }
  169. Join on=(#0 = #1) // { arity: 2 }
  170. Union // { arity: 1 }
  171. Negate // { arity: 1 }
  172. Distinct project=[#0] // { arity: 1 }
  173. Get l2 // { arity: 2 }
  174. Distinct project=[#0] // { arity: 1 }
  175. Get l1 // { arity: 1 }
  176. Get l1 // { arity: 1 }
  177. Constant // { arity: 1 }
  178. - (null)
  179. cte l7 =
  180. Union // { arity: 2 }
  181. Get l6 // { arity: 2 }
  182. Project (#0, #2) // { arity: 2 }
  183. FlatMap guard_subquery_size(#1) // { arity: 3 }
  184. Reduce group_by=[#0] aggregates=[count(*)] // { arity: 2 }
  185. Get l6 // { arity: 2 }
  186. Return // { arity: 2 }
  187. Project (#0, #2) // { arity: 2 }
  188. Join on=(#0 = #1) // { arity: 3 }
  189. Get l0 // { arity: 1 }
  190. Project (#0, #2) // { arity: 2 }
  191. Project (#0, #1, #5) // { arity: 3 }
  192. Map (#4) // { arity: 6 }
  193. Join on=(#0 = #2 AND #1 = #3) // { arity: 5 }
  194. Get l3 // { arity: 2 }
  195. Project (#0, #1, #3) // { arity: 3 }
  196. Join on=(#0 = #2) // { arity: 4 }
  197. Get l4 // { arity: 2 }
  198. Union // { arity: 2 }
  199. Get l7 // { arity: 2 }
  200. CrossJoin // { arity: 2 }
  201. Project (#0) // { arity: 1 }
  202. Join on=(#0 = #1) // { arity: 2 }
  203. Union // { arity: 1 }
  204. Negate // { arity: 1 }
  205. Distinct project=[#0] // { arity: 1 }
  206. Get l7 // { arity: 2 }
  207. Distinct project=[#0] // { arity: 1 }
  208. Get l5 // { arity: 1 }
  209. Get l5 // { arity: 1 }
  210. Constant // { arity: 1 }
  211. - (null)
  212. Target cluster: quickstart
  213. EOF
  214. # Correlated CTE used at different scope level: offset 0 and offset 1 (RHS of the join)
  215. # Note: the CTE is represented by %12 (l4)
  216. query T multiline
  217. EXPLAIN DECORRELATED PLAN WITH(arity) FOR
  218. SELECT *
  219. FROM x,
  220. LATERAL(WITH a(m) AS (SELECT max(y.a) FROM y WHERE y.a < x.a)
  221. SELECT * FROM a INNER JOIN a b ON a.m = b.m);
  222. ----
  223. With
  224. cte l0 =
  225. CrossJoin // { arity: 1 }
  226. Constant // { arity: 0 }
  227. - ()
  228. Get materialize.public.x // { arity: 1 }
  229. cte l1 =
  230. Distinct project=[#0] // { arity: 1 }
  231. Get l0 // { arity: 1 }
  232. cte l2 =
  233. Reduce group_by=[#0] aggregates=[max(#1{a})] // { arity: 2 }
  234. Filter (#1{a} < #0{a}) // { arity: 2 }
  235. CrossJoin // { arity: 2 }
  236. Get l1 // { arity: 1 }
  237. Get materialize.public.y // { arity: 1 }
  238. cte l3 =
  239. Union // { arity: 2 }
  240. Get l2 // { arity: 2 }
  241. CrossJoin // { arity: 2 }
  242. Project (#0) // { arity: 1 }
  243. Join on=(#0 = #1) // { arity: 2 }
  244. Union // { arity: 1 }
  245. Negate // { arity: 1 }
  246. Distinct project=[#0] // { arity: 1 }
  247. Get l2 // { arity: 2 }
  248. Distinct project=[#0] // { arity: 1 }
  249. Get l1 // { arity: 1 }
  250. Get l1 // { arity: 1 }
  251. Constant // { arity: 1 }
  252. - (null)
  253. Return // { arity: 3 }
  254. Project (#0, #2, #3) // { arity: 3 }
  255. Join on=(#0 = #1) // { arity: 4 }
  256. Get l0 // { arity: 1 }
  257. Filter (#1{m} = #2{m}) // { arity: 3 }
  258. Project (#0, #1, #3) // { arity: 3 }
  259. Join on=(#0 = #2) // { arity: 4 }
  260. Get l3 // { arity: 2 }
  261. Get l3 // { arity: 2 }
  262. Target cluster: quickstart
  263. EOF
  264. query III
  265. SELECT *
  266. FROM x,
  267. LATERAL(WITH a(m) AS (SELECT max(y.a) FROM y WHERE y.a < x.a)
  268. SELECT * FROM a INNER JOIN a b ON a.m = b.m);
  269. ----
  270. 3 2 2
  271. query III rowsort
  272. SELECT *
  273. FROM x,
  274. LATERAL(WITH a(m) as (SELECT max(y.a) FROM y WHERE y.a < x.a)
  275. SELECT * FROM a INNER JOIN a b ON true);
  276. ----
  277. 1 NULL NULL
  278. 2 NULL NULL
  279. 3 2 2
  280. # Correlated CTE used at different scope level: offset 0 and offset 3 (subquery in the
  281. # selection list of a derived relation in the RHS of the join)
  282. query T multiline
  283. EXPLAIN DECORRELATED PLAN WITH(arity) FOR
  284. SELECT *
  285. FROM x,
  286. LATERAL(WITH a(m) as (SELECT max(y.a) FROM y WHERE y.a < x.a)
  287. SELECT * FROM a INNER JOIN (SELECT (SELECT m FROM a) FROM y) b ON true);
  288. ----
  289. With
  290. cte l0 =
  291. CrossJoin // { arity: 1 }
  292. Constant // { arity: 0 }
  293. - ()
  294. Get materialize.public.x // { arity: 1 }
  295. cte l1 =
  296. Distinct project=[#0] // { arity: 1 }
  297. Get l0 // { arity: 1 }
  298. cte l2 =
  299. Reduce group_by=[#0] aggregates=[max(#1{a})] // { arity: 2 }
  300. Filter (#1{a} < #0{a}) // { arity: 2 }
  301. CrossJoin // { arity: 2 }
  302. Get l1 // { arity: 1 }
  303. Get materialize.public.y // { arity: 1 }
  304. cte l3 =
  305. Union // { arity: 2 }
  306. Get l2 // { arity: 2 }
  307. CrossJoin // { arity: 2 }
  308. Project (#0) // { arity: 1 }
  309. Join on=(#0 = #1) // { arity: 2 }
  310. Union // { arity: 1 }
  311. Negate // { arity: 1 }
  312. Distinct project=[#0] // { arity: 1 }
  313. Get l2 // { arity: 2 }
  314. Distinct project=[#0] // { arity: 1 }
  315. Get l1 // { arity: 1 }
  316. Get l1 // { arity: 1 }
  317. Constant // { arity: 1 }
  318. - (null)
  319. cte l4 =
  320. CrossJoin // { arity: 2 }
  321. Get l1 // { arity: 1 }
  322. Get materialize.public.y // { arity: 1 }
  323. cte l5 =
  324. Distinct project=[#0, #1] // { arity: 2 }
  325. Get l4 // { arity: 2 }
  326. cte l6 =
  327. Distinct project=[#0] // { arity: 1 }
  328. Get l5 // { arity: 2 }
  329. cte l7 =
  330. Project (#0, #2) // { arity: 2 }
  331. Join on=(#0 = #1) // { arity: 3 }
  332. Get l6 // { arity: 1 }
  333. Get l3 // { arity: 2 }
  334. cte l8 =
  335. Union // { arity: 2 }
  336. Get l7 // { arity: 2 }
  337. Project (#0, #2) // { arity: 2 }
  338. FlatMap guard_subquery_size(#1) // { arity: 3 }
  339. Reduce group_by=[#0] aggregates=[count(*)] // { arity: 2 }
  340. Get l7 // { arity: 2 }
  341. Return // { arity: 3 }
  342. Project (#0, #2, #3) // { arity: 3 }
  343. Join on=(#0 = #1) // { arity: 4 }
  344. Get l0 // { arity: 1 }
  345. Project (#0, #1, #3) // { arity: 3 }
  346. Join on=(#0 = #2) // { arity: 4 }
  347. Get l3 // { arity: 2 }
  348. Project (#0, #5) // { arity: 2 }
  349. Map (#4) // { arity: 6 }
  350. Join on=(#0 = #2 AND #1 = #3) // { arity: 5 }
  351. Get l4 // { arity: 2 }
  352. Project (#0, #1, #3) // { arity: 3 }
  353. Join on=(#0 = #2) // { arity: 4 }
  354. Get l5 // { arity: 2 }
  355. Union // { arity: 2 }
  356. Get l8 // { arity: 2 }
  357. CrossJoin // { arity: 2 }
  358. Project (#0) // { arity: 1 }
  359. Join on=(#0 = #1) // { arity: 2 }
  360. Union // { arity: 1 }
  361. Negate // { arity: 1 }
  362. Distinct project=[#0] // { arity: 1 }
  363. Get l8 // { arity: 2 }
  364. Distinct project=[#0] // { arity: 1 }
  365. Get l6 // { arity: 1 }
  366. Get l6 // { arity: 1 }
  367. Constant // { arity: 1 }
  368. - (null)
  369. Target cluster: quickstart
  370. EOF
  371. query III rowsort
  372. SELECT *
  373. FROM x,
  374. LATERAL(WITH a(m) AS (SELECT max(y.a) FROM y WHERE y.a < x.a)
  375. SELECT * FROM a INNER JOIN (SELECT (SELECT m FROM a) FROM y) b ON true);
  376. ----
  377. 1 NULL NULL
  378. 1 NULL NULL
  379. 1 NULL NULL
  380. 2 NULL NULL
  381. 2 NULL NULL
  382. 2 NULL NULL
  383. 3 2 2
  384. 3 2 2
  385. 3 2 2
  386. # Correlated CTE used from a correlated scope
  387. # Note: the CTE is represented by %12 (l4)
  388. query T multiline
  389. EXPLAIN DECORRELATED PLAN WITH(arity) FOR
  390. SELECT *
  391. FROM x,
  392. LATERAL(WITH a(m) AS (SELECT max(y.a) FROM y WHERE y.a < x.a)
  393. SELECT * FROM y INNER JOIN LATERAL(SELECT y.a FROM x WHERE (SELECT m FROM a) > 0) ON true);
  394. ----
  395. With
  396. cte l0 =
  397. CrossJoin // { arity: 1 }
  398. Constant // { arity: 0 }
  399. - ()
  400. Get materialize.public.x // { arity: 1 }
  401. cte l1 =
  402. Distinct project=[#0] // { arity: 1 }
  403. Get l0 // { arity: 1 }
  404. cte l2 =
  405. Reduce group_by=[#0] aggregates=[max(#1{a})] // { arity: 2 }
  406. Filter (#1{a} < #0{a}) // { arity: 2 }
  407. CrossJoin // { arity: 2 }
  408. Get l1 // { arity: 1 }
  409. Get materialize.public.y // { arity: 1 }
  410. cte l3 =
  411. CrossJoin // { arity: 2 }
  412. Get l1 // { arity: 1 }
  413. Get materialize.public.y // { arity: 1 }
  414. cte l4 =
  415. CrossJoin // { arity: 2 }
  416. Distinct project=[#1] // { arity: 1 }
  417. Get l3 // { arity: 2 }
  418. Get materialize.public.x // { arity: 1 }
  419. cte l5 =
  420. Distinct project=[#0] // { arity: 1 }
  421. Get l4 // { arity: 2 }
  422. cte l6 =
  423. Project (#0, #2) // { arity: 2 }
  424. Join on=(#0 = #1) // { arity: 3 }
  425. Get l5 // { arity: 1 }
  426. Union // { arity: 2 }
  427. Get l2 // { arity: 2 }
  428. CrossJoin // { arity: 2 }
  429. Project (#0) // { arity: 1 }
  430. Join on=(#0 = #1) // { arity: 2 }
  431. Union // { arity: 1 }
  432. Negate // { arity: 1 }
  433. Distinct project=[#0] // { arity: 1 }
  434. Get l2 // { arity: 2 }
  435. Distinct project=[#0] // { arity: 1 }
  436. Get l1 // { arity: 1 }
  437. Get l1 // { arity: 1 }
  438. Constant // { arity: 1 }
  439. - (null)
  440. cte l7 =
  441. Union // { arity: 2 }
  442. Get l6 // { arity: 2 }
  443. Project (#0, #2) // { arity: 2 }
  444. FlatMap guard_subquery_size(#1) // { arity: 3 }
  445. Reduce group_by=[#0] aggregates=[count(*)] // { arity: 2 }
  446. Get l6 // { arity: 2 }
  447. Return // { arity: 3 }
  448. Project (#0, #2, #3) // { arity: 3 }
  449. Join on=(#0 = #1) // { arity: 4 }
  450. Get l0 // { arity: 1 }
  451. Project (#0, #1, #3) // { arity: 3 }
  452. Join on=(#1 = #2) // { arity: 4 }
  453. Get l3 // { arity: 2 }
  454. Project (#0, #2) // { arity: 2 }
  455. Map (#0{a}) // { arity: 3 }
  456. Project (#0, #1) // { arity: 2 }
  457. Filter (#2 > 0) // { arity: 3 }
  458. Project (#0, #1, #3) // { arity: 3 }
  459. Join on=(#0 = #2) // { arity: 4 }
  460. Get l4 // { arity: 2 }
  461. Union // { arity: 2 }
  462. Get l7 // { arity: 2 }
  463. CrossJoin // { arity: 2 }
  464. Project (#0) // { arity: 1 }
  465. Join on=(#0 = #1) // { arity: 2 }
  466. Union // { arity: 1 }
  467. Negate // { arity: 1 }
  468. Distinct project=[#0] // { arity: 1 }
  469. Get l7 // { arity: 2 }
  470. Distinct project=[#0] // { arity: 1 }
  471. Get l5 // { arity: 1 }
  472. Get l5 // { arity: 1 }
  473. Constant // { arity: 1 }
  474. - (null)
  475. Target cluster: quickstart
  476. EOF
  477. # Check that CTEs are annotated with their names
  478. query T multiline
  479. EXPLAIN RAW PLAN FOR
  480. WITH a(a) AS (SELECT a FROM y),
  481. b(b) AS (SELECT a FROM y),
  482. x(x) AS (SELECT b FROM b)
  483. SELECT (WITH c(c) AS (SELECT a FROM y)
  484. SELECT c FROM c where (WITH d(d) AS (SELECT c FROM c)
  485. SELECT max(d) FROM d) > 1)
  486. FROM (WITH e(e) AS (SELECT b FROM b)
  487. SELECT e FROM e where (WITH f(f) AS (SELECT e FROM e)
  488. SELECT min(f) FROM f)
  489. < (SELECT max(x) FROM x))
  490. ----
  491. Project (#1)
  492. With
  493. cte [l0 as a] =
  494. Get materialize.public.y
  495. cte [l1 as b] =
  496. Get materialize.public.y
  497. cte [l2 as x] =
  498. Get l1
  499. cte [l8 as subquery-8] =
  500. With
  501. cte [l3 as c] =
  502. Get materialize.public.y
  503. cte [l5 as subquery-5] =
  504. With
  505. cte [l4 as d] =
  506. Get l3
  507. Return
  508. Reduce aggregates=[max(#0{d})]
  509. Get l4
  510. Return
  511. Filter (select(Get l5) > 1)
  512. Get l3
  513. Return
  514. Map (select(Get l8))
  515. With
  516. cte [l3 as e] =
  517. Get l1
  518. cte [l7 as subquery-7] =
  519. Reduce aggregates=[max(#0{x})]
  520. Get l2
  521. cte [l6 as subquery-6] =
  522. With
  523. cte [l4 as f] =
  524. Get l3
  525. Return
  526. Reduce aggregates=[min(#0{f})]
  527. Get l4
  528. Return
  529. Filter (select(Get l6) < select(Get l7))
  530. Get l3
  531. Target cluster: quickstart
  532. EOF
  533. # CTEs with the same name in nested context
  534. query T multiline
  535. EXPLAIN RAW PLAN FOR
  536. WITH a(a) AS (SELECT a FROM y) SELECT * FROM (WITH a(a) AS (SELECT a FROM a) SELECT a FROM a);
  537. ----
  538. With
  539. cte [l0 as a] =
  540. Get materialize.public.y
  541. cte [l1 as a] =
  542. Get l0
  543. Return
  544. Get l1
  545. Target cluster: quickstart
  546. EOF