From 1c92853dac621a7fdf97d005c90eddd8348c22d8 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 31 Jan 2002 15:54:21 +0000 Subject: [PATCH] Change to five conflict resolution algorithms: ROLLBACK, ABORT, FAIL, IGNORE, and REPLACE. This checkin is code only. Documentation and tests are still needed. Also, ABORT is not fully implemented. (CVS 360) FossilOrigin-Name: d0e7cf4a83e6abad7129bed356b7492dddaff474 --- manifest | 40 +++++++-------- manifest.uuid | 2 +- publish.sh | 46 ++++++++++++++++- src/build.c | 122 +++++++++++++++++++++------------------------ src/delete.c | 12 ++--- src/insert.c | 69 +++++++++++++++---------- src/main.c | 3 +- src/parse.y | 35 +++++++------ src/sqliteInt.h | 43 ++++++++++------ src/tokenize.c | 3 +- src/update.c | 12 ++--- src/vdbe.c | 17 +++++-- test/conflict.test | 50 +++++++++---------- test/copy.test | 6 +-- test/notnull.test | 84 +++++++++++++++---------------- www/download.tcl | 19 ++++++- www/lang.tcl | 7 ++- 17 files changed, 331 insertions(+), 239 deletions(-) diff --git a/manifest b/manifest index 7ad25dbe36..849134cdd3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Added\sON\sCONFLICT\ssupport\sto\sCOPY.\sUpdates\sto\sdocumentation.\sBug\sfixes.\s(CVS\s359) -D 2002-01-30T16:17:24 +C Change\sto\sfive\sconflict\sresolution\salgorithms:\sROLLBACK,\sABORT,\sFAIL,\nIGNORE,\sand\sREPLACE.\s\sThis\scheckin\sis\scode\sonly.\s\sDocumentation\sand\ntests\sare\sstill\sneeded.\s\sAlso,\sABORT\sis\snot\sfully\simplemented.\s(CVS\s360) +D 2002-01-31T15:54:21 F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 @@ -16,40 +16,40 @@ F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F libtool c56e618713c9510a103bda6b95f3ea3900dcacd6 F ltmain.sh e9ed72eb1d690f447c13945eaf69e28af531eda1 -F publish.sh 523db0d8a451df7a8300e193afaa4ac44e41f98c +F publish.sh 60adffbe50226a1d7d1a2930e8b7eb31535c4fe4 F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6 F src/btree.c c796e387da340cb628dc1e41f684fc20253f561e F src/btree.h 9ead7f54c270d8a554e59352ca7318fdaf411390 -F src/build.c 78571589a39d4b03b19b1300db8b23f1d3e1bab2 -F src/delete.c 4cdb6d2e94e2eb1b1aa79eefafd4669d43c249d6 +F src/build.c f725dc396d784f723950cf3d47a10f1a69b2f7b7 +F src/delete.c f8ad71be53cf18656b6573de65395852fe817f0c F src/expr.c a2a87dbd411a508ff89dffa90505ad42dac2f920 F src/hash.c 8f7c740ef2eaaa8decfa8751f2be30680b123e46 F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac -F src/insert.c 37971598f1cbfc9de9bd1d269529e233003652b8 -F src/main.c 0205771a6c31a9858ff131fc1e797b589afb76bf +F src/insert.c 42e89cb227ce744802622886db3572f78e72093f +F src/main.c 637582b8b80a85b0308ca5bab8f2b42ebb002af8 F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c F src/os.c c615faa4d23e742e0650e0751a6ad2a18438ad53 F src/os.h 5405a5695bf16889d4fc6caf9d42043caa41c269 F src/pager.c 1e80a3ba731e454df6bd2e58d32eeba7dd65121b F src/pager.h f78d064c780855ff70beacbeba0e2324471b26fe -F src/parse.y e80f1cf6a280e3da0f49c9b60b14edc2f15912ec +F src/parse.y 90e9fc913c60b26217f4210d48a4c5c4e78f16f2 F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d F src/random.c f6b36bec5ebd3edb3440224bf5bf811fe4ac9a1b F src/select.c fc11d5a8c2bae1b62d8028ffb111c773ad6bf161 F src/shell.c c102dfe388c7618a668c944ff157c49cb48f28e3 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in f57074c84a2c112a5093ba7a9d9636aa9cacc87c -F src/sqliteInt.h 3bf0938d01e1cc57154c39c730d7e91d9bd60359 +F src/sqliteInt.h 70fd20107f4953312e76a9630a704c9405161040 F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321 F src/test3.c d6775f95fd91f5b3cf0e2382a28e5aaeb68f745b -F src/tokenize.c 1199b96a82d5c41509b5e24fc9faa1852b7f3135 -F src/update.c c6215079d7604fd1cf785eff64ec0e03e97bd138 +F src/tokenize.c 01a09db6adf933e941db1b781789a0c175be6504 +F src/update.c 3fb7c1601bbd379e39881d6b731d3223b822188a F src/util.c 8f8973dd55a6ec63be9632fc5de86965c99d6327 -F src/vdbe.c 14667d889d9d9ebdc5f5f5d030312071f41b7873 +F src/vdbe.c 8e6f1bfff67639b7c3bd07822595fc2ef19f0f34 F src/vdbe.h 5b1bd518126fc5a30e6ea13fe11de931b32c4b59 F src/where.c 2dda39367f193194e4c7d2e0dcab31527d9d8aba F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe @@ -57,8 +57,8 @@ F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 F test/btree.test 6ab4dc5f595905a276ef588fad3c9236dc07a47b F test/btree2.test 08e9485619265cbaf5d11bd71f357cdc26bb87e0 F test/btree3.test 9caa9e22491dd8cd8aa36d7ac3b48b089817c895 -F test/conflict.test 685725a37ec13e671ec57f48285c1c08bba21c99 -F test/copy.test 4079990fb84be696d29c43de9fa6492312f165f0 +F test/conflict.test 70d40d77bb83f326574488d3cde1d0f3c51a0949 +F test/copy.test 9ff0063c0b95b3d51b8d0c7fe0ff51dabaa66549 F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8 F test/expr.test c8a495050dcec3f9e68538c3ef466726933302c1 F test/func.test 51dbe3f8a4c28972751697423e6acc5d6b551df1 @@ -73,7 +73,7 @@ F test/lock.test 19593689260c419efe7ced55b1418653a4b7bcd1 F test/main.test 1626345b5f630c5398eede500d9354813b76b0fd F test/malloc.test 70fdd0812e2a57eb746aaf015350f58bb8eee0b1 F test/misc1.test 50a5ca3481fc1f3cd6b978bcd6ed04c06f26a1e6 -F test/notnull.test 70856457c86fe50877f760e4057e99fdedd2997c +F test/notnull.test b1f3e42fc475b0b5827b27b2e9b562081995ff30 F test/pager.test 59bbc4e3d489529ed33db6e15595789e51056077 F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05 @@ -110,19 +110,19 @@ F www/c_interface.tcl 82a026b1681757f13b3f62e035f3a31407c1d353 F www/changes.tcl 3770ded78faa7a634b55fbf5316caa4cb150e5f9 F www/conflict.tcl 3f70c01680b8d763bf3305eb67f6d85fdf83b497 F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060 -F www/download.tcl 1ea61f9d89a2a5a9b2cee36b0d5cf97321bdefe0 +F www/download.tcl a6d75b8b117cd33dcb090bef7e80d7556d28ebe0 F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c F www/faq.tcl 32cbc134879871604070d4cc3a32e73fb22a35f9 F www/formatchng.tcl 2d9a35c787823b48d72a5c64bb5414a43e26d5ad F www/index.tcl 748614d8208c761ed3840e7958b8eed04de81822 -F www/lang.tcl f04d74017e627f6f133438234bd20fbe585ca4cf +F www/lang.tcl 7ad595247fd81f394012a0cfd84ccd6241b9e59a F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5 F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 9bbddb8e013b47547164f71f2d7abd995f8d7385 -R ad077c176de250ed6687e2b5636281f6 +P cf1538d71c9ce12d5e59f367e03642cbcaf6b717 +R b0c9c7a017538a09b4eca555b386a82f U drh -Z 1ba7e7bec405961a534e04fc39ece2b3 +Z b508e059fe2aafe83b423b2a1e04f6ed diff --git a/manifest.uuid b/manifest.uuid index 022d213837..89c4ee85ea 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cf1538d71c9ce12d5e59f367e03642cbcaf6b717 \ No newline at end of file +d0e7cf4a83e6abad7129bed356b7492dddaff474 \ No newline at end of file diff --git a/publish.sh b/publish.sh index b0bb888327..02448a0ed7 100644 --- a/publish.sh +++ b/publish.sh @@ -28,7 +28,9 @@ gzip sqlite.bin # under Linux # make target_source +rm sqlite_source.zip cd tsrc +zip ../sqlite_source.zip * rm shell.c TCLDIR=/home/drh/tcltk/8.2linux TCLSTUBLIB=$TCLDIR/libtclstub8.2g.a @@ -36,9 +38,14 @@ OPTS='-DUSE_TCL_STUBS=1 -DNDEBUG=1' gcc -fPIC $OPTS -O2 -I. -I$TCLDIR -shared *.c $TCLSTUBLIB -o tclsqlite.so strip tclsqlite.so mv tclsqlite.so .. +rm tclsqlite.c +gcc -fPIC -DNDEBUG=1 -O2 -I. -shared *.c -o sqlite.so +strip sqlite.so +mv sqlite.so .. cd .. -rm -f tclsqlite.so.gz +rm -f tclsqlite.so.gz sqlite.so.gz gzip tclsqlite.so +gzip sqlite.so # Build the tclsqlite.dll shared library that can be imported into tclsh # or wish on windows. @@ -69,9 +76,43 @@ i386-mingw32-dllwrap \ -dllname tclsqlite.dll -lmsvcrt *.o $TCLSTUBLIB i386-mingw32-strip tclsqlite.dll mv tclsqlite.dll .. +rm tclsqlite.o +cat >sqlite.def <<\END_OF_FILE +EXPORTS +sqlite_open +sqlite_close +sqlite_exec +sqlite_last_insert_rowid +sqlite_error_string +sqlite_interrupt +sqlite_complete +sqlite_busy_handler +sqlite_busy_timeout +sqlite_get_table +sqlite_free_table +sqlite_mprintf +sqlite_vmprintf +sqlite_exec_printf +sqlite_exec_vprintf +sqlite_get_table_printf +sqlite_get_table_vprintf +sqliteMalloc +sqliteFree +sqliteRealloc +END_OF_FILE +i386-mingw32-dllwrap \ + --def sqlite.def -v --export-all \ + --driver-name i386-mingw32-gcc \ + --dlltool-name i386-mingw32-dlltool \ + --as i386-mingw32-as \ + --target i386-mingw32 \ + -dllname sqlite.dll -lmsvcrt *.o +i386-mingw32-strip sqlite.dll +mv sqlite.dll sqlite.def .. cd .. -rm -f tclsqlite.zip +rm -f tclsqlite.zip sqlitedll.zip zip tclsqlite.zip tclsqlite.dll +zip sqlitedll.zip sqlite.dll sqlite.def # Build the sqlite.exe executable for windows. # @@ -103,3 +144,4 @@ cp $srcdir/../historical/* . rm -rf doc make doc ln sqlite.bin.gz sqlite.zip sqlite*.tar.gz tclsqlite.so.gz tclsqlite.zip doc +ln sqlitedll.zip sqlite.so.gz sqlite_source.zip doc diff --git a/src/build.c b/src/build.c index 7f6ec3f3a9..fa8d92a0a6 100644 --- a/src/build.c +++ b/src/build.c @@ -25,7 +25,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.69 2002/01/30 16:17:24 drh Exp $ +** $Id: build.c,v 1.70 2002/01/31 15:54:22 drh Exp $ */ #include "sqliteInt.h" #include @@ -422,7 +422,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){ rc = sqliteBtreeBeginTrans(db->pBeTemp); if( rc!=SQLITE_OK ){ sqliteSetNString(&pParse->zErrMsg, "unable to get a write lock on " - "the temporary datbase file", 0); + "the temporary database file", 0); pParse->nErr++; return; } @@ -474,11 +474,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){ if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); pParse->pNewTable = pTable; if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){ - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Transaction, 0, 0); - sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); - pParse->schemaVerified = 1; - } + sqliteBeginWriteOperation(pParse); if( !isTemp ){ sqliteVdbeAddOp(v, OP_SetCookie, db->file_format, 1); sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2); @@ -738,9 +734,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){ sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0); sqliteVdbeAddOp(v, OP_Close, 0, 0); } - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Commit, 0, 0); - } + sqliteEndWriteOperation(pParse); } } @@ -802,11 +796,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){ { OP_Close, 0, 0, 0}, }; Index *pIdx; - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Transaction, 0, 0); - sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); - pParse->schemaVerified = 1; - } + sqliteBeginWriteOperation(pParse); if( !pTable->isTemp ){ base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); sqliteVdbeChangeP3(v, base+2, pTable->zName, P3_STATIC); @@ -817,9 +807,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){ for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){ sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pTable->isTemp); } - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Commit, 0, 0); - } + sqliteEndWriteOperation(pParse); } /* Move the table (and all its indices) to the pending DROP queue. @@ -1057,11 +1045,7 @@ void sqliteCreateIndex( v = sqliteGetVdbe(pParse); if( v==0 ) goto exit_create_index; if( pTable!=0 ){ - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Transaction, 0, 0); - sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); - pParse->schemaVerified = 1; - } + sqliteBeginWriteOperation(pParse); if( !isTemp ){ sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2); sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC); @@ -1118,9 +1102,7 @@ void sqliteCreateIndex( sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0); sqliteVdbeAddOp(v, OP_Close, 0, 0); } - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Commit, 0, 0); - } + sqliteEndWriteOperation(pParse); } } @@ -1173,11 +1155,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){ int base; Table *pTab = pIndex->pTable; - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Transaction, 0, 0); - sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); - pParse->schemaVerified = 1; - } + sqliteBeginWriteOperation(pParse); if( !pTab->isTemp ){ base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex); sqliteVdbeChangeP3(v, base+2, pIndex->zName, P3_STATIC); @@ -1185,9 +1163,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){ sqliteVdbeChangeP1(v, base+10, db->next_cookie); } sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp); - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Commit, 0, 0); - } + sqliteEndWriteOperation(pParse); } /* Move the index onto the pending DROP queue. Or, if the index was @@ -1337,7 +1313,7 @@ void sqliteCopy( ){ Table *pTab; char *zTab; - int i, j; + int i; Vdbe *v; int addr, end; Index *pIdx; @@ -1362,11 +1338,7 @@ void sqliteCopy( v = sqliteGetVdbe(pParse); if( v ){ int openOp; - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Transaction, 0, 0); - sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); - pParse->schemaVerified = 1; - } + sqliteBeginWriteOperation(pParse); addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0); sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n); sqliteVdbeDequoteP3(v, addr); @@ -1411,9 +1383,7 @@ void sqliteCopy( sqliteVdbeAddOp(v, OP_Goto, 0, addr); sqliteVdbeResolveLabel(v, end); sqliteVdbeAddOp(v, OP_Noop, 0, 0); - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Commit, 0, 0); - } + sqliteEndWriteOperation(pParse); if( db->flags & SQLITE_CountRows ){ sqliteVdbeAddOp(v, OP_ColumnCount, 1, 0); sqliteVdbeAddOp(v, OP_ColumnName, 0, 0); @@ -1450,11 +1420,7 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){ } v = sqliteGetVdbe(pParse); if( v==0 ) goto vacuum_cleanup; - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Transaction, 0, 0); - sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); - pParse->schemaVerified = 1; - } + sqliteBeginWriteOperation(pParse); if( zName ){ sqliteVdbeAddOp(v, OP_Reorganize, 0, 0); sqliteVdbeChangeP3(v, -1, zName, strlen(zName)); @@ -1472,9 +1438,7 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){ } } } - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Commit, 0, 0); - } + sqliteEndWriteOperation(pParse); vacuum_cleanup: sqliteFree(zName); @@ -1484,20 +1448,15 @@ vacuum_cleanup: /* ** Begin a transaction */ -void sqliteBeginTransaction(Parse *pParse){ +void sqliteBeginTransaction(Parse *pParse, int onError){ sqlite *db; - Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return; if( pParse->nErr || sqlite_malloc_failed ) return; if( db->flags & SQLITE_InTrans ) return; - v = sqliteGetVdbe(pParse); - if( v ){ - sqliteVdbeAddOp(v, OP_Transaction, 1, 0); - sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); - pParse->schemaVerified = 1; - } + sqliteBeginWriteOperation(pParse); db->flags |= SQLITE_InTrans; + db->onError = onError; } /* @@ -1505,16 +1464,13 @@ void sqliteBeginTransaction(Parse *pParse){ */ void sqliteCommitTransaction(Parse *pParse){ sqlite *db; - Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return; if( pParse->nErr || sqlite_malloc_failed ) return; if( (db->flags & SQLITE_InTrans)==0 ) return; - v = sqliteGetVdbe(pParse); - if( v ){ - sqliteVdbeAddOp(v, OP_Commit, 0, 0); - } db->flags &= ~SQLITE_InTrans; + sqliteEndWriteOperation(pParse); + db->onError = OE_Default; } /* @@ -1532,8 +1488,46 @@ void sqliteRollbackTransaction(Parse *pParse){ sqliteVdbeAddOp(v, OP_Rollback, 0, 0); } db->flags &= ~SQLITE_InTrans; + db->onError = OE_Default; } +/* +** Generate VDBE code that prepares for doing an operation that +** might change the database. If we are in the middle of a transaction, +** then this sets a checkpoint. If we are not in a transaction, then +** start a transaction. +*/ +void sqliteBeginWriteOperation(Parse *pParse){ + Vdbe *v; + v = sqliteGetVdbe(pParse); + if( v==0 ) return; + if( pParse->db->flags & SQLITE_InTrans ){ + /* sqliteVdbeAddOp(v, OP_CheckPoint, 0, 0); */ + }else{ + sqliteVdbeAddOp(v, OP_Transaction, 0, 0); + sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0); + pParse->schemaVerified = 1; + } +} + +/* +** Generate code that concludes an operation that may have changed +** the database. This is a companion function to BeginWriteOperation(). +** If a transaction was started, then commit it. If a checkpoint was +** started then commit that. +*/ +void sqliteEndWriteOperation(Parse *pParse){ + Vdbe *v; + v = sqliteGetVdbe(pParse); + if( v==0 ) return; + if( pParse->db->flags & SQLITE_InTrans ){ + /* Do Nothing */ + }else{ + sqliteVdbeAddOp(v, OP_Commit, 0, 0); + } +} + + /* ** Interpret the given string as a boolean value. */ diff --git a/src/delete.c b/src/delete.c index 15e2ea3f9d..3898fdfcf1 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** -** $Id: delete.c,v 1.25 2002/01/29 23:07:02 drh Exp $ +** $Id: delete.c,v 1.26 2002/01/31 15:54:22 drh Exp $ */ #include "sqliteInt.h" @@ -82,11 +82,7 @@ void sqliteDeleteFrom( */ v = sqliteGetVdbe(pParse); if( v==0 ) goto delete_from_cleanup; - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Transaction, 0, 0); - sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); - pParse->schemaVerified = 1; - } + sqliteBeginWriteOperation(pParse); /* Initialize the counter of the number of rows deleted, if ** we are counting rows. @@ -156,9 +152,7 @@ void sqliteDeleteFrom( sqliteVdbeResolveLabel(v, end); sqliteVdbeAddOp(v, OP_ListReset, 0, 0); } - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Commit, 0, 0); - } + sqliteEndWriteOperation(pParse); /* ** Return the number of rows that were deleted. diff --git a/src/insert.c b/src/insert.c index ff7661387d..5632c76b47 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.38 2002/01/30 16:17:24 drh Exp $ +** $Id: insert.c,v 1.39 2002/01/31 15:54:22 drh Exp $ */ #include "sqliteInt.h" @@ -79,11 +79,7 @@ void sqliteInsert( */ v = sqliteGetVdbe(pParse); if( v==0 ) goto insert_cleanup; - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Transaction, 0, 0); - sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); - pParse->schemaVerified = 1; - } + sqliteBeginWriteOperation(pParse); /* Figure out how many columns of data are supplied. If the data ** is coming from a SELECT statement, then this step has to generate @@ -270,9 +266,7 @@ void sqliteInsert( for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ sqliteVdbeAddOp(v, OP_Close, idx+base, 0); } - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Commit, 0, 0); - } + sqliteEndWriteOperation(pParse); /* ** Return the number of rows inserted. @@ -312,8 +306,8 @@ insert_cleanup: ** N. The data in the last column of the entry after the update. ** ** The old recno shown as entry (1) above is omitted unless both isUpdate -** and recnoChng are both 1. isUpdate is true for UPDATEs and false for -** INSERTs and recnoChng is ture if the record number is being changed. +** and recnoChng are 1. isUpdate is true for UPDATEs and false for +** INSERTs and recnoChng is true if the record number is being changed. ** ** The code generated by this routine pushes additional entries onto ** the stack which are the keys for new index entries for the new record. @@ -323,18 +317,25 @@ insert_cleanup: ** ** This routine also generates code to check constraints. NOT NULL, ** CHECK, and UNIQUE constraints are all checked. If a constraint fails, -** then the appropriate action is performed. The default action is to -** execute OP_Halt to abort the transaction and cause sqlite_exec() to -** return SQLITE_CONSTRAINT. This is the so-called "ABORT" action. -** Other actions are REPLACE and IGNORE. The following table summarizes -** what happens. +** then the appropriate action is performed. There are five possible +** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE. ** ** Constraint type Action What Happens ** --------------- ---------- ---------------------------------------- -** any ABORT The current transaction is rolled back and +** any ROLLBACK The current transaction is rolled back and ** sqlite_exec() returns immediately with a ** return code of SQLITE_CONSTRAINT. ** +** any ABORT Back out changes from the current command +** only (do not do a complete rollback) then +** cause sqlite_exec() to return immediately +** with SQLITE_CONSTRAINT. +** +** any FAIL Sqlite_exec() returns immediately with a +** return code of SQLITE_CONSTRAINT. The +** transaction is not rolled back and any +** prior changes are retained. +** ** any IGNORE The record number and data is popped from ** the stack and there is an immediate jump ** to label ignoreDest. @@ -348,9 +349,10 @@ insert_cleanup: ** ** CHECK REPLACE Illegal. The results in an exception. ** -** The action to take is determined by the constraint itself if -** overrideError is OE_Default. Otherwise, overrideError determines -** which action to use. +** Which action to take is determined by the overrideError parameter. +** Or if overrideError==OE_Default, then the pParse->onError parameter +** is used. Or if pParse->onError==OE_Default then the onError value +** for the constraint is used. ** ** The calling routine must an open read/write cursor for pTab with ** cursor number "base". All indices of pTab must also have open @@ -390,6 +392,9 @@ void sqliteGenerateConstraintChecks( v = sqliteGetVdbe(pParse); assert( v!=0 ); nCol = pTab->nCol; + if( overrideError==OE_Default ){ + overrideError = pParse->db->onError; + } /* Test all NOT NULL constraints. */ @@ -402,6 +407,8 @@ void sqliteGenerateConstraintChecks( if( onError==OE_None ) continue; if( overrideError!=OE_Default ){ onError = overrideError; + }else if( onError==OE_Default ){ + onError = OE_Abort; } if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){ onError = OE_Abort; @@ -409,8 +416,10 @@ void sqliteGenerateConstraintChecks( sqliteVdbeAddOp(v, OP_Dup, nCol-1-i, 1); addr = sqliteVdbeAddOp(v, OP_NotNull, 0, 0); switch( onError ){ - case OE_Abort: { - sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, 0); + case OE_Rollback: + case OE_Abort: + case OE_Fail: { + sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); break; } case OE_Ignore: { @@ -441,10 +450,14 @@ void sqliteGenerateConstraintChecks( onError = pTab->keyConf; if( overrideError!=OE_Default ){ onError = overrideError; + }else if( onError==OE_Default ){ + onError = OE_Abort; } switch( onError ){ - case OE_Abort: { - sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, 0); + case OE_Rollback: + case OE_Abort: + case OE_Fail: { + sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); break; } case OE_Ignore: { @@ -479,12 +492,16 @@ void sqliteGenerateConstraintChecks( if( onError==OE_None ) continue; if( overrideError!=OE_Default ){ onError = overrideError; + }else if( onError==OE_Default ){ + onError = OE_Abort; } sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1); jumpInst = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0); switch( onError ){ - case OE_Abort: { - sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, 0); + case OE_Rollback: + case OE_Abort: + case OE_Fail: { + sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); break; } case OE_Ignore: { diff --git a/src/main.c b/src/main.c index 6d5f46f65c..5fa0cfe148 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.56 2002/01/16 21:00:27 drh Exp $ +** $Id: main.c,v 1.57 2002/01/31 15:54:22 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -276,6 +276,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){ sqliteHashInit(&db->tblDrop, SQLITE_HASH_POINTER, 0); sqliteHashInit(&db->idxDrop, SQLITE_HASH_POINTER, 0); db->nextRowid = sqliteRandomInteger(); + db->onError = OE_Default; /* Open the backend database driver */ rc = sqliteBtreeOpen(zFilename, mode, MAX_PAGES, &db->pBe); diff --git a/src/parse.y b/src/parse.y index c225cfb90a..ceaf764f8b 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.44 2002/01/30 16:17:24 drh Exp $ +** @(#) $Id: parse.y,v 1.45 2002/01/31 15:54:22 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -56,7 +56,7 @@ explain ::= EXPLAIN. {pParse->explain = 1;} ///////////////////// Begin and end transactions. //////////////////////////// // -cmd ::= BEGIN trans_opt. {sqliteBeginTransaction(pParse);} +cmd ::= BEGIN trans_opt onconf(R). {sqliteBeginTransaction(pParse,R);} trans_opt ::= . trans_opt ::= TRANSACTION. trans_opt ::= TRANSACTION ids. @@ -106,6 +106,7 @@ id(A) ::= KEY(X). {A = X;} id(A) ::= ABORT(X). {A = X;} id(A) ::= IGNORE(X). {A = X;} id(A) ::= REPLACE(X). {A = X;} +id(A) ::= FAIL(X). {A = X;} id(A) ::= CONFLICT(X). {A = X;} // And "ids" is an identifer-or-string. @@ -166,15 +167,17 @@ tcons ::= CHECK expr onconf. // default behavior when there is a constraint conflict. // %type onconf {int} -%type onconf_u {int} -%type confresolve {int} -onconf(A) ::= confresolve(X). { A = X; } -onconf(A) ::= onconf_u(X). { A = X; } -onconf_u(A) ::= ON CONFLICT confresolve(X). { A = X; } -onconf_u(A) ::= . { A = OE_Default; } -confresolve(A) ::= ABORT. { A = OE_Abort; } -confresolve(A) ::= IGNORE. { A = OE_Ignore; } -confresolve(A) ::= REPLACE. { A = OE_Replace; } +%type orconf {int} +%type resolvetype {int} +onconf(A) ::= . { A = OE_Default; } +onconf(A) ::= ON CONFLICT resolvetype(X). { A = X; } +orconf(A) ::= . { A = OE_Default; } +orconf(A) ::= OR resolvetype(X). { A = X; } +resolvetype(A) ::= ROLLBACK. { A = OE_Rollback; } +resolvetype(A) ::= ABORT. { A = OE_Abort; } +resolvetype(A) ::= FAIL. { A = OE_Fail; } +resolvetype(A) ::= IGNORE. { A = OE_Ignore; } +resolvetype(A) ::= REPLACE. { A = OE_Replace; } ////////////////////////// The DROP TABLE ///////////////////////////////////// // @@ -313,7 +316,7 @@ where_opt(A) ::= WHERE expr(X). {A = X;} ////////////////////////// The UPDATE command //////////////////////////////// // -cmd ::= UPDATE onconf_u(R) ids(X) SET setlist(Y) where_opt(Z). +cmd ::= UPDATE orconf(R) ids(X) SET setlist(Y) where_opt(Z). {sqliteUpdate(pParse,&X,Y,Z,R);} setlist(A) ::= setlist(Z) COMMA ids(X) EQ expr(Y). @@ -322,9 +325,9 @@ setlist(A) ::= ids(X) EQ expr(Y). {A = sqliteExprListAppend(0,Y,&X);} ////////////////////////// The INSERT command ///////////////////////////////// // -cmd ::= INSERT onconf(R) INTO ids(X) inscollist_opt(F) VALUES LP itemlist(Y) RP. +cmd ::= INSERT orconf(R) INTO ids(X) inscollist_opt(F) VALUES LP itemlist(Y) RP. {sqliteInsert(pParse, &X, Y, 0, F, R);} -cmd ::= INSERT onconf(R) INTO ids(X) inscollist_opt(F) select(S). +cmd ::= INSERT orconf(R) INTO ids(X) inscollist_opt(F) select(S). {sqliteInsert(pParse, &X, 0, S, F, R);} @@ -548,9 +551,9 @@ cmd ::= DROP INDEX ids(X). {sqliteDropIndex(pParse, &X);} ///////////////////////////// The COPY command /////////////////////////////// // -cmd ::= COPY onconf_u(R) ids(X) FROM ids(Y) USING DELIMITERS STRING(Z). +cmd ::= COPY orconf(R) ids(X) FROM ids(Y) USING DELIMITERS STRING(Z). {sqliteCopy(pParse,&X,&Y,&Z,R);} -cmd ::= COPY onconf_u(R) ids(X) FROM ids(Y). +cmd ::= COPY orconf(R) ids(X) FROM ids(Y). {sqliteCopy(pParse,&X,&Y,0,R);} ///////////////////////////// The VACUUM command ///////////////////////////// diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e0d81d9897..eb4630efb5 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.82 2002/01/30 16:17:24 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.83 2002/01/31 15:54:22 drh Exp $ */ #include "sqlite.h" #include "hash.h" @@ -183,6 +183,7 @@ struct sqlite { Hash idxDrop; /* Uncommitted DROP INDEXs */ int lastRowid; /* ROWID of most recent insert */ int nextRowid; /* Next generated rowID */ + int onError; /* Default conflict algorithm */ }; /* @@ -237,19 +238,31 @@ struct Table { }; /* -** SQLite supports three different ways to resolve a UNIQUE contraint -** error. (1) It can abort the transaction return SQLITE_CONSTRAINT. -** (2) It can decide to not do the INSERT or UPDATE that was causing -** the constraint violation. (3) It can delete existing records from -** the table so that the pending INSERT or UPDATE will work without -** a constraint error. The following there symbolic values are used -** to record which type of action to take. +** SQLite supports 4 or 5 different ways to resolve a contraint +** error. (Only 4 are implemented as of this writing. The fifth method +** "ABORT" is planned.) ROLLBACK processing means that a constraint violation +** causes the operation in proces to fail and for the current transaction +** to be rolled back. ABORT processing means the operation in process +** fails and any prior changes from that one operation are backed out, +** but the transaction is not rolled back. FAIL processing means that +** the operation in progress stops and returns an error code. But prior +** changes due to the same operation are not backed out and no rollback +** occurs. IGNORE means that the particular row that caused the constraint +** error is not inserted or updated. Processing continues and no error +** is returned. REPLACE means that preexisting database rows that caused +** a UNIQUE constraint violation are removed so that the new insert or +** update can proceed. Processing continues and no error is reported. +** +** The following there symbolic values are used to record which type +** of action to take. */ -#define OE_None 0 /* There is no constraint to check */ -#define OE_Abort 1 /* Abort and rollback. */ -#define OE_Ignore 2 /* Ignore the error. Do not do the INSERT or UPDATE */ -#define OE_Replace 3 /* Delete existing record, then do INSERT or UPDATE */ -#define OE_Default 9 /* Do whatever the default action is */ +#define OE_None 0 /* There is no constraint to check */ +#define OE_Rollback 1 /* Fail the operation and rollback the transaction */ +#define OE_Abort 2 /* Back out changes but do no rollback transaction */ +#define OE_Fail 3 /* Stop the operation but leave all prior changes */ +#define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */ +#define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */ +#define OE_Default 9 /* Do whatever the default action is */ /* ** Each SQL index is represented in memory by an @@ -542,7 +555,7 @@ void sqliteParseInfoReset(Parse*); Vdbe *sqliteGetVdbe(Parse*); int sqliteRandomByte(void); int sqliteRandomInteger(void); -void sqliteBeginTransaction(Parse*); +void sqliteBeginTransaction(Parse*, int); void sqliteCommitTransaction(Parse*); void sqliteRollbackTransaction(Parse*); char *sqlite_mprintf(const char *, ...); @@ -551,3 +564,5 @@ void sqliteGenerateRowDelete(Vdbe*, Table*, int); void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*); void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int); void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int); +void sqliteBeginWriteOperation(Parse*); +void sqliteEndWriteOperation(Parse*); diff --git a/src/tokenize.c b/src/tokenize.c index 0a8d0b6913..49922eaab3 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.33 2002/01/29 18:41:25 drh Exp $ +** $Id: tokenize.c,v 1.34 2002/01/31 15:54:22 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -62,6 +62,7 @@ static Keyword aKeywordTable[] = { { "END", 0, TK_END, 0 }, { "EXCEPT", 0, TK_EXCEPT, 0 }, { "EXPLAIN", 0, TK_EXPLAIN, 0 }, + { "FAIL", 0, TK_FAIL, 0 }, { "FROM", 0, TK_FROM, 0 }, { "GLOB", 0, TK_GLOB, 0 }, { "GROUP", 0, TK_GROUP, 0 }, diff --git a/src/update.c b/src/update.c index 51f648ec2c..4b3a71111e 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.31 2002/01/30 16:17:24 drh Exp $ +** $Id: update.c,v 1.32 2002/01/31 15:54:22 drh Exp $ */ #include "sqliteInt.h" @@ -161,11 +161,7 @@ void sqliteUpdate( */ v = sqliteGetVdbe(pParse); if( v==0 ) goto update_cleanup; - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Transaction, 0, 0); - sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); - pParse->schemaVerified = 1; - } + sqliteBeginWriteOperation(pParse); /* Begin the database scan */ @@ -282,9 +278,7 @@ void sqliteUpdate( sqliteVdbeAddOp(v, OP_Goto, 0, addr); sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v)); sqliteVdbeAddOp(v, OP_ListReset, 0, 0); - if( (db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_Commit, 0, 0); - } + sqliteEndWriteOperation(pParse); /* ** Return the number of rows that were changed. diff --git a/src/vdbe.c b/src/vdbe.c index 3949413c4b..acc6d33455 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -30,7 +30,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.112 2002/01/30 16:17:24 drh Exp $ +** $Id: vdbe.c,v 1.113 2002/01/31 15:54:22 drh Exp $ */ #include "sqliteInt.h" #include @@ -1072,6 +1072,7 @@ int sqliteVdbeExec( sqlite *db = p->db; /* The database */ char **zStack; /* Text stack */ Stack *aStack; /* Additional stack information */ + int rollbackOnError = 1; /* Do a ROLLBACK if an error is encountered */ char zBuf[100]; /* Space to sprintf() an integer */ @@ -1149,14 +1150,20 @@ case OP_Goto: { break; } -/* Opcode: Halt P1 * * +/* Opcode: Halt P1 P2 * ** ** Exit immediately. All open cursors, Lists, Sorts, etc are closed ** automatically. ** ** P1 is the result code returned by sqlite_exec(). For a normal ** halt, this should be SQLITE_OK (0). For errors, it can be some -** other value. +** other value. If P1!=0 then P2 will determine whether or not to +** rollback the current transaction. Do not rollback if P2==OE_Fail. +** Do the rollback if P2==OE_Rollback. If P2==OE_Abort, then back +** out all changes that have occurred during this execution of the +** VDBE, but do not rollback the transaction. (This last case has +** not yet been implemented. OE_Abort works like OE_Rollback for +** now. In the future that may change.) ** ** There is an implied "Halt 0 0 0" instruction inserted at the very end of ** every program. So a jump past the last instruction of the program @@ -1165,6 +1172,7 @@ case OP_Goto: { case OP_Halt: { if( pOp->p1!=SQLITE_OK ){ rc = pOp->p1; + rollbackOnError = pOp->p2!=OE_Fail; goto abort_due_to_error; }else{ pc = p->nOp-1; @@ -4458,12 +4466,13 @@ default: { cleanup: Cleanup(p); - if( rc!=SQLITE_OK ){ + if( rc!=SQLITE_OK && rollbackOnError ){ closeAllCursors(p); sqliteBtreeRollback(pBt); if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp); sqliteRollbackInternalChanges(db); db->flags &= ~SQLITE_InTrans; + db->onError = OE_Default; } return rc; diff --git a/test/conflict.test b/test/conflict.test index 0ae48f1879..0c91c769d3 100644 --- a/test/conflict.test +++ b/test/conflict.test @@ -13,7 +13,7 @@ # This file implements tests for the conflict resolution extension # to SQLite. # -# $Id: conflict.test,v 1.3 2002/01/30 16:17:25 drh Exp $ +# $Id: conflict.test,v 1.4 2002/01/31 15:54:23 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -36,37 +36,37 @@ do_test conflict-1.2 { } {1 {constraint failed}} do_test conflict-1.3 { catchsql { - INSERT ON CONFLICT IGNORE INTO t1 VALUES(1,2,4); + INSERT OR IGNORE INTO t1 VALUES(1,2,4); SELECT c FROM t1 ORDER BY c; } } {0 3} do_test conflict-1.4 { catchsql { - INSERT ON CONFLICT REPLACE INTO t1 VALUES(1,2,4); + INSERT OR REPLACE INTO t1 VALUES(1,2,4); SELECT c FROM t1 ORDER BY c; } } {0 4} do_test conflict-1.5 { catchsql { - INSERT ON CONFLICT ABORT INTO t1 VALUES(1,2,5); + INSERT OR ABORT INTO t1 VALUES(1,2,5); SELECT c FROM t1 ORDER BY c; } } {1 {constraint failed}} do_test conflict-1.6 { catchsql { - INSERT IGNORE INTO t1 VALUES(1,2,5); + INSERT OR IGNORE INTO t1 VALUES(1,2,5); SELECT c FROM t1 ORDER BY c; } } {0 4} do_test conflict-1.7 { catchsql { - INSERT REPLACE INTO t1 VALUES(1,2,5); + INSERT OR REPLACE INTO t1 VALUES(1,2,5); SELECT c FROM t1 ORDER BY c; } } {0 5} do_test conflict-1.8 { catchsql { - INSERT ON CONFLICT ABORT INTO t1 VALUES(1,2,6); + INSERT OR ABORT INTO t1 VALUES(1,2,6); SELECT c FROM t1 ORDER BY c; } } {1 {constraint failed}} @@ -89,13 +89,13 @@ do_test conflict-1.9 { } 8 do_test conflict-1.10 { catchsql { - INSERT IGNORE INTO t1 SELECT a,b,c FROM t2 ORDER BY c; + INSERT OR IGNORE INTO t1 SELECT a,b,c FROM t2 ORDER BY c; SELECT c FROM t1 ORDER BY c; } } {0 {5 21}} do_test conflict-1.11 { catchsql { - INSERT REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c; + INSERT OR REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c; SELECT c FROM t1 ORDER BY c; } } {0 {14 24}} @@ -103,7 +103,7 @@ do_test conflict-1.11 { ###### Fix me! do_test conflict-1.12 { catchsql { - INSERT REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c DESC; + INSERT OR REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c DESC; SELECT c FROM t1 ORDER BY c; } } {0 {14 24}} @@ -121,7 +121,7 @@ do_test conflict-1.13 { } {1 2 3 1 3 4 2 3 5} do_test conflict-1.14 { catchsql { - UPDATE ON CONFLICT ABORT t1 SET b=3 WHERE b=2; + UPDATE OR ABORT t1 SET b=3 WHERE b=2; SELECT c FROM t1 ORDER BY c; } } {1 {constraint failed}}; @@ -133,13 +133,13 @@ do_test conflict-1.15 { } {1 {constraint failed}}; do_test conflict-1.16 { catchsql { - UPDATE ON CONFLICT IGNORE t1 SET b=3 WHERE b=2; + UPDATE OR IGNORE t1 SET b=3 WHERE b=2; SELECT * FROM t1 ORDER BY c; } } {0 {1 2 3 1 3 4 2 3 5}} do_test conflict-1.17 { catchsql { - UPDATE ON CONFLICT REPLACE t1 SET b=3 WHERE b=2; + UPDATE OR REPLACE t1 SET b=3 WHERE b=2; SELECT * FROM t1 ORDER BY c; } } {0 {1 3 3 2 3 5}} @@ -163,37 +163,37 @@ do_test conflict-2.2 { } {1 {constraint failed}} do_test conflict-2.3 { catchsql { - INSERT ON CONFLICT IGNORE INTO t1 VALUES(1,2,4); + INSERT OR IGNORE INTO t1 VALUES(1,2,4); SELECT c FROM t1 ORDER BY c; } } {0 3} do_test conflict-2.4 { catchsql { - INSERT ON CONFLICT REPLACE INTO t1 VALUES(1,2,4); + INSERT OR REPLACE INTO t1 VALUES(1,2,4); SELECT c FROM t1 ORDER BY c; } } {0 4} do_test conflict-2.5 { catchsql { - INSERT ON CONFLICT ABORT INTO t1 VALUES(1,2,5); + INSERT OR ABORT INTO t1 VALUES(1,2,5); SELECT c FROM t1 ORDER BY c; } } {1 {constraint failed}} do_test conflict-2.6 { catchsql { - INSERT IGNORE INTO t1 VALUES(1,2,5); + INSERT OR IGNORE INTO t1 VALUES(1,2,5); SELECT c FROM t1 ORDER BY c; } } {0 4} do_test conflict-2.7 { catchsql { - INSERT REPLACE INTO t1 VALUES(1,2,5); + INSERT OR REPLACE INTO t1 VALUES(1,2,5); SELECT c FROM t1 ORDER BY c; } } {0 5} do_test conflict-2.8 { catchsql { - INSERT ON CONFLICT ABORT INTO t1 VALUES(1,2,6); + INSERT OR ABORT INTO t1 VALUES(1,2,6); SELECT c FROM t1 ORDER BY c; } } {1 {constraint failed}} @@ -216,13 +216,13 @@ do_test conflict-2.9 { } 8 do_test conflict-2.10 { catchsql { - INSERT IGNORE INTO t1 SELECT a,b,c FROM t2 ORDER BY c; + INSERT OR IGNORE INTO t1 SELECT a,b,c FROM t2 ORDER BY c; SELECT c FROM t1 ORDER BY c; } } {0 {5 21}} do_test conflict-2.11 { catchsql { - INSERT REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c; + INSERT OR REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c; SELECT c FROM t1 ORDER BY c; } } {0 {14 24}} @@ -230,7 +230,7 @@ do_test conflict-2.11 { ###### Fix me! do_test conflict-2.12 { catchsql { - INSERT REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c DESC; + INSERT OR REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c DESC; SELECT c FROM t1 ORDER BY c; } } {0 {14 24}} @@ -248,7 +248,7 @@ do_test conflict-2.13 { } {1 2 3 2 3 4 3 3 5} do_test conflict-2.14 { catchsql { - UPDATE ON CONFLICT ABORT t1 SET a=2, b=3 WHERE b=2; + UPDATE OR ABORT t1 SET a=2, b=3 WHERE b=2; SELECT c FROM t1 ORDER BY c; } } {1 {constraint failed}}; @@ -260,13 +260,13 @@ do_test conflict-2.15 { } {1 {constraint failed}}; do_test conflict-2.16 { catchsql { - UPDATE ON CONFLICT IGNORE t1 SET a=2, b=3 WHERE b=2; + UPDATE OR IGNORE t1 SET a=2, b=3 WHERE b=2; SELECT * FROM t1 ORDER BY c; } } {0 {1 2 3 2 3 4 3 3 5}} do_test conflict-2.17 { catchsql { - UPDATE ON CONFLICT REPLACE t1 SET a=2, b=3 WHERE b=2; + UPDATE OR REPLACE t1 SET a=2, b=3 WHERE b=2; SELECT * FROM t1 ORDER BY c; } } {0 {2 3 3 3 3 5}} diff --git a/test/copy.test b/test/copy.test index 057217effc..db0aa2b31d 100644 --- a/test/copy.test +++ b/test/copy.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the COPY statement. # -# $Id: copy.test,v 1.7 2002/01/30 16:17:25 drh Exp $ +# $Id: copy.test,v 1.8 2002/01/31 15:54:23 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -194,7 +194,7 @@ do_test copy-5.3 { puts $fd "33|22|44" close $fd catchsql { - COPY ON CONFLICT IGNORE t1 FROM 'data6.txt' USING DELIMITERS '|'; + COPY OR IGNORE t1 FROM 'data6.txt' USING DELIMITERS '|'; SELECT * FROM t1; } } {0 {11 22 33 22 33 11}} @@ -203,7 +203,7 @@ do_test copy-5.4 { puts $fd "33|22|44" close $fd catchsql { - COPY ON CONFLICT REPLACE t1 FROM 'data6.txt' USING DELIMITERS '|'; + COPY OR REPLACE t1 FROM 'data6.txt' USING DELIMITERS '|'; SELECT * FROM t1; } } {0 {22 33 11 33 22 44}} diff --git a/test/notnull.test b/test/notnull.test index 014fb97b38..2ae67b40ac 100644 --- a/test/notnull.test +++ b/test/notnull.test @@ -12,7 +12,7 @@ # # This file implements tests for the NOT NULL constraint. # -# $Id: notnull.test,v 1.1 2002/01/30 04:32:01 drh Exp $ +# $Id: notnull.test,v 1.2 2002/01/31 15:54:23 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -22,9 +22,9 @@ do_test notnull-1.0 { CREATE TABLE t1 ( a NOT NULL, b NOT NULL DEFAULT 5, - c NOT NULL REPLACE DEFAULT 6, - d NOT NULL IGNORE DEFAULT 7, - e NOT NULL ABORT DEFAULT 8 + c NOT NULL ON CONFLICT REPLACE DEFAULT 6, + d NOT NULL ON CONFLICT IGNORE DEFAULT 7, + e NOT NULL ON CONFLICT ABORT DEFAULT 8 ); SELECT * FROM t1; } @@ -46,21 +46,21 @@ do_test notnull-1.2 { do_test notnull-1.3 { catchsql { DELETE FROM t1; - INSERT IGNORE INTO t1(b,c,d,e) VALUES(2,3,4,5); + INSERT OR IGNORE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} do_test notnull-1.4 { catchsql { DELETE FROM t1; - INSERT REPLACE INTO t1(b,c,d,e) VALUES(2,3,4,5); + INSERT OR REPLACE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {constraint failed}} do_test notnull-1.5 { catchsql { DELETE FROM t1; - INSERT ABORT INTO t1(b,c,d,e) VALUES(2,3,4,5); + INSERT OR ABORT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {constraint failed}} @@ -74,21 +74,21 @@ do_test notnull-1.6 { do_test notnull-1.7 { catchsql { DELETE FROM t1; - INSERT IGNORE INTO t1(a,c,d,e) VALUES(1,3,4,5); + INSERT OR IGNORE INTO t1(a,c,d,e) VALUES(1,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} do_test notnull-1.8 { catchsql { DELETE FROM t1; - INSERT REPLACE INTO t1(a,c,d,e) VALUES(1,3,4,5); + INSERT OR REPLACE INTO t1(a,c,d,e) VALUES(1,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} do_test notnull-1.9 { catchsql { DELETE FROM t1; - INSERT ABORT INTO t1(a,c,d,e) VALUES(1,3,4,5); + INSERT OR ABORT INTO t1(a,c,d,e) VALUES(1,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} @@ -102,14 +102,14 @@ do_test notnull-1.10 { do_test notnull-1.11 { catchsql { DELETE FROM t1; - INSERT IGNORE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); + INSERT OR IGNORE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} do_test notnull-1.12 { catchsql { DELETE FROM t1; - INSERT REPLACE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); + INSERT OR REPLACE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} @@ -123,35 +123,35 @@ do_test notnull-1.13 { do_test notnull-1.14 { catchsql { DELETE FROM t1; - INSERT IGNORE INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); + INSERT OR IGNORE INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } } {0 {}} do_test notnull-1.15 { catchsql { DELETE FROM t1; - INSERT REPLACE INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); + INSERT OR REPLACE INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } } {0 {1 2 6 4 5}} do_test notnull-1.16 { catchsql { DELETE FROM t1; - INSERT ABORT INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); + INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } } {1 {constraint failed}} do_test notnull-1.17 { catchsql { DELETE FROM t1; - INSERT ABORT INTO t1(a,b,c,d,e) VALUES(1,2,3,null,5); + INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {1 {constraint failed}} do_test notnull-1.18 { catchsql { DELETE FROM t1; - INSERT ABORT INTO t1(a,b,c,e) VALUES(1,2,3,5); + INSERT OR ABORT INTO t1(a,b,c,e) VALUES(1,2,3,5); SELECT * FROM t1 order by a; } } {0 {1 2 3 7 5}} @@ -172,7 +172,7 @@ do_test notnull-1.20 { do_test notnull-1.21 { catchsql { DELETE FROM t1; - INSERT REPLACE INTO t1(e,d,c,b,a) VALUES(1,2,3,null,5); + INSERT OR REPLACE INTO t1(e,d,c,b,a) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {0 {5 5 3 2 1}} @@ -189,7 +189,7 @@ do_test notnull-2.2 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); - UPDATE ON CONFLICT REPLACE t1 SET a=null; + UPDATE OR REPLACE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {constraint failed}} @@ -197,7 +197,7 @@ do_test notnull-2.3 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); - UPDATE ON CONFLICT IGNORE t1 SET a=null; + UPDATE OR IGNORE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {0 {1 2 3 4 5}} @@ -205,7 +205,7 @@ do_test notnull-2.4 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); - UPDATE ON CONFLICT ABORT t1 SET a=null; + UPDATE OR ABORT t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {constraint failed}} @@ -221,7 +221,7 @@ do_test notnull-2.6 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); - UPDATE ON CONFLICT REPLACE t1 SET b=null, d=e, e=d; + UPDATE OR REPLACE t1 SET b=null, d=e, e=d; SELECT * FROM t1 ORDER BY a; } } {0 {1 5 3 5 4}} @@ -229,7 +229,7 @@ do_test notnull-2.7 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); - UPDATE ON CONFLICT IGNORE t1 SET b=null, d=e, e=d; + UPDATE OR IGNORE t1 SET b=null, d=e, e=d; SELECT * FROM t1 ORDER BY a; } } {0 {1 2 3 4 5}} @@ -285,21 +285,21 @@ do_test notnull-3.2 { do_test notnull-3.3 { catchsql { DELETE FROM t1; - INSERT IGNORE INTO t1(b,c,d,e) VALUES(2,3,4,5); + INSERT OR IGNORE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} do_test notnull-3.4 { catchsql { DELETE FROM t1; - INSERT REPLACE INTO t1(b,c,d,e) VALUES(2,3,4,5); + INSERT OR REPLACE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {constraint failed}} do_test notnull-3.5 { catchsql { DELETE FROM t1; - INSERT ABORT INTO t1(b,c,d,e) VALUES(2,3,4,5); + INSERT OR ABORT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {constraint failed}} @@ -313,21 +313,21 @@ do_test notnull-3.6 { do_test notnull-3.7 { catchsql { DELETE FROM t1; - INSERT IGNORE INTO t1(a,c,d,e) VALUES(1,3,4,5); + INSERT OR IGNORE INTO t1(a,c,d,e) VALUES(1,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} do_test notnull-3.8 { catchsql { DELETE FROM t1; - INSERT REPLACE INTO t1(a,c,d,e) VALUES(1,3,4,5); + INSERT OR REPLACE INTO t1(a,c,d,e) VALUES(1,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} do_test notnull-3.9 { catchsql { DELETE FROM t1; - INSERT ABORT INTO t1(a,c,d,e) VALUES(1,3,4,5); + INSERT OR ABORT INTO t1(a,c,d,e) VALUES(1,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} @@ -341,14 +341,14 @@ do_test notnull-3.10 { do_test notnull-3.11 { catchsql { DELETE FROM t1; - INSERT IGNORE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); + INSERT OR IGNORE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} do_test notnull-3.12 { catchsql { DELETE FROM t1; - INSERT REPLACE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); + INSERT OR REPLACE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} @@ -362,35 +362,35 @@ do_test notnull-3.13 { do_test notnull-3.14 { catchsql { DELETE FROM t1; - INSERT IGNORE INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); + INSERT OR IGNORE INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } } {0 {}} do_test notnull-3.15 { catchsql { DELETE FROM t1; - INSERT REPLACE INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); + INSERT OR REPLACE INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } } {0 {1 2 6 4 5}} do_test notnull-3.16 { catchsql { DELETE FROM t1; - INSERT ABORT INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); + INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } } {1 {constraint failed}} do_test notnull-3.17 { catchsql { DELETE FROM t1; - INSERT ABORT INTO t1(a,b,c,d,e) VALUES(1,2,3,null,5); + INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {1 {constraint failed}} do_test notnull-3.18 { catchsql { DELETE FROM t1; - INSERT ABORT INTO t1(a,b,c,e) VALUES(1,2,3,5); + INSERT OR ABORT INTO t1(a,b,c,e) VALUES(1,2,3,5); SELECT * FROM t1 order by a; } } {0 {1 2 3 7 5}} @@ -411,7 +411,7 @@ do_test notnull-3.20 { do_test notnull-3.21 { catchsql { DELETE FROM t1; - INSERT REPLACE INTO t1(e,d,c,b,a) VALUES(1,2,3,null,5); + INSERT OR REPLACE INTO t1(e,d,c,b,a) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {0 {5 5 3 2 1}} @@ -428,7 +428,7 @@ do_test notnull-4.2 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); - UPDATE ON CONFLICT REPLACE t1 SET a=null; + UPDATE OR REPLACE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {constraint failed}} @@ -436,7 +436,7 @@ do_test notnull-4.3 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); - UPDATE ON CONFLICT IGNORE t1 SET a=null; + UPDATE OR IGNORE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {0 {1 2 3 4 5}} @@ -444,7 +444,7 @@ do_test notnull-4.4 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); - UPDATE ON CONFLICT ABORT t1 SET a=null; + UPDATE OR ABORT t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {constraint failed}} @@ -460,7 +460,7 @@ do_test notnull-4.6 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); - UPDATE ON CONFLICT REPLACE t1 SET b=null, d=e, e=d; + UPDATE OR REPLACE t1 SET b=null, d=e, e=d; SELECT * FROM t1 ORDER BY a; } } {0 {1 5 3 5 4}} @@ -468,7 +468,7 @@ do_test notnull-4.7 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); - UPDATE ON CONFLICT IGNORE t1 SET b=null, d=e, e=d; + UPDATE OR IGNORE t1 SET b=null, d=e, e=d; SELECT * FROM t1 ORDER BY a; } } {0 {1 2 3 4 5}} diff --git a/www/download.tcl b/www/download.tcl index 105b8c1243..b8a7fddd69 100644 --- a/www/download.tcl +++ b/www/download.tcl @@ -1,7 +1,7 @@ # # Run this TCL script to generate HTML for the download.html file. # -set rcsid {$Id: download.tcl,v 1.2 2001/11/24 13:23:05 drh Exp $} +set rcsid {$Id: download.tcl,v 1.3 2002/01/31 15:54:23 drh Exp $} puts { SQLite Download Page @@ -41,6 +41,11 @@ Product tclsqlite.so.gz { See the documentation for details. } +Product sqlite.so.gz { + A precompiled shared-library for Linux. This is the same as + tclsqlite.so.gz but without the TCL bindings. +} + puts {

Precompiled Binaries For Windows

} Product sqlite.zip { @@ -52,9 +57,21 @@ Product tclsqlite.zip { tclsh or wish to get SQLite database access from Tcl/Tk. See the documentation for details. } +Product sqlitedll.zip { + This is a DLL of the SQLite library without the TCL bindings. + The only external dependency is MSVCRT.DLL. +} puts {

Source Code

} +Product {sqlite_source.zip} { + This ZIP archive contains pure C source code for the SQLite library. + Unlike the tarballs below, all of the preprocessing has already been + done on these C source code, so you can just hand the files directly to + your favorite C compiler. This file is provided as a service to + MS-Windows users who lack the build support infrastructure of Unix. +} + foreach name [lsort -dict -decreasing [glob -nocomplain sqlite-*.tar.gz]] { regexp {sqlite-(.*)\.tar\.gz} $name match vers Product $name " diff --git a/www/lang.tcl b/www/lang.tcl index a766eabd66..2bb0104248 100644 --- a/www/lang.tcl +++ b/www/lang.tcl @@ -1,7 +1,7 @@ # # Run this Tcl script to generate the sqlite.html file. # -set rcsid {$Id: lang.tcl,v 1.19 2002/01/30 16:17:25 drh Exp $} +set rcsid {$Id: lang.tcl,v 1.20 2002/01/31 15:54:23 drh Exp $} puts { @@ -333,6 +333,11 @@ default algorithm specified in the CREATE TABLE statement. See the section titled ON CONFLICT for additional information.

+

CHECK constraints are ignored in the current implementation. +Support for CHECK constraints may be added in the future. As of +version 2.3.0, NOT NULL, PRIMARY KEY, and UNIQUE constraints all +work.

+

There are no arbitrary limits on the number of columns or on the number of constraints in a table. The total amount of data in a single row is limited to about