Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Honor the MATERIALIZED keyword on a common table expression by not flattening the CTE into an outer query. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
8d631a6b9eb06b54b10eda595a4c588c |
User & Date: | drh 2022-04-22 16:15:48.995 |
Context
2022-04-22
| ||
17:36 | Improve EXPLAIN QUERY PLAN output and comments on bytecode listings by distinguishing between "subquery" and "join" and using consistent names across EQP and bytecode. (check-in: a2d3ee9242 user: drh tags: trunk) | |
16:15 | Honor the MATERIALIZED keyword on a common table expression by not flattening the CTE into an outer query. (check-in: 8d631a6b9e user: drh tags: trunk) | |
15:18 | Add test cases to check the handling of SQLITE_BUSY in rbu. (check-in: 6fccc733c6 user: dan tags: trunk) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 | if( pRet ){ int i; pRet->nCte = p->nCte; for(i=0; i<p->nCte; i++){ pRet->a[i].pSelect = sqlite3SelectDup(db, p->a[i].pSelect, 0); pRet->a[i].pCols = sqlite3ExprListDup(db, p->a[i].pCols, 0); pRet->a[i].zName = sqlite3DbStrDup(db, p->a[i].zName); } } } return pRet; } #else # define sqlite3WithDup(x,y) 0 | > | 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 | if( pRet ){ int i; pRet->nCte = p->nCte; for(i=0; i<p->nCte; i++){ pRet->a[i].pSelect = sqlite3SelectDup(db, p->a[i].pSelect, 0); pRet->a[i].pCols = sqlite3ExprListDup(db, p->a[i].pCols, 0); pRet->a[i].zName = sqlite3DbStrDup(db, p->a[i].zName); pRet->a[i].eM10d = p->a[i].eM10d; } } } return pRet; } #else # define sqlite3WithDup(x,y) 0 |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 | ** ** (26) The subquery may not be the right operand of a RIGHT JOIN. ** See also (3) for restrictions on LEFT JOIN. ** ** (27) The subquery may not contain a FULL or RIGHT JOIN unless it ** is the first element of the parent query. ** ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query ** uses aggregates. ** ** If flattening is not attempted, this routine is a no-op and returns 0. ** If flattening is attempted this routine returns 1. | > > | 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 | ** ** (26) The subquery may not be the right operand of a RIGHT JOIN. ** See also (3) for restrictions on LEFT JOIN. ** ** (27) The subquery may not contain a FULL or RIGHT JOIN unless it ** is the first element of the parent query. ** ** (28) The subquery is not a MATERIALIZED CTE. ** ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query ** uses aggregates. ** ** If flattening is not attempted, this routine is a no-op and returns 0. ** If flattening is attempted this routine returns 1. |
︙ | ︙ | |||
4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 | isOuterJoin = -1; } #endif assert( pSubSrc->nSrc>0 ); /* True by restriction (7) */ if( iFrom>0 && (pSubSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){ return 0; /* Restriction (27) */ } /* Restriction (17): If the sub-query is a compound SELECT, then it must ** use only the UNION ALL operator. And none of the simple select queries ** that make up the compound SELECT are allowed to be aggregate or distinct ** queries. */ | > > > | 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 | isOuterJoin = -1; } #endif assert( pSubSrc->nSrc>0 ); /* True by restriction (7) */ if( iFrom>0 && (pSubSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){ return 0; /* Restriction (27) */ } if( pSubitem->fg.isCte && pSubitem->u2.pCteUse->eM10d==M10d_Yes ){ return 0; /* (28) */ } /* Restriction (17): If the sub-query is a compound SELECT, then it must ** use only the UNION ALL operator. And none of the simple select queries ** that make up the compound SELECT are allowed to be aggregate or distinct ** queries. */ |
︙ | ︙ |
Changes to src/treeview.c.
︙ | ︙ | |||
111 112 113 114 115 116 117 118 119 120 121 122 123 124 | int j; for(j=0; j<pCte->pCols->nExpr; j++){ sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zEName); cSep = ','; } sqlite3_str_appendf(&x, ")"); } if( pCte->pUse ){ sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)", pCte->pUse, pCte->pUse->nUse); } sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1); sqlite3TreeViewSelect(pView, pCte->pSelect, 0); | > > > > | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | int j; for(j=0; j<pCte->pCols->nExpr; j++){ sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zEName); cSep = ','; } sqlite3_str_appendf(&x, ")"); } if( pCte->eM10d!=M10d_Any ){ sqlite3_str_appendf(&x, " %sMATERIALIZED", pCte->eM10d==M10d_No ? "NOT " : ""); } if( pCte->pUse ){ sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)", pCte->pUse, pCte->pUse->nUse); } sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1); sqlite3TreeViewSelect(pView, pCte->pSelect, 0); |
︙ | ︙ |
Changes to test/with1.test.
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 | SELECT * FROM Table0 NATURAL JOIN Table0)); } {{}} # 2019-01-17 # Make sure crazy nexted CTE joins terminate with an error quickly. # do_catchsql_test 22.1 { | | | | | | 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 | SELECT * FROM Table0 NATURAL JOIN Table0)); } {{}} # 2019-01-17 # Make sure crazy nexted CTE joins terminate with an error quickly. # do_catchsql_test 22.1 { WITH RECURSIVE c AS NOT MATERIALIZED ( WITH RECURSIVE c AS NOT MATERIALIZED ( WITH RECURSIVE c AS NOT MATERIALIZED ( WITH RECURSIVE c AS NOT MATERIALIZED ( WITH c AS (VALUES(0)) SELECT 1 FROM c LEFT JOIN c ON ltrim(1) ) SELECT 1 FROM c,c,c,c,c,c,c,c,c ) SELECT 2 FROM c,c,c,c,c,c,c,c,c ) |
︙ | ︙ |
Changes to test/with6.test.
︙ | ︙ | |||
225 226 227 228 229 230 231 | SELECT y FROM t2 ORDER BY y; } {40404 40405 40406 40504 40505 40506 40604 40605 40606} do_eqp_test 211 { SELECT y FROM t2 ORDER BY y; } { QUERY PLAN |--MATERIALIZE c1 | | > > > > | > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | SELECT y FROM t2 ORDER BY y; } {40404 40405 40406 40504 40505 40506 40604 40605 40606} do_eqp_test 211 { SELECT y FROM t2 ORDER BY y; } { QUERY PLAN |--MATERIALIZE c1 | |--CO-ROUTINE c | | `--SCAN 3 CONSTANT ROWS | `--SCAN c |--MATERIALIZE c2 | |--CO-ROUTINE c | | `--SCAN 3 CONSTANT ROWS | `--SCAN c |--SCAN c1 |--SCAN c2 |--SCAN t1 `--USE TEMP B-TREE FOR ORDER BY } do_execsql_test 220 { DROP VIEW t2; CREATE VIEW t2(y) AS WITH c(z) AS MATERIALIZED (VALUES(4),(5),(6)) SELECT c1.z+c2.z*100+t1.x*10000 FROM t1, (SELECT z FROM c LIMIT 5) AS c1, (SELECT z FROM c LIMIT 5) AS c2; SELECT y FROM t2 ORDER BY y; } {40404 40405 40406 40504 40505 40506 40604 40605 40606} # 2022-04-22: Do not allow flattening of a MATERIALIZED CTE into # an outer query. # reset_db db null - do_execsql_test 300 { CREATE TABLE t2(a INT,b INT,d INT); INSERT INTO t2 VALUES(4,5,6),(7,8,9); CREATE TABLE t3(a INT,b INT,e INT); INSERT INTO t3 VALUES(3,3,3),(8,8,8); } {} do_execsql_test 310 { WITH t23 AS MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b)) SELECT * FROM t23; } { 4 5 6 - - 7 8 9 8 8 - 3 - 3 3 } do_eqp_test 311 { WITH t23 AS MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b)) SELECT * FROM t23; } { QUERY PLAN |--MATERIALIZE t23 | |--SCAN t2 | |--SCAN t3 LEFT-JOIN | `--RIGHT-JOIN t3 | `--SCAN t3 `--SCAN t23 } do_execsql_test 320 { WITH t23 AS NOT MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b)) SELECT * FROM t23; } { 4 5 6 - - 7 8 9 8 8 - 3 - 3 3 } do_eqp_test 321 { WITH t23 AS NOT MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b)) SELECT * FROM t23; } { QUERY PLAN |--SCAN t2 |--SCAN t3 LEFT-JOIN `--RIGHT-JOIN t3 `--SCAN t3 } do_execsql_test 330 { WITH t23 AS (SELECT * FROM t2 FULL JOIN t3 USING(b)) SELECT * FROM t23; } { 4 5 6 - - 7 8 9 8 8 - 3 - 3 3 } do_eqp_test 331 { WITH t23 AS (SELECT * FROM t2 FULL JOIN t3 USING(b)) SELECT * FROM t23; } { QUERY PLAN |--SCAN t2 |--SCAN t3 LEFT-JOIN `--RIGHT-JOIN t3 `--SCAN t3 } finish_test |