mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Added transaction support (CVS 196)
FossilOrigin-Name: 35a8feed0d10e780c477f7440fbe80637fcf9906
This commit is contained in:
60
manifest
60
manifest
@ -1,5 +1,5 @@
|
||||
C Bug\sfixes\sfrom\sOleg\sOleinick\s(CVS\s195)
|
||||
D 2001-04-03T16:53:22
|
||||
C Added\stransaction\ssupport\s(CVS\s196)
|
||||
D 2001-04-04T11:48:57
|
||||
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
||||
F Makefile.in fd8815aa01a7181f60f786158b7737a35413189e
|
||||
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
||||
@ -9,11 +9,11 @@ F configure.in d892ca33db7e88a055519ce2f36dcb11020e8fff
|
||||
F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
|
||||
F doc/report1.txt 734cbae63b1310cc643fe5e9e3da1ab55a79b99e
|
||||
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
|
||||
F src/build.c 7aa5879bf58ea6bbff22c26c59d1130021fa6ca4
|
||||
F src/build.c 4c5eede16695d5e74bb3004e51923492b66eae62
|
||||
F src/dbbe.c b178f0959f6bac5ef8a109484c1571053f31abe5
|
||||
F src/dbbe.h 4b33f0cf884dfab49e39a422b2dcaf7a2a0e626c
|
||||
F src/dbbegdbm.c c4b2857e242ff8b4e8a5ac2d95e2e35f462ce8eb
|
||||
F src/dbbemem.c f0007eff4a00f28126c093f37f8e7dd2fcaa123b
|
||||
F src/dbbe.h 7235b15c6c5d8be0c4da469cef9620cee70b1cc8
|
||||
F src/dbbegdbm.c d044b9e3a463608ac4f35283c78ac372d5da64c6
|
||||
F src/dbbemem.c fa84058f79dd5e6af1ccbb0d41c85e05a6bc19ac
|
||||
F src/delete.c 7aa9dcb86d5e98c3eb9dee00a459e0ef9b73fbe3
|
||||
F src/ex/README b745b00acce2d892f60c40111dacdfc48e0c1c7a
|
||||
F src/ex/db.c f1419ae6c93e40b5ac6e39fe7efd95d868e6f9d7
|
||||
@ -23,48 +23,50 @@ F src/ex/dbbemird.c b00aef85656fa0a101dac2c32e12922ad106715a
|
||||
F src/ex/pg.c 2bbf6a94f37226d06337868b6bf4d7affc60197f
|
||||
F src/ex/pg.h 23a4ac807b0546ec2bb6239ec8bd3e06926572cd
|
||||
F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7
|
||||
F src/expr.c 49bc261fdc4f4fb91c74cd668a9a952c00e85931
|
||||
F src/expr.c cdf54a3b8a24ef99b3b7808a5a55af17d404bc67
|
||||
F src/insert.c 4bc1cab84f7805d560a1417734a532843e30b762
|
||||
F src/main.c 5afe29c425b875acede20f609485866eb5b276f6
|
||||
F src/pager.h 889c5cf517ad30704e295540793c893ac843fd5f
|
||||
F src/parse.y 25ee4d8efccc4b247c32fe4ab194e3dd8fd5a4ee
|
||||
F src/parse.y 1ba81d3b75f37ca868aa0ab990bb977fd41519eb
|
||||
F src/printf.c af0dc65c293427272e1949c7807b1d88f10004fd
|
||||
F src/random.c b36c3f57dc80c8f354e6bfbf39cf1e1de021d54a
|
||||
F src/select.c faac634ef0c717bc82ca112a4531a257886f2c7a
|
||||
F src/select.c a6bfdaa92d4614e79bf18129283c5163faa291fc
|
||||
F src/shell.c 441e20913cde0bb71281f4027623c623530241cd
|
||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in 3b446fcbed6005f0ab89632f3356c4708b349e88
|
||||
F src/sqliteInt.h 9887d207b98362392668410a11c59b3e334f51a1
|
||||
F src/sqliteInt.h 7872fa85719adff8e458f4a27d56a0ea3e8a3dd1
|
||||
F src/table.c 5be76051a8ed6f6bfa641f4adc52529efa34fbf9
|
||||
F src/tclsqlite.c f654b0399ea8a29262637dbe71fdfe7c26bd9032
|
||||
F src/tokenize.c c7ad428f38e56342eb2025320480b5ae9ece1b90
|
||||
F src/tokenize.c 8fc3936eefad84f1fff19e0892ed0542eb9ac7b3
|
||||
F src/update.c 8365b3922ea098330d1e20862d6e64911e4e03d0
|
||||
F src/util.c f4573201fc2b581dbf601c53787349310b7da150
|
||||
F src/vdbe.c aa14a8aef0229fd5cfa32c3957dc627555f42be8
|
||||
F src/vdbe.h 031b7dd7d6f94c51dc37cdf26efe43d1619bb672
|
||||
F src/where.c 478fde7c930969ca428de2d80b137959d25ee2fb
|
||||
F src/vdbe.c 53de79aa212997a8615659d7a7e6eb12aa77255d
|
||||
F src/vdbe.h dc1205da434c6a9da03b5d6b089270bbc8e6d437
|
||||
F src/where.c 459bf37ac7849599da400420984b3306484b4cbb
|
||||
F test/all.test 15cac2f6b2d4c55bf896212aff3cc9d6597b0490
|
||||
F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
|
||||
F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c
|
||||
F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf
|
||||
F test/expr.test 48273bf48a15d226c35829f702af4254c0ff6795
|
||||
F test/expr.test 83b29f29f58df80d185d163b7fab5c658a1bd29a
|
||||
F test/func.test 02aed8845b98bde1043dda97455de1d37238ebb3
|
||||
F test/in.test 2c560c0f55fb777029fd9bb5378f2997582aa603
|
||||
F test/index.test ee060ef8912be47ba616e50cce7985259a68d58a
|
||||
F test/insert.test 66f4c3bd600fec8eb1e733b928cbe6fa885eff0c
|
||||
F test/in.test ea48016c4fcc479d315932ae2b8568146686ffaf
|
||||
F test/index.test b189ac11bf8d4fbcf87402f4028c25c8a6d91bb5
|
||||
F test/insert.test dbd3bd189edb61fddbe66c236694ef23352429f1
|
||||
F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6
|
||||
F test/lock.test bca7d53de73138b1f670a2fbdb1f481ff7eaa45a
|
||||
F test/main.test 5b0ed3d586c15b9136b9fd4916dcc95086639387
|
||||
F test/select1.test 68ff778c24fc8982e63dda37acb5b0396913adf7
|
||||
F test/main.test da635f9e078cd21ddf074e727381a715064489ff
|
||||
F test/rowid.test 128453599def7435e988216f7fe89c7450b8a9a3
|
||||
F test/select1.test 824d9d5007dffd6a45edde79e89c0a04c36e3ebe
|
||||
F test/select2.test 04ac3bd69298f58c7d0883159bab42ab9ad6021c
|
||||
F test/select3.test a9234b8424b6c6d71de534f43b91ade9be68e9cc
|
||||
F test/select4.test cb5374d7c87680e294ac749307459a5cc547609d
|
||||
F test/select5.test e2b9d51d88cbd6c307c2c05b0ef55fe7ba811ac2
|
||||
F test/sort.test d582086c4bb7df3fbf50aa72e69d7e235e9f8e31
|
||||
F test/sort.test 838cd862642ed9a2c47e1a17b5c33da452b4552e
|
||||
F test/subselect.test bf8b251a92fb091973c1c469ce499dc9648a41d5
|
||||
F test/table.test eaa25951c0f18615763cd3dc248ea4bc38739c05
|
||||
F test/table.test c1704fead1af27d67850a934d531848ce5bee4a7
|
||||
F test/tclsqlite.test d2aa55926874783b2401f0146e839f773c6796e1
|
||||
F test/tester.tcl 01f881142be3bd8713abcea06747652067dafb78
|
||||
F test/tester.tcl c77fd7a4fb1f3812e469be6229ee330baaffc911
|
||||
F test/trans.test 82556605d48f56ad4679e95478d70546a763f26a
|
||||
F test/update.test 72c0c93310483b86dc904a992220c5b84c7ce100
|
||||
F test/vacuum.test b95d8119a0a83dc6c4ac63888f8872f06199e065
|
||||
F test/where.test bbab5a308055fb6087dc23d600b4ad2b72797397
|
||||
@ -73,7 +75,7 @@ F tool/gdbmstat.c 56a9033531e5f5a48413f6ec436d5fb0341632c1
|
||||
F tool/lemon.c e007bfdbc79a51a4cd7c8a5f81f517cebd121150
|
||||
F tool/lempar.c 943b476d44b319eed525e46bb29e15f2c5986b37
|
||||
F tool/memleak.awk a0a11dd84bf4582acc81c3c61271021ae49b3f15
|
||||
F tool/opNames.awk 2bd9071a138e4e2be13dc98fe066398a61219e1e
|
||||
F tool/opNames.awk 5ba1f48aa854ee3b7c3d2b54233665bc3e649ea2
|
||||
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
|
||||
F tool/report1.txt 9eae07f26a8fc53889b45fc833a66a33daa22816
|
||||
@ -81,18 +83,18 @@ F www/arch.fig 4f246003b7da23bd63b8b0af0618afb4ee3055c8
|
||||
F www/arch.png 8dae0766d42ed3de9ed013c1341a5792bcf633e6
|
||||
F www/arch.tcl a40380c1fe0080c43e6cc5c20ed70731511b06be
|
||||
F www/c_interface.tcl 11be2d5826eb7d6efd629751d3b483c1ed78ba14
|
||||
F www/changes.tcl 1be73dbd1d45471fdef05f627e8332206768f179
|
||||
F www/changes.tcl 2f8108b1c19f6b1428cd89aeb4da0f446af5a8b6
|
||||
F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
|
||||
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
||||
F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9
|
||||
F www/index.tcl 0ca6421e6e82b17ed0c1779d46463211498f9d12
|
||||
F www/lang.tcl e3905bec9f0d0fd47d9838e991cab7d6f7aff47d
|
||||
F www/lang.tcl 7fec414487ebee2cbb17c90addf5a026cd10396a
|
||||
F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60
|
||||
F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
|
||||
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
|
||||
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
|
||||
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
|
||||
P 833291c22734b2ac2342da84710320eb28f5d8cc
|
||||
R b3979afeb1b2a68085466c778c74b02f
|
||||
P 1f0197d504fa2bde15b287ac6c0102cacdb1e482
|
||||
R 0c956d20e6dabe568cbda0cb58ce5c9e
|
||||
U drh
|
||||
Z ceda48d7a4b9b3c738f23f47b38664dd
|
||||
Z 9500ff4dc470566bf1bdd893cda52c35
|
||||
|
@ -1 +1 @@
|
||||
1f0197d504fa2bde15b287ac6c0102cacdb1e482
|
||||
35a8feed0d10e780c477f7440fbe80637fcf9906
|
62
src/build.c
62
src/build.c
@ -33,7 +33,7 @@
|
||||
** COPY
|
||||
** VACUUM
|
||||
**
|
||||
** $Id: build.c,v 1.25 2001/01/15 22:51:09 drh Exp $
|
||||
** $Id: build.c,v 1.26 2001/04/04 11:48:57 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -924,3 +924,63 @@ vacuum_cleanup:
|
||||
sqliteFree(zName);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Begin a transaction
|
||||
*/
|
||||
void sqliteBeginTransaction(Parse *pParse){
|
||||
int rc;
|
||||
DbbeMethods *pM;
|
||||
sqlite *db;
|
||||
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
|
||||
if( db->flags & SQLITE_InTrans ) return;
|
||||
pM = pParse->db->pBe->x;
|
||||
if( pM && pM->BeginTransaction ){
|
||||
rc = (*pM->BeginTransaction)(pParse->db->pBe);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
db->flags |= SQLITE_InTrans;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Commit a transaction
|
||||
*/
|
||||
void sqliteCommitTransaction(Parse *pParse){
|
||||
int rc;
|
||||
DbbeMethods *pM;
|
||||
sqlite *db;
|
||||
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
|
||||
if( (db->flags & SQLITE_InTrans)==0 ) return;
|
||||
pM = pParse->db->pBe->x;
|
||||
if( pM && pM->Commit ){
|
||||
rc = (*pM->Commit)(pParse->db->pBe);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Rollback a transaction
|
||||
*/
|
||||
void sqliteRollbackTransaction(Parse *pParse){
|
||||
int rc;
|
||||
DbbeMethods *pM;
|
||||
sqlite *db;
|
||||
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
|
||||
if( (db->flags & SQLITE_InTrans)==0 ) return;
|
||||
pM = pParse->db->pBe->x;
|
||||
if( pM && pM->Rollback ){
|
||||
rc = (*pM->Rollback)(pParse->db->pBe);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
}
|
||||
}
|
||||
|
11
src/dbbe.h
11
src/dbbe.h
@ -28,7 +28,7 @@
|
||||
** This library was originally designed to support the following
|
||||
** backends: GDBM, NDBM, SDBM, Berkeley DB.
|
||||
**
|
||||
** $Id: dbbe.h,v 1.12 2001/04/03 16:53:22 drh Exp $
|
||||
** $Id: dbbe.h,v 1.13 2001/04/04 11:48:57 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_DBBE_H_
|
||||
#define _SQLITE_DBBE_H_
|
||||
@ -151,6 +151,15 @@ struct DbbeMethods {
|
||||
|
||||
/* Remove an entry from the table */
|
||||
int (*Delete)(DbbeCursor*, int nKey, char *pKey);
|
||||
|
||||
/* Begin a transaction. */
|
||||
int (*BeginTransaction)(Dbbe*);
|
||||
|
||||
/* Commit a transaction. */
|
||||
int (*Commit)(Dbbe*);
|
||||
|
||||
/* Rollback a transaction. */
|
||||
int (*Rollback)(Dbbe*);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -30,7 +30,7 @@
|
||||
** relatively simple to convert to a different database such
|
||||
** as NDBM, SDBM, or BerkeleyDB.
|
||||
**
|
||||
** $Id: dbbegdbm.c,v 1.5 2001/04/03 16:53:22 drh Exp $
|
||||
** $Id: dbbegdbm.c,v 1.6 2001/04/04 11:48:57 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <gdbm.h>
|
||||
@ -68,6 +68,7 @@ typedef struct Dbbex Dbbex;
|
||||
struct Dbbex {
|
||||
Dbbe dbbe; /* The base class */
|
||||
int write; /* True for write permission */
|
||||
int inTrans; /* Currently in a transaction */
|
||||
BeFile *pOpen; /* List of open files */
|
||||
char *zDir; /* Directory hold the database */
|
||||
};
|
||||
@ -178,6 +179,7 @@ static int sqliteGdbmOpenCursor(
|
||||
int mode; /* Mode for opening a table */
|
||||
Dbbex *pBe = (Dbbex*)pDbbe;
|
||||
|
||||
if( pBe->inTrans ) writeable = 1;
|
||||
*ppCursr = 0;
|
||||
pCursr = sqliteMalloc( sizeof(*pCursr) );
|
||||
if( pCursr==0 ) return SQLITE_NOMEM;
|
||||
@ -224,7 +226,7 @@ static int sqliteGdbmOpenCursor(
|
||||
}
|
||||
pFile->writeable = writeable;
|
||||
pFile->zName = zFile;
|
||||
pFile->nRef = 1;
|
||||
pFile->nRef = 1 + pBe->inTrans;
|
||||
pFile->pPrev = 0;
|
||||
if( pBe->pOpen ){
|
||||
pBe->pOpen->pPrev = pFile;
|
||||
@ -276,6 +278,29 @@ static void sqliteGdbmDropTable(Dbbe *pBe, const char *zTable){
|
||||
sqliteFree(zFile);
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlink a file pointer
|
||||
*/
|
||||
static void sqliteUnlinkFile(Dbbex *pBe, BeFile *pFile){
|
||||
if( pFile->dbf!=NULL ){
|
||||
gdbm_close(pFile->dbf);
|
||||
}
|
||||
if( pFile->pPrev ){
|
||||
pFile->pPrev->pNext = pFile->pNext;
|
||||
}else{
|
||||
pBe->pOpen = pFile->pNext;
|
||||
}
|
||||
if( pFile->pNext ){
|
||||
pFile->pNext->pPrev = pFile->pPrev;
|
||||
}
|
||||
if( pFile->delOnClose ){
|
||||
unlink(pFile->zName);
|
||||
}
|
||||
sqliteFree(pFile->zName);
|
||||
memset(pFile, 0, sizeof(*pFile));
|
||||
sqliteFree(pFile);
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a cursor previously opened by sqliteGdbmOpenCursor().
|
||||
**
|
||||
@ -295,23 +320,7 @@ static void sqliteGdbmCloseCursor(DbbeCursor *pCursr){
|
||||
gdbm_sync(pFile->dbf);
|
||||
}
|
||||
if( pFile->nRef<=0 ){
|
||||
if( pFile->dbf!=NULL ){
|
||||
gdbm_close(pFile->dbf);
|
||||
}
|
||||
if( pFile->pPrev ){
|
||||
pFile->pPrev->pNext = pFile->pNext;
|
||||
}else{
|
||||
pBe->pOpen = pFile->pNext;
|
||||
}
|
||||
if( pFile->pNext ){
|
||||
pFile->pNext->pPrev = pFile->pPrev;
|
||||
}
|
||||
if( pFile->delOnClose ){
|
||||
unlink(pFile->zName);
|
||||
}
|
||||
sqliteFree(pFile->zName);
|
||||
memset(pFile, 0, sizeof(*pFile));
|
||||
sqliteFree(pFile);
|
||||
sqliteUnlinkFile(pBe, pFile);
|
||||
}
|
||||
if( pCursr->key.dptr ) free(pCursr->key.dptr);
|
||||
if( pCursr->data.dptr ) free(pCursr->data.dptr);
|
||||
@ -493,7 +502,7 @@ static int sqliteGdbmNew(DbbeCursor *pCursr){
|
||||
|
||||
if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
|
||||
while( go ){
|
||||
iKey = sqliteRandomInteger();
|
||||
iKey = sqliteRandomInteger() & 0x7fffffff;
|
||||
if( iKey==0 ) continue;
|
||||
key.dptr = (char*)&iKey;
|
||||
key.dsize = 4;
|
||||
@ -543,6 +552,40 @@ static int sqliteGdbmDelete(DbbeCursor *pCursr, int nKey, char *pKey){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Begin a transaction.
|
||||
*/
|
||||
static int sqliteGdbmBeginTrans(Dbbe *pDbbe){
|
||||
Dbbex *pBe = (Dbbex*)pDbbe;
|
||||
BeFile *pFile;
|
||||
if( pBe->inTrans ) return SQLITE_OK;
|
||||
for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){
|
||||
pFile->nRef++;
|
||||
}
|
||||
pBe->inTrans = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** End a transaction.
|
||||
*/
|
||||
static int sqliteGdbmEndTrans(Dbbe *pDbbe){
|
||||
Dbbex *pBe = (Dbbex*)pDbbe;
|
||||
BeFile *pFile, *pNext;
|
||||
if( !pBe->inTrans ) return SQLITE_OK;
|
||||
for(pFile=pBe->pOpen; pFile; pFile=pNext){
|
||||
pNext = pFile->pNext;
|
||||
pFile->nRef--;
|
||||
if( pFile->nRef<=0 ){
|
||||
sqliteUnlinkFile(pBe, pFile);
|
||||
}
|
||||
}
|
||||
pBe->inTrans = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** This variable contains pointers to all of the access methods
|
||||
** used to implement the GDBM backend.
|
||||
@ -566,6 +609,9 @@ static struct DbbeMethods gdbmMethods = {
|
||||
/* New */ sqliteGdbmNew,
|
||||
/* Put */ sqliteGdbmPut,
|
||||
/* Delete */ sqliteGdbmDelete,
|
||||
/* BeginTrans */ sqliteGdbmBeginTrans,
|
||||
/* Commit */ sqliteGdbmEndTrans,
|
||||
/* Rollback */ sqliteGdbmEndTrans,
|
||||
};
|
||||
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
** Nothing is ever written to disk using this backend. All information
|
||||
** is forgotten when the program exits.
|
||||
**
|
||||
** $Id: dbbemem.c,v 1.12 2001/04/03 16:53:22 drh Exp $
|
||||
** $Id: dbbemem.c,v 1.13 2001/04/04 11:48:58 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <sys/stat.h>
|
||||
@ -669,7 +669,7 @@ static int sqliteMemNew(DbbeCursor *pCursr){
|
||||
int go = 1;
|
||||
|
||||
while( go ){
|
||||
iKey = sqliteRandomInteger();
|
||||
iKey = sqliteRandomInteger() & 0x7fffffff;
|
||||
if( iKey==0 ) continue;
|
||||
key.p = (char*)&iKey;
|
||||
key.n = 4;
|
||||
|
29
src/expr.c
29
src/expr.c
@ -24,7 +24,7 @@
|
||||
** This file contains routines used for analyzing expressions and
|
||||
** for generating VDBE code that evaluates expressions.
|
||||
**
|
||||
** $Id: expr.c,v 1.21 2001/01/15 22:51:10 drh Exp $
|
||||
** $Id: expr.c,v 1.22 2001/04/04 11:48:58 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -85,6 +85,16 @@ void sqliteExprResolveInSelect(Parse *pParse, Expr *pExpr){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the given string is a row-id column name.
|
||||
*/
|
||||
static int sqliteIsRowid(const char *z){
|
||||
if( sqliteStrICmp(z, "_ROWID_")==0 ) return 1;
|
||||
if( sqliteStrICmp(z, "ROWID")==0 ) return 1;
|
||||
if( sqliteStrICmp(z, "OID")==0 ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine walks an expression tree and resolves references to
|
||||
** table columns. Nodes of the form ID.ID or ID resolve into an
|
||||
@ -119,6 +129,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
case TK_ID: {
|
||||
int cnt = 0; /* Number of matches */
|
||||
int i; /* Loop counter */
|
||||
int isRowid = 0; /* True if this is the ROWID column */
|
||||
char *z = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
|
||||
for(i=0; i<pTabList->nId; i++){
|
||||
int j;
|
||||
@ -132,6 +143,11 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
}
|
||||
}
|
||||
}
|
||||
if( cnt==0 && sqliteIsRowid(z) ){
|
||||
pExpr->iColumn = -1;
|
||||
pExpr->iTable = pParse->nTab;
|
||||
cnt = 1 + (pTabList->nId>1);
|
||||
}
|
||||
sqliteFree(z);
|
||||
if( cnt==0 ){
|
||||
sqliteSetNString(&pParse->zErrMsg, "no such column: ", -1,
|
||||
@ -151,6 +167,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
/* A table name and column name: ID.ID */
|
||||
case TK_DOT: {
|
||||
int cnt = 0; /* Number of matches */
|
||||
int cntTab = 0; /* Number of matching tables */
|
||||
int i; /* Loop counter */
|
||||
Expr *pLeft, *pRight; /* Left and right subbranches of the expr */
|
||||
char *zLeft, *zRight; /* Text of an identifier */
|
||||
@ -161,6 +178,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
assert( pRight && pRight->op==TK_ID );
|
||||
zLeft = sqliteStrNDup(pLeft->token.z, pLeft->token.n);
|
||||
zRight = sqliteStrNDup(pRight->token.z, pRight->token.n);
|
||||
pExpr->iTable = -1;
|
||||
for(i=0; i<pTabList->nId; i++){
|
||||
int j;
|
||||
char *zTab;
|
||||
@ -172,6 +190,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
zTab = pTab->zName;
|
||||
}
|
||||
if( sqliteStrICmp(zTab, zLeft)!=0 ) continue;
|
||||
if( 0==(cntTab++) ) pExpr->iTable = i + pParse->nTab;
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
|
||||
cnt++;
|
||||
@ -180,6 +199,10 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
}
|
||||
}
|
||||
}
|
||||
if( cnt==0 && cntTab==1 && sqliteIsRowid(zRight) ){
|
||||
cnt = 1;
|
||||
pExpr->iColumn = -1;
|
||||
}
|
||||
sqliteFree(zLeft);
|
||||
sqliteFree(zRight);
|
||||
if( cnt==0 ){
|
||||
@ -483,8 +506,10 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
|
||||
case TK_COLUMN: {
|
||||
if( pParse->useAgg ){
|
||||
sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg, 0, 0);
|
||||
}else{
|
||||
}else if( pExpr->iColumn>=0 ){
|
||||
sqliteVdbeAddOp(v, OP_Field, pExpr->iTable, pExpr->iColumn, 0, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Key, pExpr->iTable, 0, 0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
106
src/parse.y
106
src/parse.y
@ -26,7 +26,7 @@
|
||||
** the parser. Lemon will also generate a header file containing
|
||||
** numeric codes for all of the tokens.
|
||||
**
|
||||
** @(#) $Id: parse.y,v 1.26 2001/01/04 14:20:18 drh Exp $
|
||||
** @(#) $Id: parse.y,v 1.27 2001/04/04 11:48:58 drh Exp $
|
||||
*/
|
||||
%token_prefix TK_
|
||||
%token_type {Token}
|
||||
@ -41,16 +41,15 @@
|
||||
#include "parse.h"
|
||||
}
|
||||
|
||||
|
||||
// Input is zero or more commands.
|
||||
input ::= cmdlist.
|
||||
|
||||
// These are extra tokens used by the lexer but never seen by the
|
||||
// parser. We put them in a rule so that the parser generator will
|
||||
// add them to the parse.h output file.
|
||||
//
|
||||
input ::= END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
|
||||
UMINUS COLUMN AGG_FUNCTION.
|
||||
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
|
||||
COLUMN AGG_FUNCTION.
|
||||
|
||||
// Input is zero or more commands.
|
||||
input ::= cmdlist.
|
||||
|
||||
// A list of commands is zero or more commands
|
||||
//
|
||||
@ -61,10 +60,22 @@ ecmd ::= cmd. {sqliteExec(pParse);}
|
||||
ecmd ::= .
|
||||
explain ::= EXPLAIN. {pParse->explain = 1;}
|
||||
|
||||
// Begin and end transactions. Transaction support is sparse.
|
||||
// Some backends support only COMMIT and not ROLLBACK. There can
|
||||
// be only a single active transaction at a time.
|
||||
//
|
||||
cmd ::= BEGIN trans_opt. {sqliteBeginTransaction(pParse);}
|
||||
trans_opt ::= .
|
||||
trans_opt ::= TRANSACTION.
|
||||
trans_opt ::= TRANSACTION ids.
|
||||
cmd ::= COMMIT trans_opt. {sqliteCommitTransaction(pParse);}
|
||||
cmd ::= END trans_opt. {sqliteCommitTransaction(pParse);}
|
||||
cmd ::= ROLLBACK trans_opt. {sqliteRollbackTransaction(pParse);}
|
||||
|
||||
// The first form of a command is a CREATE TABLE statement.
|
||||
//
|
||||
cmd ::= create_table create_table_args.
|
||||
create_table ::= CREATE(X) TABLE id(Y). {sqliteStartTable(pParse,&X,&Y);}
|
||||
create_table ::= CREATE(X) TABLE ids(Y). {sqliteStartTable(pParse,&X,&Y);}
|
||||
create_table_args ::= LP columnlist conslist_opt RP(X).
|
||||
{sqliteEndTable(pParse,&X);}
|
||||
columnlist ::= columnlist COMMA column.
|
||||
@ -75,21 +86,39 @@ columnlist ::= column.
|
||||
// an elaborate typename. Perhaps someday we'll do something with it.
|
||||
//
|
||||
column ::= columnid type carglist.
|
||||
columnid ::= id(X). {sqliteAddColumn(pParse,&X);}
|
||||
columnid ::= ids(X). {sqliteAddColumn(pParse,&X);}
|
||||
|
||||
// An IDENTIFIER can be a generic identifier, or one of several
|
||||
// keywords. Any non-standard keyword can also be an identifier.
|
||||
// We also make DESC and identifier since it comes up so often.
|
||||
//
|
||||
%type id {Token}
|
||||
id(A) ::= DESC(X). {A = X;}
|
||||
id(A) ::= ASC(X). {A = X;}
|
||||
id(A) ::= DELIMITERS(X). {A = X;}
|
||||
id(A) ::= EXPLAIN(X). {A = X;}
|
||||
id(A) ::= VACUUM(X). {A = X;}
|
||||
id(A) ::= BEGIN(X). {A = X;}
|
||||
id(A) ::= END(X). {A = X;}
|
||||
id(A) ::= ID(X). {A = X;}
|
||||
id(A) ::= STRING(X). {A = X;}
|
||||
|
||||
// And "ids" is an identifer-or-string.
|
||||
//
|
||||
%type ids {Token}
|
||||
ids(A) ::= id(X). {A = X;}
|
||||
ids(A) ::= STRING(X). {A = X;}
|
||||
|
||||
type ::= typename.
|
||||
type ::= typename LP signed RP.
|
||||
type ::= typename LP signed COMMA signed RP.
|
||||
typename ::= id.
|
||||
typename ::= typename id.
|
||||
typename ::= ids.
|
||||
typename ::= typename ids.
|
||||
signed ::= INTEGER.
|
||||
signed ::= PLUS INTEGER.
|
||||
signed ::= MINUS INTEGER.
|
||||
carglist ::= carglist carg.
|
||||
carglist ::= .
|
||||
carg ::= CONSTRAINT id ccons.
|
||||
carg ::= CONSTRAINT ids ccons.
|
||||
carg ::= ccons.
|
||||
carg ::= DEFAULT STRING(X). {sqliteAddDefaultValue(pParse,&X,0);}
|
||||
carg ::= DEFAULT ID(X). {sqliteAddDefaultValue(pParse,&X,0);}
|
||||
@ -116,16 +145,16 @@ conslist_opt ::= COMMA conslist.
|
||||
conslist ::= conslist COMMA tcons.
|
||||
conslist ::= conslist tcons.
|
||||
conslist ::= tcons.
|
||||
tcons ::= CONSTRAINT id.
|
||||
tcons ::= CONSTRAINT ids.
|
||||
tcons ::= PRIMARY KEY LP idxlist(X) RP. {sqliteCreateIndex(pParse,0,0,X,0,0);}
|
||||
tcons ::= UNIQUE LP idlist RP.
|
||||
tcons ::= CHECK expr.
|
||||
idlist ::= idlist COMMA id.
|
||||
idlist ::= id.
|
||||
idlist ::= idlist COMMA ids.
|
||||
idlist ::= ids.
|
||||
|
||||
// The next command format is dropping tables.
|
||||
//
|
||||
cmd ::= DROP TABLE id(X). {sqliteDropTable(pParse,&X);}
|
||||
cmd ::= DROP TABLE ids(X). {sqliteDropTable(pParse,&X);}
|
||||
|
||||
// The select statement
|
||||
//
|
||||
@ -175,7 +204,7 @@ sclp(A) ::= selcollist(X) COMMA. {A = X;}
|
||||
sclp(A) ::= . {A = 0;}
|
||||
selcollist(A) ::= STAR. {A = 0;}
|
||||
selcollist(A) ::= sclp(P) expr(X). {A = sqliteExprListAppend(P,X,0);}
|
||||
selcollist(A) ::= sclp(P) expr(X) as id(Y). {A = sqliteExprListAppend(P,X,&Y);}
|
||||
selcollist(A) ::= sclp(P) expr(X) as ids(Y). {A = sqliteExprListAppend(P,X,&Y);}
|
||||
as ::= .
|
||||
as ::= AS.
|
||||
|
||||
@ -190,10 +219,11 @@ as ::= AS.
|
||||
from(A) ::= FROM seltablist(X). {A = X;}
|
||||
stl_prefix(A) ::= seltablist(X) COMMA. {A = X;}
|
||||
stl_prefix(A) ::= . {A = 0;}
|
||||
seltablist(A) ::= stl_prefix(X) id(Y). {A = sqliteIdListAppend(X,&Y);}
|
||||
seltablist(A) ::= stl_prefix(X) id(Y) as id(Z).
|
||||
{A = sqliteIdListAppend(X,&Y);
|
||||
sqliteIdListAddAlias(A,&Z);}
|
||||
seltablist(A) ::= stl_prefix(X) ids(Y). {A = sqliteIdListAppend(X,&Y);}
|
||||
seltablist(A) ::= stl_prefix(X) ids(Y) as ids(Z). {
|
||||
A = sqliteIdListAppend(X,&Y);
|
||||
sqliteIdListAddAlias(A,&Z);
|
||||
}
|
||||
|
||||
%type orderby_opt {ExprList*}
|
||||
%destructor orderby_opt {sqliteExprListDelete($$);}
|
||||
@ -231,7 +261,7 @@ having_opt(A) ::= . {A = 0;}
|
||||
having_opt(A) ::= HAVING expr(X). {A = X;}
|
||||
|
||||
|
||||
cmd ::= DELETE FROM id(X) where_opt(Y).
|
||||
cmd ::= DELETE FROM ids(X) where_opt(Y).
|
||||
{sqliteDeleteFrom(pParse, &X, Y);}
|
||||
|
||||
%type where_opt {Expr*}
|
||||
@ -243,16 +273,16 @@ where_opt(A) ::= WHERE expr(X). {A = X;}
|
||||
%type setlist {ExprList*}
|
||||
%destructor setlist {sqliteExprListDelete($$);}
|
||||
|
||||
cmd ::= UPDATE id(X) SET setlist(Y) where_opt(Z).
|
||||
cmd ::= UPDATE ids(X) SET setlist(Y) where_opt(Z).
|
||||
{sqliteUpdate(pParse,&X,Y,Z);}
|
||||
|
||||
setlist(A) ::= setlist(Z) COMMA id(X) EQ expr(Y).
|
||||
setlist(A) ::= setlist(Z) COMMA ids(X) EQ expr(Y).
|
||||
{A = sqliteExprListAppend(Z,Y,&X);}
|
||||
setlist(A) ::= id(X) EQ expr(Y). {A = sqliteExprListAppend(0,Y,&X);}
|
||||
setlist(A) ::= ids(X) EQ expr(Y). {A = sqliteExprListAppend(0,Y,&X);}
|
||||
|
||||
cmd ::= INSERT INTO id(X) inscollist_opt(F) VALUES LP itemlist(Y) RP.
|
||||
cmd ::= INSERT INTO ids(X) inscollist_opt(F) VALUES LP itemlist(Y) RP.
|
||||
{sqliteInsert(pParse, &X, Y, 0, F);}
|
||||
cmd ::= INSERT INTO id(X) inscollist_opt(F) select(S).
|
||||
cmd ::= INSERT INTO ids(X) inscollist_opt(F) select(S).
|
||||
{sqliteInsert(pParse, &X, 0, S, F);}
|
||||
|
||||
|
||||
@ -285,8 +315,8 @@ item(A) ::= NULL. {A = sqliteExpr(TK_NULL, 0, 0, 0);}
|
||||
|
||||
inscollist_opt(A) ::= . {A = 0;}
|
||||
inscollist_opt(A) ::= LP inscollist(X) RP. {A = X;}
|
||||
inscollist(A) ::= inscollist(X) COMMA id(Y). {A = sqliteIdListAppend(X,&Y);}
|
||||
inscollist(A) ::= id(Y). {A = sqliteIdListAppend(0,&Y);}
|
||||
inscollist(A) ::= inscollist(X) COMMA ids(Y). {A = sqliteIdListAppend(X,&Y);}
|
||||
inscollist(A) ::= ids(Y). {A = sqliteIdListAppend(0,&Y);}
|
||||
|
||||
%left OR.
|
||||
%left AND.
|
||||
@ -302,9 +332,9 @@ inscollist(A) ::= id(Y). {A = sqliteIdListAppend(0,&Y);}
|
||||
%destructor expr {sqliteExprDelete($$);}
|
||||
|
||||
expr(A) ::= LP(B) expr(X) RP(E). {A = X; sqliteExprSpan(A,&B,&E);}
|
||||
expr(A) ::= ID(X). {A = sqliteExpr(TK_ID, 0, 0, &X);}
|
||||
expr(A) ::= NULL(X). {A = sqliteExpr(TK_NULL, 0, 0, &X);}
|
||||
expr(A) ::= id(X) DOT id(Y). {
|
||||
expr(A) ::= id(X). {A = sqliteExpr(TK_ID, 0, 0, &X);}
|
||||
expr(A) ::= ids(X) DOT ids(Y). {
|
||||
Expr *temp1 = sqliteExpr(TK_ID, 0, 0, &X);
|
||||
Expr *temp2 = sqliteExpr(TK_ID, 0, 0, &Y);
|
||||
A = sqliteExpr(TK_DOT, temp1, temp2, 0);
|
||||
@ -422,7 +452,7 @@ expritem(A) ::= expr(X). {A = X;}
|
||||
expritem(A) ::= . {A = 0;}
|
||||
|
||||
|
||||
cmd ::= CREATE(S) uniqueflag INDEX id(X) ON id(Y) LP idxlist(Z) RP(E).
|
||||
cmd ::= CREATE(S) uniqueflag INDEX ids(X) ON ids(Y) LP idxlist(Z) RP(E).
|
||||
{sqliteCreateIndex(pParse, &X, &Y, Z, &S, &E);}
|
||||
uniqueflag ::= UNIQUE.
|
||||
uniqueflag ::= .
|
||||
@ -435,14 +465,14 @@ idxlist(A) ::= idxlist(X) COMMA idxitem(Y).
|
||||
{A = sqliteIdListAppend(X,&Y);}
|
||||
idxlist(A) ::= idxitem(Y).
|
||||
{A = sqliteIdListAppend(0,&Y);}
|
||||
idxitem(A) ::= id(X). {A = X;}
|
||||
idxitem(A) ::= ids(X). {A = X;}
|
||||
|
||||
cmd ::= DROP INDEX id(X). {sqliteDropIndex(pParse, &X);}
|
||||
cmd ::= DROP INDEX ids(X). {sqliteDropIndex(pParse, &X);}
|
||||
|
||||
cmd ::= COPY id(X) FROM id(Y) USING DELIMITERS STRING(Z).
|
||||
cmd ::= COPY ids(X) FROM ids(Y) USING DELIMITERS STRING(Z).
|
||||
{sqliteCopy(pParse,&X,&Y,&Z);}
|
||||
cmd ::= COPY id(X) FROM id(Y).
|
||||
cmd ::= COPY ids(X) FROM ids(Y).
|
||||
{sqliteCopy(pParse,&X,&Y,0);}
|
||||
|
||||
cmd ::= VACUUM. {sqliteVacuum(pParse,0);}
|
||||
cmd ::= VACUUM id(X). {sqliteVacuum(pParse,&X);}
|
||||
cmd ::= VACUUM ids(X). {sqliteVacuum(pParse,&X);}
|
||||
|
@ -24,7 +24,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements.
|
||||
**
|
||||
** $Id: select.c,v 1.29 2001/02/19 23:23:38 drh Exp $
|
||||
** $Id: select.c,v 1.30 2001/04/04 11:48:58 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -620,7 +620,9 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
**
|
||||
** SRT_Union Store results as a key in a temporary table iParm
|
||||
**
|
||||
** SRT_Except Remove results form the temporary talbe iParm.
|
||||
** SRT_Except Remove results form the temporary table iParm.
|
||||
**
|
||||
** SRT_Table Store results in temporary table iParm
|
||||
**
|
||||
** This routine returns the number of errors. If any errors are
|
||||
** encountered, then an appropriate error message is left in
|
||||
|
@ -23,7 +23,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.37 2001/03/20 22:05:00 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.38 2001/04/04 11:48:58 drh Exp $
|
||||
*/
|
||||
#include "sqlite.h"
|
||||
#include "dbbe.h"
|
||||
@ -144,6 +144,7 @@ struct sqlite {
|
||||
#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 */
|
||||
|
||||
/*
|
||||
** Current file format version
|
||||
@ -428,3 +429,6 @@ int sqliteRandomByte(void);
|
||||
int sqliteRandomInteger(void);
|
||||
void sqliteRandomName(char*,char*);
|
||||
char *sqliteDbbeNameToFile(const char*,const char*,const char*);
|
||||
void sqliteBeginTransaction(Parse*);
|
||||
void sqliteCommitTransaction(Parse*);
|
||||
void sqliteRollbackTransaction(Parse*);
|
||||
|
@ -27,7 +27,7 @@
|
||||
** individual tokens and sends those tokens one-by-one over to the
|
||||
** parser for analysis.
|
||||
**
|
||||
** $Id: tokenize.c,v 1.17 2001/02/11 16:56:24 drh Exp $
|
||||
** $Id: tokenize.c,v 1.18 2001/04/04 11:48:58 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -53,9 +53,11 @@ static Keyword aKeywordTable[] = {
|
||||
{ "AND", 0, TK_AND, 0 },
|
||||
{ "AS", 0, TK_AS, 0 },
|
||||
{ "ASC", 0, TK_ASC, 0 },
|
||||
{ "BEGIN", 0, TK_BEGIN, 0 },
|
||||
{ "BETWEEN", 0, TK_BETWEEN, 0 },
|
||||
{ "BY", 0, TK_BY, 0 },
|
||||
{ "CHECK", 0, TK_CHECK, 0 },
|
||||
{ "COMMIT", 0, TK_COMMIT, 0 },
|
||||
{ "CONSTRAINT", 0, TK_CONSTRAINT, 0 },
|
||||
{ "COPY", 0, TK_COPY, 0 },
|
||||
{ "CREATE", 0, TK_CREATE, 0 },
|
||||
@ -65,6 +67,7 @@ static Keyword aKeywordTable[] = {
|
||||
{ "DESC", 0, TK_DESC, 0 },
|
||||
{ "DISTINCT", 0, TK_DISTINCT, 0 },
|
||||
{ "DROP", 0, TK_DROP, 0 },
|
||||
{ "END", 0, TK_END, 0 },
|
||||
{ "EXCEPT", 0, TK_EXCEPT, 0 },
|
||||
{ "EXPLAIN", 0, TK_EXPLAIN, 0 },
|
||||
{ "FROM", 0, TK_FROM, 0 },
|
||||
@ -87,9 +90,11 @@ static Keyword aKeywordTable[] = {
|
||||
{ "OR", 0, TK_OR, 0 },
|
||||
{ "ORDER", 0, TK_ORDER, 0 },
|
||||
{ "PRIMARY", 0, TK_PRIMARY, 0 },
|
||||
{ "ROLLBACK", 0, TK_ROLLBACK, 0 },
|
||||
{ "SELECT", 0, TK_SELECT, 0 },
|
||||
{ "SET", 0, TK_SET, 0 },
|
||||
{ "TABLE", 0, TK_TABLE, 0 },
|
||||
{ "TRANSACTION", 0, TK_TRANSACTION, 0 },
|
||||
{ "UNION", 0, TK_UNION, 0 },
|
||||
{ "UNIQUE", 0, TK_UNIQUE, 0 },
|
||||
{ "UPDATE", 0, TK_UPDATE, 0 },
|
||||
|
@ -41,7 +41,7 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.53 2001/03/20 22:05:00 drh Exp $
|
||||
** $Id: vdbe.c,v 1.54 2001/04/04 11:48:58 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <unistd.h>
|
||||
|
@ -27,7 +27,7 @@
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
**
|
||||
** $Id: vdbe.h,v 1.16 2001/02/19 23:23:39 drh Exp $
|
||||
** $Id: vdbe.h,v 1.17 2001/04/04 11:48:58 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@ -178,7 +178,7 @@ typedef struct VdbeOp VdbeOp;
|
||||
#define OP_Strlen 91
|
||||
#define OP_Substr 92
|
||||
|
||||
#define OP_MAX 92
|
||||
#define OP_MAX 93
|
||||
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
|
81
src/where.c
81
src/where.c
@ -25,7 +25,7 @@
|
||||
** the WHERE clause of SQL statements. Also found here are subroutines
|
||||
** to generate VDBE code to evaluate expressions.
|
||||
**
|
||||
** $Id: where.c,v 1.12 2001/02/19 23:23:39 drh Exp $
|
||||
** $Id: where.c,v 1.13 2001/04/04 11:48:58 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -160,6 +160,7 @@ WhereInfo *sqliteWhereBegin(
|
||||
int haveKey; /* True if KEY is on the stack */
|
||||
int base; /* First available index for OP_Open opcodes */
|
||||
Index *aIdx[32]; /* Index to use on each nested loop. */
|
||||
int aDirect[32]; /* If TRUE, then index this table using ROWID */
|
||||
ExprInfo aExpr[50]; /* The WHERE clause is divided into these expressions */
|
||||
|
||||
/* Allocate space for aOrder[]. */
|
||||
@ -209,18 +210,43 @@ WhereInfo *sqliteWhereBegin(
|
||||
/* Figure out what index to use (if any) for each nested loop.
|
||||
** Make aIdx[i] point to the index to use for the i-th nested loop
|
||||
** where i==0 is the outer loop and i==pTabList->nId-1 is the inner
|
||||
** loop.
|
||||
** loop. If the expression uses only the ROWID field, then set
|
||||
** aDirect[i] to 1.
|
||||
**
|
||||
** Actually, if there are more than 32 tables in the join, only the
|
||||
** first 32 tables are candidates for indices.
|
||||
*/
|
||||
loopMask = 0;
|
||||
for(i=0; i<pTabList->nId && i<ARRAYSIZE(aIdx); i++){
|
||||
int j;
|
||||
int idx = aOrder[i];
|
||||
Table *pTab = pTabList->a[idx].pTab;
|
||||
Index *pIdx;
|
||||
Index *pBestIdx = 0;
|
||||
|
||||
/* Check to see if there is an expression that uses only the
|
||||
** ROWID field of this table. If so, set aDirect[i] to 1.
|
||||
** If not, set aDirect[i] to 0.
|
||||
*/
|
||||
aDirect[i] = 0;
|
||||
for(j=0; j<nExpr; j++){
|
||||
if( aExpr[j].idxLeft==idx && aExpr[j].p->pLeft->iColumn<0
|
||||
&& (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
|
||||
aDirect[i] = 1;
|
||||
break;
|
||||
}
|
||||
if( aExpr[j].idxRight==idx && aExpr[j].p->pRight->iColumn<0
|
||||
&& (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){
|
||||
aDirect[i] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( aDirect[i] ){
|
||||
loopMask |= 1<<idx;
|
||||
aIdx[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Do a search for usable indices. Leave pBestIdx pointing to
|
||||
** the most specific usable index.
|
||||
**
|
||||
@ -230,7 +256,6 @@ WhereInfo *sqliteWhereBegin(
|
||||
** index.
|
||||
*/
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int j;
|
||||
int columnMask = 0;
|
||||
|
||||
if( pIdx->nColumn>32 ) continue;
|
||||
@ -285,18 +310,58 @@ WhereInfo *sqliteWhereBegin(
|
||||
for(i=0; i<pTabList->nId; i++){
|
||||
int j, k;
|
||||
int idx = aOrder[i];
|
||||
Index *pIdx = i<ARRAYSIZE(aIdx) ? aIdx[i] : 0;
|
||||
int goDirect;
|
||||
Index *pIdx;
|
||||
|
||||
cont = sqliteVdbeMakeLabel(v);
|
||||
if( pIdx==0 ){
|
||||
/* Case 1: There was no usable index. We must do a complete
|
||||
if( i<ARRAYSIZE(aIdx) ){
|
||||
pIdx = aIdx[i];
|
||||
goDirect = aDirect[i];
|
||||
}else{
|
||||
pIdx = 0;
|
||||
goDirect = 0;
|
||||
}
|
||||
|
||||
if( goDirect ){
|
||||
/* Case 1: We can directly reference a single row using the ROWID field.
|
||||
*/
|
||||
cont = brk;
|
||||
for(k=0; k<nExpr; k++){
|
||||
if( aExpr[k].p==0 ) continue;
|
||||
if( aExpr[k].idxLeft==idx
|
||||
&& (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
|
||||
&& aExpr[k].p->pLeft->iColumn<0
|
||||
){
|
||||
sqliteExprCode(pParse, aExpr[k].p->pRight);
|
||||
aExpr[k].p = 0;
|
||||
break;
|
||||
}
|
||||
if( aExpr[k].idxRight==idx
|
||||
&& (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
|
||||
&& aExpr[k].p->pRight->iColumn<0
|
||||
){
|
||||
sqliteExprCode(pParse, aExpr[k].p->pLeft);
|
||||
aExpr[k].p = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_AddImm, 0, 0, 0, 0);
|
||||
if( i==pTabList->nId-1 && pushKey ){
|
||||
haveKey = 1;
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Fetch, base+idx, 0, 0, 0);
|
||||
haveKey = 0;
|
||||
}
|
||||
}else if( pIdx==0 ){
|
||||
/* Case 2: There was no usable index. We must do a complete
|
||||
** scan of the table.
|
||||
*/
|
||||
cont = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_Next, base+idx, brk, 0, cont);
|
||||
haveKey = 0;
|
||||
}else{
|
||||
/* Case 2: We do have a usable index in pIdx.
|
||||
/* Case 3: We do have a usable index in pIdx.
|
||||
*/
|
||||
cont = sqliteVdbeMakeLabel(v);
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
for(k=0; k<nExpr; k++){
|
||||
if( aExpr[k].p==0 ) continue;
|
||||
|
@ -23,7 +23,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing expressions.
|
||||
#
|
||||
# $Id: expr.test,v 1.9 2000/09/14 01:21:11 drh Exp $
|
||||
# $Id: expr.test,v 1.10 2001/04/04 11:48:58 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -76,6 +76,10 @@ test_expr expr-1.34 {i1=1, i2=2} {i1=2 OR i2=2} {1}
|
||||
test_expr expr-1.35 {i1=1, i2=2} {i1-i2=-1} {1}
|
||||
test_expr expr-1.36 {i1=1, i2=0} {not i1} {0}
|
||||
test_expr expr-1.37 {i1=1, i2=NULL} {not i2} {1}
|
||||
test_expr expr-1.38 {i1=1} {-i1} {-1}
|
||||
test_expr expr-1.39 {i1=1} {+i1} {1}
|
||||
test_expr expr-1.40 {i1=1, i2=2} {+(i2+i1)} {3}
|
||||
test_expr expr-1.41 {i1=1, i2=2} {-(i2+i1)} {-3}
|
||||
|
||||
test_expr expr-2.1 {r1=1.23, r2=2.34} {r1+r2} 3.57
|
||||
test_expr expr-2.2 {r1=1.23, r2=2.34} {r1-r2} -1.11
|
||||
|
@ -23,7 +23,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the IN and BETWEEN operator.
|
||||
#
|
||||
# $Id: in.test,v 1.3 2000/06/21 13:59:13 drh Exp $
|
||||
# $Id: in.test,v 1.4 2001/04/04 11:48:58 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -145,6 +145,12 @@ do_test in-4.2 {
|
||||
}
|
||||
execsql {SELECT a FROM t1 ORDER BY a}
|
||||
} {1 2 3 4 5 6 7 8}
|
||||
do_test in-4.3 {
|
||||
execsql {
|
||||
DELETE FROM t1 WHERE b NOT IN (SELECT b FROM t1 WHERE a>4)
|
||||
}
|
||||
execsql {SELECT a FROM t1 ORDER BY a}
|
||||
} {5 6 7 8}
|
||||
|
||||
# Do an IN with a constant RHS but where the RHS has many, many
|
||||
# elements. We need to test that collisions in the hash table
|
||||
|
@ -23,7 +23,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the CREATE INDEX statement.
|
||||
#
|
||||
# $Id: index.test,v 1.8 2000/10/19 14:10:09 drh Exp $
|
||||
# $Id: index.test,v 1.9 2001/04/04 11:48:58 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -334,5 +334,21 @@ do_test index-10.8 {
|
||||
}
|
||||
} {0}
|
||||
|
||||
# Automatically create an index when we specify a primary key.
|
||||
#
|
||||
do_test index-11.1 {
|
||||
execsql {
|
||||
CREATE TABLE t3(
|
||||
a text,
|
||||
b int,
|
||||
c float,
|
||||
PRIMARY KEY(b)
|
||||
);
|
||||
}
|
||||
for {set i 1} {$i<=50} {incr i} {
|
||||
execsql "INSERT INTO t3 VALUES('x${i}x',$i,0.$i)"
|
||||
}
|
||||
execsql {SELECT c, fcnt() FROM t3 WHERE b==10}
|
||||
} {0.10 2}
|
||||
|
||||
finish_test
|
||||
|
@ -23,7 +23,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the INSERT statement.
|
||||
#
|
||||
# $Id: insert.test,v 1.4 2000/06/07 14:42:27 drh Exp $
|
||||
# $Id: insert.test,v 1.5 2001/04/04 11:48:58 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -100,7 +100,32 @@ do_test insert-1.6c {
|
||||
|
||||
# A table to use for testing default values
|
||||
#
|
||||
do_test insert-2.1 {
|
||||
execsql {
|
||||
CREATE TABLE test2(
|
||||
f1 int default -111,
|
||||
f2 real default +4.32,
|
||||
f3 int default +222,
|
||||
f4 int default 7.89
|
||||
)
|
||||
}
|
||||
execsql {SELECT * from test2}
|
||||
} {}
|
||||
do_test insert-2.2 {
|
||||
execsql {INSERT INTO test2(f1,f3) VALUES(+10,-10)}
|
||||
execsql {SELECT * FROM test2}
|
||||
} {10 4.32 -10 7.89}
|
||||
do_test insert-2.3 {
|
||||
execsql {INSERT INTO test2(f2,f4) VALUES(1.23,-3.45)}
|
||||
execsql {SELECT * FROM test2 WHERE f1==-111}
|
||||
} {-111 1.23 222 -3.45}
|
||||
do_test insert-2.4 {
|
||||
execsql {INSERT INTO test2(f1,f2,f4) VALUES(77,+1.23,3.45)}
|
||||
execsql {SELECT * FROM test2 WHERE f1==77}
|
||||
} {77 1.23 222 3.45}
|
||||
do_test insert-2.10 {
|
||||
execsql {
|
||||
DROP TABLE test2;
|
||||
CREATE TABLE test2(
|
||||
f1 int default 111,
|
||||
f2 real default -4.32,
|
||||
@ -109,15 +134,13 @@ execsql {
|
||||
f5 varchar(10)
|
||||
)
|
||||
}
|
||||
|
||||
do_test insert-2.1 {
|
||||
execsql {SELECT * from test2}
|
||||
} {}
|
||||
do_test insert-2.2 {
|
||||
do_test insert-2.11 {
|
||||
execsql {INSERT INTO test2(f2,f4) VALUES(-2.22,'hi!')}
|
||||
execsql {SELECT * FROM test2}
|
||||
} {111 -2.22 hi hi! {}}
|
||||
do_test insert-2.3 {
|
||||
do_test insert-2.12 {
|
||||
execsql {INSERT INTO test2(f1,f5) VALUES(1,'xyzzy')}
|
||||
execsql {SELECT * FROM test2 ORDER BY f1}
|
||||
} {1 -4.32 hi abc-123 xyzzy 111 -2.22 hi hi! {}}
|
||||
|
@ -23,7 +23,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is exercising the code in main.c.
|
||||
#
|
||||
# $Id: main.test,v 1.5 2001/03/20 12:55:14 drh Exp $
|
||||
# $Id: main.test,v 1.6 2001/04/04 11:48:58 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -76,6 +76,12 @@ do_test main-1.13 {
|
||||
db complete {DROP TABLE xyz; -- hi
|
||||
}
|
||||
} {1}
|
||||
do_test main-1.14 {
|
||||
db complete {SELECT a-b FROM t1; }
|
||||
} {1}
|
||||
do_test main-1.15 {
|
||||
db complete {SELECT a-b FROM t1 }
|
||||
} {0}
|
||||
|
||||
# Try to open a database with a corrupt master file.
|
||||
#
|
||||
|
267
test/rowid.test
Normal file
267
test/rowid.test
Normal file
@ -0,0 +1,267 @@
|
||||
# Copyright (c) 1999, 2000 D. Richard Hipp
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this library; if not, write to the
|
||||
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
# Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# Author contact information:
|
||||
# drh@hwaci.com
|
||||
# http://www.hwaci.com/drh/
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the magic ROWID column that is
|
||||
# found on all tables.
|
||||
#
|
||||
# $Id: rowid.test,v 1.1 2001/04/04 11:48:58 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Basic ROWID functionality tests.
|
||||
#
|
||||
do_test rowid-1.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(x int, y int);
|
||||
INSERT INTO t1 VALUES(1,2);
|
||||
INSERT INTO t1 VALUES(3,4);
|
||||
SELECT x FROM t1 ORDER BY y;
|
||||
}
|
||||
} {1 3}
|
||||
do_test rowid-1.2 {
|
||||
set r [execsql {SELECT rowid FROM t1 ORDER BY x}]
|
||||
global x2rowid rowid2x
|
||||
set x2rowid(1) [lindex $r 0]
|
||||
set x2rowid(3) [lindex $r 1]
|
||||
set rowid2x($x2rowid(1)) 1
|
||||
set rowid2x($x2rowid(3)) 3
|
||||
llength $r
|
||||
} {2}
|
||||
do_test rowid-1.3 {
|
||||
global x2rowid
|
||||
set sql "SELECT x FROM t1 WHERE rowid==$x2rowid(1)"
|
||||
execsql $sql
|
||||
} {1}
|
||||
do_test rowid-1.4 {
|
||||
global x2rowid
|
||||
set sql "SELECT x FROM t1 WHERE rowid==$x2rowid(3)"
|
||||
execsql $sql
|
||||
} {3}
|
||||
do_test rowid-1.5 {
|
||||
global x2rowid
|
||||
set sql "SELECT x FROM t1 WHERE oid==$x2rowid(1)"
|
||||
execsql $sql
|
||||
} {1}
|
||||
do_test rowid-1.6 {
|
||||
global x2rowid
|
||||
set sql "SELECT x FROM t1 WHERE OID==$x2rowid(3)"
|
||||
execsql $sql
|
||||
} {3}
|
||||
do_test rowid-1.7 {
|
||||
global x2rowid
|
||||
set sql "SELECT x FROM t1 WHERE _rowid_==$x2rowid(1)"
|
||||
execsql $sql
|
||||
} {1}
|
||||
do_test rowid-1.8 {
|
||||
global x2rowid
|
||||
set v [execsql {SELECT x, oid FROM t1 order by x}]
|
||||
set v2 [list 1 $x2rowid(1) 3 $x2rowid(3)]
|
||||
expr {$v==$v2}
|
||||
} {1}
|
||||
do_test rowid-1.9 {
|
||||
global x2rowid
|
||||
set v [execsql {SELECT x, RowID FROM t1 order by x}]
|
||||
set v2 [list 1 $x2rowid(1) 3 $x2rowid(3)]
|
||||
expr {$v==$v2}
|
||||
} {1}
|
||||
do_test rowid-1.9 {
|
||||
global x2rowid
|
||||
set v [execsql {SELECT x, _rowid_ FROM t1 order by x}]
|
||||
set v2 [list 1 $x2rowid(1) 3 $x2rowid(3)]
|
||||
expr {$v==$v2}
|
||||
} {1}
|
||||
|
||||
# We cannot update or insert the ROWID column
|
||||
#
|
||||
do_test rowid-2.1 {
|
||||
set v [catch {execsql {INSERT INTO t1(rowid,x,y) VALUES(1234,5,6)}} msg]
|
||||
lappend v $msg
|
||||
} {1 {table t1 has no column named rowid}}
|
||||
do_test rowid-2.2 {
|
||||
set v [catch {execsql {UPDATE t1 SET rowid=12345 WHERE x==1}}]
|
||||
lappend v $msg
|
||||
} {1 {table t1 has no column named rowid}}
|
||||
do_test rowid-2.3 {
|
||||
set v [catch {execsql {INSERT INTO t1(oid,x,y) VALUES(1234,5,6)}} msg]
|
||||
lappend v $msg
|
||||
} {1 {table t1 has no column named oid}}
|
||||
do_test rowid-2.4 {
|
||||
set v [catch {execsql {UPDATE t1 SET oid=12345 WHERE x==1}}]
|
||||
lappend v $msg
|
||||
} {1 {table t1 has no column named oid}}
|
||||
do_test rowid-2.5 {
|
||||
set v [catch {execsql {INSERT INTO t1(_rowid_,x,y) VALUES(1234,5,6)}} msg]
|
||||
lappend v $msg
|
||||
} {1 {table t1 has no column named _rowid_}}
|
||||
do_test rowid-2.6 {
|
||||
set v [catch {execsql {UPDATE t1 SET _rowid_=12345 WHERE x==1}}]
|
||||
lappend v $msg
|
||||
} {1 {table t1 has no column named _rowid_}}
|
||||
|
||||
# But we can use ROWID in the WHERE clause of an UPDATE that does not
|
||||
# change the ROWID.
|
||||
#
|
||||
do_test rowid-2.7 {
|
||||
global x2rowid
|
||||
set sql "UPDATE t1 SET x=2 WHERE OID==$x2rowid(3)"
|
||||
execsql $sql
|
||||
execsql {SELECT x FROM t1 ORDER BY x}
|
||||
} {1 2}
|
||||
do_test rowid-2.8 {
|
||||
global x2rowid
|
||||
set sql "UPDATE t1 SET x=3 WHERE _rowid_==$x2rowid(3)"
|
||||
execsql $sql
|
||||
execsql {SELECT x FROM t1 ORDER BY x}
|
||||
} {1 3}
|
||||
|
||||
# We cannot index by ROWID
|
||||
#
|
||||
do_test rowid-2.9 {
|
||||
set v [catch {execsql {CREATE INDEX idxt1 ON t1(rowid)}} msg]
|
||||
lappend v $msg
|
||||
} {1 {table t1 has no column named rowid}}
|
||||
do_test rowid-2.10 {
|
||||
set v [catch {execsql {CREATE INDEX idxt1 ON t1(_rowid_)}} msg]
|
||||
lappend v $msg
|
||||
} {1 {table t1 has no column named _rowid_}}
|
||||
do_test rowid-2.11 {
|
||||
set v [catch {execsql {CREATE INDEX idxt1 ON t1(oid)}} msg]
|
||||
lappend v $msg
|
||||
} {1 {table t1 has no column named oid}}
|
||||
do_test rowid-2.12 {
|
||||
set v [catch {execsql {CREATE INDEX idxt1 ON t1(x, rowid)}} msg]
|
||||
lappend v $msg
|
||||
} {1 {table t1 has no column named rowid}}
|
||||
|
||||
# Columns defined in the CREATE statement override the buildin ROWID
|
||||
# column names.
|
||||
#
|
||||
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(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}
|
||||
do_test rowid-3.2 {
|
||||
execsql {SELECT * FROM t2 ORDER BY rowid}
|
||||
} {1 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}
|
||||
do_test rowid-3.4 {
|
||||
set r1 [execsql {SELECT _rowid_, rowid FROM t2 ORDER BY rowid}]
|
||||
foreach {a b c d e f} $r1 {}
|
||||
set r2 [execsql {SELECT _rowid_, rowid FROM t2 ORDER BY x DESC}]
|
||||
foreach {u v w x y z} $r2 {}
|
||||
expr {$u==$e && $w==$c && $y==$a}
|
||||
} {1}
|
||||
do_probtest rowid-3.5 {
|
||||
set r1 [execsql {SELECT _rowid_, rowid FROM t2 ORDER BY rowid}]
|
||||
foreach {a b c d e f} $r1 {}
|
||||
expr {$a!=$b && $c!=$d && $e!=$f}
|
||||
} {1}
|
||||
|
||||
# Let's try some more complex examples, including some joins.
|
||||
#
|
||||
do_test rowid-4.1 {
|
||||
execsql {
|
||||
DELETE FROM t1;
|
||||
DELETE FROM t2;
|
||||
}
|
||||
for {set i 1} {$i<=50} {incr i} {
|
||||
execsql "INSERT INTO t1(x,y) VALUES($i,[expr {$i*$i}])"
|
||||
}
|
||||
execsql {INSERT INTO t2 SELECT _rowid_, x*y, y*y FROM t1}
|
||||
execsql {SELECT t2.y FROM t1, t2 WHERE t1.x==4 AND t1.rowid==t2.rowid}
|
||||
} {256}
|
||||
do_test rowid-4.2 {
|
||||
execsql {SELECT t2.y FROM t2, t1 WHERE t1.x==4 AND t1.rowid==t2.rowid}
|
||||
} {256}
|
||||
do_test rowid-4.2.1 {
|
||||
execsql {SELECT t2.y FROM t2, t1 WHERE t1.x==4 AND t1.oid==t2.rowid}
|
||||
} {256}
|
||||
do_test rowid-4.2.2 {
|
||||
execsql {SELECT t2.y FROM t2, t1 WHERE t1.x==4 AND t1._rowid_==t2.rowid}
|
||||
} {256}
|
||||
do_test rowid-4.2.3 {
|
||||
execsql {SELECT t2.y FROM t2, t1 WHERE t1.x==4 AND t2.rowid==t1.rowid}
|
||||
} {256}
|
||||
do_test rowid-4.2.4 {
|
||||
execsql {SELECT t2.y FROM t2, t1 WHERE t2.rowid==t1.oid AND t1.x==4}
|
||||
} {256}
|
||||
do_test rowid-4.2.5 {
|
||||
execsql {SELECT t2.y FROM t1, t2 WHERE t1.x==4 AND t1._rowid_==t2.rowid}
|
||||
} {256}
|
||||
do_test rowid-4.2.6 {
|
||||
execsql {SELECT t2.y FROM t1, t2 WHERE t1.x==4 AND t2.rowid==t1.rowid}
|
||||
} {256}
|
||||
do_test rowid-4.2.7 {
|
||||
execsql {SELECT t2.y FROM t1, t2 WHERE t2.rowid==t1.oid AND t1.x==4}
|
||||
} {256}
|
||||
do_test rowid-4.3 {
|
||||
execsql {CREATE INDEX idxt1 ON t1(x)}
|
||||
execsql {SELECT t2.y FROM t1, t2 WHERE t1.x==4 AND t1.rowid==t2.rowid}
|
||||
} {256}
|
||||
do_test rowid-4.3.1 {
|
||||
execsql {SELECT t2.y FROM t1, t2 WHERE t1.x==4 AND t1._rowid_==t2.rowid}
|
||||
} {256}
|
||||
do_test rowid-4.3.2 {
|
||||
execsql {SELECT t2.y FROM t1, t2 WHERE t2.rowid==t1.oid AND 4==t1.x}
|
||||
} {256}
|
||||
do_test rowid-4.4 {
|
||||
execsql {SELECT t2.y FROM t2, t1 WHERE t1.x==4 AND t1.rowid==t2.rowid}
|
||||
} {256}
|
||||
do_test rowid-4.4.1 {
|
||||
execsql {SELECT t2.y FROM t2, t1 WHERE t1.x==4 AND t1._rowid_==t2.rowid}
|
||||
} {256}
|
||||
do_test rowid-4.4.2 {
|
||||
execsql {SELECT t2.y FROM t2, t1 WHERE t2.rowid==t1.oid AND 4==t1.x}
|
||||
} {256}
|
||||
do_test rowid-4.5 {
|
||||
execsql {CREATE INDEX idxt2 ON t2(y)}
|
||||
execsql {
|
||||
SELECT t1.x, fcnt() FROM t2, t1
|
||||
WHERE t2.y==256 AND t1.rowid==t2.rowid
|
||||
}
|
||||
} {4 3}
|
||||
do_test rowid-4.5.1 {
|
||||
execsql {
|
||||
SELECT t1.x, fcnt() FROM t2, t1
|
||||
WHERE t1.OID==t2.rowid AND t2.y==81
|
||||
}
|
||||
} {3 3}
|
||||
do_test rowid-4.6 {
|
||||
execsql {
|
||||
SELECT t1.x FROM t1, t2
|
||||
WHERE t2.y==256 AND t1.rowid==t2.rowid
|
||||
}
|
||||
} {4}
|
||||
|
||||
do_test rowid-5.1 {
|
||||
execsql {DELETE FROM t1 WHERE _rowid_ IN (SELECT oid FROM t1 WHERE x>8)}
|
||||
execsql {SELECT max(x) FROM t1}
|
||||
} {8}
|
@ -23,7 +23,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the SELECT statement.
|
||||
#
|
||||
# $Id: select1.test,v 1.7 2000/07/29 13:07:00 drh Exp $
|
||||
# $Id: select1.test,v 1.8 2001/04/04 11:48:58 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -262,6 +262,10 @@ do_test select1-6.4 {
|
||||
set v [catch {execsql2 {SELECT f1+F2 as xyzzy FROM test1 ORDER BY f2}} msg]
|
||||
lappend v $msg
|
||||
} {0 {xyzzy 33 xyzzy 77}}
|
||||
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
|
||||
@ -296,5 +300,19 @@ do_test select1-6.9 {
|
||||
ORDER BY A.f1, B.f1}} msg]
|
||||
lappend v $msg
|
||||
} {0 {A.f1 11 B.f1 11 A.f1 11 B.f1 33 A.f1 33 B.f1 11 A.f1 33 B.f1 33}}
|
||||
do_test select1-6.10 {
|
||||
set v [catch {execsql2 {
|
||||
SELECT f1 FROM test1 UNION SELECT f2 FROM test1
|
||||
ORDER BY f2;
|
||||
}} msg]
|
||||
lappend v $msg
|
||||
} {0 {f2 11 f2 22 f2 33 f2 44}}
|
||||
do_test select1-6.11 {
|
||||
set v [catch {execsql2 {
|
||||
SELECT f1 FROM test1 UNION SELECT f2+100 FROM test1
|
||||
ORDER BY f2+100;
|
||||
}} msg]
|
||||
lappend v $msg
|
||||
} {0 {f2+100 11 f2+100 33 f2+100 122 f2+100 144}}
|
||||
|
||||
finish_test
|
||||
|
@ -23,7 +23,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the CREATE TABLE statement.
|
||||
#
|
||||
# $Id: sort.test,v 1.1 2000/06/07 00:12:25 drh Exp $
|
||||
# $Id: sort.test,v 1.2 2001/04/04 11:48:58 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -58,6 +58,12 @@ do_test sort-1.0 {
|
||||
do_test sort-1.1 {
|
||||
execsql {SELECT n FROM t1 ORDER BY n}
|
||||
} {1 2 3 4 5 6 7 8}
|
||||
do_test sort-1.1.1 {
|
||||
execsql {SELECT n FROM t1 ORDER BY n ASC}
|
||||
} {1 2 3 4 5 6 7 8}
|
||||
do_test sort-1.1.1 {
|
||||
execsql {SELECT ALL n FROM t1 ORDER BY n ASC}
|
||||
} {1 2 3 4 5 6 7 8}
|
||||
do_test sort-1.2 {
|
||||
execsql {SELECT n FROM t1 ORDER BY n DESC}
|
||||
} {8 7 6 5 4 3 2 1}
|
||||
@ -82,9 +88,21 @@ do_test sort-1.7 {
|
||||
do_test sort-1.8 {
|
||||
execsql {SELECT n FROM t1 ORDER BY log, flt}
|
||||
} {1 2 3 5 4 6 7 8}
|
||||
do_test sort-1.8.1 {
|
||||
execsql {SELECT n FROM t1 ORDER BY log asc, flt}
|
||||
} {1 2 3 5 4 6 7 8}
|
||||
do_test sort-1.8.2 {
|
||||
execsql {SELECT n FROM t1 ORDER BY log, flt ASC}
|
||||
} {1 2 3 5 4 6 7 8}
|
||||
do_test sort-1.8.3 {
|
||||
execsql {SELECT n FROM t1 ORDER BY log ASC, flt asc}
|
||||
} {1 2 3 5 4 6 7 8}
|
||||
do_test sort-1.9 {
|
||||
execsql {SELECT n FROM t1 ORDER BY log, flt DESC}
|
||||
} {1 3 2 7 6 4 5 8}
|
||||
do_test sort-1.9.1 {
|
||||
execsql {SELECT n FROM t1 ORDER BY log ASC, flt DESC}
|
||||
} {1 3 2 7 6 4 5 8}
|
||||
do_test sort-1.10 {
|
||||
execsql {SELECT n FROM t1 ORDER BY log DESC, flt}
|
||||
} {8 5 4 6 7 2 3 1}
|
||||
@ -92,4 +110,27 @@ do_test sort-1.11 {
|
||||
execsql {SELECT n FROM t1 ORDER BY log DESC, flt DESC}
|
||||
} {8 7 6 4 5 3 2 1}
|
||||
|
||||
# These tests are designed to reach some hard-to-reach places
|
||||
# inside the string comparison routines.
|
||||
#
|
||||
do_test sort-2.1 {
|
||||
execsql {
|
||||
UPDATE t1 SET v='x' || -flt;
|
||||
UPDATE t1 SET v='x-2b' where v=='x-0.123';
|
||||
SELECT v FROM t1 ORDER BY v;
|
||||
}
|
||||
} {x-2b x-2.15 x-3.141592653 x-123 x-4221 x0.0013442 x1.6 x11}
|
||||
do_test sort-2.2 {
|
||||
execsql {
|
||||
UPDATE t1 SET v='x-2_' where v=='x0.0013442';
|
||||
SELECT v FROM t1 ORDER BY v;
|
||||
}
|
||||
} {x-2_ x-2b x-2.15 x-3.141592653 x-123 x-4221 x1.6 x11}
|
||||
do_test sort-2.3 {
|
||||
execsql {
|
||||
UPDATE t1 SET v='x ' || (-1.3+0.01*n);
|
||||
SELECT v FROM t1 ORDER BY v;
|
||||
}
|
||||
} {{x -1.29} {x -1.28} {x -1.27} {x -1.26} {x -1.25} {x -1.24} {x -1.23} {x -1.22}}
|
||||
|
||||
finish_test
|
||||
|
@ -23,7 +23,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the CREATE TABLE statement.
|
||||
#
|
||||
# $Id: table.test,v 1.7 2000/10/19 14:10:09 drh Exp $
|
||||
# $Id: table.test,v 1.8 2001/04/04 11:48:58 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -242,7 +242,7 @@ do_test table-4.1b {
|
||||
execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
|
||||
} $r
|
||||
|
||||
# Drop the even number tables
|
||||
# Drop the even numbered tables
|
||||
#
|
||||
set r {}
|
||||
for {set i 1} {$i<=100} {incr i 2} {
|
||||
@ -304,4 +304,30 @@ do_test table-6.1 {
|
||||
set list [glob -nocomplain testdb/spaces*.tbl]
|
||||
} {testdb/spaces+in+this+name+.tbl}
|
||||
|
||||
# Try using keywords as table names or column names.
|
||||
#
|
||||
do_test table-7.1 {
|
||||
set v [catch {execsql {
|
||||
CREATE TABLE weird(
|
||||
desc text,
|
||||
asc text,
|
||||
explain int,
|
||||
vacuum boolean,
|
||||
delimiters varchar(10)
|
||||
)
|
||||
}} msg]
|
||||
lappend v $msg
|
||||
} {0 {}}
|
||||
do_test table-7.2 {
|
||||
execsql {
|
||||
INSERT INTO weird VALUES('a','b',9,0,'xyz');
|
||||
SELECT * FROM weird;
|
||||
}
|
||||
} {a b 9 0 xyz}
|
||||
do_test table-7.3 {
|
||||
execsql2 {
|
||||
SELECT * FROM weird;
|
||||
}
|
||||
} {desc a asc b explain 9 vacuum 0 delimiters xyz}
|
||||
|
||||
finish_test
|
||||
|
@ -23,7 +23,7 @@
|
||||
# This file implements some common TCL routines used for regression
|
||||
# testing the SQLite library
|
||||
#
|
||||
# $Id: tester.tcl,v 1.12 2001/03/20 12:55:14 drh Exp $
|
||||
# $Id: tester.tcl,v 1.13 2001/04/04 11:48:58 drh Exp $
|
||||
|
||||
# Create a test database
|
||||
#
|
||||
@ -186,9 +186,9 @@ proc finish_test {} {
|
||||
|
||||
# A procedure to execute SQL
|
||||
#
|
||||
proc execsql {sql} {
|
||||
proc execsql {sql {db db}} {
|
||||
# puts "SQL = $sql"
|
||||
return [db eval $sql]
|
||||
return [$db eval $sql]
|
||||
}
|
||||
|
||||
# Another procedure to execute SQL. This one includes the field
|
||||
|
191
test/trans.test
Normal file
191
test/trans.test
Normal file
@ -0,0 +1,191 @@
|
||||
# Copyright (c) 1999, 2000 D. Richard Hipp
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this library; if not, write to the
|
||||
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
# Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# Author contact information:
|
||||
# drh@hwaci.com
|
||||
# http://www.hwaci.com/drh/
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is database locks.
|
||||
#
|
||||
# $Id: trans.test,v 1.1 2001/04/04 11:48:58 drh Exp $
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
if {$dbprefix=="gdbm:" && $::tcl_platform(platform)!="windows"} {
|
||||
|
||||
# Create several tables to work with.
|
||||
#
|
||||
do_test trans-1.0 {
|
||||
execsql {
|
||||
CREATE TABLE one(a int PRIMARY KEY, b text);
|
||||
INSERT INTO one VALUES(1,'one');
|
||||
INSERT INTO one VALUES(2,'two');
|
||||
INSERT INTO one VALUES(3,'three');
|
||||
SELECT b FROM one ORDER BY a;
|
||||
}
|
||||
} {one two three}
|
||||
do_test trans-1.1 {
|
||||
execsql {
|
||||
CREATE TABLE two(a int PRIMARY KEY, b text);
|
||||
INSERT INTO two VALUES(1,'I');
|
||||
INSERT INTO two VALUES(5,'V');
|
||||
INSERT INTO two VALUES(10,'X');
|
||||
SELECT b FROM two ORDER BY a;
|
||||
}
|
||||
} {I V X}
|
||||
do_test trans-1.9 {
|
||||
sqlite altdb ${dbprefix}testdb
|
||||
execsql {SELECT b FROM one ORDER BY a} altdb
|
||||
} {one two three}
|
||||
do_test trans-1.10 {
|
||||
execsql {SELECT b FROM two ORDER BY a} altdb
|
||||
} {I V X}
|
||||
|
||||
# Basic transactions
|
||||
#
|
||||
do_test trans-2.1 {
|
||||
set v [catch {execsql {BEGIN}} msg]
|
||||
lappend v $msg
|
||||
} {0 {}}
|
||||
do_test trans-2.2 {
|
||||
set v [catch {execsql {END}} msg]
|
||||
lappend v $msg
|
||||
} {0 {}}
|
||||
do_test trans-2.3 {
|
||||
set v [catch {execsql {BEGIN TRANSACTION}} msg]
|
||||
lappend v $msg
|
||||
} {0 {}}
|
||||
do_test trans-2.4 {
|
||||
set v [catch {execsql {COMMIT TRANSACTION}} msg]
|
||||
lappend v $msg
|
||||
} {0 {}}
|
||||
do_test trans-2.5 {
|
||||
set v [catch {execsql {BEGIN TRANSACTION 'foo'}} msg]
|
||||
lappend v $msg
|
||||
} {0 {}}
|
||||
do_test trans-2.6 {
|
||||
set v [catch {execsql {ROLLBACK TRANSACTION 'foo'}} msg]
|
||||
lappend v $msg
|
||||
} {0 {}}
|
||||
do_test trans-2.10 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT a FROM one ORDER BY a;
|
||||
SELECT a FROM two ORDER BY a;
|
||||
END;
|
||||
}
|
||||
} {1 2 3 1 5 10}
|
||||
|
||||
# Check the locking behavior
|
||||
#
|
||||
do_test trans-3.1 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT a FROM one ORDER BY a;
|
||||
}
|
||||
} {1 2 3}
|
||||
do_test trans-3.2 {
|
||||
set v [catch {execsql {
|
||||
SELECT a FROM two ORDER BY a;
|
||||
} altdb} msg]
|
||||
lappend v $msg
|
||||
} {0 {1 5 10}}
|
||||
do_test trans-3.3 {
|
||||
set v [catch {execsql {
|
||||
SELECT a FROM one ORDER BY a;
|
||||
} altdb} msg]
|
||||
lappend v $msg
|
||||
} {1 {table one is locked}}
|
||||
do_test trans-3.4 {
|
||||
set v [catch {execsql {
|
||||
INSERT INTO one VALUES(4,'four');
|
||||
}} msg]
|
||||
lappend v $msg
|
||||
} {0 {}}
|
||||
do_test trans-3.2 {
|
||||
set v [catch {execsql {
|
||||
SELECT a FROM two ORDER BY a;
|
||||
} altdb} msg]
|
||||
lappend v $msg
|
||||
} {0 {1 5 10}}
|
||||
do_test trans-3.3 {
|
||||
set v [catch {execsql {
|
||||
SELECT a FROM one ORDER BY a;
|
||||
} altdb} msg]
|
||||
lappend v $msg
|
||||
} {1 {table one is locked}}
|
||||
do_test trans-3.5 {
|
||||
set v [catch {execsql {
|
||||
INSERT INTO two VALUES(4,'IV');
|
||||
}} msg]
|
||||
lappend v $msg
|
||||
} {0 {}}
|
||||
do_test trans-3.6 {
|
||||
set v [catch {execsql {
|
||||
SELECT a FROM two ORDER BY a;
|
||||
} altdb} msg]
|
||||
lappend v $msg
|
||||
} {1 {table two is locked}}
|
||||
do_test trans-3.7 {
|
||||
set v [catch {execsql {
|
||||
SELECT a FROM one ORDER BY a;
|
||||
} altdb} msg]
|
||||
lappend v $msg
|
||||
} {1 {table one is locked}}
|
||||
do_test trans-3.10 {
|
||||
execsql {END TRANSACTION}
|
||||
} {}
|
||||
do_test trans-3.11 {
|
||||
set v [catch {execsql {
|
||||
SELECT a FROM two ORDER BY a;
|
||||
} altdb} msg]
|
||||
lappend v $msg
|
||||
} {0 {1 4 5 10}}
|
||||
do_test trans-3.12 {
|
||||
set v [catch {execsql {
|
||||
SELECT a FROM one ORDER BY a;
|
||||
} altdb} msg]
|
||||
lappend v $msg
|
||||
} {0 {1 2 3 4}}
|
||||
do_test trans-3.13 {
|
||||
set v [catch {execsql {
|
||||
SELECT a FROM two ORDER BY a;
|
||||
} db} msg]
|
||||
lappend v $msg
|
||||
} {0 {1 4 5 10}}
|
||||
do_test trans-3.14 {
|
||||
set v [catch {execsql {
|
||||
SELECT a FROM one ORDER BY a;
|
||||
} db} msg]
|
||||
lappend v $msg
|
||||
} {0 {1 2 3 4}}
|
||||
|
||||
do_test trans-99.1 {
|
||||
altdb close
|
||||
execsql {
|
||||
DROP TABLE one;
|
||||
DROP TABLE two;
|
||||
}
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
} ;# end if(gdbm and not windows)
|
@ -10,7 +10,7 @@ BEGIN {
|
||||
/^#define OP_/ {
|
||||
name = "\"" substr($2,4) "\","
|
||||
if( n<3 ){
|
||||
printf " %-16s", name
|
||||
printf " %-19s", name
|
||||
n++
|
||||
} else {
|
||||
printf " %s\n", name
|
||||
|
@ -17,7 +17,14 @@ proc chng {date desc} {
|
||||
puts "<DD><P><UL>$desc</UL></P></DD>"
|
||||
}
|
||||
|
||||
chng {2001 Apr 3 (1.0.28)} {
|
||||
chng {2001 Apr 4 (1.0.28)} {
|
||||
<li>Added limited support for transactions. At this point, transactions
|
||||
will do table locking on the GDBM backend. There is no support (yet)
|
||||
for rollback or atomic commit.</li>
|
||||
<li>Added special column names ROWID, OID, and _ROWID_ that refer to the
|
||||
unique random integer key associated with every row of every table.</li>
|
||||
<li>Additional tests added to the regression suite to cover the new ROWID
|
||||
feature and the TCL interface bugs mentioned below.</li>
|
||||
<li>Changes to the "lemon" parser generator to help it work better when
|
||||
compiled using MSVC.</li>
|
||||
<li>Bug fixes in the TCL interface identified by Oleg Oleinick.</li>
|
||||
|
67
www/lang.tcl
67
www/lang.tcl
@ -1,7 +1,7 @@
|
||||
#
|
||||
# Run this Tcl script to generate the sqlite.html file.
|
||||
#
|
||||
set rcsid {$Id: lang.tcl,v 1.6 2001/02/20 13:06:31 drh Exp $}
|
||||
set rcsid {$Id: lang.tcl,v 1.7 2001/04/04 11:48:58 drh Exp $}
|
||||
|
||||
puts {<html>
|
||||
<head>
|
||||
@ -48,6 +48,7 @@ foreach {section} [lsort -index 0 -dictionary {
|
||||
{COPY copy}
|
||||
{EXPLAIN explain}
|
||||
{expression expr}
|
||||
{{BEGIN TRANSACTION} transaction}
|
||||
}] {
|
||||
puts "<li><a href=\"#[lindex $section 1]\">[lindex $section 0]</a></li>"
|
||||
}
|
||||
@ -99,6 +100,57 @@ proc Example {text} {
|
||||
puts "<blockquote><pre>$text</pre></blockquote>"
|
||||
}
|
||||
|
||||
Section {BEGIN TRANSACTION} createindex
|
||||
|
||||
Syntax {sql-statement} {
|
||||
BEGIN [TRANSACTION [<name>]]
|
||||
}
|
||||
Syntax {sql-statement} {
|
||||
END [TRANSACTION [<name>]]
|
||||
}
|
||||
Syntax {sql-statement} {
|
||||
COMMIT [TRANSACTION [<name>]]
|
||||
}
|
||||
Syntax {sql-statement} {
|
||||
ROLLBACK [TRANSACTION [<name>]]
|
||||
}
|
||||
|
||||
puts {
|
||||
<p>Support for transactions in SQLite is thin. Transactions
|
||||
may not be nested. The GDBM backend does not support an atomic
|
||||
commit or rollback, but it does support locking. (Note, however,
|
||||
that the compilation instructions on this website for using GDBM under
|
||||
Windows will disable locking.) The MEM backend has no transaction
|
||||
support and silently ignores all requests to begin or end
|
||||
transactions. A new backend is currently under
|
||||
development for SQLite 2.0 that will support both atomic commits and rollback,
|
||||
but that driver is not yet available.</p>
|
||||
|
||||
<p>Under GDBM, starting a transaction just locks all
|
||||
tables that are either read or written during the course of the
|
||||
transaction. The locks are removed when the transaction is ended.
|
||||
Thus, transactions can be used to make changes to multiple tables
|
||||
with the assurance that other threads or processes will not touch
|
||||
the same tables at the same time. For example:</p>
|
||||
|
||||
<blockquote>
|
||||
<b>SELECT data1, data2, ... FROM table1 WHERE ...;</b><br>
|
||||
... Make a decision to update the table ...<br>
|
||||
<b>BEGIN TRANSACTION;<br>
|
||||
SELECT data1, data2, ... FROM table1 WHERE ...;</b><br>
|
||||
... Make sure no other process changed the table in between
|
||||
the first SELECT and the BEGIN TRANSACTION. ...<br>
|
||||
<b>UPDATE table1 SET data1=... WHERE ...;<br>
|
||||
END TRANSACTION;</b>
|
||||
</blockquote>
|
||||
|
||||
<p>In the code above, the <b>table1</b> table is locked by
|
||||
the second SELECT because of the transaction. Thus we know that
|
||||
no other process has modified <b>table1</b> when the UPDATE
|
||||
occurs. The END TRANSACTION releases the lock.</p>
|
||||
}
|
||||
|
||||
|
||||
Section COPY copy
|
||||
|
||||
Syntax {sql-statement} {
|
||||
@ -342,6 +394,19 @@ file globbing syntax for its wildcards. Also, GLOB is case
|
||||
sensitive, unlike LIKE. Both GLOB and LIKE may be preceded by
|
||||
the NOT keyword to invert the sense of the test.</p>
|
||||
|
||||
<p>A column name can be any of the names defined in the CREATE TABLE
|
||||
statement or one of the following special identifiers: "<b>ROWID</b>",
|
||||
"<b>OID</b>", or "<b>_ROWID_</b>".
|
||||
These special identifiers all describe the
|
||||
unique random integer key (the "row key") associated every every
|
||||
row of every table.
|
||||
The special identifiers only refer to the row key if the CREATE TABLE
|
||||
statement does not define a real column with the same name. Row keys
|
||||
act like read-only columns. A row key can be used anywhere a regular
|
||||
column can be used, except that you cannot change the value
|
||||
of a row key in an UPDATE or INSERT statement.
|
||||
"SELECT * ..." does not return the row key.</p>
|
||||
|
||||
<p>SELECT statements can appear in expressions as either the
|
||||
right-hand operand of the IN operator or as a scalar quantity.
|
||||
In both cases, the SELECT should have only a single column in its
|
||||
|
Reference in New Issue
Block a user