/ Check-in [b957dafc]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix the memory leak introduced by check-in (725). (CVS 726)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:b957dafc26383af514795df18bc7b8f367c9bd21
User & Date: drh 2002-08-25 18:29:12
Context
2002-08-25
19:20
Fix for ticket #136: Added the OP_RenameCursor VDBE instruction and used it to make cursor numbers right on nested subqueries. Also added OP_Gosub and OP_Return but have not actually used them for anything yet. (CVS 727) check-in: c602603e user: drh tags: trunk
18:29
Fix the memory leak introduced by check-in (725). (CVS 726) check-in: b957dafc user: drh tags: trunk
2002-08-24
18:24
Change the way token memory is allocated in an effort to fix ticket #136. There is now a memory leak when using views of views. (CVS 725) check-in: 22d8726e user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/select.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
804
805
806
807
808
809
810

811
812
813
814
815
816
817
....
1305
1306
1307
1308
1309
1310
1311

1312

1313

1314
1315
1316
1317
1318
1319
1320
....
1491
1492
1493
1494
1495
1496
1497

1498
1499
1500
1501
1502
1503
1504
**    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.108 2002/08/24 18:24:54 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
................................................................................
        pParse->nErr++;
        return 1;
      }
      if( pTab->pSelect ){
        if( sqliteViewGetColumnNames(pParse, pTab) ){
          return 1;
        }

        pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect);
      }
    }
  }

  /* Process NATURAL keywords, and ON and USING clauses of joins.
  */
................................................................................
  if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable && pExpr->iColumn>=0 ){
    Expr *pNew;
    assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
    assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
    pNew = pEList->a[pExpr->iColumn].pExpr;
    assert( pNew!=0 );
    pExpr->op = pNew->op;

    pExpr->pLeft = sqliteExprDup(pNew->pLeft);

    pExpr->pRight = sqliteExprDup(pNew->pRight);

    pExpr->pList = sqliteExprListDup(pNew->pList);
    pExpr->iTable = pNew->iTable;
    pExpr->iColumn = pNew->iColumn;
    pExpr->iAgg = pNew->iAgg;
    pExpr->nFuncName = pNew->nFuncName;
    sqliteTokenCopy(&pExpr->token, &pNew->token);
    if( iSub!=iTable ){
................................................................................
  }
  p->nOffset += pSub->nOffset;
  if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){
    sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
  }
  pSrc->a[iFrom].pTab = pSubSrc->a[0].pTab;
  pSubSrc->a[0].pTab = 0;

  pSrc->a[iFrom].pSelect = pSubSrc->a[0].pSelect;
  pSubSrc->a[0].pSelect = 0;
  sqliteSelectDelete(pSub);
  return 1;
}

/*







|







 







>







 







>

>

>







 







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
....
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
....
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
**    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.109 2002/08/25 18:29:12 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
................................................................................
        pParse->nErr++;
        return 1;
      }
      if( pTab->pSelect ){
        if( sqliteViewGetColumnNames(pParse, pTab) ){
          return 1;
        }
        sqliteSelectDelete(pTabList->a[i].pSelect);
        pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect);
      }
    }
  }

  /* Process NATURAL keywords, and ON and USING clauses of joins.
  */
................................................................................
  if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable && pExpr->iColumn>=0 ){
    Expr *pNew;
    assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
    assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
    pNew = pEList->a[pExpr->iColumn].pExpr;
    assert( pNew!=0 );
    pExpr->op = pNew->op;
    assert( pExpr->pLeft==0 );
    pExpr->pLeft = sqliteExprDup(pNew->pLeft);
    assert( pExpr->pRight==0 );
    pExpr->pRight = sqliteExprDup(pNew->pRight);
    assert( pExpr->pList==0 );
    pExpr->pList = sqliteExprListDup(pNew->pList);
    pExpr->iTable = pNew->iTable;
    pExpr->iColumn = pNew->iColumn;
    pExpr->iAgg = pNew->iAgg;
    pExpr->nFuncName = pNew->nFuncName;
    sqliteTokenCopy(&pExpr->token, &pNew->token);
    if( iSub!=iTable ){
................................................................................
  }
  p->nOffset += pSub->nOffset;
  if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){
    sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
  }
  pSrc->a[iFrom].pTab = pSubSrc->a[0].pTab;
  pSubSrc->a[0].pTab = 0;
  assert( pSrc->a[iFrom].pSelect==pSub );
  pSrc->a[iFrom].pSelect = pSubSrc->a[0].pSelect;
  pSubSrc->a[0].pSelect = 0;
  sqliteSelectDelete(pSub);
  return 1;
}

/*

Changes to src/util.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
35
36
37
38
39
40
41



42
43
44
45
46
47
48
..
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
..
97
98
99
100
101
102
103

104
105
106
107
108
109
110
111
...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
**
*************************************************************************
** Utility functions used throughout sqlite.
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.48 2002/08/13 23:02:57 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

/*
** If malloc() ever fails, this global variable gets set to 1.
................................................................................
/*
** For keeping track of the number of mallocs and frees.   This
** is used to check for memory leaks.
*/
int sqlite_nMalloc;         /* Number of sqliteMalloc() calls */
int sqlite_nFree;           /* Number of sqliteFree() calls */
int sqlite_iMallocFail;     /* Fail sqliteMalloc() after this many calls */





/*
** Allocate new memory and set it to zero.  Return NULL if
** no memory is available.
*/
void *sqliteMalloc_(int n, char *zFile, int line){
................................................................................
  sqlite_nMalloc++;
  pi[0] = 0xdead1122;
  pi[1] = n;
  pi[k+2] = 0xdead3344;
  p = &pi[2];
  memset(p, 0, n);
#if MEMORY_DEBUG>1
  fprintf(stderr,"malloc %d bytes at 0x%x from %s:%d\n", n, (int)p, zFile,line);

#endif
  return p;
}

/*
** Free memory previously obtained from sqliteMalloc()
*/
................................................................................
    k = (n+sizeof(int)-1)/sizeof(int);
    if( pi[k+2]!=0xdead3344 ){
      fprintf(stderr,"High-end memory corruption at 0x%x\n", (int)p);
      return;
    }
    memset(pi, 0xff, (k+3)*sizeof(int));
#if MEMORY_DEBUG>1

    fprintf(stderr,"free %d bytes at 0x%x from %s:%d\n", n, (int)p, zFile,line);
#endif
    free(pi);
  }
}

/*
** Resize a prior allocation.  If p==0, then this routine
................................................................................
  memcpy(p, oldP, n>oldN ? oldN : n);
  if( n>oldN ){
    memset(&((char*)p)[oldN], 0, n-oldN);
  }
  memset(oldPi, 0, (oldK+3)*sizeof(int));
  free(oldPi);
#if MEMORY_DEBUG>1
  fprintf(stderr,"realloc %d to %d bytes at 0x%x to 0x%x at %s:%d\n", oldN, n,
    (int)oldP, (int)p, zFile, line);
#endif
  return p;
}

/*
** Make a duplicate of a string into memory obtained from malloc()
** Free the original string using sqliteFree().







|







 







>
>
>







 







|
>







 







>
|







 







|
|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
**
*************************************************************************
** Utility functions used throughout sqlite.
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.49 2002/08/25 18:29:12 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

/*
** If malloc() ever fails, this global variable gets set to 1.
................................................................................
/*
** For keeping track of the number of mallocs and frees.   This
** is used to check for memory leaks.
*/
int sqlite_nMalloc;         /* Number of sqliteMalloc() calls */
int sqlite_nFree;           /* Number of sqliteFree() calls */
int sqlite_iMallocFail;     /* Fail sqliteMalloc() after this many calls */
#if MEMORY_DEBUG>1
static int memcnt = 0;
#endif


/*
** Allocate new memory and set it to zero.  Return NULL if
** no memory is available.
*/
void *sqliteMalloc_(int n, char *zFile, int line){
................................................................................
  sqlite_nMalloc++;
  pi[0] = 0xdead1122;
  pi[1] = n;
  pi[k+2] = 0xdead3344;
  p = &pi[2];
  memset(p, 0, n);
#if MEMORY_DEBUG>1
  fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n",
      ++memcnt, n, (int)p, zFile,line);
#endif
  return p;
}

/*
** Free memory previously obtained from sqliteMalloc()
*/
................................................................................
    k = (n+sizeof(int)-1)/sizeof(int);
    if( pi[k+2]!=0xdead3344 ){
      fprintf(stderr,"High-end memory corruption at 0x%x\n", (int)p);
      return;
    }
    memset(pi, 0xff, (k+3)*sizeof(int));
#if MEMORY_DEBUG>1
    fprintf(stderr,"%06d free %d bytes at 0x%x from %s:%d\n",
         ++memcnt, n, (int)p, zFile,line);
#endif
    free(pi);
  }
}

/*
** Resize a prior allocation.  If p==0, then this routine
................................................................................
  memcpy(p, oldP, n>oldN ? oldN : n);
  if( n>oldN ){
    memset(&((char*)p)[oldN], 0, n-oldN);
  }
  memset(oldPi, 0, (oldK+3)*sizeof(int));
  free(oldPi);
#if MEMORY_DEBUG>1
  fprintf(stderr,"%06d realloc %d to %d bytes at 0x%x to 0x%x at %s:%d\n",
    ++memcnt, oldN, n, (int)oldP, (int)p, zFile, line);
#endif
  return p;
}

/*
** Make a duplicate of a string into memory obtained from malloc()
** Free the original string using sqliteFree().

Changes to src/vdbe.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
...
248
249
250
251
252
253
254










255
256
257
258
259
260
261
...
308
309
310
311
312
313
314



315
316
317
318
319
320
321
...
393
394
395
396
397
398
399



400
401
402
403
404
405
406
....
1262
1263
1264
1265
1266
1267
1268




















1269
1270
1271
1272
1273
1274
1275
....
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.169 2002/08/15 01:26:10 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
  int nSet;           /* Number of sets allocated */
  Set *aSet;          /* An array of sets */
  int nCallback;      /* Number of callbacks invoked so far */
  int keylistStackDepth;  /* The size of the "keylist" stack */
  Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */
};











/*
** Create a new virtual database engine.
*/
Vdbe *sqliteVdbeCreate(sqlite *db){
  Vdbe *p;
  p = sqliteMalloc( sizeof(Vdbe) );
  if( p==0 ) return 0;
................................................................................
  p->aOp[i].p1 = p1;
  if( p2<0 && (-1-p2)<p->nLabel && p->aLabel[-1-p2]>=0 ){
    p2 = p->aLabel[-1-p2];
  }
  p->aOp[i].p2 = p2;
  p->aOp[i].p3 = 0;
  p->aOp[i].p3type = P3_NOTUSED;



  return i;
}

/*
** Create a new symbolic label for an instruction that has yet to be
** coded.  The symbolic label is really just a negative number.  The
** label can be used as the P2 value of an operation.  Later, when
................................................................................
  if( nOp>0 ){
    int i;
    for(i=0; i<nOp; i++){
      int p2 = aOp[i].p2;
      p->aOp[i+addr] = aOp[i];
      if( p2<0 ) p->aOp[i+addr].p2 = addr + ADDR(p2);
      p->aOp[i+addr].p3type = aOp[i].p3 ? P3_STATIC : P3_NOTUSED;



    }
    p->nOp += nOp;
  }
  return addr;
}

/*
................................................................................
      break;
    }
  }
  zBuf[i]  = 0;
  return i>0 ? zBuf : 0;
}





















/*
** Execute the program in the VDBE.
**
** If an error occurs, an error message is written to memory obtained
** from sqliteMalloc() and *pzErrMsg is made to point to that memory.
** The return parameter is the number of errors.
**
................................................................................
      break;
    }

    /* Only allow tracing if NDEBUG is not defined.
    */
#ifndef NDEBUG
    if( p->trace ){
      char *zP3;
      char zPtr[40];
      if( pOp->p3type==P3_POINTER ){
        sprintf(zPtr, "ptr(%#x)", (int)pOp->p3);
        zP3 = zPtr;
      }else{
        zP3 = pOp->p3;
      }
      fprintf(p->trace,"%4d %-12s %4d %4d %s\n",
        pc, zOpName[pOp->opcode], pOp->p1, pOp->p2, zP3 ? zP3 : "");
      fflush(p->trace);
    }
#endif

    switch( pOp->opcode ){

/*****************************************************************************
** What follows is a massive switch statement where each case implements a







|







 







>
>
>
>
>
>
>
>
>
>







 







>
>
>







 







>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<
<
<
<
<
<
<
<
<
|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
...
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
...
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
....
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
....
1390
1391
1392
1393
1394
1395
1396










1397
1398
1399
1400
1401
1402
1403
1404
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.170 2002/08/25 18:29:13 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
  int nSet;           /* Number of sets allocated */
  Set *aSet;          /* An array of sets */
  int nCallback;      /* Number of callbacks invoked so far */
  int keylistStackDepth;  /* The size of the "keylist" stack */
  Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */
};

/*
** When debugging the code generator in a symbolic debugger, on can
** set the sqlite_vdbe_addop_trace to 1 and all opcodes will be printed
** as they are added to the instruction stream.
*/
#ifndef NDEBUG
int sqlite_vdbe_addop_trace = 0;
static void vdbePrintOp(FILE*, int, Op*);
#endif

/*
** Create a new virtual database engine.
*/
Vdbe *sqliteVdbeCreate(sqlite *db){
  Vdbe *p;
  p = sqliteMalloc( sizeof(Vdbe) );
  if( p==0 ) return 0;
................................................................................
  p->aOp[i].p1 = p1;
  if( p2<0 && (-1-p2)<p->nLabel && p->aLabel[-1-p2]>=0 ){
    p2 = p->aLabel[-1-p2];
  }
  p->aOp[i].p2 = p2;
  p->aOp[i].p3 = 0;
  p->aOp[i].p3type = P3_NOTUSED;
#ifndef NDEBUG
  if( sqlite_vdbe_addop_trace ) vdbePrintOp(0, i, &p->aOp[i]);
#endif
  return i;
}

/*
** Create a new symbolic label for an instruction that has yet to be
** coded.  The symbolic label is really just a negative number.  The
** label can be used as the P2 value of an operation.  Later, when
................................................................................
  if( nOp>0 ){
    int i;
    for(i=0; i<nOp; i++){
      int p2 = aOp[i].p2;
      p->aOp[i+addr] = aOp[i];
      if( p2<0 ) p->aOp[i+addr].p2 = addr + ADDR(p2);
      p->aOp[i+addr].p3type = aOp[i].p3 ? P3_STATIC : P3_NOTUSED;
#ifndef NDEBUG
      if( sqlite_vdbe_addop_trace ) vdbePrintOp(0, i+addr, &p->aOp[i+addr]);
#endif
    }
    p->nOp += nOp;
  }
  return addr;
}

/*
................................................................................
      break;
    }
  }
  zBuf[i]  = 0;
  return i>0 ? zBuf : 0;
}

#ifndef NDEBUG
/*
** Print a single opcode.  This routine is used for debugging only.
*/
static void vdbePrintOp(FILE *pOut, int pc, Op *pOp){
  char *zP3;
  char zPtr[40];
  if( pOp->p3type==P3_POINTER ){
    sprintf(zPtr, "ptr(%#x)", (int)pOp->p3);
    zP3 = zPtr;
  }else{
    zP3 = pOp->p3;
  }
  if( pOut==0 ) pOut = stdout;
  fprintf(pOut,"%4d %-12s %4d %4d %s\n",
      pc, zOpName[pOp->opcode], pOp->p1, pOp->p2, zP3 ? zP3 : "");
  fflush(pOut);
}
#endif

/*
** Execute the program in the VDBE.
**
** If an error occurs, an error message is written to memory obtained
** from sqliteMalloc() and *pzErrMsg is made to point to that memory.
** The return parameter is the number of errors.
**
................................................................................
      break;
    }

    /* Only allow tracing if NDEBUG is not defined.
    */
#ifndef NDEBUG
    if( p->trace ){










      vdbePrintOp(p->trace, pc, pOp);
    }
#endif

    switch( pOp->opcode ){

/*****************************************************************************
** What follows is a massive switch statement where each case implements a

Changes to test/view.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
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
#    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.  The
# focus of this file is testing VIEW statements.
#
# $Id: view.test,v 1.9 2002/08/24 18:24:57 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test view-1.0 {
  execsql {
    CREATE TABLE t1(a,b,c);
    INSERT INTO t1 VALUES(1,2,3);
................................................................................

do_test view-8.1 {
  execsql {
    CREATE VIEW v6 AS SELECT pqr, xyz FROM v1;
    SELECT * FROM v6 ORDER BY xyz;
  }
} {7 2 13 5 19 8 27 12}
if 0 {
do_test view-8.2 {
  db close
  sqlite db test.db
  execsql {
    SELECT * FROM v6 ORDER BY xyz;
  }
} {7 2 13 5 19 8 27 12}
do_test view-8.3 {
  execsql {
    CREATE VIEW v7 AS SELECT pqr+xyz AS a FROM v6;
    SELECT * FROM v7 ORDER BY a;
  }
} {9 18 27 39}

do_test view-8.4 {
  execsql { PRAGMA vdbe_trace=on;
    CREATE VIEW v8 AS SELECT max(cnt) FROM
      (SELECT a%2 AS eo, count(*) AS cnt FROM t1 GROUP BY eo);
    SELECT * FROM v8;
  }
} 3
}

finish_test







|







 







<













>










7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
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
#    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.  The
# focus of this file is testing VIEW statements.
#
# $Id: view.test,v 1.10 2002/08/25 18:29:16 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test view-1.0 {
  execsql {
    CREATE TABLE t1(a,b,c);
    INSERT INTO t1 VALUES(1,2,3);
................................................................................

do_test view-8.1 {
  execsql {
    CREATE VIEW v6 AS SELECT pqr, xyz FROM v1;
    SELECT * FROM v6 ORDER BY xyz;
  }
} {7 2 13 5 19 8 27 12}

do_test view-8.2 {
  db close
  sqlite db test.db
  execsql {
    SELECT * FROM v6 ORDER BY xyz;
  }
} {7 2 13 5 19 8 27 12}
do_test view-8.3 {
  execsql {
    CREATE VIEW v7 AS SELECT pqr+xyz AS a FROM v6;
    SELECT * FROM v7 ORDER BY a;
  }
} {9 18 27 39}
if 0 {
do_test view-8.4 {
  execsql { PRAGMA vdbe_trace=on;
    CREATE VIEW v8 AS SELECT max(cnt) FROM
      (SELECT a%2 AS eo, count(*) AS cnt FROM t1 GROUP BY eo);
    SELECT * FROM v8;
  }
} 3
}

finish_test

Changes to tool/memleak.awk.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#
# This script looks for memory leaks by analyzing the output of "sqlite" 
# when compiled with the MEMORY_DEBUG=2 option.
#
/^malloc / {
  mem[$5] = $0
}
/^realloc / {
  mem[$7] = "";
  mem[$9] = $0
}
/^free / {
  mem[$5] = "";
  str[$5] = ""
}
/^string at / {
  addr = $3
  sub("string at " addr " is ","")
  str[addr] = $0
}
END {
  for(addr in mem){
    if( mem[addr]=="" ) continue
    print mem[addr], str[addr]
  }
}




|
|

|
|
|

|
|
|


|









1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#
# This script looks for memory leaks by analyzing the output of "sqlite" 
# when compiled with the MEMORY_DEBUG=2 option.
#
/[0-9]+ malloc / {
  mem[$6] = $0
}
/[0-9]+ realloc / {
  mem[$8] = "";
  mem[$10] = $0
}
/[0-9]+ free / {
  mem[$6] = "";
  str[$6] = ""
}
/^string at / {
  addr = $4
  sub("string at " addr " is ","")
  str[addr] = $0
}
END {
  for(addr in mem){
    if( mem[addr]=="" ) continue
    print mem[addr], str[addr]
  }
}