/ Check-in [6ee71f4d]
Login

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 | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6ee71f4ddb4fa934f58c87dad2d30560af2e55d7
User & Date: danielk1977 2008-07-01 16:05:26
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: 5c9cc22c user: drh tags: trunk
16:05
Fix a memory leak to do with the recent UNION ALL sub-select optimization. (CVS 5333) check-in: 6ee71f4d 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: a79786a9 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/select.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
1914
1915
1916
1917
1918
1919
1920

1921
1922
1923
1924
1925
1926
1927
....
1996
1997
1998
1999
2000
2001
2002

2003
2004
2005
2006
2007
2008
2009
....
2072
2073
2074
2075
2076
2077
2078

2079
2080
2081
2082
2083
2084
2085
....
2155
2156
2157
2158
2159
2160
2161

2162
2163
2164
2165
2166
2167
2168
....
2300
2301
2302
2303
2304
2305
2306

2307
2308
2309
2310
2311
2312
2313
**    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.442 2008/07/01 14:39:35 danielk1977 Exp $
*/
#include "sqliteInt.h"


/*
** Delete all the content of a Select structure but do not deallocate
** the select structure itself.
................................................................................
  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;
................................................................................
        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);
        }
................................................................................
      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;
................................................................................
      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;
      }
................................................................................

    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.







|







 







>







 







>







 







>







 







>







 







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
....
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
....
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
....
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
....
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
**    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.
................................................................................
  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;
................................................................................
        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);
        }
................................................................................
      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;
................................................................................
      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;
      }
................................................................................

    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.

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
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
#    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.2 2008/07/01 14:39:35 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

proc test_transform {testname sql1 sql2 results} {
  set ::vdbe1 [list]
  set ::vdbe2 [list]
................................................................................

    INSERT INTO t2 VALUES(3,   6,  9);
    INSERT INTO t2 VALUES(12, 15, 18);
    INSERT INTO t2 VALUES(21, 24, 27);
  }
} {}












test_transform selectB-1.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-1.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-1.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-1.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-1.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-1.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-1.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}














































































finish_test








|







 







>
>
>
>
>
>
>
>
>
>
>
|





|





|







|










|










|
|
>




|
|
|
|
|
|
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
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
#    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]
................................................................................

    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