1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

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)

FossilOrigin-Name: 747bf1b30b74cfd0e9c27e7c0bc5172637f35520
This commit is contained in:
drh
2001-10-15 00:44:35 +00:00
parent f2d6a64495
commit 1bee3d7b43
19 changed files with 349 additions and 101 deletions

View File

@@ -58,6 +58,7 @@ EXE =
#
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

View File

@@ -1 +1 @@
2.0.4
2.0.5

View File

@@ -1,9 +1,9 @@
C Version\s2.0.4\s(CVS\s466)
D 2001-10-13T22:00:00
C Added\ssupport\sfor\sthe\sCOUNT_CHANGES\spragma\sin\sorder\sto\shelp\sout\sthe\nODBC\sdriver.\s\sFixed\sa\sbut\son\scount(*)\swhen\sapplied\sto\sempty\stables.\s(CVS\s289)
D 2001-10-15T00:44:35
F Makefile.in 6801df952cb1df64aa32e4de85fed24511d28efd
F Makefile.template 582916b263aa40a70521dfb3d99d574028abd47b
F Makefile.template 1fdb891f14083ee0b63cf7282f91529634438e7a
F README 93d2977cc5c6595c448de16bdefc312b9d401533
F VERSION 930f436b9878b6b1a49f546e86a54c17df3e0ca9
F VERSION e14d2010c343ae28a0dd038c3850eae3a88a9307
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
F config.log 6a73d03433669b10a3f0c221198c3f26b9413914
@@ -19,35 +19,35 @@ F libtool c56e618713c9510a103bda6b95f3ea3900dcacd6
F ltmain.sh e9ed72eb1d690f447c13945eaf69e28af531eda1
F publish.sh badcd69b8e3a8bc69b162c4c9d7c209b2a0b119e
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c 7e9c33a714ed1630562f89ad19847f5f28bd6d4d
F src/btree.c 97653e88bc4b7396226b93c878b153c77f1d3d03
F src/btree.h 57d653ef5137b91f2a068aaf71a2905468dd2cb7
F src/build.c 9c3e3634b20c358e538f33f5ae125667e65447b2
F src/delete.c bed54503368e0976aa2e8487d8914e7b7fb63aae
F src/build.c fe71d516148226bd6249403e82f8d07129206489
F src/delete.c 6fe2191c49c4a31336e2fac11b3ad665ddcd4246
F src/expr.c c1381b8229a5573b0928ede962e45c1c49d067af
F src/hash.c b7ced0735287c142a3b2db46c3cae3e6826afb75
F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
F src/insert.c ae283e85a301bb3cd6af955f62bde1ca4ba4b56d
F src/insert.c b65c1d4b848e45d41e9dcccd2b226ca335de67b6
F src/main.c 9a18e97290d41844e8c12e021fb7c42948a19dc9
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
F src/os.c cece4ac6cabc9d377ef0a4ab4c16f6f0f6c84377
F src/os.c 886bdd6c1dff71116f688e8b736d82e43e7ac9ed
F src/os.h bed702c9e3b768bc3cb1b12c90b83d099c1546be
F src/pager.c e2e189a15e230c60e811f5e2ab25e68ae41c90be
F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
F src/parse.y 148e4cd134d3cbd816dcb0df50e49e498faa6ba4
F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
F src/random.c 2a9cc2c9716d14815fd4c2accf89d87a1143e46b
F src/select.c ff4dc2271bb6de7a94f22e651be4d29b4f24ff3f
F src/select.c 75bb3ca7fd42f7c6d86fc565688e7834587a9f0d
F src/shell.c cb8c41f1b2173efd212dab3f35f1fc6bf32ead76
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in b95c161abf1d58bceb05290fa3f657d8f388fc11
F src/sqliteInt.h 5d6a79c70bdd9f993958c9c4a7970079fda495dd
F src/sqliteInt.h 04bfa79fcf6ade1961f6e3b9dc679a63be25cbd7
F src/table.c abd0adbe0fee39d995287b3bcccd908d174dfcac
F src/tclsqlite.c 765599686c19ed777ac379928d732c8bfc63ebac
F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
F src/tokenize.c c3fcb76a41a22803b6060bddb5fbadc80bbe309c
F src/update.c 0b287faf0cc1d2bfa437f8a54061dd12ae6df91d
F src/update.c c916182c6bfbc8a6f20c24920c4560fece6c9569
F src/util.c 4da3be37d0fd3c640d2d3033503768afdc8e5387
F src/vdbe.c 0f8ea6ca59f0899e9e0d71a81c0bf46110447cf6
F src/vdbe.h 86fc2ef42f48024c9a2e1b7fb01eda22b65a5295
@@ -57,13 +57,13 @@ F test/bigrow.test a35f2de9948b24e427fb292c35947795efe182d0
F test/btree.test 47952c7a0c22660566264c68c0664592b7da85ce
F test/btree2.test 20ce47ab804f15b6563736528bdd38aabe5193dc
F test/copy.test 768e6f1701a07d08090e1ca7f7dcce0a7a72b43e
F test/delete.test 5ebb114582457428b3e0e30b21b477fedcb85609
F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
F test/expr.test b4171c84b767f7b7e94dbce4824ba8e981a1c72f
F test/func.test fb0f44de6d8487359a4455accbae120bde267772
F test/in.test 9323681388be301dc73f370b4cd62c5a33f79d1e
F test/index.test 6076f29d09a4f26a2efa38b03b8cc338b8662f0e
F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11
F test/insert2.test 252d7130d8cc20f649b31a4f503cd87e660abda8
F test/insert2.test d6901ca931e308fea7fca8c95ebe7dc957cc9fc2
F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
F test/lock.test 19593689260c419efe7ced55b1418653a4b7bcd1
F test/main.test 1626345b5f630c5398eede500d9354813b76b0fd
@@ -74,11 +74,11 @@ F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da
F test/quick.test b6ec50f808efc06595fd324bf4f3fabadb9c7e9c
F test/quote.test 286db944717afa9a9bf829dd85e59185c65d5435
F test/rowid.test 427bfbbe9684fe7a2f851aa05badaae6d4972ce8
F test/select1.test b59e8c713277d7545f5b6e782e6223e51fea45a5
F test/select1.test 5f47445fa3a033e02e1b07e4fcd4f142e5a46403
F test/select2.test f91c903e2bab0e9d45274855a981eebf846d5e32
F test/select3.test 5e1fe8e5a4e63fb2827ab3b89527e0fd4ae35259
F test/select4.test 29a2ffb187f3d8b6ca42a0a6b619e9cabe12e228
F test/select5.test 00a240e3311b6c4ff0f27a252ad33811211fa8d8
F test/select5.test c2a6c4a003316ee42cbbd689eebef8fdce0db2ac
F test/sort.test 462c1161eee1abaa7cc93990e0b34d5fdb70ce19
F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78
F test/table.test 3ef4254d62ece31a3872ab11cdaec846f6fa8fd1
@@ -88,7 +88,7 @@ F test/temptable.test 37acd9e39781c2ff7cff2ba741b6b27ce020a44a
F test/tester.tcl c7ddeebc14cc841abb37134cd5d40c1e3ad367c1
F test/trans.test 855337b8a178c73c433fcf8ee88e4b2f5efff0d9
F test/unique.test ef1f67607a7109e9c0842cd8557550fb121d7ec6
F test/update.test b320ea22899e80b32b4d21c54591eb7a6ba4d6bd
F test/update.test 8cf76467d46b1650539763c95d5208340c61d561
F test/vacuum.test 8acf8669f3b627e54149b25165b034aa06c2432e
F test/where.test 43d5ac94da3f3722375307f948884dc79b326a91
F tool/lemon.c 5533b63e5cdbb1efc939abac3c2f4f37ac839488
@@ -102,19 +102,19 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
F www/arch.tcl 03b521d252575f93b9c52f7c8b0007011512fcfb
F www/c_interface.tcl a59ee0835d1b33fcddab7d4fd65cf9e50f7d2dc7
F www/changes.tcl 5407ebb20a046f1f12dd4b8acd23c135f8e45f91
F www/changes.tcl 00cfa817042f33097616ff0de388e6503aab3968
F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
F www/download.tcl 3e51c9ff1326b0a182846134987301310dff7d60
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
F www/index.tcl 68c815d64b35b2dcc4d4f6845827df71c6869f9f
F www/lang.tcl 8cf5de0e7b5d038506cd0b8fd26567ba43777b16
F www/lang.tcl 37d4a44bdafe42a270b9e28554651278086ce806
F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60
F www/opcode.tcl 4365ad9798872491dbd7d3071510ebe461785ac3
F www/speed.tcl ab7d6d3bc898472bd94320a5d3c63de928d4804b
F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e
F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44
P 26972afd645e21e0d16de9a0bb0d03754e909044
R 4a79f4243a1c67e525408e6bb2f97ed5
P 444447007a32f9ebd9e0714c6cbe0d9a63e193b1
R 27dbd8ccaf5ffe5bb0031ee011cf1c46
U drh
Z bda58aec2ebf892c3a56d60499b5a93d
Z 7a6d7f82de1493c63c9271f60dfef892

View File

@@ -1 +1 @@
444447007a32f9ebd9e0714c6cbe0d9a63e193b1
747bf1b30b74cfd0e9c27e7c0bc5172637f35520

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.33 2001/10/06 16:33:02 drh Exp $
** $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
@@ -597,8 +597,8 @@ static void pageDestructor(void *pData){
** 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.
** 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 */
@@ -807,6 +807,13 @@ int sqliteBtreeRollback(Btree *pBt){
** 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;
@@ -1357,6 +1364,7 @@ int sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){
int sqliteBtreeNext(BtCursor *pCur, int *pRes){
int rc;
if( pCur->pPage==0 ){
if( pRes ) *pRes = 1;
return SQLITE_ABORT;
}
if( pCur->bSkipNext ){

View File

@@ -25,7 +25,7 @@
** ROLLBACK
** PRAGMA
**
** $Id: build.c,v 1.49 2001/10/13 02:59:09 drh Exp $
** $Id: build.c,v 1.50 2001/10/15 00:44:36 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -1441,6 +1441,14 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
}
}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;

View File

@@ -12,7 +12,7 @@
** 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 $
** $Id: delete.c,v 1.18 2001/10/15 00:44:36 drh Exp $
*/
#include "sqliteInt.h"
@@ -33,6 +33,8 @@ void sqliteDeleteFrom(
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;
@@ -86,11 +88,31 @@ void sqliteDeleteFrom(
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);
@@ -101,8 +123,6 @@ void sqliteDeleteFrom(
** the table an pick which records to delete.
*/
else{
int openOp;
/* Begin the database scan
*/
sqliteVdbeAddOp(v, OP_ListOpen, 0, 0);
@@ -112,6 +132,9 @@ void sqliteDeleteFrom(
/* 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.
*/
@@ -151,6 +174,15 @@ void sqliteDeleteFrom(
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);

View File

@@ -12,7 +12,7 @@
** 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 $
** $Id: insert.c,v 1.24 2001/10/15 00:44:36 drh Exp $
*/
#include "sqliteInt.h"
@@ -170,6 +170,9 @@ void sqliteInsert(
** 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);
@@ -201,6 +204,7 @@ void sqliteInsert(
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.
*/
@@ -230,6 +234,14 @@ void sqliteInsert(
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 ){
@@ -241,6 +253,18 @@ void sqliteInsert(
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);

View File

@@ -68,7 +68,7 @@
** 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)
** 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

View File

@@ -12,7 +12,7 @@
** 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 $
** $Id: select.c,v 1.40 2001/10/15 00:44:36 drh Exp $
*/
#include "sqliteInt.h"
@@ -239,6 +239,7 @@ void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){
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);
@@ -247,17 +248,13 @@ void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){
}
p = pEList->a[i].pExpr;
if( p==0 ) continue;
if( p->span.z && p->span.z[0] ){
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==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 ){
}else if( p->op==TK_COLUMN && pTabList ){
if( pTabList->nId>1 || showFullNames ){
char *zName = 0;
Table *pTab = pTabList->a[p->iTable].pTab;
char *zTab;
@@ -274,6 +271,16 @@ void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){
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));
}
}
}
@@ -867,6 +874,23 @@ int sqliteSelect(
*/
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
@@ -898,28 +922,13 @@ int sqliteSelect(
** processing.
*/
else{
int doFocus;
if( pGroupBy ){
int lbl1;
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);
lbl1 = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_AggFocus, 0, lbl1);
for(i=0; i<pParse->nAgg; i++){
if( pParse->aAgg[i].isAgg ) continue;

View File

@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.61 2001/10/13 02:59:09 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.62 2001/10/15 00:44:36 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
@@ -163,6 +163,9 @@ struct sqlite {
#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

View File

@@ -12,7 +12,7 @@
** 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 $
** $Id: update.c,v 1.19 2001/10/15 00:44:36 drh Exp $
*/
#include "sqliteInt.h"
@@ -155,6 +155,12 @@ void sqliteUpdate(
*/
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.
*/
@@ -216,6 +222,12 @@ void sqliteUpdate(
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.
*/
@@ -226,6 +238,16 @@ void sqliteUpdate(
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);

View File

@@ -11,7 +11,7 @@
# 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 $
# $Id: delete.test,v 1.10 2001/10/15 00:44:36 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -32,7 +32,7 @@ do_test delete-2.1 {
# Delete selected entries from a table with and without an index.
#
do_test delete-3.1a {
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)}
@@ -40,17 +40,24 @@ do_test delete-3.1a {
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 {
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.1c {
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.1d {
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}
@@ -69,14 +76,44 @@ do_test delete-4.2 {
# Lots of deletes
#
do_test delete-5.1 {
do_test delete-5.1.1 {
execsql {DELETE FROM table1}
} {2}
do_test delete-5.1.2 {
execsql {SELECT count(*) FROM table1}
} {}
do_test delete-5.2 {
} {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 {

View File

@@ -12,7 +12,7 @@
# 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 $
# $Id: insert2.test,v 1.5 2001/10/15 00:44:36 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -30,32 +30,43 @@ do_test insert2-1.0 {
# Insert into a new table from the old one.
#
do_test insert2-1.1 {
do_test insert2-1.1.1 {
execsql {
CREATE TABLE t1(log int, cnt int);
---vdbe-trace-on--
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 {
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 {
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}

View File

@@ -11,7 +11,7 @@
# 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 $
# $Id: select1.test,v 1.12 2001/10/15 00:44:36 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -242,13 +242,17 @@ 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}}
} {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.2 {
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}}
@@ -276,6 +280,12 @@ 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]

View File

@@ -12,7 +12,7 @@
# 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 $
# $Id: select5.test,v 1.6 2001/10/15 00:44:36 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -88,12 +88,32 @@ do_test select5-3.1 {
}
} {1 1 5 2 1 5 3 1 5}
# Run the AVG() function when the count is zero.
# 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

View File

@@ -11,7 +11,7 @@
# 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 $
# $Id: update.test,v 1.7 2001/10/15 00:44:36 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -61,25 +61,37 @@ do_test update-3.4 {
#
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.6 {
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.7 {
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.8 {
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.9 {
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}
@@ -117,8 +129,16 @@ do_test update-4.5 {
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}
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.
@@ -154,34 +174,44 @@ do_test update-5.4.3 {
} {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.1 {
do_test update-5.5.2 {
execsql {SELECT * FROM test1 WHERE f1==78 ORDER BY f1,f2}
} {78 128}
do_test update-5.5.2 {
do_test update-5.5.3 {
execsql {SELECT * FROM test1 WHERE f1==778 ORDER BY f1,f2}
} {}
do_test update-5.5.3 {
do_test update-5.5.4 {
execsql {SELECT * FROM test1 WHERE f1==777 ORDER BY f1,f2}
} {777 128}
do_test update-5.5.4 {
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 {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}
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.2 {
do_test update-5.6.3 {
execsql {SELECT * FROM test1 WHERE f1==778 ORDER BY f1,f2}
} {}
do_test update-5.6.3 {
do_test update-5.6.4 {
execsql {SELECT * FROM test1 WHERE f1==777 ORDER BY f1,f2}
} {777 128}
do_test update-5.6.4 {
do_test update-5.6.5 {
execsql {SELECT * FROM test1 WHERE f1==8 ORDER BY f1,f2}
} {8 88 8 256 8 888}

View File

@@ -17,6 +17,13 @@ proc chng {date desc} {
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

View File

@@ -1,7 +1,7 @@
#
# 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 $}
set rcsid {$Id: lang.tcl,v 1.13 2001/10/15 00:44:36 drh Exp $}
puts {<html>
<head>
@@ -631,6 +631,12 @@ with caution.</p>
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
@@ -638,12 +644,32 @@ with caution.</p>
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 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>