limit_expr.slt 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  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. # ---------------------------------------------------------
  10. # Non-literal expressions in LIMIT.
  11. # (For literals, see `order_by.slt`)
  12. # ---------------------------------------------------------
  13. mode cockroach
  14. simple conn=mz_system,user=mz_system
  15. ALTER SYSTEM SET enable_expressions_in_limit_syntax TO true;
  16. ----
  17. COMPLETE 0
  18. # Schema
  19. # ------
  20. statement ok
  21. CREATE TABLE people (id int, first_name text, allowance int);
  22. statement ok
  23. CREATE TABLE preferred_fruits (person_id int, fruit text, preference int);
  24. statement ok
  25. INSERT INTO people VALUES
  26. (1, 'frank', 4),
  27. (2, 'rj' , 2),
  28. (3, 'nick' , 1);
  29. statement ok
  30. INSERT INTO preferred_fruits VALUES
  31. (1, 'apple' , 1),
  32. (1, 'banana', 2),
  33. (1, 'orange', 3),
  34. (1, 'kiwi' , 4),
  35. (1, 'mango' , 5),
  36. (2, 'apple' , 1),
  37. (2, 'orange', 2),
  38. (2, 'banana', 3),
  39. (2, 'kiwi' , 4),
  40. (3, 'mango' , 1),
  41. (3, 'pickle', 2);
  42. statement ok
  43. CREATE TABLE cities (
  44. name text NOT NULL,
  45. state text NOT NULL,
  46. pop int NOT NULL
  47. );
  48. statement ok
  49. INSERT INTO cities VALUES
  50. ('Los_Angeles', 'CA', 3979576),
  51. ('Phoenix', 'AZ', 1680992),
  52. ('Houston', 'TX', 2320268),
  53. ('San_Diego', 'CA', 1423851),
  54. ('San_Francisco', 'CA', 881549),
  55. ('New_York', 'NY', 8336817),
  56. ('Dallas', 'TX', 1343573),
  57. ('San_Antonio', 'TX', 1547253),
  58. ('San_Jose', 'CA', 1021795),
  59. ('Chicago', 'IL', 2695598),
  60. ('Austin', 'TX', 978908);
  61. statement ok
  62. CREATE TABLE limits (sl text, l int);
  63. statement ok
  64. INSERT INTO limits VALUES
  65. ('C', 2),
  66. ('T', NULL);
  67. # Happy cases
  68. # -----------
  69. # Correlated inner join.
  70. # Result:
  71. query TT
  72. SELECT
  73. first_name, fruit
  74. FROM
  75. people,
  76. LATERAL (SELECT fruit, preference FROM preferred_fruits WHERE person_id = id ORDER BY preference ASC LIMIT allowance OFFSET 1)
  77. ORDER BY
  78. first_name, preference
  79. ----
  80. frank banana
  81. frank orange
  82. frank kiwi
  83. frank mango
  84. nick pickle
  85. rj orange
  86. rj banana
  87. # Correlated inner join.
  88. # Plan:
  89. query T multiline
  90. EXPLAIN OPTIMIZED PLAN WITH(arity, humanized expressions) AS VERBOSE TEXT FOR
  91. SELECT
  92. first_name, fruit
  93. FROM
  94. people,
  95. LATERAL (SELECT fruit, preference FROM preferred_fruits WHERE person_id = id ORDER BY preference ASC LIMIT allowance OFFSET 1)
  96. ORDER BY
  97. first_name, preference
  98. ----
  99. Explained Query:
  100. Finish order_by=[#1{first_name} asc nulls_last, #4{preference} asc nulls_last] output=[#1, #3]
  101. Project (#0{id}..=#2{allowance}, #5{fruit}, #6{preference}) // { arity: 5 }
  102. Join on=(#0{id} = #3{id} AND #2{allowance} = #4{allowance}) type=differential // { arity: 7 }
  103. ArrangeBy keys=[[#0{id}, #2{allowance}]] // { arity: 3 }
  104. ReadStorage materialize.public.people // { arity: 3 }
  105. ArrangeBy keys=[[#0{id}, #1{allowance}]] // { arity: 4 }
  106. TopK group_by=[#0{id}, #1{allowance}] order_by=[#3{preference} asc nulls_last] limit=integer_to_bigint(#1{allowance}) offset=1 // { arity: 4 }
  107. Project (#0{id}, #1{allowance}, #3{fruit}, #4{preference}) // { arity: 4 }
  108. Join on=(#0{id} = #2{person_id}) type=differential // { arity: 5 }
  109. ArrangeBy keys=[[#0{id}]] // { arity: 2 }
  110. Distinct project=[#0{id}, #1{allowance}] // { arity: 2 }
  111. Project (#0{id}, #2{allowance}) // { arity: 2 }
  112. Filter (#0{id}) IS NOT NULL // { arity: 3 }
  113. ReadStorage materialize.public.people // { arity: 3 }
  114. ArrangeBy keys=[[#0{person_id}]] // { arity: 3 }
  115. Filter (#0{person_id}) IS NOT NULL // { arity: 3 }
  116. ReadStorage materialize.public.preferred_fruits // { arity: 3 }
  117. Source materialize.public.people
  118. Source materialize.public.preferred_fruits
  119. filter=((#0{person_id}) IS NOT NULL)
  120. Target cluster: quickstart
  121. EOF
  122. # Outer context is a singleton literal collection.
  123. # Result:
  124. query TT
  125. SELECT
  126. first_name, fruit
  127. FROM
  128. (VALUES (1, 'frank', 4)) AS people(id, first_name, allowance),
  129. LATERAL (SELECT fruit, preference FROM preferred_fruits WHERE person_id = id ORDER BY preference ASC LIMIT allowance OFFSET 1)
  130. ORDER BY
  131. first_name, preference
  132. ----
  133. frank banana
  134. frank orange
  135. frank kiwi
  136. frank mango
  137. # Outer context is a singleton literal collection.
  138. # Plan:
  139. query T multiline
  140. EXPLAIN OPTIMIZED PLAN WITH(arity, humanized expressions) AS VERBOSE TEXT FOR
  141. SELECT
  142. first_name, fruit
  143. FROM
  144. (VALUES (1, 'frank', -4)) AS people(id, first_name, allowance),
  145. LATERAL (SELECT fruit, preference FROM preferred_fruits WHERE person_id = id ORDER BY preference ASC LIMIT allowance OFFSET 1)
  146. ORDER BY
  147. first_name, preference
  148. ----
  149. Explained Query:
  150. Finish order_by=[#1 asc nulls_last, #4{preference} asc nulls_last] output=[#1, #3]
  151. Project (#2..=#4, #0{fruit}, #1{preference}) // { arity: 5 }
  152. Map (1, "frank", -4) // { arity: 5 }
  153. TopK order_by=[#1{preference} asc nulls_last] limit=-4 offset=1 // { arity: 2 }
  154. Project (#1{fruit}, #2{preference}) // { arity: 2 }
  155. Filter (#0{person_id} = 1) // { arity: 3 }
  156. ReadStorage materialize.public.preferred_fruits // { arity: 3 }
  157. Source materialize.public.preferred_fruits
  158. filter=((#0{person_id} = 1))
  159. Target cluster: quickstart
  160. EOF
  161. # More complex limit expression.
  162. # Result:
  163. query TT
  164. SELECT s.state, c.name FROM
  165. (SELECT DISTINCT state FROM cities) s,
  166. LATERAL (SELECT name FROM cities WHERE state = s.state LIMIT ascii(substring(state, 1, 1)) - 64) c
  167. ORDER BY s.state, c.name
  168. LIMIT 3;
  169. ----
  170. AZ Phoenix
  171. CA Los_Angeles
  172. CA San_Diego
  173. # More complex limit expression.
  174. # Plan:
  175. query T multiline
  176. EXPLAIN OPTIMIZED PLAN WITH(arity, humanized expressions) AS VERBOSE TEXT FOR
  177. SELECT s.state, c.name FROM
  178. (SELECT DISTINCT state FROM cities) s,
  179. LATERAL (SELECT name FROM cities WHERE state = s.state LIMIT ascii(substring(state, 1, 1)) - 64) c
  180. ORDER BY s.state, c.name
  181. LIMIT 3;
  182. ----
  183. Explained Query:
  184. Finish order_by=[#0{state} asc nulls_last, #1{name} asc nulls_last] limit=3 output=[#0, #1]
  185. TopK group_by=[#0{state}] limit=integer_to_bigint((ascii(substr(#0{state}, 1, 1)) - 64)) // { arity: 2 }
  186. Project (#1{state}, #0{name}) // { arity: 2 }
  187. ReadStorage materialize.public.cities // { arity: 3 }
  188. Source materialize.public.cities
  189. Target cluster: quickstart
  190. EOF
  191. # A correlated subquery in the limit clause.
  192. # Result:
  193. query TT
  194. SELECT s.state, c.name
  195. FROM
  196. (SELECT DISTINCT state FROM cities) s,
  197. LATERAL (
  198. SELECT name FROM cities c
  199. WHERE state = s.state
  200. ORDER BY c.name
  201. LIMIT (SELECT l FROM limits WHERE sl = substring(s.state, 1, 1))) c
  202. ORDER BY s.state, c.name;
  203. ----
  204. AZ Phoenix
  205. CA Los_Angeles
  206. CA San_Diego
  207. IL Chicago
  208. NY New_York
  209. TX Austin
  210. TX Dallas
  211. TX Houston
  212. TX San_Antonio
  213. # A correlated subquery in the limit clause.
  214. # Plan:
  215. query T multiline
  216. EXPLAIN OPTIMIZED PLAN WITH(arity, humanized expressions) AS VERBOSE TEXT FOR
  217. SELECT s.state, c.name
  218. FROM
  219. (SELECT DISTINCT state FROM cities) s,
  220. LATERAL (
  221. SELECT name FROM cities c
  222. WHERE state = s.state
  223. ORDER BY c.name
  224. LIMIT (SELECT l FROM limits WHERE sl = substring(s.state, 1, 1))) c
  225. ORDER BY s.state, c.name;
  226. ----
  227. Explained Query:
  228. Finish order_by=[#0{state} asc nulls_last, #1{name} asc nulls_last] output=[#0, #1]
  229. With
  230. cte l0 =
  231. Distinct project=[#0{state}] // { arity: 1 }
  232. Project (#1{state}) // { arity: 1 }
  233. ReadStorage materialize.public.cities // { arity: 3 }
  234. cte l1 =
  235. Project (#0{state}, #2{l}) // { arity: 2 }
  236. Join on=(#1{sl} = substr(#0{state}, 1, 1)) type=differential // { arity: 3 }
  237. ArrangeBy keys=[[substr(#0{state}, 1, 1)]] // { arity: 1 }
  238. Get l0 // { arity: 1 }
  239. ArrangeBy keys=[[#0{sl}]] // { arity: 2 }
  240. Filter (#0{sl}) IS NOT NULL // { arity: 2 }
  241. ReadStorage materialize.public.limits // { arity: 2 }
  242. cte l2 =
  243. Union // { arity: 2 }
  244. Get l1 // { arity: 2 }
  245. Project (#0{state}, #2) // { arity: 2 }
  246. FlatMap guard_subquery_size(#1{count}) // { arity: 3 }
  247. Reduce group_by=[#0{state}] aggregates=[count(*)] // { arity: 2 }
  248. Project (#0{state}) // { arity: 1 }
  249. Get l1 // { arity: 2 }
  250. Return // { arity: 2 }
  251. Project (#1{state}, #0{name}) // { arity: 2 }
  252. TopK group_by=[#1{state}, #2{l}] order_by=[#0{name} asc nulls_last] limit=integer_to_bigint(#2{l}) // { arity: 3 }
  253. Project (#0{name}, #1{state}, #3{l}) // { arity: 3 }
  254. Join on=(#1{state} = #2{state}) type=differential // { arity: 4 }
  255. ArrangeBy keys=[[#1{state}]] // { arity: 2 }
  256. Project (#0{name}, #1{state}) // { arity: 2 }
  257. ReadStorage materialize.public.cities // { arity: 3 }
  258. ArrangeBy keys=[[#0{state}]] // { arity: 2 }
  259. Union // { arity: 2 }
  260. Get l2 // { arity: 2 }
  261. Map (null) // { arity: 2 }
  262. Union // { arity: 1 }
  263. Negate // { arity: 1 }
  264. Distinct project=[#0{state}] // { arity: 1 }
  265. Project (#0{state}) // { arity: 1 }
  266. Get l2 // { arity: 2 }
  267. Get l0 // { arity: 1 }
  268. Source materialize.public.cities
  269. Source materialize.public.limits
  270. filter=((#0{sl}) IS NOT NULL)
  271. Target cluster: quickstart
  272. EOF
  273. # Limit is a cast.
  274. # Result:
  275. query TT
  276. SELECT s.state, c.name FROM
  277. (SELECT DISTINCT state FROM cities) s,
  278. LATERAL (SELECT name FROM cities c LIMIT '1'::INT) c;
  279. ----
  280. AZ Austin
  281. CA Austin
  282. IL Austin
  283. NY Austin
  284. TX Austin
  285. # Limit is a cast.
  286. # Result:
  287. query T multiline
  288. EXPLAIN OPTIMIZED PLAN WITH(arity, humanized expressions) AS VERBOSE TEXT FOR
  289. SELECT s.state, c.name FROM
  290. (SELECT DISTINCT state FROM cities) s,
  291. LATERAL (SELECT name FROM cities c LIMIT '1'::INT) c;
  292. ----
  293. Explained Query:
  294. CrossJoin type=differential // { arity: 2 }
  295. ArrangeBy keys=[[]] // { arity: 1 }
  296. Distinct project=[#0{state}] // { arity: 1 }
  297. Project (#1{state}) // { arity: 1 }
  298. ReadStorage materialize.public.cities // { arity: 3 }
  299. ArrangeBy keys=[[]] // { arity: 1 }
  300. TopK limit=1 // { arity: 1 }
  301. Project (#0{name}) // { arity: 1 }
  302. ReadStorage materialize.public.cities // { arity: 3 }
  303. Source materialize.public.cities
  304. Target cluster: quickstart
  305. EOF
  306. # A chain of lateral queries with different complex LIMIT expressions.
  307. # Result:
  308. query TTT rowsort
  309. SELECT s.state, c1.name, c2.name FROM
  310. (SELECT DISTINCT state FROM cities) s,
  311. LATERAL (SELECT name FROM cities c WHERE state = s.state LIMIT mod(length(s.state), 3)) c1,
  312. LATERAL (SELECT name FROM cities c WHERE state = s.state LIMIT mod(length(s.state), 4)) c2;
  313. ----
  314. TX Austin Austin
  315. TX Austin Dallas
  316. TX Dallas Austin
  317. TX Dallas Dallas
  318. AZ Phoenix Phoenix
  319. IL Chicago Chicago
  320. NY New_York New_York
  321. CA San_Diego San_Diego
  322. CA San_Diego Los_Angeles
  323. CA Los_Angeles San_Diego
  324. CA Los_Angeles Los_Angeles
  325. # A chain of lateral queries with different complex LIMIT expressions.
  326. #
  327. # TODO: this can be further simplified: similarly to how l2 corresponds to the
  328. # first lateral join we can have an almost identical variant that corresponds to
  329. # the second one followed by a three-way inner join.
  330. #
  331. # Plan:
  332. query T multiline
  333. EXPLAIN OPTIMIZED PLAN WITH(arity, humanized expressions) AS VERBOSE TEXT FOR
  334. SELECT s.state, c1.name, c2.name FROM
  335. (SELECT DISTINCT state FROM cities) s,
  336. LATERAL (SELECT name FROM cities c WHERE state = s.state LIMIT mod(length(s.state), 3)) c1,
  337. LATERAL (SELECT name FROM cities c WHERE state = s.state LIMIT mod(length(s.state), 4)) c2;
  338. ----
  339. Explained Query:
  340. With
  341. cte l0 =
  342. Project (#0{name}, #1{state}) // { arity: 2 }
  343. ReadStorage materialize.public.cities // { arity: 3 }
  344. cte l1 =
  345. TopK group_by=[#1{state}] limit=integer_to_bigint((char_length(#1{state}) % 3)) // { arity: 2 }
  346. Get l0 // { arity: 2 }
  347. Return // { arity: 3 }
  348. Project (#1{state}, #0{name}, #3{name}) // { arity: 3 }
  349. Join on=(#1{state} = #2{state}) type=differential // { arity: 4 }
  350. ArrangeBy keys=[[#1{state}]] // { arity: 2 }
  351. Get l1 // { arity: 2 }
  352. ArrangeBy keys=[[#0{state}]] // { arity: 2 }
  353. TopK group_by=[#0{state}] limit=integer_to_bigint((char_length(#0{state}) % 4)) // { arity: 2 }
  354. Project (#0{state}, #1{name}) // { arity: 2 }
  355. Join on=(#0{state} = #2{state}) type=differential // { arity: 3 }
  356. ArrangeBy keys=[[#0{state}]] // { arity: 1 }
  357. Distinct project=[#0{state}] // { arity: 1 }
  358. Project (#1{state}) // { arity: 1 }
  359. Get l1 // { arity: 2 }
  360. ArrangeBy keys=[[#1{state}]] // { arity: 2 }
  361. Get l0 // { arity: 2 }
  362. Source materialize.public.cities
  363. Target cluster: quickstart
  364. EOF
  365. # Corner cases
  366. # ------------
  367. # Limit 0 produces no results.
  368. query TT
  369. SELECT s.state, c.name FROM
  370. (SELECT DISTINCT state FROM cities) s,
  371. LATERAL (SELECT name FROM cities c LIMIT 0) c;
  372. ----
  373. # Limit 0 reduces to the empty result during optimization.
  374. query T multiline
  375. EXPLAIN OPTIMIZED PLAN WITH(arity, humanized expressions) AS VERBOSE TEXT FOR
  376. SELECT s.state, c.name FROM
  377. (SELECT DISTINCT state FROM cities) s,
  378. LATERAL (SELECT name FROM cities c LIMIT 0) c;
  379. ----
  380. Explained Query (fast path):
  381. Constant <empty>
  382. Target cluster: quickstart
  383. EOF
  384. # Limit NULL produces all results.
  385. query TT rowsort
  386. SELECT s.state, c.name FROM
  387. (SELECT DISTINCT state FROM cities) s,
  388. LATERAL (SELECT name FROM cities c LIMIT NULL) c;
  389. ----
  390. AZ Austin
  391. AZ Dallas
  392. CA Austin
  393. CA Dallas
  394. IL Austin
  395. IL Dallas
  396. NY Austin
  397. NY Dallas
  398. TX Austin
  399. TX Dallas
  400. AZ Chicago
  401. AZ Houston
  402. AZ Phoenix
  403. CA Chicago
  404. CA Houston
  405. CA Phoenix
  406. IL Chicago
  407. IL Houston
  408. IL Phoenix
  409. NY Chicago
  410. NY Houston
  411. NY Phoenix
  412. TX Chicago
  413. TX Houston
  414. TX Phoenix
  415. AZ New_York
  416. AZ San_Jose
  417. CA New_York
  418. CA San_Jose
  419. IL New_York
  420. IL San_Jose
  421. NY New_York
  422. NY San_Jose
  423. TX New_York
  424. TX San_Jose
  425. AZ San_Diego
  426. CA San_Diego
  427. IL San_Diego
  428. NY San_Diego
  429. TX San_Diego
  430. AZ Los_Angeles
  431. AZ San_Antonio
  432. CA Los_Angeles
  433. CA San_Antonio
  434. IL Los_Angeles
  435. IL San_Antonio
  436. NY Los_Angeles
  437. NY San_Antonio
  438. TX Los_Angeles
  439. TX San_Antonio
  440. AZ San_Francisco
  441. CA San_Francisco
  442. IL San_Francisco
  443. NY San_Francisco
  444. TX San_Francisco
  445. # Limit NULL is removed during optimization. (TODO)
  446. query T multiline
  447. EXPLAIN OPTIMIZED PLAN WITH(arity, humanized expressions) AS VERBOSE TEXT FOR
  448. SELECT s.state, c.name FROM
  449. (SELECT DISTINCT state FROM cities) s,
  450. LATERAL (SELECT name FROM cities c LIMIT NULL) c;
  451. ----
  452. Explained Query:
  453. CrossJoin type=differential // { arity: 2 }
  454. ArrangeBy keys=[[]] // { arity: 1 }
  455. Distinct project=[#0{state}] // { arity: 1 }
  456. Project (#1{state}) // { arity: 1 }
  457. ReadStorage materialize.public.cities // { arity: 3 }
  458. ArrangeBy keys=[[]] // { arity: 1 }
  459. Project (#0{name}) // { arity: 1 }
  460. ReadStorage materialize.public.cities // { arity: 3 }
  461. Source materialize.public.cities
  462. Target cluster: quickstart
  463. EOF
  464. # Expected errors
  465. # ---------------
  466. # Simple column refs from `cities` are not in scope for `LIMIT <expr>`.
  467. query error column "name" does not exist
  468. SELECT s.state, c.name FROM
  469. (SELECT DISTINCT state FROM cities) s,
  470. LATERAL (SELECT name FROM cities LIMIT pow(1000, length(name))) c;
  471. # Qualified column refs from `cities c` are not in scope for `LIMIT <expr>`.
  472. query error column "c.state" does not exist
  473. SELECT s.state, c.name FROM
  474. (SELECT DISTINCT state FROM cities) s,
  475. LATERAL (SELECT name FROM cities c LIMIT pow(1000, length(c.state))) c;
  476. # Invalid LIMIT expression evaluated at runtime.
  477. query error Evaluation error: LIMIT must not be negative
  478. SELECT s.state, c.name FROM
  479. (SELECT DISTINCT state FROM cities) s,
  480. LATERAL (SELECT name FROM cities c LIMIT length(state) - 100) c;
  481. # Invalid LIMIT expression evaluated at planning time.
  482. query error LIMIT must not be negative
  483. SELECT s.state, c.name FROM
  484. (SELECT DISTINCT state FROM cities) s,
  485. LATERAL (SELECT name FROM cities c LIMIT -1) c;
  486. # Invalid LIMIT expression evaluated at planning time.
  487. query error LIMIT must not be negative
  488. SELECT s.state, c.name FROM
  489. (SELECT DISTINCT state FROM cities) s,
  490. LATERAL (SELECT name FROM cities c LIMIT '-1') c;
  491. # Invalid LIMIT expression evaluated at planning time.
  492. query error LIMIT must not be negative
  493. SELECT s.state, c.name FROM
  494. (SELECT DISTINCT state FROM cities) s,
  495. LATERAL (SELECT name FROM cities c LIMIT 3 * 4 - 13) c;
  496. # Invalid LIMIT expression evaluated at planning time.
  497. query error value out of range: overflow
  498. SELECT s.state, c.name FROM
  499. (SELECT DISTINCT state FROM cities) s,
  500. LATERAL (SELECT name FROM cities LIMIT pow(10000, 1000)) c;