mirror of https://github.com/sqlite/sqlite
New ROWIDs are numbered sequentially. (CVS 383)
FossilOrigin-Name: 1686196a8aea326f616bc8205df99cd84d955ec4
This commit is contained in:
parent
9562b55115
commit
5cf8e8c7fa
31
manifest
31
manifest
|
@ -1,5 +1,5 @@
|
|||
C Optimize\ssimple\smin()\sand\smax()\squeries.\s(CVS\s382)
|
||||
D 2002-02-19T15:00:07
|
||||
C New\sROWIDs\sare\snumbered\ssequentially.\s(CVS\s383)
|
||||
D 2002-02-19T22:42:05
|
||||
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
|
||||
F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834
|
||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||
|
@ -27,7 +27,7 @@ F src/expr.c 7aff65ea0732b07d36925087ad611019103ad69a
|
|||
F src/hash.c 8f7c740ef2eaaa8decfa8751f2be30680b123e46
|
||||
F src/hash.h d1ce47900c7325af5e41c4feb4855c4bf2b841e7
|
||||
F src/insert.c eae5aa2e9ac68c4d465e71b2ad34bcbb882979cf
|
||||
F src/main.c 669cfd9a8c40f6c9ff2d478e1695d1ea1fdafad1
|
||||
F src/main.c fada622b468c54fb211372f38a27ee636915e2ee
|
||||
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
||||
F src/os.c f6bc9b7ab530346bb7fef2ed39f2f1f214bc14ea
|
||||
F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
|
||||
|
@ -36,11 +36,11 @@ F src/pager.h b28f004e2f5541dc60cc32db01bf80cf4d056283
|
|||
F src/parse.y b82278917959eefd05bd08c90e07a4fa5917ea51
|
||||
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
|
||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||
F src/select.c 6dadbd3ba1e86334c9af321b48f6e3df1992f602
|
||||
F src/select.c 282f37b2fdb9367f0230811e1cf7bba48665fb72
|
||||
F src/shell.c c102dfe388c7618a668c944ff157c49cb48f28e3
|
||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in f57074c84a2c112a5093ba7a9d9636aa9cacc87c
|
||||
F src/sqliteInt.h 75cf79d3d0a0ea40f43bbc2d74a4aefb2ea37ccf
|
||||
F src/sqliteInt.h e19efd5b1c6accfb3418cbb5c0e8c143fc1d18d7
|
||||
F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
|
||||
F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
|
||||
F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
|
||||
|
@ -50,7 +50,7 @@ F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
|
|||
F src/tokenize.c 9e98f94469694a763992860596137e78dbae0cc0
|
||||
F src/update.c 95459f94a061860bf8e5716b3426a5ba85c79103
|
||||
F src/util.c f31f3d6198a0d1296a16f5a6ceec423a932cbbf6
|
||||
F src/vdbe.c 2b03a7d39f05321e5570373cb2f3734c3cf86b70
|
||||
F src/vdbe.c 18b6e9ed3bcdd76ae74d60a977a6d8a3a1b0f797
|
||||
F src/vdbe.h b4d35e159fbb80a74728b4a96e5b789fffce6f57
|
||||
F src/where.c f79bc3179379b46b131a67ab10713779368dceee
|
||||
F test/all.test 7a8a8a7a579ed2bb4d8976d55402f21eacd58049
|
||||
|
@ -67,19 +67,20 @@ F test/in.test c09312672e3f0709fa02c8e2e9cd8fb4bd6269aa
|
|||
F test/index.test c8a471243bbf878974b99baf5badd59407237cf3
|
||||
F test/insert.test c36d534a4ab58c2cd452a273e51b2b0dd1ede1f9
|
||||
F test/insert2.test 65c2b2aae0bae7a7bbe500f77981cd916b81e91b
|
||||
F test/intpkey.test ce3de8326082929667cf356855426519cfe2f5c7
|
||||
F test/intpkey.test 101ec266222e88b24e6f1e204b9b6873404cd4dc
|
||||
F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
|
||||
F test/limit.test a930f3eba2a7691c8397ccab33710b931589566a
|
||||
F test/lock.test 19593689260c419efe7ced55b1418653a4b7bcd1
|
||||
F test/main.test 1626345b5f630c5398eede500d9354813b76b0fd
|
||||
F test/malloc.test 70fdd0812e2a57eb746aaf015350f58bb8eee0b1
|
||||
F test/minmax.test fb6ab400271ae1f5bc88617c2882f2f081ea8e6d
|
||||
F test/misc1.test 7fd54d33547177da86e39e13e9608c5112681831
|
||||
F test/notnull.test b1f3e42fc475b0b5827b27b2e9b562081995ff30
|
||||
F test/pager.test b0c0d00cd5dce0ce21f16926956b195c0ab5044c
|
||||
F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da
|
||||
F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
|
||||
F test/quote.test 286db944717afa9a9bf829dd85e59185c65d5435
|
||||
F test/rowid.test cb023f2df36886e1fc4cdfd32eaba05cf7db4331
|
||||
F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274
|
||||
F test/select1.test fd2936aa907559153c78edf2740ea65eb9a614f5
|
||||
F test/select2.test ed2c1882857106b85478f54f67000e14966be4c4
|
||||
F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18
|
||||
|
@ -108,23 +109,23 @@ F tool/report1.txt 9eae07f26a8fc53889b45fc833a66a33daa22816
|
|||
F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
|
||||
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
||||
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
|
||||
F www/c_interface.tcl 82a026b1681757f13b3f62e035f3a31407c1d353
|
||||
F www/changes.tcl 7f9375639b6fefe75670e1881a2ccdc144c6230a
|
||||
F www/c_interface.tcl 63efc40f09e2f0d8fea43d174103248b160fdf0e
|
||||
F www/changes.tcl e9ac5ffc030ad355fb5973bc2c68e622c3bc9ae2
|
||||
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
|
||||
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
||||
F www/download.tcl a6d75b8b117cd33dcb090bef7e80d7556d28ebe0
|
||||
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
||||
F www/faq.tcl 32cbc134879871604070d4cc3a32e73fb22a35f9
|
||||
F www/faq.tcl c6d1d6d69a9083734ee73d1b5ee4253ae8f10074
|
||||
F www/formatchng.tcl 2d9a35c787823b48d72a5c64bb5414a43e26d5ad
|
||||
F www/index.tcl eacd99bcc3132d6e6b74a51422d415cc0bf7bfdf
|
||||
F www/lang.tcl abf67afeb6527eb20b9088813160877fb413e933
|
||||
F www/lang.tcl 01e47b43cb81cd24bd2918a2e1bd31a959097279
|
||||
F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
|
||||
F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
|
||||
F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
|
||||
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
||||
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
|
||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||
P c6e9048e66c8d8e2d5f6c62aa724eef3e9d9f572
|
||||
R 41f437c3e65a91e5a2a52b6609362036
|
||||
P cc5abfe392bdb8c3ed00e0610bc2b41851bfc9d7
|
||||
R d110cdfb274a665cf18a7abdadd913ff
|
||||
U drh
|
||||
Z ee034e966e6d17b9655294654ff0765f
|
||||
Z 2f4375a6c2ee111a8d6db399f5e3350c
|
||||
|
|
|
@ -1 +1 @@
|
|||
cc5abfe392bdb8c3ed00e0610bc2b41851bfc9d7
|
||||
1686196a8aea326f616bc8205df99cd84d955ec4
|
|
@ -14,7 +14,7 @@
|
|||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.59 2002/02/18 18:30:33 drh Exp $
|
||||
** $Id: main.c,v 1.60 2002/02/19 22:42:05 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -275,8 +275,8 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
|
|||
sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);
|
||||
sqliteHashInit(&db->tblDrop, SQLITE_HASH_POINTER, 0);
|
||||
sqliteHashInit(&db->idxDrop, SQLITE_HASH_POINTER, 0);
|
||||
db->nextRowid = sqliteRandomInteger();
|
||||
db->onError = OE_Default;
|
||||
db->priorNewRowid = 0;
|
||||
|
||||
/* Open the backend database driver */
|
||||
rc = sqliteBtreeOpen(zFilename, mode, MAX_PAGES, &db->pBe);
|
||||
|
|
19
src/select.c
19
src/select.c
|
@ -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.62 2002/02/19 15:00:08 drh Exp $
|
||||
** $Id: select.c,v 1.63 2002/02/19 22:42:05 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -783,22 +783,28 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
|||
|
||||
/* Begin generating code
|
||||
*/
|
||||
base = pParse->nTab;
|
||||
eList.nExpr = 1;
|
||||
memset(&eListItem, 0, sizeof(eListItem));
|
||||
eList.a = &eListItem;
|
||||
eList.a[0].pExpr = pExpr;
|
||||
if( !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
|
||||
base = pParse->nTab;
|
||||
sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
if( pIdx==0 ){
|
||||
sqliteVdbeAddOp(v, seekOp, base, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, openOp, base+1, pIdx->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
|
||||
sqliteVdbeAddOp(v, seekOp, base+1, 0);
|
||||
sqliteVdbeAddOp(v, OP_IdxRecno, base+1, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, base+1, 0);
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
||||
}
|
||||
eList.nExpr = 1;
|
||||
memset(&eListItem, 0, sizeof(eListItem));
|
||||
eList.a = &eListItem;
|
||||
eList.a[0].pExpr = pExpr;
|
||||
cont = sqliteVdbeMakeLabel(v);
|
||||
selectInnerLoop(pParse, &eList, base, 1, 0, -1, eDest, iParm, cont, cont);
|
||||
sqliteVdbeResolveLabel(v, cont);
|
||||
|
@ -1011,6 +1017,7 @@ int sqliteSelect(
|
|||
** in the result set.
|
||||
*/
|
||||
if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){
|
||||
rc = 0;
|
||||
goto select_end;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.87 2002/02/18 18:30:33 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.88 2002/02/19 22:42:05 drh Exp $
|
||||
*/
|
||||
#include "sqlite.h"
|
||||
#include "hash.h"
|
||||
|
@ -182,7 +182,7 @@ struct sqlite {
|
|||
Hash tblDrop; /* Uncommitted DROP TABLEs */
|
||||
Hash idxDrop; /* Uncommitted DROP INDEXs */
|
||||
int lastRowid; /* ROWID of most recent insert */
|
||||
int nextRowid; /* Next generated rowID */
|
||||
int priorNewRowid; /* Last randomly generated ROWID */
|
||||
int onError; /* Default conflict algorithm */
|
||||
};
|
||||
|
||||
|
|
67
src/vdbe.c
67
src/vdbe.c
|
@ -30,7 +30,7 @@
|
|||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.119 2002/02/19 15:00:08 drh Exp $
|
||||
** $Id: vdbe.c,v 1.120 2002/02/19 22:42:05 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
@ -71,6 +71,7 @@ struct Cursor {
|
|||
Bool recnoIsValid; /* True if lastRecno is valid */
|
||||
Bool keyAsData; /* The OP_Column command works on key instead of data */
|
||||
Bool atFirst; /* True if pointing to first entry */
|
||||
Bool useRandomRowid; /* Generate new record numbers semi-randomly */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
};
|
||||
typedef struct Cursor Cursor;
|
||||
|
@ -2913,10 +2914,18 @@ case OP_NewRecno: {
|
|||
if( VERIFY( i<0 || i>=p->nCursor || ) (pC = &p->aCsr[i])->pCursor==0 ){
|
||||
v = 0;
|
||||
}else{
|
||||
/* A probablistic algorithm is used to locate an unused rowid.
|
||||
** We select a rowid at random and see if it exists in the table.
|
||||
** If it does not exist, we have succeeded. If the random rowid
|
||||
** does exist, we select a new one and try again, up to 1000 times.
|
||||
/* The next rowid or record number (different terms for the same
|
||||
** thing) is obtained in a two-step algorithm.
|
||||
**
|
||||
** First we attempt to find the largest existing rowid and add one
|
||||
** to that. But if the largest existing rowid is already the maximum
|
||||
** positive integer, we have to fall through to the second
|
||||
** probabilistic algorithm
|
||||
**
|
||||
** The second algorithm is to select a rowid at random and see if
|
||||
** it already exists in the table. If it does not exist, we have
|
||||
** succeeded. If the random rowid does exist, we select a new one
|
||||
** and try again, up to 1000 times.
|
||||
**
|
||||
** For a table with less than 2 billion entries, the probability
|
||||
** of not finding a unused rowid is about 1.0e-300. This is a
|
||||
|
@ -2932,28 +2941,46 @@ case OP_NewRecno: {
|
|||
** random number generator based on the RC4 algorithm.
|
||||
**
|
||||
** To promote locality of reference for repetitive inserts, the
|
||||
** first few attempts at chosing a rowid pick values just a little
|
||||
** first few attempts at chosing a random rowid pick values just a little
|
||||
** larger than the previous rowid. This has been shown experimentally
|
||||
** to double the speed of the COPY operation.
|
||||
*/
|
||||
int res, rx, cnt, x;
|
||||
cnt = 0;
|
||||
v = db->nextRowid;
|
||||
do{
|
||||
if( cnt>5 ){
|
||||
v = sqliteRandomInteger();
|
||||
if( !pC->useRandomRowid ){
|
||||
rx = sqliteBtreeLast(pC->pCursor, &res);
|
||||
if( res ){
|
||||
v = 1;
|
||||
}else{
|
||||
v += sqliteRandomByte() + 1;
|
||||
sqliteBtreeKey(pC->pCursor, 0, sizeof(v), (void*)&v);
|
||||
v = keyToInt(v);
|
||||
if( v==0x7fffffff ){
|
||||
pC->useRandomRowid = 1;
|
||||
}else{
|
||||
v++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pC->useRandomRowid ){
|
||||
v = db->priorNewRowid;
|
||||
cnt = 0;
|
||||
do{
|
||||
if( v==0 || cnt>2 ){
|
||||
v = sqliteRandomInteger();
|
||||
if( cnt<5 ) v &= 0xffffff;
|
||||
}else{
|
||||
v += sqliteRandomByte() + 1;
|
||||
}
|
||||
if( v==0 ) continue;
|
||||
x = intToKey(v);
|
||||
rx = sqliteBtreeMoveto(pC->pCursor, &x, sizeof(int), &res);
|
||||
cnt++;
|
||||
}while( cnt<1000 && rx==SQLITE_OK && res==0 );
|
||||
db->priorNewRowid = v;
|
||||
if( rx==SQLITE_OK && res==0 ){
|
||||
rc = SQLITE_FULL;
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
if( v==0 ) continue;
|
||||
x = intToKey(v);
|
||||
rx = sqliteBtreeMoveto(pC->pCursor, &x, sizeof(int), &res);
|
||||
cnt++;
|
||||
}while( cnt<1000 && rx==SQLITE_OK && res==0 );
|
||||
db->nextRowid = v;
|
||||
if( rx==SQLITE_OK && res==0 ){
|
||||
rc = SQLITE_FULL;
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
}
|
||||
VERIFY( NeedStack(p, p->tos+1); )
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# This file implements tests for the special processing associated
|
||||
# with INTEGER PRIMARY KEY columns.
|
||||
#
|
||||
# $Id: intpkey.test,v 1.7 2002/01/29 23:07:02 drh Exp $
|
||||
# $Id: intpkey.test,v 1.8 2002/02/19 22:42:06 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
@ -111,19 +111,19 @@ do_test intpkey-1.10 {
|
|||
#
|
||||
do_test intpkey-1.11 {
|
||||
execsql {
|
||||
UPDATE t1 SET a=7 WHERE b='one';
|
||||
UPDATE t1 SET a=4 WHERE b='one';
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {5 hello world 6 second entry 7 one two}
|
||||
} {4 one two 5 hello world 6 second entry}
|
||||
|
||||
# Make sure SELECT statements are able to use the primary key column
|
||||
# as an index.
|
||||
#
|
||||
do_test intpkey-1.12 {
|
||||
execsql {
|
||||
SELECT * FROM t1 WHERE a==7;
|
||||
SELECT * FROM t1 WHERE a==4;
|
||||
}
|
||||
} {7 one two}
|
||||
} {4 one two}
|
||||
|
||||
# Try to insert a non-integer value into the primary key field. This
|
||||
# should result in a data type mismatch.
|
||||
|
@ -148,7 +148,7 @@ do_test intpkey-1.15 {
|
|||
} {0 {}}
|
||||
do_test intpkey-1.16 {
|
||||
execsql {SELECT * FROM t1}
|
||||
} {-3 y z 5 hello world 6 second entry 7 one two}
|
||||
} {-3 y z 4 one two 5 hello world 6 second entry}
|
||||
|
||||
#### INDICES
|
||||
# Check to make sure indices work correctly with integer primary keys
|
||||
|
@ -190,35 +190,35 @@ do_test intpkey-2.3 {
|
|||
execsql {
|
||||
SELECT rowid, * FROM t1;
|
||||
}
|
||||
} {5 5 hello world 6 6 second entry 7 7 one two 8 8 y z}
|
||||
} {4 4 one two 5 5 hello world 6 6 second entry 8 8 y z}
|
||||
do_test intpkey-2.4 {
|
||||
execsql {
|
||||
SELECT rowid, * FROM t1 WHERE b<'second'
|
||||
}
|
||||
} {5 5 hello world 7 7 one two}
|
||||
} {5 5 hello world 4 4 one two}
|
||||
do_test intpkey-2.4.1 {
|
||||
execsql {
|
||||
SELECT rowid, * FROM t1 WHERE 'second'>b
|
||||
}
|
||||
} {5 5 hello world 7 7 one two}
|
||||
} {5 5 hello world 4 4 one two}
|
||||
do_test intpkey-2.4.2 {
|
||||
execsql {
|
||||
SELECT rowid, * FROM t1 WHERE 8>rowid AND 'second'>b
|
||||
}
|
||||
} {5 5 hello world 7 7 one two}
|
||||
} {4 4 one two 5 5 hello world}
|
||||
do_test intpkey-2.4.3 {
|
||||
execsql {
|
||||
SELECT rowid, * FROM t1 WHERE 8>rowid AND 'second'>b AND 0<rowid
|
||||
}
|
||||
} {5 5 hello world 7 7 one two}
|
||||
} {4 4 one two 5 5 hello world}
|
||||
do_test intpkey-2.5 {
|
||||
execsql {
|
||||
SELECT rowid, * FROM t1 WHERE b>'a'
|
||||
}
|
||||
} {5 5 hello world 7 7 one two 6 6 second entry 8 8 y z}
|
||||
} {5 5 hello world 4 4 one two 6 6 second entry 8 8 y z}
|
||||
do_test intpkey-2.6 {
|
||||
execsql {
|
||||
DELETE FROM t1 WHERE rowid=7;
|
||||
DELETE FROM t1 WHERE rowid=4;
|
||||
SELECT * FROM t1 WHERE b>'a';
|
||||
}
|
||||
} {5 hello world 6 second entry 8 y z}
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
# 2001 September 15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing SELECT statements that contain
|
||||
# aggregate min() and max() functions and which are handled as
|
||||
# as a special case.
|
||||
#
|
||||
# $Id: minmax.test,v 1.1 2002/02/19 22:42:06 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_test minmax-1.0 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
CREATE TABLE t1(x, y);
|
||||
INSERT INTO t1 VALUES(1,1);
|
||||
INSERT INTO t1 VALUES(2,2);
|
||||
INSERT INTO t1 VALUES(3,2);
|
||||
INSERT INTO t1 VALUES(4,3);
|
||||
INSERT INTO t1 VALUES(5,3);
|
||||
INSERT INTO t1 VALUES(6,3);
|
||||
INSERT INTO t1 VALUES(7,3);
|
||||
INSERT INTO t1 VALUES(8,4);
|
||||
INSERT INTO t1 VALUES(9,4);
|
||||
INSERT INTO t1 VALUES(10,4);
|
||||
INSERT INTO t1 VALUES(11,4);
|
||||
INSERT INTO t1 VALUES(12,4);
|
||||
INSERT INTO t1 VALUES(13,4);
|
||||
INSERT INTO t1 VALUES(14,4);
|
||||
INSERT INTO t1 VALUES(15,4);
|
||||
INSERT INTO t1 VALUES(16,5);
|
||||
INSERT INTO t1 VALUES(17,5);
|
||||
INSERT INTO t1 VALUES(18,5);
|
||||
INSERT INTO t1 VALUES(19,5);
|
||||
INSERT INTO t1 VALUES(20,5);
|
||||
COMMIT;
|
||||
SELECT DISTINCT y FROM t1 ORDER BY y;
|
||||
}
|
||||
} {1 2 3 4 5}
|
||||
|
||||
do_test minmax-1.1 {
|
||||
set sqlite_search_count 0
|
||||
execsql {SELECT min(x) FROM t1}
|
||||
} {1}
|
||||
do_test minmax-1.2 {
|
||||
set sqlite_search_count
|
||||
} {19}
|
||||
do_test minmax-1.3 {
|
||||
set sqlite_search_count 0
|
||||
execsql {SELECT max(x) FROM t1}
|
||||
} {20}
|
||||
do_test minmax-1.4 {
|
||||
set sqlite_search_count
|
||||
} {19}
|
||||
do_test minmax-1.5 {
|
||||
execsql {CREATE INDEX t1i1 ON t1(x)}
|
||||
set sqlite_search_count 0
|
||||
execsql {SELECT min(x) FROM t1}
|
||||
} {1}
|
||||
do_test minmax-1.6 {
|
||||
set sqlite_search_count
|
||||
} {1}
|
||||
do_test minmax-1.7 {
|
||||
set sqlite_search_count 0
|
||||
execsql {SELECT max(x) FROM t1}
|
||||
} {20}
|
||||
do_test minmax-1.8 {
|
||||
set sqlite_search_count
|
||||
} {1}
|
||||
do_test minmax-1.9 {
|
||||
set sqlite_search_count 0
|
||||
execsql {SELECT max(y) FROM t1}
|
||||
} {5}
|
||||
do_test minmax-1.10 {
|
||||
set sqlite_search_count
|
||||
} {19}
|
||||
|
||||
do_test minmax-2.0 {
|
||||
execsql {
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
}
|
||||
set sqlite_search_count 0
|
||||
execsql {SELECT min(a) FROM t2}
|
||||
} {1}
|
||||
do_test minmax-2.1 {
|
||||
set sqlite_search_count
|
||||
} {0}
|
||||
do_test minmax-2.2 {
|
||||
set sqlite_search_count 0
|
||||
execsql {SELECT max(a) FROM t2}
|
||||
} {20}
|
||||
do_test minmax-2.3 {
|
||||
set sqlite_search_count
|
||||
} {0}
|
||||
|
||||
do_test minmax-3.0 {
|
||||
execsql {INSERT INTO t2 VALUES((SELECT max(a) FROM t2)+1,999)}
|
||||
set sqlite_search_count 0
|
||||
execsql {SELECT max(a) FROM t2}
|
||||
} {21}
|
||||
do_test minmax-3.1 {
|
||||
set sqlite_search_count
|
||||
} {0}
|
||||
do_test minmax-3.2 {
|
||||
execsql {INSERT INTO t2 VALUES((SELECT max(a) FROM t2)+1,999)}
|
||||
set sqlite_search_count 0
|
||||
execsql {
|
||||
SELECT b FROM t2 WHERE a=(SELECT max(a) FROM t2)
|
||||
}
|
||||
} {999}
|
||||
do_test minmax-3.3 {
|
||||
set sqlite_search_count
|
||||
} {0}
|
||||
|
||||
|
||||
finish_test
|
|
@ -12,7 +12,7 @@
|
|||
# focus of this file is testing the magic ROWID column that is
|
||||
# found on all tables.
|
||||
#
|
||||
# $Id: rowid.test,v 1.7 2002/01/04 03:09:30 drh Exp $
|
||||
# $Id: rowid.test,v 1.8 2002/02/19 22:42:06 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
@ -155,18 +155,18 @@ do_test rowid-2.12 {
|
|||
do_test rowid-3.1 {
|
||||
execsql {
|
||||
CREATE TABLE t2(rowid int, x int, y int);
|
||||
INSERT INTO t2 VALUES(1,2,3);
|
||||
INSERT INTO t2 VALUES(0,2,3);
|
||||
INSERT INTO t2 VALUES(4,5,6);
|
||||
INSERT INTO t2 VALUES(7,8,9);
|
||||
SELECT * FROM t2 ORDER BY x;
|
||||
}
|
||||
} {1 2 3 4 5 6 7 8 9}
|
||||
} {0 2 3 4 5 6 7 8 9}
|
||||
do_test rowid-3.2 {
|
||||
execsql {SELECT * FROM t2 ORDER BY rowid}
|
||||
} {1 2 3 4 5 6 7 8 9}
|
||||
} {0 2 3 4 5 6 7 8 9}
|
||||
do_test rowid-3.3 {
|
||||
execsql {SELECT rowid, x, y FROM t2 ORDER BY rowid}
|
||||
} {1 2 3 4 5 6 7 8 9}
|
||||
} {0 2 3 4 5 6 7 8 9}
|
||||
do_test rowid-3.4 {
|
||||
set r1 [execsql {SELECT _rowid_, rowid FROM t2 ORDER BY rowid}]
|
||||
foreach {a b c d e f} $r1 {}
|
||||
|
@ -271,8 +271,9 @@ do_test rowid-6.1 {
|
|||
}
|
||||
} {1 2 3 4 5 6 7 8}
|
||||
do_test rowid-6.2 {
|
||||
for {set ::norow 1} {[execsql {SELECT x FROM t1 WHERE rowid=10}]!=""} \
|
||||
{incr ::norow} {}
|
||||
for {set ::norow 1} {1} {incr ::norow} {
|
||||
if {[execsql "SELECT x FROM t1 WHERE rowid=$::norow"]==""} break
|
||||
}
|
||||
execsql [subst {
|
||||
DELETE FROM t1 WHERE rowid=$::norow
|
||||
}]
|
||||
|
@ -283,5 +284,73 @@ do_test rowid-6.3 {
|
|||
}
|
||||
} {1 2 3 4 5 6 7 8}
|
||||
|
||||
# Beginning with version 2.3.4, SQLite computes rowids of new rows by
|
||||
# finding the maximum current rowid and adding one. It falls back to
|
||||
# the old random algorithm if the maximum rowid is the largest integer.
|
||||
# The following tests are for this new behavior.
|
||||
#
|
||||
do_test rowid-7.0 {
|
||||
execsql {
|
||||
DELETE FROM t1;
|
||||
DROP TABLE t2;
|
||||
DROP INDEX idxt1;
|
||||
INSERT INTO t1 VALUES(1,2);
|
||||
SELECT rowid, * FROM t1;
|
||||
}
|
||||
} {1 1 2}
|
||||
do_test rowid-7.1 {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(99,100);
|
||||
SELECT rowid,* FROM t1
|
||||
}
|
||||
} {1 1 2 2 99 100}
|
||||
do_test rowid-7.2 {
|
||||
execsql {
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t2(b) VALUES(55);
|
||||
SELECT * FROM t2;
|
||||
}
|
||||
} {1 55}
|
||||
do_test rowid-7.3 {
|
||||
execsql {
|
||||
INSERT INTO t2(b) VALUES(66);
|
||||
SELECT * FROM t2;
|
||||
}
|
||||
} {1 55 2 66}
|
||||
do_test rowid-7.4 {
|
||||
execsql {
|
||||
INSERT INTO t2(a,b) VALUES(1000000,77);
|
||||
INSERT INTO t2(b) VALUES(88);
|
||||
SELECT * FROM t2;
|
||||
}
|
||||
} {1 55 2 66 1000000 77 1000001 88}
|
||||
do_test rowid-7.5 {
|
||||
execsql {
|
||||
INSERT INTO t2(a,b) VALUES(2147483647,99);
|
||||
INSERT INTO t2(b) VALUES(11);
|
||||
SELECT b FROM t2 ORDER BY b;
|
||||
}
|
||||
} {11 55 66 77 88 99}
|
||||
do_test rowid-7.6 {
|
||||
execsql {
|
||||
SELECT b FROM t2 WHERE a NOT IN(1,2,1000000,1000001,2147483647);
|
||||
}
|
||||
} {11}
|
||||
do_test rowid-7.7 {
|
||||
execsql {
|
||||
INSERT INTO t2(b) VALUES(22);
|
||||
INSERT INTO t2(b) VALUES(33);
|
||||
INSERT INTO t2(b) VALUES(44);
|
||||
INSERT INTO t2(b) VALUES(55);
|
||||
SELECT b FROM t2 WHERE a NOT IN(1,2,1000000,1000001,2147483647) ORDER BY b;
|
||||
}
|
||||
} {11 22 33 44 55}
|
||||
do_test rowid-7.8 {
|
||||
execsql {
|
||||
DELETE FROM t2 WHERE a!=2;
|
||||
INSERT INTO t2(b) VALUES(111);
|
||||
SELECT * FROM t2;
|
||||
}
|
||||
} {2 66 3 111}
|
||||
|
||||
finish_test
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
# Run this Tcl script to generate the sqlite.html file.
|
||||
#
|
||||
set rcsid {$Id: c_interface.tcl,v 1.23 2002/01/16 21:00:28 drh Exp $}
|
||||
set rcsid {$Id: c_interface.tcl,v 1.24 2002/02/19 22:42:06 drh Exp $}
|
||||
|
||||
puts {<html>
|
||||
<head>
|
||||
|
@ -378,7 +378,7 @@ header file that comes in the source tree.</p>
|
|||
<p>Every row of an SQLite table has a unique integer key. If the
|
||||
table has a column labeled INTEGER PRIMARY KEY, then that column
|
||||
servers as the key. If there is no INTEGER PRIMARY KEY column then
|
||||
the key is a random integer. The key for a row can be accessed in
|
||||
the key is a unique integer. The key for a row can be accessed in
|
||||
a SELECT statement or used in a WHERE or ORDER BY clause using any
|
||||
of the names "ROWID", "OID", or "_ROWID_".</p>
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ proc chng {date desc} {
|
|||
chng {2002 Feb * (2.3.4)} {
|
||||
<li>Change the name of the sanity_check PRAGMA to <b>integrity_check</b>
|
||||
and make it available in all compiles.</li>
|
||||
<li>SELECT min() or max() of an indexed column with no WHERE or GROUP BY
|
||||
clause is handled as a special case which avoids a complete table scan.</li>
|
||||
<li>Automatically generated ROWIDs are now sequential.</li>
|
||||
}
|
||||
|
||||
chng {2002 Feb 18 (2.3.3)} {
|
||||
|
|
83
www/faq.tcl
83
www/faq.tcl
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
# Run this script to generated a faq.html output file
|
||||
#
|
||||
set rcsid {$Id: faq.tcl,v 1.7 2002/01/22 03:13:43 drh Exp $}
|
||||
set rcsid {$Id: faq.tcl,v 1.8 2002/02/19 22:42:06 drh Exp $}
|
||||
|
||||
puts {<html>
|
||||
<head>
|
||||
|
@ -27,60 +27,39 @@ proc faq {question answer} {
|
|||
faq {
|
||||
How do I create an AUTOINCREMENT field.
|
||||
} {
|
||||
SQLite does not support AUTOINCREMENT. If you need a unique key for
|
||||
a new entry in a table, you can create an auxiliary table
|
||||
with a single entry that holds the next available value for that key.
|
||||
Like this:
|
||||
<p>Short answer: A column declared INTEGER PRIMARY KEY will
|
||||
autoincrement.</p>
|
||||
|
||||
<p>Here is the long answer:
|
||||
Beginning with version SQLite 2.3.4, If you declare a column of
|
||||
a table to be INTEGER PRIMARY KEY, then whenever you insert a NULL
|
||||
into that column of the table, the NULL is automatically converted
|
||||
into an integer which is one greater than the largest value of that
|
||||
column over all other rows in the table, or 1 if the table is empty.
|
||||
For example, suppose you have a table like this:
|
||||
<blockquote><pre>
|
||||
CREATE TABLE counter(cnt);
|
||||
INSERT INTO counter VALUES(1);
|
||||
</pre></blockquote>
|
||||
Once you have a counter set up, you can generate a unique key as follows:
|
||||
<blockquote><pre>
|
||||
BEGIN TRANSACTION;
|
||||
SELECT cnt FROM counter;
|
||||
UPDATE counter SET cnt=cnt+1;
|
||||
COMMIT;
|
||||
</pre></blockquote>
|
||||
There are other ways of simulating the effect of AUTOINCREMENT but
|
||||
this approach seems to be the easiest and most efficient.
|
||||
|
||||
<p><i>New in SQLite version 2.2.0:</i>
|
||||
If one of the columns in a table has type INTEGER PRIMARY KEY and
|
||||
you do an INSERT on that table that does not specify a value for
|
||||
the primary key, then a unique random number is inserted automatically
|
||||
in that column. This automatically generated key is random, not
|
||||
sequential, but you can still use it as a unique identifier.</p>
|
||||
|
||||
<p>Here is an example of how the INTEGER PRIMARY KEY feature can be
|
||||
used:</p>
|
||||
|
||||
<blockquote><pre>
|
||||
CREATE TABLE ex2(
|
||||
cnum INTEGER PRIMARY KEY,
|
||||
name TEXT,
|
||||
email TEXT
|
||||
CREATE TABLE t1(
|
||||
a INTEGER PRIMARY KEY,
|
||||
b INTEGER
|
||||
);
|
||||
INSERT INTO ex2(name,email) VALUES('drh','drh@hwaci.com');
|
||||
INSERT INTO ex2(name,email) VALUES('alle','alle@hwaci.com');
|
||||
SELECT * FROM ex1;
|
||||
</pre></blockquote>
|
||||
|
||||
<p>Notice that the primary key column <b>cnum</b> is not specified on
|
||||
the INSERT statements. The output of the SELECT on the last line will
|
||||
be something like this:</p>
|
||||
|
||||
<blockquote>
|
||||
1597027670|drh|drh@hwaci.com<br>
|
||||
1597027853|alle|alle@hwaci.com
|
||||
</blockquote>
|
||||
|
||||
<p>The randomly generated keys in this case are 1597027670 and
|
||||
1597027853. You will probably get different keys every time you
|
||||
try this. The keys will often be ascending, but this is not always
|
||||
the case and you cannot count on that behavior. The keys will never
|
||||
be sequential. If you need sequential keys, use the counter implemention
|
||||
described first.</p>
|
||||
<p>With this table, the statement</p>
|
||||
<blockquote><pre>
|
||||
INSERT INTO t1 VALUES(NULL,123);
|
||||
</pre></blockquote>
|
||||
<p>is logically equivalent to saying:</p>
|
||||
<blockquote><pre>
|
||||
INSERT INTO t1 VALUES((SELECT max(a) FROM t1)+1,123);
|
||||
</pre></blockquote>
|
||||
<p>For SQLite version 2.2.0 through 2.3.3, if you insert a NULL into
|
||||
an INTEGER PRIMARY KEY column, the NULL will be changed to a unique
|
||||
integer, but it will a semi-random integer. Unique keys generated this
|
||||
way will not be sequential. For SQLite version 2.3.4 and beyond, the
|
||||
unique keys will be sequential until the largest key reaches a value
|
||||
of 2147483647. That is the largest 32-bit signed integer and cannot
|
||||
be incremented, so subsequent insert attempts will revert to the
|
||||
semi-random key generation algorithm of SQLite version 2.3.3 and
|
||||
earlier.</p>
|
||||
|
||||
<p>Beginning with version 2.2.3, there is a new API function named
|
||||
<b>sqlite_last_insert_rowid()</b> which will return the integer key
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
# Run this Tcl script to generate the sqlite.html file.
|
||||
#
|
||||
set rcsid {$Id: lang.tcl,v 1.25 2002/02/19 13:39:23 drh Exp $}
|
||||
set rcsid {$Id: lang.tcl,v 1.26 2002/02/19 22:42:06 drh Exp $}
|
||||
|
||||
puts {<html>
|
||||
<head>
|
||||
|
@ -292,7 +292,7 @@ may only hold unique integer values. (Except for this one case,
|
|||
SQLite ignores the datatype specification of columns and allows
|
||||
any kind of data to be put in a column regardless of its declared
|
||||
datatype.) If a table does not have an INTEGER PRIMARY KEY column,
|
||||
then the B-Tree key will be a randomly generated integer. The
|
||||
then the B-Tree key will be a automatically generated integer. The
|
||||
B-Tree key for a row can always be accessed using one of the
|
||||
special names "<b>ROWID</b>", "<b>OID</b>", or "<b>_ROWID_</b>".
|
||||
This is true regardless of whether or not there is an INTEGER
|
||||
|
|
Loading…
Reference in New Issue