-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
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
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
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
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
-1f0197d504fa2bde15b287ac6c0102cacdb1e482
\ No newline at end of file
+35a8feed0d10e780c477f7440fbe80637fcf9906
\ No newline at end of file
** 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"
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;
+ }
+}
** 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_
/* 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*);
};
/*
** 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>
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 */
};
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;
}
pFile->writeable = writeable;
pFile->zName = zFile;
- pFile->nRef = 1;
+ pFile->nRef = 1 + pBe->inTrans;
pFile->pPrev = 0;
if( pBe->pOpen ){
pBe->pOpen->pPrev = pFile;
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().
**
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);
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;
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.
/* New */ sqliteGdbmNew,
/* Put */ sqliteGdbmPut,
/* Delete */ sqliteGdbmDelete,
+ /* BeginTrans */ sqliteGdbmBeginTrans,
+ /* Commit */ sqliteGdbmEndTrans,
+ /* Rollback */ sqliteGdbmEndTrans,
};
** 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>
int go = 1;
while( go ){
- iKey = sqliteRandomInteger();
+ iKey = sqliteRandomInteger() & 0x7fffffff;
if( iKey==0 ) continue;
key.p = (char*)&iKey;
key.n = 4;
** 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"
}
}
+/*
+** 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
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;
}
}
}
+ 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,
/* 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 */
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;
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++;
}
}
}
+ if( cnt==0 && cntTab==1 && sqliteIsRowid(zRight) ){
+ cnt = 1;
+ pExpr->iColumn = -1;
+ }
sqliteFree(zLeft);
sqliteFree(zRight);
if( cnt==0 ){
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;
}
** 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}
#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
//
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.
// 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);}
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
//
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.
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($$);}
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*}
%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);}
%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.
%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);
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 ::= .
{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);}
** 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"
**
** 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
*************************************************************************
** 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"
#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
int sqliteRandomInteger(void);
void sqliteRandomName(char*,char*);
char *sqliteDbbeNameToFile(const char*,const char*,const char*);
+void sqliteBeginTransaction(Parse*);
+void sqliteCommitTransaction(Parse*);
+void sqliteRollbackTransaction(Parse*);
** 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>
{ "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 },
{ "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 },
{ "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 },
** 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>
** 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",
};
/*
** 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_
#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
** 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"
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[]. */
/* 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.
**
** index.
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- int j;
int columnMask = 0;
if( pIdx->nColumn>32 ) continue;
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;
+
+ if( i<ARRAYSIZE(aIdx) ){
+ pIdx = aIdx[i];
+ goDirect = aDirect[i];
+ }else{
+ pIdx = 0;
+ goDirect = 0;
+ }
- cont = sqliteVdbeMakeLabel(v);
- if( pIdx==0 ){
- /* Case 1: There was no usable index. We must do a complete
+ 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;
# 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
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
# 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
}
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
# 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
}
} {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
# 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
# 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! {}}
# 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
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.
#
--- /dev/null
+# 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}
# 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
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
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
# 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
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}
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}
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
# 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
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} {
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
# 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
#
# 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
--- /dev/null
+# 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)
/^#define OP_/ {
name = "\"" substr($2,4) "\","
if( n<3 ){
- printf " %-16s", name
+ printf " %-19s", name
n++
} else {
printf " %s\n", name
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>
#
# 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>
{COPY copy}
{EXPLAIN explain}
{expression expr}
+ {{BEGIN TRANSACTION} transaction}
}] {
puts "<li><a href=\"#[lindex $section 1]\">[lindex $section 0]</a></li>"
}
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} {
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