/ Check-in [747bf1b3]
Login

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

Overview
Comment:Added support for the COUNT_CHANGES pragma in order to help out the ODBC driver. Fixed a but on count(*) when applied to empty tables. (CVS 289)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:747bf1b30b74cfd0e9c27e7c0bc5172637f35520
User & Date: drh 2001-10-15 00:44:35
Context
2001-10-15
00:45
Version 2.0.5 (CVS 465) check-in: e2d84f71 user: drh tags: trunk
00:44
Added support for the COUNT_CHANGES pragma in order to help out the ODBC driver. Fixed a but on count(*) when applied to empty tables. (CVS 289) check-in: 747bf1b3 user: drh tags: trunk
2001-10-13
22:00
Version 2.0.4 (CVS 466) check-in: 44444700 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.template.

54
55
56
57
58
59
60

61
62
63
64
65
66
67

#### C Compile and options for use in building executables that 
#    will run on the target platform.  This is usually the same
#    as BCC, unless you are cross-compiling.
#
TCC = gcc -O6
#TCC = gcc -g -O0 -Wall

#TCC = /opt/mingw/bin/i386-mingw32-gcc -O6
#TCC = /opt/ansic/bin/c89 -O +z -Wl,-a,archive

#### Tools used to build a static library.
#
AR = ar cr
#AR = /opt/mingw/bin/i386-mingw32-ar cr







>







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

#### C Compile and options for use in building executables that 
#    will run on the target platform.  This is usually the same
#    as BCC, unless you are cross-compiling.
#
TCC = gcc -O6
#TCC = gcc -g -O0 -Wall
#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
#TCC = /opt/mingw/bin/i386-mingw32-gcc -O6
#TCC = /opt/ansic/bin/c89 -O +z -Wl,-a,archive

#### Tools used to build a static library.
#
AR = ar cr
#AR = /opt/mingw/bin/i386-mingw32-ar cr

Changes to VERSION.

1
2.0.4
|
1
2.0.5

Changes to src/btree.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
...
803
804
805
806
807
808
809







810
811
812
813
814
815
816
....
1353
1354
1355
1356
1357
1358
1359

1360
1361
1362
1363
1364
1365
1366
** 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.
**
*************************************************************************
** $Id: btree.c,v 1.33 2001/10/06 16:33:02 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
**     "Sorting And Searching", pages 473-480. Addison-Wesley
**     Publishing Company, Reading, Massachusetts.
................................................................................
** Open a new database.
**
** Actually, this routine just sets up the internal data structures
** for accessing the database.  We do not open the database file 
** until the first page is loaded.
**
** zFilename is the name of the database file.  If zFilename is NULL
** a new database with a random name is created.  The database will be
** destroyed when sqliteBtreeClose() is called.
*/
int sqliteBtreeOpen(
  const char *zFilename,    /* Name of the file containing the BTree database */
  int mode,                 /* Not currently used */
  int nCache,               /* How many pages in the page cache */
  Btree **ppBtree           /* Pointer to new Btree object written here */
){
................................................................................
  return rc;
}

/*
** Create a new cursor for the BTree whose root is on the page
** iTable.  The act of acquiring a cursor gets a read lock on 
** the database file.







*/
int sqliteBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){
  int rc;
  BtCursor *pCur;
  int nLock;

  if( pBt->page1==0 ){
................................................................................
** successful and pRes!=NULL then set *pRes=0.  If the cursor
** was already pointing to the last entry in the database before
** this routine was called, then set *pRes=1 if pRes!=NULL.
*/
int sqliteBtreeNext(BtCursor *pCur, int *pRes){
  int rc;
  if( pCur->pPage==0 ){

    return SQLITE_ABORT;
  }
  if( pCur->bSkipNext ){
    pCur->bSkipNext = 0;
    if( pRes ) *pRes = 0;
    return SQLITE_OK;
  }







|







 







|
|







 







>
>
>
>
>
>
>







 







>







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
...
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
....
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
** 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.
**
*************************************************************************
** $Id: btree.c,v 1.34 2001/10/15 00:44:35 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
**     "Sorting And Searching", pages 473-480. Addison-Wesley
**     Publishing Company, Reading, Massachusetts.
................................................................................
** Open a new database.
**
** Actually, this routine just sets up the internal data structures
** for accessing the database.  We do not open the database file 
** until the first page is loaded.
**
** zFilename is the name of the database file.  If zFilename is NULL
** a new database with a random name is created.  This randomly named
** database file will be deleted when sqliteBtreeClose() is called.
*/
int sqliteBtreeOpen(
  const char *zFilename,    /* Name of the file containing the BTree database */
  int mode,                 /* Not currently used */
  int nCache,               /* How many pages in the page cache */
  Btree **ppBtree           /* Pointer to new Btree object written here */
){
................................................................................
  return rc;
}

/*
** Create a new cursor for the BTree whose root is on the page
** iTable.  The act of acquiring a cursor gets a read lock on 
** the database file.
**
** If wrFlag==0, then the cursor can only be used for reading.
** If wrFlag==1, then the cursor can be used for reading or writing.
** A read/write cursor requires exclusive access to its table.  There
** cannot be two or more cursors open on the same table is any one of
** cursors is a read/write cursor.  But there can be two or more
** read-only cursors open on the same table.
*/
int sqliteBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){
  int rc;
  BtCursor *pCur;
  int nLock;

  if( pBt->page1==0 ){
................................................................................
** successful and pRes!=NULL then set *pRes=0.  If the cursor
** was already pointing to the last entry in the database before
** this routine was called, then set *pRes=1 if pRes!=NULL.
*/
int sqliteBtreeNext(BtCursor *pCur, int *pRes){
  int rc;
  if( pCur->pPage==0 ){
    if( pRes ) *pRes = 1;
    return SQLITE_ABORT;
  }
  if( pCur->bSkipNext ){
    pCur->bSkipNext = 0;
    if( pRes ) *pRes = 0;
    return SQLITE_OK;
  }

Changes to src/build.c.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
....
1436
1437
1438
1439
1440
1441
1442








1443
1444
1445
1446
1447
1448
1449
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.49 2001/10/13 02:59:09 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
................................................................................
  if( sqliteStrICmp(zLeft, "full_column_names")==0 ){
    if( getBoolean(zRight) ){
      db->flags |= SQLITE_FullColNames;
    }else{
      db->flags &= ~SQLITE_FullColNames;
    }
  }else









  if( sqliteStrICmp(zLeft, "table_info")==0 ){
    Table *pTab;
    Vdbe *v;
    pTab = sqliteFindTable(db, zRight);
    if( pTab ) v = sqliteGetVdbe(pParse);
    if( pTab && v ){







|







 







>
>
>
>
>
>
>
>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
....
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.50 2001/10/15 00:44:36 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
................................................................................
  if( sqliteStrICmp(zLeft, "full_column_names")==0 ){
    if( getBoolean(zRight) ){
      db->flags |= SQLITE_FullColNames;
    }else{
      db->flags &= ~SQLITE_FullColNames;
    }
  }else

  if( sqliteStrICmp(zLeft, "count_changes")==0 ){
    if( getBoolean(zRight) ){
      db->flags |= SQLITE_CountRows;
    }else{
      db->flags &= ~SQLITE_CountRows;
    }
  }else

  if( sqliteStrICmp(zLeft, "table_info")==0 ){
    Table *pTab;
    Vdbe *v;
    pTab = sqliteFindTable(db, zRight);
    if( pTab ) v = sqliteGetVdbe(pParse);
    if( pTab && v ){

Changes to src/delete.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
29
30
31
32
33
34
35


36
37
38
39
40
41
42
..
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
...
147
148
149
150
151
152
153









154
155
156
157
158
159
**    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 DELETE FROM statements.
**
** $Id: delete.c,v 1.17 2001/10/13 01:06:48 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process a DELETE FROM statement.
*/
void sqliteDeleteFrom(
................................................................................
  IdList *pTabList;      /* An ID list holding pTab and nothing else */
  int end, addr;         /* A couple addresses of generated code */
  int i;                 /* Loop counter */
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Index *pIdx;           /* For looping over indices of the table */
  int base;              /* Index of the first available table cursor */
  sqlite *db;            /* Main database structure */



  if( pParse->nErr || sqlite_malloc_failed ){
    pTabList = 0;
    goto delete_from_cleanup;
  }
  db = pParse->db;

................................................................................
  if( v==0 ) goto delete_from_cleanup;
  if( (db->flags & SQLITE_InTrans)==0 ){
    sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
    sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0);
    pParse->schemaVerified = 1;
  }








  /* Special case: A DELETE without a WHERE clause deletes everything.
  ** It is easier just to erase the whole table.
  */
  if( pWhere==0 ){














    sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->isTemp);
    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
      sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pTab->isTemp);
    }
  }

  /* The usual case: There is a WHERE clause so we have to scan through
  ** the table an pick which records to delete.
  */
  else{
    int openOp;

    /* Begin the database scan
    */
    sqliteVdbeAddOp(v, OP_ListOpen, 0, 0);
    pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
    if( pWInfo==0 ) goto delete_from_cleanup;

    /* Remember the key of every item to be deleted.
    */
    sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);




    /* End the database scan loop.
    */
    sqliteWhereEnd(pWInfo);

    /* Delete every item whose key was written to the list during the
    ** database scan.  We have to delete items after the scan is complete
................................................................................
    sqliteVdbeResolveLabel(v, end);
    sqliteVdbeAddOp(v, OP_ListClose, 0, 0);
  }
  if( (db->flags & SQLITE_InTrans)==0 ){
    sqliteVdbeAddOp(v, OP_Commit, 0, 0);
  }











delete_from_cleanup:
  sqliteIdListDelete(pTabList);
  sqliteExprDelete(pWhere);
  return;
}







|







 







>
>







 







>
>
>
>
>
>





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










<
<









>
>
>







 







>
>
>
>
>
>
>
>
>






8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
..
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
...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
**    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 DELETE FROM statements.
**
** $Id: delete.c,v 1.18 2001/10/15 00:44:36 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process a DELETE FROM statement.
*/
void sqliteDeleteFrom(
................................................................................
  IdList *pTabList;      /* An ID list holding pTab and nothing else */
  int end, addr;         /* A couple addresses of generated code */
  int i;                 /* Loop counter */
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Index *pIdx;           /* For looping over indices of the table */
  int base;              /* Index of the first available table cursor */
  sqlite *db;            /* Main database structure */
  int openOp;            /* Opcode used to open a cursor to the table */


  if( pParse->nErr || sqlite_malloc_failed ){
    pTabList = 0;
    goto delete_from_cleanup;
  }
  db = pParse->db;

................................................................................
  if( v==0 ) goto delete_from_cleanup;
  if( (db->flags & SQLITE_InTrans)==0 ){
    sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
    sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0);
    pParse->schemaVerified = 1;
  }

  /* Initialize the counter of the number of rows deleted, if
  ** we are counting rows.
  */
  if( db->flags & SQLITE_CountRows ){
    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
  }

  /* Special case: A DELETE without a WHERE clause deletes everything.
  ** It is easier just to erase the whole table.
  */
  if( pWhere==0 ){
    if( db->flags & SQLITE_CountRows ){
      /* If counting rows deleted, just count the total number of
      ** entries in the table. */
      int endOfLoop = sqliteVdbeMakeLabel(v);
      int addr;
      openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
      sqliteVdbeAddOp(v, openOp, 0, pTab->tnum);
      sqliteVdbeAddOp(v, OP_Rewind, 0, 0);
      addr = sqliteVdbeAddOp(v, OP_Next, 0, endOfLoop);
      sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
      sqliteVdbeAddOp(v, OP_Goto, 0, addr);
      sqliteVdbeResolveLabel(v, endOfLoop);
      sqliteVdbeAddOp(v, OP_Close, 0, 0);
    }
    sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->isTemp);
    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
      sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pTab->isTemp);
    }
  }

  /* The usual case: There is a WHERE clause so we have to scan through
  ** the table an pick which records to delete.
  */
  else{


    /* Begin the database scan
    */
    sqliteVdbeAddOp(v, OP_ListOpen, 0, 0);
    pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
    if( pWInfo==0 ) goto delete_from_cleanup;

    /* Remember the key of every item to be deleted.
    */
    sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);
    if( db->flags & SQLITE_CountRows ){
      sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
    }

    /* End the database scan loop.
    */
    sqliteWhereEnd(pWInfo);

    /* Delete every item whose key was written to the list during the
    ** database scan.  We have to delete items after the scan is complete
................................................................................
    sqliteVdbeResolveLabel(v, end);
    sqliteVdbeAddOp(v, OP_ListClose, 0, 0);
  }
  if( (db->flags & SQLITE_InTrans)==0 ){
    sqliteVdbeAddOp(v, OP_Commit, 0, 0);
  }

  /*
  ** Return the number of rows that were deleted.
  */
  if( db->flags & SQLITE_CountRows ){
    sqliteVdbeAddOp(v, OP_ColumnCount, 1, 0);
    sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
    sqliteVdbeChangeP3(v, -1, "rows deleted", P3_STATIC);
    sqliteVdbeAddOp(v, OP_Callback, 1, 0);
  }

delete_from_cleanup:
  sqliteIdListDelete(pTabList);
  sqliteExprDelete(pWhere);
  return;
}

Changes to src/insert.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
166
167
168
169
170
171
172



173
174
175
176
177
178
179
...
196
197
198
199
200
201
202

203
204
205
206
207
208
209
...
226
227
228
229
230
231
232








233
234
235
236
237
238
239
240
241
242
243












244
245
246
247
248
249
**    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 INSERT statements in SQLite.
**
** $Id: insert.c,v 1.23 2001/10/13 01:06:48 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................

  /* If the data source is a SELECT statement, then we have to create
  ** a loop because there might be multiple rows of data.  If the data
  ** source is an expression list, then exactly one row will be inserted
  ** and the loop is not used.
  */
  if( srcTab>=0 ){



    sqliteVdbeAddOp(v, OP_Rewind, srcTab, 0);
    iBreak = sqliteVdbeMakeLabel(v);
    iCont = sqliteVdbeAddOp(v, OP_Next, srcTab, iBreak);
  }

  /* Create a new entry in the table and fill it with data.
  */
................................................................................
      sqliteVdbeAddOp(v, OP_Column, srcTab, i); 
    }else{
      sqliteExprCode(pParse, pList->a[j].pExpr);
    }
  }
  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
  sqliteVdbeAddOp(v, OP_Put, base, 0);


  /* Create appropriate entries for the new data row in all indices
  ** of the table.
  */
  for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
    if( pIdx->pNext ){
      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
................................................................................
        sqliteExprCode(pParse, pList->a[j].pExpr);
      }
    }
    sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
    sqliteVdbeAddOp(v, OP_PutIdx, idx+base, pIdx->isUnique);
  }









  /* The bottom of the loop, if the data source is a SELECT statement
  */
  if( srcTab>=0 ){
    sqliteVdbeAddOp(v, OP_Goto, 0, iCont);
    sqliteVdbeResolveLabel(v, iBreak);
    sqliteVdbeAddOp(v, OP_Noop, 0, 0);
  }
  if( (db->flags & SQLITE_InTrans)==0 ){
    sqliteVdbeAddOp(v, OP_Commit, 0, 0);
  }














insert_cleanup:
  if( pList ) sqliteExprListDelete(pList);
  if( pSelect ) sqliteSelectDelete(pSelect);
  sqliteIdListDelete(pColumn);
}







|







 







>
>
>







 







>







 







>
>
>
>
>
>
>
>











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






8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
**    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 INSERT statements in SQLite.
**
** $Id: insert.c,v 1.24 2001/10/15 00:44:36 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................

  /* If the data source is a SELECT statement, then we have to create
  ** a loop because there might be multiple rows of data.  If the data
  ** source is an expression list, then exactly one row will be inserted
  ** and the loop is not used.
  */
  if( srcTab>=0 ){
    if( db->flags & SQLITE_CountRows ){
      sqliteVdbeAddOp(v, OP_Integer, 0, 0);  /* Initialize the row count */
    }
    sqliteVdbeAddOp(v, OP_Rewind, srcTab, 0);
    iBreak = sqliteVdbeMakeLabel(v);
    iCont = sqliteVdbeAddOp(v, OP_Next, srcTab, iBreak);
  }

  /* Create a new entry in the table and fill it with data.
  */
................................................................................
      sqliteVdbeAddOp(v, OP_Column, srcTab, i); 
    }else{
      sqliteExprCode(pParse, pList->a[j].pExpr);
    }
  }
  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
  sqliteVdbeAddOp(v, OP_Put, base, 0);
  

  /* Create appropriate entries for the new data row in all indices
  ** of the table.
  */
  for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
    if( pIdx->pNext ){
      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
................................................................................
        sqliteExprCode(pParse, pList->a[j].pExpr);
      }
    }
    sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
    sqliteVdbeAddOp(v, OP_PutIdx, idx+base, pIdx->isUnique);
  }


  /* If inserting from a SELECT, keep a count of the number of
  ** rows inserted.
  */
  if( srcTab>=0 && (db->flags & SQLITE_CountRows)!=0 ){
    sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
  }

  /* The bottom of the loop, if the data source is a SELECT statement
  */
  if( srcTab>=0 ){
    sqliteVdbeAddOp(v, OP_Goto, 0, iCont);
    sqliteVdbeResolveLabel(v, iBreak);
    sqliteVdbeAddOp(v, OP_Noop, 0, 0);
  }
  if( (db->flags & SQLITE_InTrans)==0 ){
    sqliteVdbeAddOp(v, OP_Commit, 0, 0);
  }

  /*
  ** Return the number of rows inserted.
  */
  if( db->flags & SQLITE_CountRows ){
    sqliteVdbeAddOp(v, OP_ColumnCount, 1, 0);
    sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
    sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC);
    if( srcTab<0 ){
      sqliteVdbeAddOp(v, OP_Integer, 1, 0);
    }
    sqliteVdbeAddOp(v, OP_Callback, 1, 0);
  }

insert_cleanup:
  if( pList ) sqliteExprListDelete(pList);
  if( pSelect ) sqliteSelectDelete(pSelect);
  sqliteIdListDelete(pColumn);
}

Changes to src/os.c.

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
** competing threads of the same process.  POSIX locks will work fine
** to synchronize access for threads in separate processes, but not
** threads within the same process.
**
** To work around the problem, SQLite has to manage file locks internally
** on its own.  Whenever a new database is opened, we have to find the
** specific inode of the database file (the inode is determined by the
** st_dev and st_ino fields of the stat structure the stat() fills in)
** and check for locks already existing on that inode.  When locks are
** created or removed, we have to look at our own internal record of the
** locks to see if another thread has previously set a lock on that same
** inode.
**
** The OsFile structure for POSIX is no longer just an integer file
** descriptor.  It is now a structure that holds the integer file







|







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
** competing threads of the same process.  POSIX locks will work fine
** to synchronize access for threads in separate processes, but not
** threads within the same process.
**
** To work around the problem, SQLite has to manage file locks internally
** on its own.  Whenever a new database is opened, we have to find the
** specific inode of the database file (the inode is determined by the
** st_dev and st_ino fields of the stat structure that fstat() fills in)
** and check for locks already existing on that inode.  When locks are
** created or removed, we have to look at our own internal record of the
** locks to see if another thread has previously set a lock on that same
** inode.
**
** The OsFile structure for POSIX is no longer just an integer file
** descriptor.  It is now a structure that holds the integer file

Changes to src/select.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
235
236
237
238
239
240
241

242
243
244
245
246
247
248
249

250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
...
270
271
272
273
274
275
276










277
278
279
280
281
282
283
...
863
864
865
866
867
868
869

















870
871
872
873
874
875
876
...
894
895
896
897
898
899
900
901
902

903
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
**    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.39 2001/10/13 01:06:48 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
................................................................................
  Vdbe *v = pParse->pVdbe;
  int i;
  if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return;
  pParse->colNamesSet = 1;
  sqliteVdbeAddOp(v, OP_ColumnCount, pEList->nExpr, 0);
  for(i=0; i<pEList->nExpr; i++){
    Expr *p;

    if( pEList->a[i].zName ){
      char *zName = pEList->a[i].zName;
      sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
      sqliteVdbeChangeP3(v, -1, zName, strlen(zName));
      continue;
    }
    p = pEList->a[i].pExpr;
    if( p==0 ) continue;

    if( p->span.z && p->span.z[0] ){
      int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0);
      sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n);
      sqliteVdbeCompressSpace(v, addr);
    }else if( p->op!=TK_COLUMN || pTabList==0 ){
      char zName[30];
      sprintf(zName, "column%d", i+1);
      sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
      sqliteVdbeChangeP3(v, -1, zName, strlen(zName));
    }else{
      if( pTabList->nId>1 || (pParse->db->flags & SQLITE_FullColNames)!=0 ){
        char *zName = 0;
        Table *pTab = pTabList->a[p->iTable].pTab;
        char *zTab;
 
        zTab = pTabList->a[p->iTable].zAlias;
        if( zTab==0 ) zTab = pTab->zName;
        sqliteSetString(&zName, zTab, ".", pTab->aCol[p->iColumn].zName, 0);
................................................................................
        sqliteFree(zName);
      }else{
        Table *pTab = pTabList->a[0].pTab;
        char *zName = pTab->aCol[p->iColumn].zName;
        sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
        sqliteVdbeChangeP3(v, -1, zName, P3_STATIC);
      }










    }
  }
}

/*
** Name of the connection operator, used for error messages.
*/
................................................................................
    generateColumnNames(pParse, pTabList, pEList);
  }

  /* Reset the aggregator
  */
  if( isAgg ){
    sqliteVdbeAddOp(v, OP_AggReset, 0, pParse->nAgg);

















  }

  /* Initialize the memory cell to NULL
  */
  if( eDest==SRT_Mem ){
    sqliteVdbeAddOp(v, OP_String, 0, 0);
    sqliteVdbeAddOp(v, OP_MemStore, iParm, 0);
................................................................................
    }
  }

  /* If we are dealing with aggregates, then to the special aggregate
  ** processing.  
  */
  else{
    int doFocus;
    if( pGroupBy ){

      for(i=0; i<pGroupBy->nExpr; i++){
        sqliteExprCode(pParse, pGroupBy->a[i].pExpr);
      }
      sqliteVdbeAddOp(v, OP_MakeKey, pGroupBy->nExpr, 0);
      doFocus = 1;
    }else{
      doFocus = 0;
      for(i=0; i<pParse->nAgg; i++){
        if( !pParse->aAgg[i].isAgg ){
          doFocus = 1;
          break;
        }
      }
      if( doFocus ){
        sqliteVdbeAddOp(v, OP_String, 0, 0);
        sqliteVdbeChangeP3(v, -1, "", P3_STATIC);
      }
    }
    if( doFocus ){
      int lbl1 = sqliteVdbeMakeLabel(v);
      sqliteVdbeAddOp(v, OP_AggFocus, 0, lbl1);
      for(i=0; i<pParse->nAgg; i++){
        if( pParse->aAgg[i].isAgg ) continue;
        sqliteExprCode(pParse, pParse->aAgg[i].pExpr);
        sqliteVdbeAddOp(v, OP_AggSet, 0, i);
      }
      sqliteVdbeResolveLabel(v, lbl1);







|







 







>








>
|



|
<
<
<
<
<
|







 







>
>
>
>
>
>
>
>
>
>







 







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







 







<

>




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256





257
258
259
260
261
262
263
264
...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
...
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
895
896
897
898
899
900
...
918
919
920
921
922
923
924

925
926
927
928
929
930















931
932
933
934
935
936
937
938
**    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.40 2001/10/15 00:44:36 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
................................................................................
  Vdbe *v = pParse->pVdbe;
  int i;
  if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return;
  pParse->colNamesSet = 1;
  sqliteVdbeAddOp(v, OP_ColumnCount, pEList->nExpr, 0);
  for(i=0; i<pEList->nExpr; i++){
    Expr *p;
    int showFullNames;
    if( pEList->a[i].zName ){
      char *zName = pEList->a[i].zName;
      sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
      sqliteVdbeChangeP3(v, -1, zName, strlen(zName));
      continue;
    }
    p = pEList->a[i].pExpr;
    if( p==0 ) continue;
    showFullNames = (pParse->db->flags & SQLITE_FullColNames)!=0;
    if( p->span.z && p->span.z[0] && !showFullNames ){
      int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0);
      sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n);
      sqliteVdbeCompressSpace(v, addr);
    }else if( p->op==TK_COLUMN && pTabList ){





      if( pTabList->nId>1 || showFullNames ){
        char *zName = 0;
        Table *pTab = pTabList->a[p->iTable].pTab;
        char *zTab;
 
        zTab = pTabList->a[p->iTable].zAlias;
        if( zTab==0 ) zTab = pTab->zName;
        sqliteSetString(&zName, zTab, ".", pTab->aCol[p->iColumn].zName, 0);
................................................................................
        sqliteFree(zName);
      }else{
        Table *pTab = pTabList->a[0].pTab;
        char *zName = pTab->aCol[p->iColumn].zName;
        sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
        sqliteVdbeChangeP3(v, -1, zName, P3_STATIC);
      }
    }else if( p->span.z && p->span.z[0] ){
      int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0);
      sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n);
      sqliteVdbeCompressSpace(v, addr);
    }else{
      char zName[30];
      assert( p->op!=TK_COLUMN || pTabList==0 );
      sprintf(zName, "column%d", i+1);
      sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
      sqliteVdbeChangeP3(v, -1, zName, strlen(zName));
    }
  }
}

/*
** Name of the connection operator, used for error messages.
*/
................................................................................
    generateColumnNames(pParse, pTabList, pEList);
  }

  /* Reset the aggregator
  */
  if( isAgg ){
    sqliteVdbeAddOp(v, OP_AggReset, 0, pParse->nAgg);
    if( pGroupBy==0 ){
      sqliteVdbeAddOp(v, OP_String, 0, 0);
      sqliteVdbeChangeP3(v, -1, "", P3_STATIC);
      sqliteVdbeAddOp(v, OP_AggFocus, 0, 0);
      for(i=0; i<pParse->nAgg; i++){
        Expr *pE;
        if( !pParse->aAgg[i].isAgg ) continue;
        pE = pParse->aAgg[i].pExpr;
        assert( pE==0 || pE->op==TK_AGG_FUNCTION );
        assert( pE==0 || (pE->pList!=0 && pE->pList->nExpr==1) );
        if( pE==0 || pE->iColumn==FN_Sum ){
          sqliteVdbeAddOp(v, OP_Integer, 0, 0);
          sqliteVdbeAddOp(v, OP_AggSet, 0, i);
          continue;
        }
      }
    }
  }

  /* Initialize the memory cell to NULL
  */
  if( eDest==SRT_Mem ){
    sqliteVdbeAddOp(v, OP_String, 0, 0);
    sqliteVdbeAddOp(v, OP_MemStore, iParm, 0);
................................................................................
    }
  }

  /* If we are dealing with aggregates, then to the special aggregate
  ** processing.  
  */
  else{

    if( pGroupBy ){
      int lbl1;
      for(i=0; i<pGroupBy->nExpr; i++){
        sqliteExprCode(pParse, pGroupBy->a[i].pExpr);
      }
      sqliteVdbeAddOp(v, OP_MakeKey, pGroupBy->nExpr, 0);















      lbl1 = sqliteVdbeMakeLabel(v);
      sqliteVdbeAddOp(v, OP_AggFocus, 0, lbl1);
      for(i=0; i<pParse->nAgg; i++){
        if( pParse->aAgg[i].isAgg ) continue;
        sqliteExprCode(pParse, pParse->aAgg[i].pExpr);
        sqliteVdbeAddOp(v, OP_AggSet, 0, i);
      }
      sqliteVdbeResolveLabel(v, lbl1);

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
159
160
161
162
163
164
165



166
167
168
169
170
171
172
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.61 2001/10/13 02:59:09 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
#define SQLITE_Initialized    0x00000002  /* True after initialization */
#define SQLITE_Interrupt      0x00000004  /* Cancel current operation */
#define SQLITE_InTrans        0x00000008  /* True if in a transaction */
#define SQLITE_InternChanges  0x00000010  /* Uncommitted Hash table changes */
#define SQLITE_FullColNames   0x00000020  /* Show full column names on SELECT */




/*
** Current file format version
*/
#define SQLITE_FileFormat 2

/*







|







 







>
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.62 2001/10/15 00:44:36 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
#define SQLITE_Initialized    0x00000002  /* True after initialization */
#define SQLITE_Interrupt      0x00000004  /* Cancel current operation */
#define SQLITE_InTrans        0x00000008  /* True if in a transaction */
#define SQLITE_InternChanges  0x00000010  /* Uncommitted Hash table changes */
#define SQLITE_FullColNames   0x00000020  /* Show full column names on SELECT */
#define SQLITE_CountRows      0x00000040  /* Count rows changed by INSERT, */
                                          /*   DELETE, or UPDATE and return */
                                          /*   the count using a callback. */

/*
** Current file format version
*/
#define SQLITE_FileFormat 2

/*

Changes to src/update.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
150
151
152
153
154
155
156






157
158
159
160
161
162
163
...
211
212
213
214
215
216
217






218
219
220
221
222
223
224
225
226
227










228
229
230
231
232
233
234
235
236
**    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 UPDATE statements.
**
** $Id: update.c,v 1.18 2001/10/13 01:06:48 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process an UPDATE statement.
*/
void sqliteUpdate(
................................................................................
  /* Remember the index of every item to be updated.
  */
  sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);

  /* End the database scan loop.
  */
  sqliteWhereEnd(pWInfo);







  /* Rewind the list of records that need to be updated and
  ** open every index that needs updating.
  */
  sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
  base = pParse->nTab;
  openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
................................................................................
    sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, pIdx->isUnique);
  }

  /* Write the new data back into the database.
  */
  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
  sqliteVdbeAddOp(v, OP_Put, base, 0);







  /* Repeat the above with the next record to be updated, until
  ** all record selected by the WHERE clause have been updated.
  */
  sqliteVdbeAddOp(v, OP_Goto, 0, addr);
  sqliteVdbeResolveLabel(v, end);
  sqliteVdbeAddOp(v, OP_ListClose, 0, 0);
  if( (db->flags & SQLITE_InTrans)==0 ){
    sqliteVdbeAddOp(v, OP_Commit, 0, 0);
  }











update_cleanup:
  sqliteFree(apIdx);
  sqliteFree(aXRef);
  sqliteIdListDelete(pTabList);
  sqliteExprListDelete(pChanges);
  sqliteExprDelete(pWhere);
  return;
}







|







 







>
>
>
>
>
>







 







>
>
>
>
>
>










>
>
>
>
>
>
>
>
>
>









8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
**    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 UPDATE statements.
**
** $Id: update.c,v 1.19 2001/10/15 00:44:36 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process an UPDATE statement.
*/
void sqliteUpdate(
................................................................................
  /* Remember the index of every item to be updated.
  */
  sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);

  /* End the database scan loop.
  */
  sqliteWhereEnd(pWInfo);

  /* Initialize the count of updated rows
  */
  if( db->flags & SQLITE_CountRows ){
    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
  }

  /* Rewind the list of records that need to be updated and
  ** open every index that needs updating.
  */
  sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
  base = pParse->nTab;
  openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
................................................................................
    sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, pIdx->isUnique);
  }

  /* Write the new data back into the database.
  */
  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
  sqliteVdbeAddOp(v, OP_Put, base, 0);

  /* Increment the count of rows affected by the update
  */
  if( db->flags & SQLITE_CountRows ){
    sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
  }

  /* Repeat the above with the next record to be updated, until
  ** all record selected by the WHERE clause have been updated.
  */
  sqliteVdbeAddOp(v, OP_Goto, 0, addr);
  sqliteVdbeResolveLabel(v, end);
  sqliteVdbeAddOp(v, OP_ListClose, 0, 0);
  if( (db->flags & SQLITE_InTrans)==0 ){
    sqliteVdbeAddOp(v, OP_Commit, 0, 0);
  }

  /*
  ** Return the number of rows that were changed.
  */
  if( db->flags & SQLITE_CountRows ){
    sqliteVdbeAddOp(v, OP_ColumnCount, 1, 0);
    sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
    sqliteVdbeChangeP3(v, -1, "rows updated", P3_STATIC);
    sqliteVdbeAddOp(v, OP_Callback, 1, 0);
  }

update_cleanup:
  sqliteFree(apIdx);
  sqliteFree(aXRef);
  sqliteIdListDelete(pTabList);
  sqliteExprListDelete(pChanges);
  sqliteExprDelete(pWhere);
  return;
}

Changes to test/delete.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44


45
46
47
48

49


50
51
52
53


54
55
56
57
58
59
60
..
65
66
67
68
69
70
71
72
73


74























75
76




77
78
79

80
81
82
83
84
85
86
#    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 DELETE FROM statement.
#
# $Id: delete.test,v 1.9 2001/09/16 00:13:28 drh Exp $

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

# Try to delete from a non-existant table.
#
do_test delete-1.1 {
................................................................................
do_test delete-2.1 {
  set v [catch {execsql {DELETE FROM sqlite_master}} msg]
  lappend v $msg
} {1 {table sqlite_master may not be modified}}

# Delete selected entries from a table with and without an index.
#
do_test delete-3.1a {
  execsql {CREATE TABLE table1(f1 int, f2 int)}
  execsql {INSERT INTO table1 VALUES(1,2)}
  execsql {INSERT INTO table1 VALUES(2,4)}
  execsql {INSERT INTO table1 VALUES(3,8)}
  execsql {INSERT INTO table1 VALUES(4,16)}
  execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 2 4 3 8 4 16}
do_test delete-3.1b {
  execsql {DELETE FROM table1 WHERE f1=3}


  execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 2 4 4 16}
do_test delete-3.1c {
  execsql {CREATE INDEX index1 ON table1(f1)}

  execsql {DELETE FROM 'table1' WHERE f1=3}


  execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 2 4 4 16}
do_test delete-3.1d {
  execsql {DELETE FROM table1 WHERE f1=2}


  execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 4 16}

# Semantic errors in the WHERE clause
#
do_test delete-4.1 {
  execsql {CREATE TABLE table2(f1 int, f2 int)}
................................................................................
do_test delete-4.2 {
  set v [catch {execsql {DELETE FROM table2 WHERE xyzzy(f1+4)}} msg]
  lappend v $msg
} {1 {no such function: xyzzy}}

# Lots of deletes
#
do_test delete-5.1 {
  execsql {DELETE FROM table1}


  execsql {SELECT count(*) FROM table1}























} {}
do_test delete-5.2 {




  for {set i 1} {$i<=200} {incr i} {
     execsql "INSERT INTO table1 VALUES($i,[expr {$i*$i}])"
  }

  execsql {SELECT count(*) FROM table1}
} {200}
do_test delete-5.3 {
  for {set i 1} {$i<=200} {incr i 4} {
     execsql "DELETE FROM table1 WHERE f1==$i"
  }
  execsql {SELECT count(*) FROM table1}







|







 







|







|

>
>


|

>

>
>


|

>
>







 







|

>
>

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

|
>
>
>
>



>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
..
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
#    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 DELETE FROM statement.
#
# $Id: delete.test,v 1.10 2001/10/15 00:44:36 drh Exp $

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

# Try to delete from a non-existant table.
#
do_test delete-1.1 {
................................................................................
do_test delete-2.1 {
  set v [catch {execsql {DELETE FROM sqlite_master}} msg]
  lappend v $msg
} {1 {table sqlite_master may not be modified}}

# Delete selected entries from a table with and without an index.
#
do_test delete-3.1.1 {
  execsql {CREATE TABLE table1(f1 int, f2 int)}
  execsql {INSERT INTO table1 VALUES(1,2)}
  execsql {INSERT INTO table1 VALUES(2,4)}
  execsql {INSERT INTO table1 VALUES(3,8)}
  execsql {INSERT INTO table1 VALUES(4,16)}
  execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 2 4 3 8 4 16}
do_test delete-3.1.2 {
  execsql {DELETE FROM table1 WHERE f1=3}
} {}
do_test delete-3.1.3 {
  execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 2 4 4 16}
do_test delete-3.1.4 {
  execsql {CREATE INDEX index1 ON table1(f1)}
  execsql {PRAGMA count_changes=on}
  execsql {DELETE FROM 'table1' WHERE f1=3}
} {0}
do_test delete-3.1.5 {
  execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 2 4 4 16}
do_test delete-3.1.6 {
  execsql {DELETE FROM table1 WHERE f1=2}
} {1}
do_test delete-3.1.7 {
  execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 4 16}

# Semantic errors in the WHERE clause
#
do_test delete-4.1 {
  execsql {CREATE TABLE table2(f1 int, f2 int)}
................................................................................
do_test delete-4.2 {
  set v [catch {execsql {DELETE FROM table2 WHERE xyzzy(f1+4)}} msg]
  lappend v $msg
} {1 {no such function: xyzzy}}

# Lots of deletes
#
do_test delete-5.1.1 {
  execsql {DELETE FROM table1}
} {2}
do_test delete-5.1.2 {
  execsql {SELECT count(*) FROM table1}
} {0}
do_test delete-5.2.1 {
  execsql {BEGIN TRANSACTION}
  for {set i 1} {$i<=200} {incr i} {
     execsql "INSERT INTO table1 VALUES($i,[expr {$i*$i}])"
  }
  execsql {COMMIT}
  execsql {SELECT count(*) FROM table1}
} {200}
do_test delete-5.2.2 {
  execsql {DELETE FROM table1}
} {200}
do_test delete-5.2.3 {
  execsql {BEGIN TRANSACTION}
  for {set i 1} {$i<=200} {incr i} {
     execsql "INSERT INTO table1 VALUES($i,[expr {$i*$i}])"
  }
  execsql {COMMIT}
  execsql {SELECT count(*) FROM table1}
} {200}
do_test delete-5.2.4 {
  execsql {PRAGMA count_changes=off}
  execsql {DELETE FROM table1}
} {}
do_test delete-5.2.5 {
  execsql {SELECT count(*) FROM table1}
} {0}
do_test delete-5.2.6 {
  execsql {BEGIN TRANSACTION}
  for {set i 1} {$i<=200} {incr i} {
     execsql "INSERT INTO table1 VALUES($i,[expr {$i*$i}])"
  }
  execsql {COMMIT}
  execsql {SELECT count(*) FROM table1}
} {200}
do_test delete-5.3 {
  for {set i 1} {$i<=200} {incr i 4} {
     execsql "DELETE FROM table1 WHERE f1==$i"
  }
  execsql {SELECT count(*) FROM table1}

Changes to test/insert2.test.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
26
27
28
29
30
31
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48




49
50
51
52
53
54
55

56
57
58




59
60
61
62
63
64
65
#    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 INSERT statement that takes is
# result from a SELECT.
#
# $Id: insert2.test,v 1.4 2001/09/16 00:13:28 drh Exp $

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

# Create some tables with data that we can select against
#
do_test insert2-1.0 {
................................................................................
    execsql "INSERT INTO d1 VALUES($i,$j)"
  }
  execsql {SELECT * FROM d1 ORDER BY n}
} {1 0 2 1 3 2 4 2 5 3 6 3 7 3 8 3 9 4 10 4 11 4 12 4 13 4 14 4 15 4 16 4 17 5 18 5 19 5 20 5}

# Insert into a new table from the old one.
#
do_test insert2-1.1 {
  execsql {
    CREATE TABLE t1(log int, cnt int);
---vdbe-trace-on--
    INSERT INTO t1 SELECT log, count(*) FROM d1 GROUP BY log;
  }


  execsql {SELECT * FROM t1 ORDER BY log}
} {0 1 1 1 2 2 3 4 4 8 5 4}

do_test insert2-1.2 {
  catch {execsql {DROP TABLE t1}}
  execsql {
    CREATE TABLE t1(log int, cnt int);
    INSERT INTO t1 
       SELECT log, count(*) FROM d1 GROUP BY log
       EXCEPT SELECT n-1,log FROM d1;




    SELECT * FROM t1 ORDER BY log;
  }
} {0 1 3 4 4 8 5 4}
do_test insert2-1.3 {
  catch {execsql {DROP TABLE t1}}
  execsql {
    CREATE TABLE t1(log int, cnt int);

    INSERT INTO t1 
       SELECT log, count(*) FROM d1 GROUP BY log
       INTERSECT SELECT n-1,log FROM d1;




    SELECT * FROM t1 ORDER BY log;
  }
} {1 1 2 2}
do_test insert2-1.4 {
  catch {execsql {DROP TABLE t1}}
  set r [execsql {
    CREATE TABLE t1(log int, cnt int);







|







 







|


|


>
>



|






>
>
>
>



|



>



>
>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
#    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 INSERT statement that takes is
# result from a SELECT.
#
# $Id: insert2.test,v 1.5 2001/10/15 00:44:36 drh Exp $

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

# Create some tables with data that we can select against
#
do_test insert2-1.0 {
................................................................................
    execsql "INSERT INTO d1 VALUES($i,$j)"
  }
  execsql {SELECT * FROM d1 ORDER BY n}
} {1 0 2 1 3 2 4 2 5 3 6 3 7 3 8 3 9 4 10 4 11 4 12 4 13 4 14 4 15 4 16 4 17 5 18 5 19 5 20 5}

# Insert into a new table from the old one.
#
do_test insert2-1.1.1 {
  execsql {
    CREATE TABLE t1(log int, cnt int);
    PRAGMA count_changes=on;
    INSERT INTO t1 SELECT log, count(*) FROM d1 GROUP BY log;
  }
} {6}
do_test insert2-1.1.2 {
  execsql {SELECT * FROM t1 ORDER BY log}
} {0 1 1 1 2 2 3 4 4 8 5 4}

do_test insert2-1.2.1 {
  catch {execsql {DROP TABLE t1}}
  execsql {
    CREATE TABLE t1(log int, cnt int);
    INSERT INTO t1 
       SELECT log, count(*) FROM d1 GROUP BY log
       EXCEPT SELECT n-1,log FROM d1;
  }
} {4}
do_test insert2-1.2.2 {
  execsql {
    SELECT * FROM t1 ORDER BY log;
  }
} {0 1 3 4 4 8 5 4}
do_test insert2-1.3.1 {
  catch {execsql {DROP TABLE t1}}
  execsql {
    CREATE TABLE t1(log int, cnt int);
    PRAGMA count_changes=off;
    INSERT INTO t1 
       SELECT log, count(*) FROM d1 GROUP BY log
       INTERSECT SELECT n-1,log FROM d1;
  }
} {}
do_test insert2-1.3.2 {
  execsql {
    SELECT * FROM t1 ORDER BY log;
  }
} {1 1 2 2}
do_test insert2-1.4 {
  catch {execsql {DROP TABLE t1}}
  set r [execsql {
    CREATE TABLE t1(log int, cnt int);

Changes to test/select1.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
238
239
240
241
242
243
244




245
246
247
248
249
250
251
252
253
254
255
256
257
258
...
271
272
273
274
275
276
277






278
279
280
281
282
283
284
#    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 SELECT statement.
#
# $Id: select1.test,v 1.11 2001/10/06 16:33:03 drh Exp $

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

# Try to select on a non-existant table.
#
do_test select1-1.1 {
................................................................................
  set v [catch {execsql2 {SELECT f1 FROM test1 ORDER BY f2}} msg]
  lappend v $msg
} {0 {f1 11 f1 33}}
do_test select1-6.1.1 {
  execsql {PRAGMA full_column_names=on}
  set v [catch {execsql2 {SELECT f1 FROM test1 ORDER BY f2}} msg]
  lappend v $msg




} {0 {f1 11 f1 33}}
do_test select1-6.1.2 {
  set v [catch {execsql2 {SELECT * FROM test1 WHERE f1==11}} msg]
  execsql {PRAGMA full_column_names=off}
  lappend v $msg
} {0 {test1.f1 11 test1.f2 22}}
do_test select1-6.1.2 {
  set v [catch {execsql2 {SELECT * FROM test1 WHERE f1==11}} msg]
  lappend v $msg
} {0 {f1 11 f2 22}}
do_test select1-6.2 {
  set v [catch {execsql2 {SELECT f1 as xyzzy FROM test1 ORDER BY f2}} msg]
  lappend v $msg
} {0 {xyzzy 11 xyzzy 33}}
................................................................................
do_test select1-6.4a {
  set v [catch {execsql2 {SELECT f1+F2 FROM test1 ORDER BY f2}} msg]
  lappend v $msg
} {0 {f1+F2 33 f1+F2 77}}
do_test select1-6.5 {
  set v [catch {execsql2 {SELECT test1.f1+F2 FROM test1 ORDER BY f2}} msg]
  lappend v $msg






} {0 {test1.f1+F2 33 test1.f1+F2 77}}
do_test select1-6.6 {
  set v [catch {execsql2 {SELECT test1.f1+F2, t1 FROM test1, test2 
         ORDER BY f2}} msg]
  lappend v $msg
} {0 {test1.f1+F2 33 t1 abc test1.f1+F2 77 t1 abc}}
do_test select1-6.7 {







|







 







>
>
>
>

|




|







 







>
>
>
>
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
...
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
#    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 SELECT statement.
#
# $Id: select1.test,v 1.12 2001/10/15 00:44:36 drh Exp $

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

# Try to select on a non-existant table.
#
do_test select1-1.1 {
................................................................................
  set v [catch {execsql2 {SELECT f1 FROM test1 ORDER BY f2}} msg]
  lappend v $msg
} {0 {f1 11 f1 33}}
do_test select1-6.1.1 {
  execsql {PRAGMA full_column_names=on}
  set v [catch {execsql2 {SELECT f1 FROM test1 ORDER BY f2}} msg]
  lappend v $msg
} {0 {test1.f1 11 test1.f1 33}}
do_test select1-6.1.2 {
  set v [catch {execsql2 {SELECT f1 as 'f1' FROM test1 ORDER BY f2}} msg]
  lappend v $msg
} {0 {f1 11 f1 33}}
do_test select1-6.1.3 {
  set v [catch {execsql2 {SELECT * FROM test1 WHERE f1==11}} msg]
  execsql {PRAGMA full_column_names=off}
  lappend v $msg
} {0 {test1.f1 11 test1.f2 22}}
do_test select1-6.1.4 {
  set v [catch {execsql2 {SELECT * FROM test1 WHERE f1==11}} msg]
  lappend v $msg
} {0 {f1 11 f2 22}}
do_test select1-6.2 {
  set v [catch {execsql2 {SELECT f1 as xyzzy FROM test1 ORDER BY f2}} msg]
  lappend v $msg
} {0 {xyzzy 11 xyzzy 33}}
................................................................................
do_test select1-6.4a {
  set v [catch {execsql2 {SELECT f1+F2 FROM test1 ORDER BY f2}} msg]
  lappend v $msg
} {0 {f1+F2 33 f1+F2 77}}
do_test select1-6.5 {
  set v [catch {execsql2 {SELECT test1.f1+F2 FROM test1 ORDER BY f2}} msg]
  lappend v $msg
} {0 {test1.f1+F2 33 test1.f1+F2 77}}
do_test select1-6.5.1 {
  execsql2 {PRAGMA full_column_names=on}
  set v [catch {execsql2 {SELECT test1.f1+F2 FROM test1 ORDER BY f2}} msg]
  execsql2 {PRAGMA full_column_names=off}
  lappend v $msg
} {0 {test1.f1+F2 33 test1.f1+F2 77}}
do_test select1-6.6 {
  set v [catch {execsql2 {SELECT test1.f1+F2, t1 FROM test1, test2 
         ORDER BY f2}} msg]
  lappend v $msg
} {0 {test1.f1+F2 33 t1 abc test1.f1+F2 77 t1 abc}}
do_test select1-6.7 {

Changes to test/select5.test.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
84
85
86
87
88
89
90
91
92
93
94
95
96





97



98












99
#    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 aggregate functions and the
# GROUP BY and HAVING clauses of SELECT statements.
#
# $Id: select5.test,v 1.5 2001/09/16 00:13:28 drh Exp $

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

# Build some test data
#
set fd [open data1.txt w]
................................................................................
#
do_test select5-3.1 {
  execsql {
    SELECT x, count(*), avg(y) FROM t1 GROUP BY x HAVING x<4 ORDER BY x
  }
} {1 1 5 2 1 5 3 1 5}

# Run the AVG() function when the count is zero.
#
do_test select5-4.1 {
  execsql {
    SELECT avg(x) FROM t1 WHERE x>100
  }





} {}
















finish_test







|







 







|





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

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
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
#    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 aggregate functions and the
# GROUP BY and HAVING clauses of SELECT statements.
#
# $Id: select5.test,v 1.6 2001/10/15 00:44:36 drh Exp $

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

# Build some test data
#
set fd [open data1.txt w]
................................................................................
#
do_test select5-3.1 {
  execsql {
    SELECT x, count(*), avg(y) FROM t1 GROUP BY x HAVING x<4 ORDER BY x
  }
} {1 1 5 2 1 5 3 1 5}

# Run various aggregate functions when the count is zero.
#
do_test select5-4.1 {
  execsql {
    SELECT avg(x) FROM t1 WHERE x>100
  }
} {{}}
do_test select5-4.2 {
  execsql {
    SELECT count(x) FROM t1 WHERE x>100
  }
} {0}
do_test select5-4.3 {
  execsql {
    SELECT min(x) FROM t1 WHERE x>100
  }
} {{}}
do_test select5-4.4 {
  execsql {
    SELECT max(x) FROM t1 WHERE x>100
  }
} {{}}
do_test select5-4.5 {
  execsql {
    SELECT sum(x) FROM t1 WHERE x>100
  }
} {0}

finish_test

Changes to test/update.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
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
...
113
114
115
116
117
118
119


120





121

122
123
124
125
126
127
128
...
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
#    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 UPDATE statement.
#
# $Id: update.test,v 1.6 2001/09/16 00:13:28 drh Exp $

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

# Try to update an non-existent table
#
do_test update-1.1 {
................................................................................
  lappend v $msg
} {1 {no such column: f3}}

# Actually do some updates
#
do_test update-3.5 {
  execsql {UPDATE test1 SET f2=f2*3}


  execsql {SELECT * FROM test1 ORDER BY f1}
} {1 6 2 12 3 24 4 48 5 96 6 192 7 384 8 768 9 1536 10 3072}
do_test update-3.6 {

  execsql {UPDATE test1 SET f2=f2/3 WHERE f1<=5}


  execsql {SELECT * FROM test1 ORDER BY f1}
} {1 2 2 4 3 8 4 16 5 32 6 192 7 384 8 768 9 1536 10 3072}
do_test update-3.7 {
  execsql {UPDATE test1 SET f2=f2/3 WHERE f1>5}


  execsql {SELECT * FROM test1 ORDER BY f1}
} {1 2 2 4 3 8 4 16 5 32 6 64 7 128 8 256 9 512 10 1024}

# Swap the values of f1 and f2 for all elements
#
do_test update-3.8 {
  execsql {UPDATE test1 SET F2=f1, F1=f2}


  execsql {SELECT * FROM test1 ORDER BY F1}
} {2 1 4 2 8 3 16 4 32 5 64 6 128 7 256 8 512 9 1024 10}
do_test update-3.9 {

  execsql {UPDATE test1 SET F2=f1, F1=f2}


  execsql {SELECT * FROM test1 ORDER BY F1}
} {1 2 2 4 3 8 4 16 5 32 6 64 7 128 8 256 9 512 10 1024}

# Create duplicate entries and make sure updating still
# works.
#
do_test update-4.0 {
................................................................................
  execsql {SELECT * FROM test1 ORDER BY f1,f2}
} {6 64 8 88 8 128 8 256 8 888 9 512 10 1024 78 128 778 128}
do_test update-4.5 {
  execsql {UPDATE test1 SET f1=f1-1 WHERE f1>100 and f2==128}
  execsql {SELECT * FROM test1 ORDER BY f1,f2}
} {6 64 8 88 8 128 8 256 8 888 9 512 10 1024 78 128 777 128}
do_test update-4.6 {


  execsql {UPDATE test1 SET f1=f1-1 WHERE f1<=100 and f2==128}





  execsql {SELECT * FROM test1 ORDER BY f1,f2}

} {6 64 7 128 8 88 8 256 8 888 9 512 10 1024 77 128 777 128}

# Repeat the previous sequence of tests with an index.
#
do_test update-5.0 {
  execsql {CREATE INDEX idx1 ON test1(f1)}
  execsql {SELECT * FROM test1 ORDER BY f1,f2}
................................................................................
  execsql {SELECT * FROM test1 WHERE f1==778 ORDER BY f1,f2}
} {778 128}
do_test update-5.4.3 {
  execsql {SELECT * FROM test1 WHERE f1==8 ORDER BY f1,f2}
} {8 88 8 128 8 256 8 888}
do_test update-5.5 {
  execsql {UPDATE test1 SET f1=f1-1 WHERE f1>100 and f2==128}


  execsql {SELECT * FROM test1 ORDER BY f1,f2}
} {6 64 8 88 8 128 8 256 8 888 9 512 10 1024 78 128 777 128}
do_test update-5.5.1 {
  execsql {SELECT * FROM test1 WHERE f1==78 ORDER BY f1,f2}
} {78 128}
do_test update-5.5.2 {
  execsql {SELECT * FROM test1 WHERE f1==778 ORDER BY f1,f2}
} {}
do_test update-5.5.3 {
  execsql {SELECT * FROM test1 WHERE f1==777 ORDER BY f1,f2}
} {777 128}
do_test update-5.5.4 {
  execsql {SELECT * FROM test1 WHERE f1==8 ORDER BY f1,f2}
} {8 88 8 128 8 256 8 888}
do_test update-5.6 {


  execsql {UPDATE test1 SET f1=f1-1 WHERE f1<=100 and f2==128}





  execsql {SELECT * FROM test1 ORDER BY f1,f2}

} {6 64 7 128 8 88 8 256 8 888 9 512 10 1024 77 128 777 128}
do_test update-5.6.1 {
  execsql {SELECT * FROM test1 WHERE f1==77 ORDER BY f1,f2}
} {77 128}
do_test update-5.6.2 {
  execsql {SELECT * FROM test1 WHERE f1==778 ORDER BY f1,f2}
} {}
do_test update-5.6.3 {
  execsql {SELECT * FROM test1 WHERE f1==777 ORDER BY f1,f2}
} {777 128}
do_test update-5.6.4 {
  execsql {SELECT * FROM test1 WHERE f1==8 ORDER BY f1,f2}
} {8 88 8 256 8 888}

# Repeat the previous sequence of tests with a different index.
#
do_test update-6.0 {
  execsql {DROP INDEX idx1}







|







 







>
>


|
>

>
>


|

>
>





|

>
>


|
>

>
>







 







>
>
|
>
>
>
>
>
|
>







 







>
>


|


|


|


|



>
>
|
>
>
>
>
>
|
>

|


|


|


|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
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
...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
...
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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#    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 UPDATE statement.
#
# $Id: update.test,v 1.7 2001/10/15 00:44:36 drh Exp $

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

# Try to update an non-existent table
#
do_test update-1.1 {
................................................................................
  lappend v $msg
} {1 {no such column: f3}}

# Actually do some updates
#
do_test update-3.5 {
  execsql {UPDATE test1 SET f2=f2*3}
} {}
do_test update-3.6 {
  execsql {SELECT * FROM test1 ORDER BY f1}
} {1 6 2 12 3 24 4 48 5 96 6 192 7 384 8 768 9 1536 10 3072}
do_test update-3.7 {
  execsql {PRAGMA count_changes=on}
  execsql {UPDATE test1 SET f2=f2/3 WHERE f1<=5}
} {5}
do_test update-3.8 {
  execsql {SELECT * FROM test1 ORDER BY f1}
} {1 2 2 4 3 8 4 16 5 32 6 192 7 384 8 768 9 1536 10 3072}
do_test update-3.9 {
  execsql {UPDATE test1 SET f2=f2/3 WHERE f1>5}
} {5}
do_test update-3.10 {
  execsql {SELECT * FROM test1 ORDER BY f1}
} {1 2 2 4 3 8 4 16 5 32 6 64 7 128 8 256 9 512 10 1024}

# Swap the values of f1 and f2 for all elements
#
do_test update-3.11 {
  execsql {UPDATE test1 SET F2=f1, F1=f2}
} {10}
do_test update-3.12 {
  execsql {SELECT * FROM test1 ORDER BY F1}
} {2 1 4 2 8 3 16 4 32 5 64 6 128 7 256 8 512 9 1024 10}
do_test update-3.13 {
  execsql {PRAGMA count_changes=off}
  execsql {UPDATE test1 SET F2=f1, F1=f2}
} {}
do_test update-3.14 {
  execsql {SELECT * FROM test1 ORDER BY F1}
} {1 2 2 4 3 8 4 16 5 32 6 64 7 128 8 256 9 512 10 1024}

# Create duplicate entries and make sure updating still
# works.
#
do_test update-4.0 {
................................................................................
  execsql {SELECT * FROM test1 ORDER BY f1,f2}
} {6 64 8 88 8 128 8 256 8 888 9 512 10 1024 78 128 778 128}
do_test update-4.5 {
  execsql {UPDATE test1 SET f1=f1-1 WHERE f1>100 and f2==128}
  execsql {SELECT * FROM test1 ORDER BY f1,f2}
} {6 64 8 88 8 128 8 256 8 888 9 512 10 1024 78 128 777 128}
do_test update-4.6 {
  execsql {
    PRAGMA count_changes=on;
    UPDATE test1 SET f1=f1-1 WHERE f1<=100 and f2==128;
  }
} {2}
do_test update-4.7 {
  execsql {
    PRAGMA count_changes=off;
    SELECT * FROM test1 ORDER BY f1,f2
  }
} {6 64 7 128 8 88 8 256 8 888 9 512 10 1024 77 128 777 128}

# Repeat the previous sequence of tests with an index.
#
do_test update-5.0 {
  execsql {CREATE INDEX idx1 ON test1(f1)}
  execsql {SELECT * FROM test1 ORDER BY f1,f2}
................................................................................
  execsql {SELECT * FROM test1 WHERE f1==778 ORDER BY f1,f2}
} {778 128}
do_test update-5.4.3 {
  execsql {SELECT * FROM test1 WHERE f1==8 ORDER BY f1,f2}
} {8 88 8 128 8 256 8 888}
do_test update-5.5 {
  execsql {UPDATE test1 SET f1=f1-1 WHERE f1>100 and f2==128}
} {}
do_test update-5.5.1 {
  execsql {SELECT * FROM test1 ORDER BY f1,f2}
} {6 64 8 88 8 128 8 256 8 888 9 512 10 1024 78 128 777 128}
do_test update-5.5.2 {
  execsql {SELECT * FROM test1 WHERE f1==78 ORDER BY f1,f2}
} {78 128}
do_test update-5.5.3 {
  execsql {SELECT * FROM test1 WHERE f1==778 ORDER BY f1,f2}
} {}
do_test update-5.5.4 {
  execsql {SELECT * FROM test1 WHERE f1==777 ORDER BY f1,f2}
} {777 128}
do_test update-5.5.5 {
  execsql {SELECT * FROM test1 WHERE f1==8 ORDER BY f1,f2}
} {8 88 8 128 8 256 8 888}
do_test update-5.6 {
  execsql {
    PRAGMA count_changes=on;
    UPDATE test1 SET f1=f1-1 WHERE f1<=100 and f2==128;
  }
} {2}
do_test update-5.6.1 {
  execsql {
    PRAGMA count_changes=off;
    SELECT * FROM test1 ORDER BY f1,f2
  }
} {6 64 7 128 8 88 8 256 8 888 9 512 10 1024 77 128 777 128}
do_test update-5.6.2 {
  execsql {SELECT * FROM test1 WHERE f1==77 ORDER BY f1,f2}
} {77 128}
do_test update-5.6.3 {
  execsql {SELECT * FROM test1 WHERE f1==778 ORDER BY f1,f2}
} {}
do_test update-5.6.4 {
  execsql {SELECT * FROM test1 WHERE f1==777 ORDER BY f1,f2}
} {777 128}
do_test update-5.6.5 {
  execsql {SELECT * FROM test1 WHERE f1==8 ORDER BY f1,f2}
} {8 88 8 256 8 888}

# Repeat the previous sequence of tests with a different index.
#
do_test update-6.0 {
  execsql {DROP INDEX idx1}

Changes to www/changes.tcl.

12
13
14
15
16
17
18







19
20
21
22
23
24
25
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}








chng {2001 Oct 13 (2.0.4)} {
<li>Bug fix: an abscure and relatively harmless bug was causing one of
    the tests to fail when gcc optimizations are turned on.  This release
    fixes the problem.</li>
}








>
>
>
>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}

chng {2001 Oct 14 (2.0.5)} {
<li>Added the COUNT_CHANGES pragma.</li>
<li>Changes to the FULL_COLUMN_NAMES pragma to help out the ODBC driver.</li>
<li>Bug fix: "SELECT count(*)" was returning NULL for empty tables.
    Now it returns 0.</li>
}

chng {2001 Oct 13 (2.0.4)} {
<li>Bug fix: an abscure and relatively harmless bug was causing one of
    the tests to fail when gcc optimizations are turned on.  This release
    fixes the problem.</li>
}

Changes to www/lang.tcl.

1
2
3
4
5
6
7
8
9
10
11
...
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
#
# Run this Tcl script to generate the sqlite.html file.
#
set rcsid {$Id: lang.tcl,v 1.12 2001/10/13 02:59:10 drh Exp $}

puts {<html>
<head>
  <title>Query Language Understood By SQLite</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
    <p>Change the maximum number of database disk pages that SQLite
    will hold in memory at once.  Each page uses about 1.5K of RAM.
    The default cache size is 100.  If you are doing UPDATEs or DELETEs
    that change many rows of a database and you do not mind if SQLite
    uses more memory, you can increase the cache size for a possible speed
    improvement.</p></li>







<li><p><b>PRAGMA full_column_names = ON;
       <br>PRAGMA full_column_names = OFF;</b></p>
    <p>The column names reported in an SQLite callback are normally just
    the name of the column itself, except for joins when "TABLE.COLUMN"
    is used.  But when full_column_names is turned on, column names are
    always reported as "TABLE.COLUMN" even for simple queries.</p></li>

<li><p><b>PRAGMA vdbe_trace = ON;<br>PRAGMA vdbe_trace = OFF;</b></p>
    <p>Turn tracing of the virtual database engine inside of the
    SQLite library on and off.  This is used for debugging.</p></li>









<li><p><b>PRAGMA parser_trace = ON;<br>PRAGMA parser_trace = OFF;</b></p>
    <p>Turn tracing of the SQL parser inside of the












    SQLite library on and off.  This is used for debugging.</p></li>
</ul>

<p>No error message is generated if an unknown pragma is issued.
Unknown pragmas are ignored.</p>
}




|







 







>
>
>
>
>
>







|
|
|
>
>

>
>
>
>
>
>


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







1
2
3
4
5
6
7
8
9
10
11
...
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
#
# Run this Tcl script to generate the sqlite.html file.
#
set rcsid {$Id: lang.tcl,v 1.13 2001/10/15 00:44:36 drh Exp $}

puts {<html>
<head>
  <title>Query Language Understood By SQLite</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
    <p>Change the maximum number of database disk pages that SQLite
    will hold in memory at once.  Each page uses about 1.5K of RAM.
    The default cache size is 100.  If you are doing UPDATEs or DELETEs
    that change many rows of a database and you do not mind if SQLite
    uses more memory, you can increase the cache size for a possible speed
    improvement.</p></li>

<li><p><b>PRAGMA count_changes = ON;
       <br>PRAGMA count_changes = OFF;</b></p>
    <p>When on, the COUNT_CHANGES pragma causes the callback function to
    be invoked once for each DELETE, INSERT, or UPDATE operation.  The
    argument is the number of rows that were changed.</p>

<li><p><b>PRAGMA full_column_names = ON;
       <br>PRAGMA full_column_names = OFF;</b></p>
    <p>The column names reported in an SQLite callback are normally just
    the name of the column itself, except for joins when "TABLE.COLUMN"
    is used.  But when full_column_names is turned on, column names are
    always reported as "TABLE.COLUMN" even for simple queries.</p></li>

<li><p><b>PRAGMA index_info(</b><i>index-name</i><b>);</b></p>
    <p>For each column that the named index references, invoke the 
    callback function
    once with information about that column, including the column name,
    and the column number.</p>

<li><p><b>PRAGMA index_list(</b><i>table-name</i><b>);</b></p>
    <p>For each index on the named table, invoke the callback function
    once with information about that index.  Arguments include the
    index name and a flag to indicate whether or not the index must be
    unique.</p>

<li><p><b>PRAGMA parser_trace = ON;<br>PRAGMA parser_trace = OFF;</b></p>
    <p>Turn tracing of the SQL parser inside of the
    SQLite library on and off.  This is used for debugging.
    This only works if the library is compiled without the NDEBUG macro.
    </p></li>

<li><p><b>PRAGMA table_info(</b><i>table-name</i><b>);</b></p>
    <p>For each column in the named table, invoke the callback function
    once with information about that column, including the column name,
    data type, whether or not the column can be NULL, and the default
    value for the column.</p>

<li><p><b>PRAGMA vdbe_trace = ON;<br>PRAGMA vdbe_trace = OFF;</b></p>
    <p>Turn tracing of the virtual database engine inside of the
    SQLite library on and off.  This is used for debugging.</p></li>
</ul>

<p>No error message is generated if an unknown pragma is issued.
Unknown pragmas are ignored.</p>
}