New ROWIDs are numbered sequentially. (CVS 383)

FossilOrigin-Name: 1686196a8aea326f616bc8205df99cd84d955ec4
This commit is contained in:
drh 2002-02-19 22:42:05 +00:00
parent 9562b55115
commit 5cf8e8c7fa
13 changed files with 334 additions and 122 deletions

View File

@ -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

View File

@ -1 +1 @@
cc5abfe392bdb8c3ed00e0610bc2b41851bfc9d7
1686196a8aea326f616bc8205df99cd84d955ec4

View File

@ -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);

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.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;
}

View File

@ -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 */
};

View File

@ -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); )

View File

@ -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}

126
test/minmax.test Normal file
View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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)} {

View File

@ -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

View File

@ -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