Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a memory leak to do with the recent UNION ALL sub-select optimization. (CVS 5333) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
6ee71f4ddb4fa934f58c87dad2d30560 |
User & Date: | danielk1977 2008-07-01 16:05:26.000 |
Context
2008-07-01
| ||
16:34 | In Lemon, if a non-terminal has the same type as a terminal, then reuse the terminal type in the YYMINORTYPE union for the non-terminal. This gives better table compression. (CVS 5334) (check-in: 5c9cc22cd8 user: drh tags: trunk) | |
16:05 | Fix a memory leak to do with the recent UNION ALL sub-select optimization. (CVS 5333) (check-in: 6ee71f4ddb user: danielk1977 tags: trunk) | |
14:39 | Fix a problem with LIMIT and OFFSET clauses on the parent query when optimizing a UNION ALL sub-select. (CVS 5332) (check-in: a79786a961 user: danielk1977 tags: trunk) | |
Changes
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.443 2008/07/01 16:05:26 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Delete all the content of a Select structure but do not deallocate ** the select structure itself. |
︙ | ︙ | |||
1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 | Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ int nCol; /* Number of columns in the result set */ ExprList *pOrderBy; /* The ORDER BY clause on p */ int aSetP2[2]; /* Set P2 value of these op to number of columns */ int nSetP2 = 0; /* Number of slots in aSetP2[] used */ SelectDest dest; /* Alternative data destination */ /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. */ if( p==0 || p->pPrior==0 ){ rc = 1; goto multi_select_end; | > | 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 | Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ int nCol; /* Number of columns in the result set */ ExprList *pOrderBy; /* The ORDER BY clause on p */ int aSetP2[2]; /* Set P2 value of these op to number of columns */ int nSetP2 = 0; /* Number of slots in aSetP2[] used */ SelectDest dest; /* Alternative data destination */ Select *pDelete = 0; /* Chain of simple selects to delete */ /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. */ if( p==0 || p->pPrior==0 ){ rc = 1; goto multi_select_end; |
︙ | ︙ | |||
1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 | p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; if( p->iLimit ){ addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit); VdbeComment((v, "Jump ahead if LIMIT reached")); } rc = sqlite3Select(pParse, p, &dest, 0, 0, 0, aff); p->pPrior = pPrior; if( rc ){ goto multi_select_end; } if( addr ){ sqlite3VdbeJumpHere(v, addr); } | > | 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 | p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; if( p->iLimit ){ addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit); VdbeComment((v, "Jump ahead if LIMIT reached")); } rc = sqlite3Select(pParse, p, &dest, 0, 0, 0, aff); pDelete = p->pPrior; p->pPrior = pPrior; if( rc ){ goto multi_select_end; } if( addr ){ sqlite3VdbeJumpHere(v, addr); } |
︙ | ︙ | |||
2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 | pOffset = p->pOffset; p->pOffset = 0; uniondest.eDest = op; rc = sqlite3Select(pParse, p, &uniondest, 0, 0, 0, aff); /* Query flattening in sqlite3Select() might refill p->pOrderBy. ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */ sqlite3ExprListDelete(p->pOrderBy); p->pPrior = pPrior; p->pOrderBy = pOrderBy; sqlite3ExprDelete(p->pLimit); p->pLimit = pLimit; p->pOffset = pOffset; p->iLimit = 0; p->iOffset = 0; | > | 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 | pOffset = p->pOffset; p->pOffset = 0; uniondest.eDest = op; rc = sqlite3Select(pParse, p, &uniondest, 0, 0, 0, aff); /* Query flattening in sqlite3Select() might refill p->pOrderBy. ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */ sqlite3ExprListDelete(p->pOrderBy); pDelete = p->pPrior; p->pPrior = pPrior; p->pOrderBy = pOrderBy; sqlite3ExprDelete(p->pLimit); p->pLimit = pLimit; p->pOffset = pOffset; p->iLimit = 0; p->iOffset = 0; |
︙ | ︙ | |||
2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 | p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; pOffset = p->pOffset; p->pOffset = 0; intersectdest.iParm = tab2; rc = sqlite3Select(pParse, p, &intersectdest, 0, 0, 0, aff); p->pPrior = pPrior; sqlite3ExprDelete(p->pLimit); p->pLimit = pLimit; p->pOffset = pOffset; if( rc ){ goto multi_select_end; } | > | 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 | p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; pOffset = p->pOffset; p->pOffset = 0; intersectdest.iParm = tab2; rc = sqlite3Select(pParse, p, &intersectdest, 0, 0, 0, aff); pDelete = p->pPrior; p->pPrior = pPrior; sqlite3ExprDelete(p->pLimit); p->pLimit = pLimit; p->pOffset = pOffset; if( rc ){ goto multi_select_end; } |
︙ | ︙ | |||
2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 | sqlite3_free(pKeyInfo); } multi_select_end: pDest->iMem = dest.iMem; pDest->nMem = dest.nMem; return rc; } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ /* ** Code an output subroutine for a coroutine implementation of a ** SELECT statment. | > | 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 | sqlite3_free(pKeyInfo); } multi_select_end: pDest->iMem = dest.iMem; pDest->nMem = dest.nMem; sqlite3SelectDelete(pDelete); return rc; } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ /* ** Code an output subroutine for a coroutine implementation of a ** SELECT statment. |
︙ | ︙ |
Changes to test/selectB.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2008 June 24 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2008 June 24 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # $Id: selectB.test,v 1.3 2008/07/01 16:05:26 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl proc test_transform {testname sql1 sql2 results} { set ::vdbe1 [list] set ::vdbe2 [list] |
︙ | ︙ | |||
47 48 49 50 51 52 53 | INSERT INTO t2 VALUES(3, 6, 9); INSERT INTO t2 VALUES(12, 15, 18); INSERT INTO t2 VALUES(21, 24, 27); } } {} | > > > > > > > > > > > | | | | | | | > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | INSERT INTO t2 VALUES(3, 6, 9); INSERT INTO t2 VALUES(12, 15, 18); INSERT INTO t2 VALUES(21, 24, 27); } } {} for {set ii 1} {$ii <= 2} {incr ii} { if {$ii == 2} { do_test selectB-2.1 { execsql { CREATE INDEX i1 ON t1(a); CREATE INDEX i2 ON t2(d); } } {} } test_transform selectB-$ii.2 { SELECT * FROM (SELECT a FROM t1 UNION ALL SELECT d FROM t2) } { SELECT a FROM t1 UNION ALL SELECT d FROM t2 } {2 8 14 3 12 21} test_transform selectB-$ii.3 { SELECT * FROM (SELECT a FROM t1 UNION ALL SELECT d FROM t2) ORDER BY 1 } { SELECT a FROM t1 UNION ALL SELECT d FROM t2 ORDER BY 1 } {2 3 8 12 14 21} test_transform selectB-$ii.4 { SELECT * FROM (SELECT a FROM t1 UNION ALL SELECT d FROM t2) WHERE a>10 ORDER BY 1 } { SELECT a FROM t1 WHERE a>10 UNION ALL SELECT d FROM t2 WHERE d>10 ORDER BY 1 } {12 14 21} test_transform selectB-$ii.5 { SELECT * FROM (SELECT a FROM t1 UNION ALL SELECT d FROM t2) WHERE a>10 ORDER BY a } { SELECT a FROM t1 WHERE a>10 UNION ALL SELECT d FROM t2 WHERE d>10 ORDER BY a } {12 14 21} test_transform selectB-$ii.6 { SELECT * FROM (SELECT a FROM t1 UNION ALL SELECT d FROM t2 WHERE d > 12) WHERE a>10 ORDER BY a } { SELECT a FROM t1 WHERE a>10 UNION ALL SELECT d FROM t2 WHERE d>12 AND d>10 ORDER BY a } {14 21} test_transform selectB-$ii.7 { SELECT * FROM (SELECT a FROM t1 UNION ALL SELECT d FROM t2) ORDER BY 1 LIMIT 2 } { SELECT a FROM t1 UNION ALL SELECT d FROM t2 ORDER BY 1 LIMIT 2 } {2 3} test_transform selectB-$ii.8 { SELECT * FROM (SELECT a FROM t1 UNION ALL SELECT d FROM t2) ORDER BY 1 LIMIT 2 OFFSET 3 } { SELECT a FROM t1 UNION ALL SELECT d FROM t2 ORDER BY 1 LIMIT 2 OFFSET 3 } {12 14} test_transform selectB-$ii.9 { SELECT * FROM ( SELECT a FROM t1 UNION ALL SELECT d FROM t2 UNION ALL SELECT c FROM t1 ) } { SELECT a FROM t1 UNION ALL SELECT d FROM t2 UNION ALL SELECT c FROM t1 } {2 8 14 3 12 21 6 12 18} test_transform selectB-$ii.10 { SELECT * FROM ( SELECT a FROM t1 UNION ALL SELECT d FROM t2 UNION ALL SELECT c FROM t1 ) ORDER BY 1 } { SELECT a FROM t1 UNION ALL SELECT d FROM t2 UNION ALL SELECT c FROM t1 ORDER BY 1 } {2 3 6 8 12 12 14 18 21} test_transform selectB-$ii.11 { SELECT * FROM ( SELECT a FROM t1 UNION ALL SELECT d FROM t2 UNION ALL SELECT c FROM t1 ) WHERE a>=10 ORDER BY 1 LIMIT 3 } { SELECT a FROM t1 WHERE a>=10 UNION ALL SELECT d FROM t2 WHERE d>=10 UNION ALL SELECT c FROM t1 WHERE c>=10 ORDER BY 1 LIMIT 3 } {12 12 14} } do_test selectB-2.1 { execsql { SELECT DISTINCT * FROM (SELECT c FROM t1 UNION ALL SELECT e FROM t2) ORDER BY 1; } } {6 12 15 18 24} do_test selectB-2.2 { execsql { SELECT c, count(*) FROM (SELECT c FROM t1 UNION ALL SELECT e FROM t2) GROUP BY c ORDER BY 1; } } {6 2 12 1 15 1 18 1 24 1} do_test selectB-2.3 { execsql { SELECT c, count(*) FROM (SELECT c FROM t1 UNION ALL SELECT e FROM t2) GROUP BY c HAVING count(*)>1; } } {6 2} do_test selectB-2.4 { execsql { SELECT t4.c, t3.a FROM (SELECT c FROM t1 UNION ALL SELECT e FROM t2) AS t4, t1 AS t3 WHERE t3.a=14 ORDER BY 1 } } {6 14 6 14 12 14 15 14 18 14 24 14} do_test selectB-2.5 { execsql { SELECT d FROM t2 EXCEPT SELECT a FROM (SELECT a FROM t1 UNION ALL SELECT d FROM t2) } } {} do_test selectB-2.6 { execsql { SELECT * FROM (SELECT a FROM t1 UNION ALL SELECT d FROM t2) EXCEPT SELECT * FROM (SELECT a FROM t1 UNION ALL SELECT d FROM t2) } } {} finish_test |