1
0
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:
drh
2001-04-04 11:48:57 +00:00
parent 960e8c6317
commit c4a3c779b1
28 changed files with 1081 additions and 163 deletions

View File

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

View File

@ -1 +1 @@
1f0197d504fa2bde15b287ac6c0102cacdb1e482
35a8feed0d10e780c477f7440fbe80637fcf9906

View File

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

View File

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

View File

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

View File

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

View File

@ -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
@ -117,8 +127,9 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
switch( pExpr->op ){
/* A lone identifier */
case TK_ID: {
int cnt = 0; /* Number of matches */
int i; /* Loop counter */
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;
}

View File

@ -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) ::= ID(X). {A = X;}
id(A) ::= STRING(X). {A = X;}
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;}
// 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);}
@ -283,10 +313,10 @@ item(A) ::= NULL. {A = sqliteExpr(TK_NULL, 0, 0, 0);}
%type inscollist {IdList*}
%destructor inscollist {sqliteIdListDelete($$);}
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_opt(A) ::= . {A = 0;}
inscollist_opt(A) ::= LP inscollist(X) RP. {A = X;}
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);}

View File

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

View File

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

View File

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

View File

@ -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>
@ -811,29 +811,29 @@ void sqliteVdbeDelete(Vdbe *p){
** this array, then copy and paste it into this file, if you want.
*/
static char *zOpName[] = { 0,
"OpenIdx", "OpenTbl", "Close", "Fetch",
"Fcnt", "New", "Put", "Distinct",
"Found", "NotFound", "Delete", "Field",
"KeyAsData", "Key", "FullKey", "Rewind",
"Next", "Destroy", "Reorganize", "ResetIdx",
"NextIdx", "PutIdx", "DeleteIdx", "MemLoad",
"MemStore", "ListOpen", "ListWrite", "ListRewind",
"ListRead", "ListClose", "SortOpen", "SortPut",
"SortMakeRec", "SortMakeKey", "Sort", "SortNext",
"SortKey", "SortCallback", "SortClose", "FileOpen",
"FileRead", "FileField", "FileClose", "AggReset",
"AggFocus", "AggIncr", "AggNext", "AggSet",
"AggGet", "SetInsert", "SetFound", "SetNotFound",
"SetClear", "MakeRecord", "MakeKey", "Goto",
"If", "Halt", "ColumnCount", "ColumnName",
"Callback", "Integer", "String", "Null",
"Pop", "Dup", "Pull", "Add",
"AddImm", "Subtract", "Multiply", "Divide",
"Min", "Max", "Like", "Glob",
"Eq", "Ne", "Lt", "Le",
"Gt", "Ge", "IsNull", "NotNull",
"Negative", "And", "Or", "Not",
"Concat", "Noop", "Strlen", "Substr",
"OpenIdx", "OpenTbl", "Close", "Fetch",
"Fcnt", "New", "Put", "Distinct",
"Found", "NotFound", "Delete", "Field",
"KeyAsData", "Key", "FullKey", "Rewind",
"Next", "Destroy", "Reorganize", "ResetIdx",
"NextIdx", "PutIdx", "DeleteIdx", "MemLoad",
"MemStore", "ListOpen", "ListWrite", "ListRewind",
"ListRead", "ListClose", "SortOpen", "SortPut",
"SortMakeRec", "SortMakeKey", "Sort", "SortNext",
"SortKey", "SortCallback", "SortClose", "FileOpen",
"FileRead", "FileField", "FileClose", "AggReset",
"AggFocus", "AggIncr", "AggNext", "AggSet",
"AggGet", "SetInsert", "SetFound", "SetNotFound",
"SetClear", "MakeRecord", "MakeKey", "Goto",
"If", "Halt", "ColumnCount", "ColumnName",
"Callback", "Integer", "String", "Null",
"Pop", "Dup", "Pull", "Add",
"AddImm", "Subtract", "Multiply", "Divide",
"Min", "Max", "Like", "Glob",
"Eq", "Ne", "Lt", "Le",
"Gt", "Ge", "IsNull", "NotNull",
"Negative", "And", "Or", "Not",
"Concat", "Noop", "Strlen", "Substr",
};
/*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,24 +100,47 @@ do_test insert-1.6c {
# A table to use for testing default values
#
execsql {
CREATE TABLE test2(
f1 int default 111,
f2 real default -4.32,
f3 text default hi,
f4 text default 'abc-123',
f5 varchar(10)
)
}
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,
f3 text default hi,
f4 text default 'abc-123',
f5 varchar(10)
)
}
execsql {SELECT * from test2}
} {}
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! {}}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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