SQLite

Check-in [9771ad1e81]
Login

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

Overview
Comment:The sqlite_exec() function is now implemented using sqlite_compile() and sqlite_step(). This opens up lots of opportunity to remove old code. (CVS 1240)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 9771ad1e811e02e10bb738550fbea447749083c5
User & Date: drh 2004-02-14 16:31:03.000
Context
2004-02-14
17:35
Fix problems with malloc-failure handling. (CVS 1241) (check-in: 398bc294c8 user: drh tags: trunk)
16:31
The sqlite_exec() function is now implemented using sqlite_compile() and sqlite_step(). This opens up lots of opportunity to remove old code. (CVS 1240) (check-in: 9771ad1e81 user: drh tags: trunk)
01:39
Disable the malloc.test tests if not compiled with -DMEMORY_DEBUG (CVS 1239) (check-in: 41b6ad78a6 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/build.c.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.167 2004/02/13 16:22:23 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.168 2004/02/14 16:31:03 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
      pParse->pVdbe = 0;
      pParse->rc = rc;
      if( rc ) pParse->nErr++;
    }else{
      pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
    }
    pParse->colNamesSet = 0;
  }else if( pParse->useCallback==0 ){
    pParse->rc = SQLITE_ERROR;
  }
  pParse->nTab = 0;
  pParse->nMem = 0;
  pParse->nSet = 0;
  pParse->nAgg = 0;
  pParse->nVar = 0;







|







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
      pParse->pVdbe = 0;
      pParse->rc = rc;
      if( rc ) pParse->nErr++;
    }else{
      pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
    }
    pParse->colNamesSet = 0;
  }else if( pParse->useCallback==0 && pParse->rc==SQLITE_OK ){
    pParse->rc = SQLITE_ERROR;
  }
  pParse->nTab = 0;
  pParse->nMem = 0;
  pParse->nSet = 0;
  pParse->nAgg = 0;
  pParse->nVar = 0;
Changes to src/main.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.151 2004/02/13 16:30:10 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** A pointer to this structure is used to communicate information







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.152 2004/02/14 16:31:03 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** A pointer to this structure is used to communicate information
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  rc = sqlite_exec_printf(pData->db,
    "CREATE TEMP TABLE sqlite_x AS SELECT * FROM '%q'; "
    "DELETE FROM '%q'; "
    "INSERT INTO '%q' SELECT * FROM sqlite_x; "
    "DROP TABLE sqlite_x;",
    0, 0, &zErr, argv[0], argv[0], argv[0]);
  if( zErr ){
    sqliteSetString(pData->pzErrMsg, zErr, (char*)0);
    sqlite_freemem(zErr);
  }

  /* If an error occurred in the SQL above, then the transaction will
  ** rollback which will delete the internal symbol tables.  This will
  ** cause the structure that pTab points to be deleted.  In case that
  ** happened, we need to refetch pTab.
  */







|
|







149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  rc = sqlite_exec_printf(pData->db,
    "CREATE TEMP TABLE sqlite_x AS SELECT * FROM '%q'; "
    "DELETE FROM '%q'; "
    "INSERT INTO '%q' SELECT * FROM sqlite_x; "
    "DROP TABLE sqlite_x;",
    0, 0, &zErr, argv[0], argv[0], argv[0]);
  if( zErr ){
    if( *pData->pzErrMsg ) sqlite_freemem(*pData->pzErrMsg);
    *pData->pzErrMsg = zErr;
  }

  /* If an error occurred in the SQL above, then the transaction will
  ** rollback which will delete the internal symbol tables.  This will
  ** cause the structure that pTab points to be deleted.  In case that
  ** happened, we need to refetch pTab.
  */
584
585
586
587
588
589
590
591
592

593




594
595
596
597
598
599



























































600
601
602
603
604
605
606
    }
  }
  sqliteResetInternalSchema(db, 0);
  /* sqliteRollbackInternalChanges(db); */
}

/*
** This routine does the work of either sqlite_exec() or sqlite_compile().
** It works like sqlite_exec() if pVm==NULL and it works like sqlite_compile()

** otherwise.




*/
static int sqliteMain(
  sqlite *db,                 /* The database on which the SQL executes */
  const char *zSql,           /* The SQL to be executed */
  sqlite_callback xCallback,  /* Invoke this callback routine */
  void *pArg,                 /* First argument to xCallback() */



























































  const char **pzTail,        /* OUT: Next statement after the first */
  sqlite_vm **ppVm,           /* OUT: The virtual machine */
  char **pzErrMsg             /* OUT: Write error messages here */
){
  Parse sParse;

  if( pzErrMsg ) *pzErrMsg = 0;







|
|
>
|
>
>
>
>

|




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







584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
    }
  }
  sqliteResetInternalSchema(db, 0);
  /* sqliteRollbackInternalChanges(db); */
}

/*
** Execute SQL code.  Return one of the SQLITE_ success/failure
** codes.  Also write an error message into memory obtained from
** malloc() and make *pzErrMsg point to that message.
**
** If the SQL is a query, then for each row in the query result
** the xCallback() function is called.  pArg becomes the first
** argument to xCallback().  If xCallback=NULL then no callback
** is invoked, even for queries.
*/
int sqlite_exec(
  sqlite *db,                 /* The database on which the SQL executes */
  const char *zSql,           /* The SQL to be executed */
  sqlite_callback xCallback,  /* Invoke this callback routine */
  void *pArg,                 /* First argument to xCallback() */
  char **pzErrMsg             /* Write error messages here */
){
  int rc = SQLITE_OK;
  const char *zLeftover;
  sqlite_vm *pVm;
  int nRetry = 0;
  int nChange = 0;

  if( zSql==0 ) return SQLITE_OK;
  while( rc==SQLITE_OK && zSql[0] ){
    pVm = 0;
    rc = sqlite_compile(db, zSql, &zLeftover, &pVm, pzErrMsg);
    if( rc!=SQLITE_OK ){
      assert( pVm==0 );
      return rc;
    }
    if( pVm==0 ){
      /* This happens if the zSql input contained only whitespace */
      break;
    }
    db->nChange += nChange;
    while(1){
      int nArg;
      char **azArg, **azCol;
      rc = sqlite_step(pVm, &nArg, (const char***)&azArg,(const char***)&azCol);
      if( rc==SQLITE_ROW ){
        if( xCallback(pArg, nArg, azArg, azCol) ){
          sqlite_finalize(pVm, 0);
          return SQLITE_ABORT;
        }
      }else{
        rc = sqlite_finalize(pVm, pzErrMsg);
        if( rc==SQLITE_SCHEMA && nRetry<2 ){
          nRetry++;
          rc = SQLITE_OK;
          break;
        }
        if( db->pVdbe==0 ){
          nChange = db->nChange;
        }
        nRetry = 0;
        zSql = zLeftover;
        while( isspace(zSql[0]) ) zSql++;
        break;
      }
    }
  }
  return rc;
}


/*
** Compile a single statement of SQL into a virtual machine.  Return one
** of the SQLITE_ success/failure codes.  Also write an error message into
** memory obtained from malloc() and make *pzErrMsg point to that message.
*/
int sqlite_compile(
  sqlite *db,                 /* The database on which the SQL executes */
  const char *zSql,           /* The SQL to be executed */
  const char **pzTail,        /* OUT: Next statement after the first */
  sqlite_vm **ppVm,           /* OUT: The virtual machine */
  char **pzErrMsg             /* OUT: Write error messages here */
){
  Parse sParse;

  if( pzErrMsg ) *pzErrMsg = 0;
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
    sqliteSafetyOff(db);
    sqliteSetString(pzErrMsg, "obsolete database file format", (char*)0);
    return SQLITE_ERROR;
  }
  if( db->pVdbe==0 ){ db->nChange = 0; }
  memset(&sParse, 0, sizeof(sParse));
  sParse.db = db;
  sParse.xCallback = xCallback;
  sParse.pArg = pArg;
  sParse.useCallback = ppVm==0;
  if( db->xTrace ) db->xTrace(db->pTraceArg, zSql);
  sqliteRunParser(&sParse, zSql, pzErrMsg);
  if( sqlite_malloc_failed ){
    sqliteSetString(pzErrMsg, "out of memory", (char*)0);
    sParse.rc = SQLITE_NOMEM;
    sqliteRollbackAll(db);
    sqliteResetInternalSchema(db, 0);
    db->flags &= ~SQLITE_InTrans;
  }
  if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
  if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){
    sqliteSetString(pzErrMsg, sqlite_error_string(sParse.rc), (char*)0);
  }
  sqliteStrRealloc(pzErrMsg);
  if( sParse.rc==SQLITE_SCHEMA ){
    sqliteResetInternalSchema(db, 0);
  }
  if( sParse.useCallback==0 ){
    assert( ppVm );
    *ppVm = (sqlite_vm*)sParse.pVdbe;
    if( pzTail ) *pzTail = sParse.zTail;
  }
  if( sqliteSafetyOff(db) ) goto exec_misuse;
  return sParse.rc;

exec_misuse:
  if( pzErrMsg ){
    *pzErrMsg = 0;
    sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0);
    sqliteStrRealloc(pzErrMsg);
  }
  return SQLITE_MISUSE;
}

/*
** Execute SQL code.  Return one of the SQLITE_ success/failure
** codes.  Also write an error message into memory obtained from
** malloc() and make *pzErrMsg point to that message.
**
** If the SQL is a query, then for each row in the query result
** the xCallback() function is called.  pArg becomes the first
** argument to xCallback().  If xCallback=NULL then no callback
** is invoked, even for queries.
*/
int sqlite_exec(
  sqlite *db,                 /* The database on which the SQL executes */
  const char *zSql,           /* The SQL to be executed */
  sqlite_callback xCallback,  /* Invoke this callback routine */
  void *pArg,                 /* First argument to xCallback() */
  char **pzErrMsg             /* Write error messages here */
){
#if 1
  return sqliteMain(db, zSql, xCallback, pArg, 0, 0, pzErrMsg);
#else
  int rc;
  const char *zLeftover;
  sqlite_vm *pVm;

  if( zSql==0 ) return SQLITE_OK;
  while( zSql[0] ){
    int nBusy = 0;
    rc = sqlite_compile(db, zSql, &zLeftover, &pVm, pzErrMsg);
    if( rc!=SQLITE_OK ){
      /* sqlite_finalize(pVm, 0); */
      return rc;
    }
    while(1){
      int nArg;
      char **azArg, **azCol;
      rc = sqlite_step(pVm, &nArg, &azArg, &azCol);
      if( rc==SQLITE_ROW ){
        if( xCallback(pArg, nArg, azArg, azCol) ){
          sqlite_finalize(pVm, 0);
          return SQLITE_ABORT;
        }
#if 0
      }else if( rc==SQLITE_BUSY ){
        if( db->xBusyCallback==0
              || db->xBusyCallback(db->pBusyArg, "", nBusy++)==0 ){
          sqlite_finalize(pVm, 0);
          return SQLITE_BUSY;
        }
#endif
      }else if( rc==SQLITE_SCHEMA ){
        sqlite_finalize(pVm, 0);
        break;
      }else{
        rc = sqlite_finalize(pVm, pzErrMsg);
        if( rc==SQLITE_SCHEMA ){
          sqliteResetInternalSchema(db, 0);
          /* break; */
        }
        if( rc!=SQLITE_OK ){
          return rc;
        }
        zSql = zLeftover;
        while( isspace(zSql[0]) ) zSql++;
        break;
      }
    }
  }
  return SQLITE_OK;
#endif
}


/*
** Compile a single statement of SQL into a virtual machine.  Return one
** of the SQLITE_ success/failure codes.  Also write an error message into
** memory obtained from malloc() and make *pzErrMsg point to that message.
*/
int sqlite_compile(
  sqlite *db,                 /* The database on which the SQL executes */
  const char *zSql,           /* The SQL to be executed */
  const char **pzTail,        /* OUT: Next statement after the first */
  sqlite_vm **ppVm,           /* OUT: The virtual machine */
  char **pzErrMsg             /* OUT: Write error messages here */
){
  return sqliteMain(db, zSql, 0, 0, pzTail, ppVm, pzErrMsg);
}


/*
** The following routine destroys a virtual machine that is created by
** the sqlite_compile() routine.
**
** The integer returned is an SQLITE_ success/failure code that describes
** the result of executing the virtual machine.  An error message is







<
<
|

















<
|
|
|
<












<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







687
688
689
690
691
692
693


694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711

712
713
714

715
716
717
718
719
720
721
722
723
724
725
726























































































727
728
729
730
731
732
733
    sqliteSafetyOff(db);
    sqliteSetString(pzErrMsg, "obsolete database file format", (char*)0);
    return SQLITE_ERROR;
  }
  if( db->pVdbe==0 ){ db->nChange = 0; }
  memset(&sParse, 0, sizeof(sParse));
  sParse.db = db;


  sParse.useCallback = 0;
  if( db->xTrace ) db->xTrace(db->pTraceArg, zSql);
  sqliteRunParser(&sParse, zSql, pzErrMsg);
  if( sqlite_malloc_failed ){
    sqliteSetString(pzErrMsg, "out of memory", (char*)0);
    sParse.rc = SQLITE_NOMEM;
    sqliteRollbackAll(db);
    sqliteResetInternalSchema(db, 0);
    db->flags &= ~SQLITE_InTrans;
  }
  if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
  if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){
    sqliteSetString(pzErrMsg, sqlite_error_string(sParse.rc), (char*)0);
  }
  sqliteStrRealloc(pzErrMsg);
  if( sParse.rc==SQLITE_SCHEMA ){
    sqliteResetInternalSchema(db, 0);
  }

  assert( ppVm );
  *ppVm = (sqlite_vm*)sParse.pVdbe;
  if( pzTail ) *pzTail = sParse.zTail;

  if( sqliteSafetyOff(db) ) goto exec_misuse;
  return sParse.rc;

exec_misuse:
  if( pzErrMsg ){
    *pzErrMsg = 0;
    sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0);
    sqliteStrRealloc(pzErrMsg);
  }
  return SQLITE_MISUSE;
}

























































































/*
** The following routine destroys a virtual machine that is created by
** the sqlite_compile() routine.
**
** The integer returned is an SQLITE_ success/failure code that describes
** the result of executing the virtual machine.  An error message is
Changes to src/select.c.
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.153 2004/02/13 16:22:23 drh Exp $
*/
#include "sqliteInt.h"


/*
** Allocate a new Select structure and return a pointer to that
** structure.







|







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.154 2004/02/14 16:31:04 drh Exp $
*/
#include "sqliteInt.h"


/*
** Allocate a new Select structure and return a pointer to that
** structure.
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
    sqliteErrorMsg(pParse, "SELECTs to the left and right of %s"
      " do not have the same number of result columns", selectOpName(p->op));
    return 1;
  }

  /* Issue a null callback if that is what the user wants.
  */
  if( eDest==SRT_Callback &&
    (pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0)
  ){
    sqliteVdbeAddOp(v, OP_NullCallback, p->pEList->nExpr, 0);
  }
  return 0;
}

/*







|
|







1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
    sqliteErrorMsg(pParse, "SELECTs to the left and right of %s"
      " do not have the same number of result columns", selectOpName(p->op));
    return 1;
  }

  /* Issue a null callback if that is what the user wants.
  */
  if( eDest==SRT_Callback /* &&
    (pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0) */
  ){
    sqliteVdbeAddOp(v, OP_NullCallback, p->pEList->nExpr, 0);
  }
  return 0;
}

/*
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
  if( pOrderBy ){
    generateSortTail(p, v, pEList->nExpr, eDest, iParm);
  }


  /* Issue a null callback if that is what the user wants.
  */
  if( eDest==SRT_Callback &&
    (pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0)
  ){
    sqliteVdbeAddOp(v, OP_NullCallback, pEList->nExpr, 0);
  }

  /* If this was a subquery, we have now converted the subquery into a
  ** temporary table.  So delete the subquery structure from the parent
  ** to prevent this subquery from being evaluated again and to force the







|
|







2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
  if( pOrderBy ){
    generateSortTail(p, v, pEList->nExpr, eDest, iParm);
  }


  /* Issue a null callback if that is what the user wants.
  */
  if( eDest==SRT_Callback /* &&
    (pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0) */
  ){
    sqliteVdbeAddOp(v, OP_NullCallback, pEList->nExpr, 0);
  }

  /* If this was a subquery, we have now converted the subquery into a
  ** temporary table.  So delete the subquery structure from the parent
  ** to prevent this subquery from being evaluated again and to force the
Changes to src/shell.c.
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 code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.89 2004/02/13 20:09:42 drh Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "sqlite.h"
#include <ctype.h>








|







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 code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.90 2004/02/14 16:31:04 drh Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "sqlite.h"
#include <ctype.h>

747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
    if( p->out!=stdout ){
      fclose(p->out);
    }
    if( strcmp(azArg[1],"stdout")==0 ){
      p->out = stdout;
      strcpy(p->outfile,"stdout");
    }else{
      p->out = fopen(azArg[1], "w");
      if( p->out==0 ){
        fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
        p->out = stdout;
      } else {
         strcpy(p->outfile,azArg[1]);
      }
    }







|







747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
    if( p->out!=stdout ){
      fclose(p->out);
    }
    if( strcmp(azArg[1],"stdout")==0 ){
      p->out = stdout;
      strcpy(p->outfile,"stdout");
    }else{
      p->out = fopen(azArg[1], "wb");
      if( p->out==0 ){
        fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
        p->out = stdout;
      } else {
         strcpy(p->outfile,azArg[1]);
      }
    }
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786

  if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
    if( p->db ) sqlite_close(p->db);
    exit(0);
  }else

  if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
    FILE *alt = fopen(azArg[1], "r");
    if( alt==0 ){
      fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
    }else{
      process_input(p, alt);
      fclose(alt);
    }
  }else







|







772
773
774
775
776
777
778
779
780
781
782
783
784
785
786

  if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
    if( p->db ) sqlite_close(p->db);
    exit(0);
  }else

  if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
    FILE *alt = fopen(azArg[1], "rb");
    if( alt==0 ){
      fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
    }else{
      process_input(p, alt);
      fclose(alt);
    }
  }else
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
      fprintf(stderr,"%s: out of memory!\n", Argv0);
      exit(1);
    }
    sprintf(zBuf,"%s/.sqliterc",home_dir);
    free(home_dir);
    sqliterc = (const char*)zBuf;
  }
  in = fopen(sqliterc,"r");
  if( in ){
    if( isatty(fileno(stdout)) ){
      printf("Loading resources from %s\n",sqliterc);
    }
    process_input(p,in);
    fclose(in);
  }







|







1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
      fprintf(stderr,"%s: out of memory!\n", Argv0);
      exit(1);
    }
    sprintf(zBuf,"%s/.sqliterc",home_dir);
    free(home_dir);
    sqliterc = (const char*)zBuf;
  }
  in = fopen(sqliterc,"rb");
  if( in ){
    if( isatty(fileno(stdout)) ){
      printf("Loading resources from %s\n",sqliterc);
    }
    process_input(p,in);
    fclose(in);
  }
Changes to src/vdbe.c.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.261 2004/02/13 14:07:13 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.262 2004/02/14 16:31:04 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
115
116
117
118
119
120
121

122
123
124
125
126
127
128
  int rc;

  if( p->magic!=VDBE_MAGIC_RUN ){
    return SQLITE_MISUSE;
  }
  db = p->db;
  if( sqliteSafetyOn(db) ){

    return SQLITE_MISUSE;
  }
  if( p->explain ){
    rc = sqliteVdbeList(p);
  }else{
    rc = sqliteVdbeExec(p);
  }







>







115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  int rc;

  if( p->magic!=VDBE_MAGIC_RUN ){
    return SQLITE_MISUSE;
  }
  db = p->db;
  if( sqliteSafetyOn(db) ){
    p->rc = SQLITE_MISUSE;
    return SQLITE_MISUSE;
  }
  if( p->explain ){
    rc = sqliteVdbeList(p);
  }else{
    rc = sqliteVdbeExec(p);
  }
866
867
868
869
870
871
872

873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
      azArgv[i] = 0;
    }else{
      Stringify(pCol);
      azArgv[i] = pCol->z;
    }
  }
  azArgv[i] = 0;

  if( p->xCallback==0 ){
    p->azResColumn = azArgv;
    p->nResColumn = pOp->p1;
    p->popStack = pOp->p1;
    p->pc = pc + 1;
    p->pTos = pTos;
    return SQLITE_ROW;
  }
  if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; 
  if( p->xCallback(p->pCbArg, pOp->p1, azArgv, p->azColName)!=0 ){
    rc = SQLITE_ABORT;
  }
  if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
  p->nCallback++;
  popStack(&pTos, pOp->p1);
  assert( pTos>=&p->aStack[-1] );
  if( sqlite_malloc_failed ) goto no_mem;
  break;
}

/* Opcode: NullCallback P1 * *







>













<







867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887

888
889
890
891
892
893
894
      azArgv[i] = 0;
    }else{
      Stringify(pCol);
      azArgv[i] = pCol->z;
    }
  }
  azArgv[i] = 0;
  p->nCallback++;
  if( p->xCallback==0 ){
    p->azResColumn = azArgv;
    p->nResColumn = pOp->p1;
    p->popStack = pOp->p1;
    p->pc = pc + 1;
    p->pTos = pTos;
    return SQLITE_ROW;
  }
  if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; 
  if( p->xCallback(p->pCbArg, pOp->p1, azArgv, p->azColName)!=0 ){
    rc = SQLITE_ABORT;
  }
  if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;

  popStack(&pTos, pOp->p1);
  assert( pTos>=&p->aStack[-1] );
  if( sqlite_malloc_failed ) goto no_mem;
  break;
}

/* Opcode: NullCallback P1 * *
903
904
905
906
907
908
909
910

911
912
913
914
915
916
917









918
919
920
921
922
923
924
** The callback is only invoked if there have been no prior calls
** to OP_Callback or OP_SortCallback.
**
** This opcode is used to report the number and names of columns
** in cases where the result set is empty.
*/
case OP_NullCallback: {
  if( p->nCallback==0 && p->xCallback!=0 ){

    if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; 
    if( p->xCallback(p->pCbArg, pOp->p1, 0, p->azColName)!=0 ){
      rc = SQLITE_ABORT;
    }
    if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
    p->nCallback++;
    if( sqlite_malloc_failed ) goto no_mem;









  }
  p->nResColumn = pOp->p1;
  break;
}

/* Opcode: Concat P1 P2 P3
**







|
>
|
|
|
|
|
<
|
>
>
>
>
>
>
>
>
>







904
905
906
907
908
909
910
911
912
913
914
915
916
917

918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
** The callback is only invoked if there have been no prior calls
** to OP_Callback or OP_SortCallback.
**
** This opcode is used to report the number and names of columns
** in cases where the result set is empty.
*/
case OP_NullCallback: {
  if( p->nCallback==0 && (db->flags & SQLITE_NullCallback)!=0 ){
    if( p->xCallback!=0 ){
      if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; 
      if( p->xCallback(p->pCbArg, pOp->p1, 0, p->azColName)!=0 ){
        rc = SQLITE_ABORT;
      }
      if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;

      if( sqlite_malloc_failed ) goto no_mem;
    }else{
      p->azResColumn = 0;
      p->nResColumn = pOp->p1;
      p->popStack = 0;
      p->pc = pc + 1;
      p->pTos = pTos;
      return SQLITE_ROW;
    }
    p->nCallback++;
  }
  p->nResColumn = pOp->p1;
  break;
}

/* Opcode: Concat P1 P2 P3
**
4080
4081
4082
4083
4084
4085
4086

4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
** the SortMakeRec operation with the same P1 value as this
** instruction.  Pop this record from the stack and invoke the
** callback on it.
*/
case OP_SortCallback: {
  assert( pTos>=p->aStack );
  assert( pTos->flags & MEM_Str );

  if( p->xCallback==0 ){
    p->pc = pc+1;
    p->azResColumn = (char**)pTos->z;
    p->nResColumn = pOp->p1;
    p->popStack = 1;
    p->pTos = pTos;
    return SQLITE_ROW;
  }else{
    if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
    if( p->xCallback(p->pCbArg, pOp->p1, (char**)pTos->z, p->azColName)!=0){
      rc = SQLITE_ABORT;
    }
    if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
    p->nCallback++;
  }
  Release(pTos);
  pTos--;
  if( sqlite_malloc_failed ) goto no_mem;
  break;
}








>













<







4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110

4111
4112
4113
4114
4115
4116
4117
** the SortMakeRec operation with the same P1 value as this
** instruction.  Pop this record from the stack and invoke the
** callback on it.
*/
case OP_SortCallback: {
  assert( pTos>=p->aStack );
  assert( pTos->flags & MEM_Str );
  p->nCallback++;
  if( p->xCallback==0 ){
    p->pc = pc+1;
    p->azResColumn = (char**)pTos->z;
    p->nResColumn = pOp->p1;
    p->popStack = 1;
    p->pTos = pTos;
    return SQLITE_ROW;
  }else{
    if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
    if( p->xCallback(p->pCbArg, pOp->p1, (char**)pTos->z, p->azColName)!=0){
      rc = SQLITE_ABORT;
    }
    if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;

  }
  Release(pTos);
  pTos--;
  if( sqlite_malloc_failed ) goto no_mem;
  break;
}

Changes to src/vdbeaux.c.
822
823
824
825
826
827
828


829
830
831
832
833
834
835
  if( p->zErrMsg ){
    if( pzErrMsg && *pzErrMsg==0 ){
      *pzErrMsg = p->zErrMsg;
    }else{
      sqliteFree(p->zErrMsg);
    }
    p->zErrMsg = 0;


  }
  Cleanup(p);
  if( p->rc!=SQLITE_OK ){
    switch( p->errorAction ){
      case OE_Abort: {
        if( !p->undoTransOnError ){
          for(i=0; i<db->nDb; i++){







>
>







822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
  if( p->zErrMsg ){
    if( pzErrMsg && *pzErrMsg==0 ){
      *pzErrMsg = p->zErrMsg;
    }else{
      sqliteFree(p->zErrMsg);
    }
    p->zErrMsg = 0;
  }else if( p->rc ){
    sqliteSetString(pzErrMsg, sqlite_error_string(p->rc), (char*)0);
  }
  Cleanup(p);
  if( p->rc!=SQLITE_OK ){
    switch( p->errorAction ){
      case OE_Abort: {
        if( !p->undoTransOnError ){
          for(i=0; i<db->nDb; i++){
905
906
907
908
909
910
911



912
913
914
915
916
917
918
  }
  db = p->db;
  rc = sqliteVdbeReset(p, pzErrMsg);
  sqliteVdbeDelete(p);
  if( db->want_to_close && db->pVdbe==0 ){
    sqlite_close(db);
  }



  return rc;
}

/*
** Set the values of all variables.  Variable $1 in the original SQL will
** be the string azValue[0].  $2 will have the value azValue[1].  And
** so forth.  If a value is out of range (for example $3 when nValue==2)







>
>
>







907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
  }
  db = p->db;
  rc = sqliteVdbeReset(p, pzErrMsg);
  sqliteVdbeDelete(p);
  if( db->want_to_close && db->pVdbe==0 ){
    sqlite_close(db);
  }
  if( rc==SQLITE_SCHEMA ){
    sqliteResetInternalSchema(db, 0);
  }
  return rc;
}

/*
** Set the values of all variables.  Variable $1 in the original SQL will
** be the string azValue[0].  $2 will have the value azValue[1].  And
** so forth.  If a value is out of range (for example $3 when nValue==2)
Changes to test/lock.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# 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.  The
# focus of this script is database locks.
#
# $Id: lock.test,v 1.19 2004/01/15 13:29:40 drh Exp $


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

# Create an alternative connection to the database
#













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# 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.  The
# focus of this script is database locks.
#
# $Id: lock.test,v 1.20 2004/02/14 16:31:04 drh Exp $


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

# Create an alternative connection to the database
#
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
do_test lock-1.2 {
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
} {}
do_test lock-1.3 {
  execsql {CREATE TABLE t1(a int, b int)}
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {t1}
do_test lock-1.4 {
  catchsql {
    SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
  } db2
} {1 {database schema has changed}}
do_test lock-1.5 {
  catchsql {
     SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
  } db2
} {0 t1}

do_test lock-1.6 {







|
|
|
|
|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
do_test lock-1.2 {
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
} {}
do_test lock-1.3 {
  execsql {CREATE TABLE t1(a int, b int)}
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {t1}
#do_test lock-1.4 {
#  catchsql {
#    SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
#  } db2
#} {1 {database schema has changed}}
do_test lock-1.5 {
  catchsql {
     SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
  } db2
} {0 t1}

do_test lock-1.6 {
71
72
73
74
75
76
77
78



79
80
81
82
83
84
85
86
87
} {0 {2 1}}

do_test lock-1.13 {
  execsql {CREATE TABLE t2(x int, y int)}
  execsql {INSERT INTO t2 VALUES(8,9)}
  execsql {SELECT * FROM t2}
} {8 9}
do_test lock-1.14 {



  catchsql {SELECT * FROM t1} db2
} {1 {database schema has changed}}
do_test lock-1.15 {
  catchsql {SELECT * FROM t2} db2
} {0 {8 9}}

do_test lock-1.16 {
  db eval {SELECT * FROM t1} qv {
    set x [db eval {SELECT * FROM t1}]







|
>
>
>

|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
} {0 {2 1}}

do_test lock-1.13 {
  execsql {CREATE TABLE t2(x int, y int)}
  execsql {INSERT INTO t2 VALUES(8,9)}
  execsql {SELECT * FROM t2}
} {8 9}
do_test lock-1.14.1 {
  catchsql {SELECT * FROM t2} db2
} {1 {no such table: t2}}
do_test lock-1.14.2 {
  catchsql {SELECT * FROM t1} db2
} {0 {2 1}}
do_test lock-1.15 {
  catchsql {SELECT * FROM t2} db2
} {0 {8 9}}

do_test lock-1.16 {
  db eval {SELECT * FROM t1} qv {
    set x [db eval {SELECT * FROM t1}]
Changes to test/temptable.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for temporary tables and indices.
#
# $Id: temptable.test,v 1.10 2003/05/17 17:35:13 drh Exp $

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

# Create an alternative connection to the database
#
do_test temptable-1.0 {







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for temporary tables and indices.
#
# $Id: temptable.test,v 1.11 2004/02/14 16:31:04 drh Exp $

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

# Create an alternative connection to the database
#
do_test temptable-1.0 {
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  } db2
} {0 {10 20}}
do_test temptable-4.4.2 {
  catchsql {
    SELECT * FROM main.t2;
  } db2
} {1 {no such table: main.t2}}
do_test temptable-4.4.3 {
  catchsql {
    SELECT name FROM main.sqlite_master WHERE type='table';
  } db2
} {1 {database schema has changed}}
do_test temptable-4.4.4 {
  catchsql {
    SELECT name FROM main.sqlite_master WHERE type='table';
  } db2
} {0 {t1 t2}}
do_test temptable-4.4.5 {
  catchsql {







|
|
|
|
|







172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  } db2
} {0 {10 20}}
do_test temptable-4.4.2 {
  catchsql {
    SELECT * FROM main.t2;
  } db2
} {1 {no such table: main.t2}}
#do_test temptable-4.4.3 {
#  catchsql {
#    SELECT name FROM main.sqlite_master WHERE type='table';
#  } db2
#} {1 {database schema has changed}}
do_test temptable-4.4.4 {
  catchsql {
    SELECT name FROM main.sqlite_master WHERE type='table';
  } db2
} {0 {t1 t2}}
do_test temptable-4.4.5 {
  catchsql {
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  }
} {3 4}
do_test temptable-4.10.1 {
  catchsql {
    SELECT * FROM t2;
  } db2
} {0 {1 2}}
do_test temptable-4.10.2 {
  catchsql {
    SELECT name FROM sqlite_master WHERE type='table'
  } db2
} {1 {database schema has changed}}
do_test temptable-4.10.3 {
  catchsql {
    SELECT name FROM sqlite_master WHERE type='table'
  } db2
} {0 {t1 t2}}
do_test temptable-4.11 {
  execsql {







|
|
|
|
|







233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  }
} {3 4}
do_test temptable-4.10.1 {
  catchsql {
    SELECT * FROM t2;
  } db2
} {0 {1 2}}
#do_test temptable-4.10.2 {
#  catchsql {
#    SELECT name FROM sqlite_master WHERE type='table'
#  } db2
#} {1 {database schema has changed}}
do_test temptable-4.10.3 {
  catchsql {
    SELECT name FROM sqlite_master WHERE type='table'
  } db2
} {0 {t1 t2}}
do_test temptable-4.11 {
  execsql {
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
    CREATE TEMP TABLE mask(a,b,c)
  } db2
  execsql {
    CREATE INDEX mask ON t2(x);
    SELECT * FROM t2;
  }
} {3 4}
do_test temptable-5.2 {
  catchsql {
    SELECT * FROM t2;
  } db2
} {1 {database schema has changed}}
do_test temptable-5.3 {
  catchsql {
    SELECT * FROM t2;
  } db2
} {0 {3 4}}
do_test temptable-5.4 {
  execsql {







|
|
|
|
|







286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
    CREATE TEMP TABLE mask(a,b,c)
  } db2
  execsql {
    CREATE INDEX mask ON t2(x);
    SELECT * FROM t2;
  }
} {3 4}
#do_test temptable-5.2 {
#  catchsql {
#    SELECT * FROM t2;
#  } db2
#} {1 {database schema has changed}}
do_test temptable-5.3 {
  catchsql {
    SELECT * FROM t2;
  } db2
} {0 {3 4}}
do_test temptable-5.4 {
  execsql {
Changes to test/trigger1.test.
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
      delete from t1 WHERE a=old.a+2;
    end;
  }
} {1 {cannot create BEFORE trigger on view: v1}}
# Ensure that we cannot create AFTER triggers on views
do_test trigger1-1.14 {
  catchsql {
    create table t1(a,b);
    create view v1 as select * from t1;
    create trigger v1t AFTER update on v1 for each row begin
      delete from t1 WHERE a=old.a+2;
    end;
  }
} {1 {cannot create AFTER trigger on view: v1}}








|







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
      delete from t1 WHERE a=old.a+2;
    end;
  }
} {1 {cannot create BEFORE trigger on view: v1}}
# Ensure that we cannot create AFTER triggers on views
do_test trigger1-1.14 {
  catchsql {
    drop view v1;
    create view v1 as select * from t1;
    create trigger v1t AFTER update on v1 for each row begin
      delete from t1 WHERE a=old.a+2;
    end;
  }
} {1 {cannot create AFTER trigger on view: v1}}

Changes to test/vacuum.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# 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.  The
# focus of this file is testing the VACUUM statement.
#
# $Id: vacuum.test,v 1.14 2003/12/07 00:24:35 drh Exp $

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

proc cksum {{db db}} {
  set txt [$db eval {SELECT name, type, sql FROM sqlite_master}]\n
  foreach tbl [$db eval {SELECT name FROM sqlite_master WHERE type='table'}] {













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# 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.  The
# focus of this file is testing the VACUUM statement.
#
# $Id: vacuum.test,v 1.15 2004/02/14 16:31:04 drh Exp $

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

proc cksum {{db db}} {
  set txt [$db eval {SELECT name, type, sql FROM sqlite_master}]\n
  foreach tbl [$db eval {SELECT name FROM sqlite_master WHERE type='table'}] {
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    DROP TABLE t4;
    DROP TABLE t5;
  } db2
  set ::cksum [cksum db2]
  catchsql {
    VACUUM
  }
} {1 {database schema has changed}}
do_test vacuum-2.3 {
  execsql {
    VACUUM;
  }
  cksum
} $cksum
do_test vacuum-2.4 {
  catch {db2 eval {SELECT count(*) FROM sqlite_master}}
  cksum db2
} $cksum








|

<
<
<







103
104
105
106
107
108
109
110
111



112
113
114
115
116
117
118
    DROP TABLE t4;
    DROP TABLE t5;
  } db2
  set ::cksum [cksum db2]
  catchsql {
    VACUUM
  }
} {0 {}}
do_test vacuum-2.3 {



  cksum
} $cksum
do_test vacuum-2.4 {
  catch {db2 eval {SELECT count(*) FROM sqlite_master}}
  cksum db2
} $cksum