From 355c53b6ef9c15e883f087c93d3f9508c2b2a033 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 19 Apr 2011 06:43:22 +0000 Subject: [PATCH 01/22] Avoid passing NULL to the xOpen method of an FTS3/4 tokenizer. FossilOrigin-Name: 0dd09fc034c127718366d3a3183e367d2f9fd82d --- ext/fts3/fts3_write.c | 16 +++++++++++----- manifest | 16 ++++++++-------- manifest.uuid | 2 +- test/fts3atoken.test | 12 ++++++++++++ 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 1e71874384..1a00f8a961 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -542,6 +542,14 @@ static int fts3PendingTermsAdd( assert( pTokenizer && pModule ); + /* If the user has inserted a NULL value, this function may be called with + ** zText==0. In this case, add zero token entries to the hash table and + ** return early. */ + if( zText==0 ){ + *pnWord = 0; + return SQLITE_OK; + } + rc = pModule->xOpen(pTokenizer, zText, -1, &pCsr); if( rc!=SQLITE_OK ){ return rc; @@ -632,11 +640,9 @@ static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal, u32 *aSz){ int i; /* Iterator variable */ for(i=2; inColumn+2; i++){ const char *zText = (const char *)sqlite3_value_text(apVal[i]); - if( zText ){ - int rc = fts3PendingTermsAdd(p, zText, i-2, &aSz[i-2]); - if( rc!=SQLITE_OK ){ - return rc; - } + int rc = fts3PendingTermsAdd(p, zText, i-2, &aSz[i-2]); + if( rc!=SQLITE_OK ){ + return rc; } aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]); } diff --git a/manifest b/manifest index 9f1f44ec21..166c7ddd75 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sprototype\sfor\sthe\sopen()\ssystem\scall\sto\sagree\swith\sPosix.\s\sThough\na\sfaulty\sfunction\sprototype\sin\sa\spointer\scast\sis\sa\sseemingly\sinnocuous\serror,\s\nthe\scorrect\sprototype\sis\snecessary\sfor\spthreads\sto\swork\scorrectly\son\sNetBSD. -D 2011-04-17T17:09:58.565 +C Avoid\spassing\sNULL\sto\sthe\sxOpen\smethod\sof\san\sFTS3/4\stokenizer. +D 2011-04-19T06:43:22.111 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -74,7 +74,7 @@ F ext/fts3/fts3_snippet.c e857c6a89d81d3b89df59f3b44b35c68d8ed5c62 F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3 F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d -F ext/fts3/fts3_write.c 813495ed106eb9461044e3c0374f4db69b37eb09 +F ext/fts3/fts3_write.c c0af09a04021926d7d84094fa950defc9213416d F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9 @@ -450,7 +450,7 @@ F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8 F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18 F test/fts3ao.test b83f99f70e9eec85f27d75801a974b3f820e01f9 -F test/fts3atoken.test 25c2070e1e8755d414bf9c8200427b277a9f99fa +F test/fts3atoken.test bbb9e63a915f3df0e35d06e0add932b5bf2d54a9 F test/fts3aux1.test 719c35cbbcc04dde8e5a54a6f69851a0af9ed1f2 F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 @@ -929,7 +929,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 9d6c6129fd8be42c164f14bb90011b252c1f2c46 -R 4ae7f108651e5730cd8c416e7800e26e -U drh -Z 939cf52c691885a86594e39d90974750 +P 3e135748f1efacb52b414b3ac3f4ae2c08bcd8fb +R a6226e702419163cd5db7bb5053e7329 +U dan +Z 2b55d93cd349a17e33ad50a5d9dd90a0 diff --git a/manifest.uuid b/manifest.uuid index 2958ad9dcd..55819abd1a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3e135748f1efacb52b414b3ac3f4ae2c08bcd8fb \ No newline at end of file +0dd09fc034c127718366d3a3183e367d2f9fd82d \ No newline at end of file diff --git a/test/fts3atoken.test b/test/fts3atoken.test index cf9574e860..d4c4825004 100644 --- a/test/fts3atoken.test +++ b/test/fts3atoken.test @@ -24,6 +24,8 @@ ifcapable !fts3 { return } +set ::testprefix fts3token + proc escape_string {str} { set out "" foreach char [split $str ""] { @@ -167,8 +169,18 @@ ifcapable icu { do_icu_test fts3token-4.8 en_US $input $output } +do_execsql_test 5.1 { + CREATE VIRTUAL TABLE x1 USING fts3(name,TOKENIZE icu en_US); + insert into x1 (name) values (NULL); + insert into x1 (name) values (NULL); + delete from x1; +} + do_test fts3token-internal { execsql { SELECT fts3_tokenizer_internal_test() } } {ok} + finish_test + + From fc083ab9731a59ceeece88453a097297260d414e Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 20 Apr 2011 13:35:44 +0000 Subject: [PATCH 02/22] Update a comment in e_createtable.test. FossilOrigin-Name: d8b149f5e465f7794739ed0210e1e5c53110ee9a --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/e_createtable.test | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 166c7ddd75..bcd5754bbe 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\spassing\sNULL\sto\sthe\sxOpen\smethod\sof\san\sFTS3/4\stokenizer. -D 2011-04-19T06:43:22.111 +C Update\sa\scomment\sin\se_createtable.test. +D 2011-04-20T13:35:44.094 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -365,7 +365,7 @@ F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d F test/descidx3.test fe720e8b37d59f4cef808b0bf4e1b391c2e56b6f F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 -F test/e_createtable.test b40fc61bc4f1ad2a3c84590bd1d711507263d921 +F test/e_createtable.test 4771686a586b6ae414f927c389b2c101cc05c028 F test/e_delete.test 55d868b647acc091c261a10b9b0cb0ab660a6acb F test/e_droptrigger.test ddd4b28ed8a3d81bd5153fa0ab7559529a2ca03a F test/e_dropview.test b347bab30fc8de67b131594b3cd6f3d3bdaa753d @@ -929,7 +929,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 3e135748f1efacb52b414b3ac3f4ae2c08bcd8fb -R a6226e702419163cd5db7bb5053e7329 +P 0dd09fc034c127718366d3a3183e367d2f9fd82d +R 056a0ea57c930302e35ea6c4f7c5b4b7 U dan -Z 2b55d93cd349a17e33ad50a5d9dd90a0 +Z b72241c9e230cb141bfcaf5fbf022480 diff --git a/manifest.uuid b/manifest.uuid index 55819abd1a..fde4759710 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0dd09fc034c127718366d3a3183e367d2f9fd82d \ No newline at end of file +d8b149f5e465f7794739ed0210e1e5c53110ee9a \ No newline at end of file diff --git a/test/e_createtable.test b/test/e_createtable.test index c67195ed77..f61db1cd61 100644 --- a/test/e_createtable.test +++ b/test/e_createtable.test @@ -989,9 +989,9 @@ do_execsql_test e_createtable-3.7.4 { SELECT quote(a), quote(b) FROM t6; } {1 2 'X' 3 1 4 'X' 5} -# EVIDENCE-OF: R-18683-56219 If the default value of a column is -# CURRENT_TIME, CURRENT_DATE or CURRENT_DATETIME, then the value used in -# the new row is a text representation of the current UTC date and/or +# EVIDENCE-OF: R-15363-55230 If the default value of a column is +# CURRENT_TIME, CURRENT_DATE or CURRENT_TIMESTAMP, then the value used +# in the new row is a text representation of the current UTC date and/or # time. # # This is difficult to test literally without knowing what time the From 092e4bdb9119a1365a8919ef18d646cb5ab09ee0 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 22 Apr 2011 22:55:10 +0000 Subject: [PATCH 03/22] Add the "getlock" utility for determining if a database file (on unix) is currently locked. FossilOrigin-Name: 0ab24b133e332ad7f4517b8e113e9c241ee9af9f --- manifest | 13 ++--- manifest.uuid | 2 +- tool/getlock.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 tool/getlock.c diff --git a/manifest b/manifest index bcd5754bbe..65bc4f3b22 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sa\scomment\sin\se_createtable.test. -D 2011-04-20T13:35:44.094 +C Add\sthe\s"getlock"\sutility\sfor\sdetermining\sif\sa\sdatabase\sfile\s(on\sunix)\sis\ncurrently\slocked. +D 2011-04-22T22:55:10.113 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -899,6 +899,7 @@ F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 +F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/lemon.c dfd81a51b6e27e469ba21d01a75ddf092d429027 F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309 @@ -929,7 +930,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 0dd09fc034c127718366d3a3183e367d2f9fd82d -R 056a0ea57c930302e35ea6c4f7c5b4b7 -U dan -Z b72241c9e230cb141bfcaf5fbf022480 +P d8b149f5e465f7794739ed0210e1e5c53110ee9a +R 46d4cc9c199137dd735f2ac252175f1e +U drh +Z 48df56ba9c3ee078a0d4702e2f08ce89 diff --git a/manifest.uuid b/manifest.uuid index fde4759710..92d78b219d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d8b149f5e465f7794739ed0210e1e5c53110ee9a \ No newline at end of file +0ab24b133e332ad7f4517b8e113e9c241ee9af9f \ No newline at end of file diff --git a/tool/getlock.c b/tool/getlock.c new file mode 100644 index 0000000000..7eff04d7f9 --- /dev/null +++ b/tool/getlock.c @@ -0,0 +1,134 @@ +/* +** This utility program looks at an SQLite database and determines whether +** or not it is locked, the kind of lock, and who is holding this lock. +** +** This only works on unix when the posix advisory locking method is used +** (which is the default on unix) and when the PENDING_BYTE is in its +** usual place. +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +static void usage(const char *argv0){ + fprintf(stderr, "Usage: %s database\n", argv0); + exit(1); +} + +/* Check for a conflicting lock. If one is found, print an this +** on standard output using the format string given and return 1. +** If there are no conflicting locks, return 0. +*/ +static int isLocked( + int h, /* File descriptor to check */ + int type, /* F_RDLCK or F_WRLCK */ + unsigned int iOfst, /* First byte of the lock */ + unsigned int iCnt, /* Number of bytes in the lock range */ + const char *zType /* Type of lock */ +){ + struct flock lk; + + memset(&lk, 0, sizeof(lk)); + lk.l_type = type; + lk.l_whence = SEEK_SET; + lk.l_start = iOfst; + lk.l_len = iCnt; + if( fcntl(h, F_GETLK, &lk)==(-1) ){ + fprintf(stderr, "fcntl(%d) failed: errno=%d\n", h, errno); + exit(1); + } + if( lk.l_type==F_UNLCK ) return 0; + printf("%s lock held by %d\n", zType, (int)lk.l_pid); + return 1; +} + +/* +** Location of locking bytes in the database file +*/ +#define PENDING_BYTE (0x40000000) +#define RESERVED_BYTE (PENDING_BYTE+1) +#define SHARED_FIRST (PENDING_BYTE+2) +#define SHARED_SIZE 510 + +/* +** Lock locations for shared-memory locks used by WAL mode. +*/ +#define SHM_BASE 120 +#define SHM_WRITE SHM_BASE +#define SHM_CHECKPOINT (SHM_BASE+1) +#define SHM_RECOVER (SHM_BASE+2) +#define SHM_READ_FIRST (SHM_BASE+3) +#define SHM_READ_SIZE 5 + + +int main(int argc, char **argv){ + int hDb; /* File descriptor for the open database file */ + int hShm; /* File descriptor for WAL shared-memory file */ + char *zShm; /* Name of the shared-memory file for WAL mode */ + ssize_t got; /* Bytes read from header */ + int isWal; /* True if in WAL mode */ + int nName; /* Length of filename */ + unsigned char aHdr[100]; /* Database header */ + int nLock = 0; /* Number of locks held */ + int i; /* Loop counter */ + + if( argc!=2 ) usage(argv[0]); + hDb = open(argv[1], O_RDONLY, 0); + if( hDb<0 ){ + fprintf(stderr, "cannot open %s\n", argv[1]); + return 1; + } + + /* Make sure we are dealing with an database file */ + got = read(hDb, aHdr, 100); + if( got!=100 || memcmp(aHdr, "SQLite format 3",16)!=0 ){ + fprintf(stderr, "not an SQLite database: %s\n", argv[1]); + exit(1); + } + + /* First check for an exclusive lock */ + if( isLocked(hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE") ){ + return 0; + } + isWal = aHdr[18]==2; + if( isWal==0 ){ + /* Rollback mode */ + if( isLocked(hDb, F_RDLCK, PENDING_BYTE, 1, "PENDING") ) return 0; + if( isLocked(hDb, F_RDLCK, RESERVED_BYTE, 1, "RESERVED") ) return 0; + if( isLocked(hDb, F_WRLCK, SHARED_FIRST, SHARED_SIZE, "SHARED") ){ + return 0; + } + }else{ + /* WAL mode */ + nName = (int)strlen(argv[1]); + zShm = malloc( nName + 100 ); + if( zShm==0 ){ + fprintf(stderr, "out of memory\n"); + exit(1); + } + memcpy(zShm, argv[1], nName); + memcpy(&zShm[nName], "-shm", 5); + hShm = open(zShm, O_RDONLY, 0); + if( hShm<0 ){ + fprintf(stderr, "cannot open %s\n", zShm); + return 1; + } + if( isLocked(hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ){ + return 0; + } + nLock += isLocked(hShm, F_RDLCK, SHM_CHECKPOINT, 1, "WAL-CHECKPOINT"); + nLock += isLocked(hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE"); + for(i=0; i Date: Sun, 24 Apr 2011 22:56:07 +0000 Subject: [PATCH 04/22] Disable the transfer optimization if the destination table contains any foreign key constraint and foreign key constraints are enabled. Ticket [6284df89debdf]. FossilOrigin-Name: ddeea5ab5f6c0c4a86cdfbbb9f24d9d54bf8d301 --- manifest | 14 +++++------ manifest.uuid | 2 +- src/insert.c | 12 ++++++++++ test/insert4.test | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 65bc4f3b22..8eaf915520 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\s"getlock"\sutility\sfor\sdetermining\sif\sa\sdatabase\sfile\s(on\sunix)\sis\ncurrently\slocked. -D 2011-04-22T22:55:10.113 +C Disable\sthe\stransfer\soptimization\sif\sthe\sdestination\stable\scontains\nany\sforeign\skey\sconstraint\sand\sforeign\skey\sconstraints\sare\senabled.\nTicket\s[6284df89debdf]. +D 2011-04-24T22:56:07.596 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -138,7 +138,7 @@ F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c acfb89fe4a73d703e425e167bfcc72985f4299ae +F src/insert.c cdee360e5cea59db6c4a980e4360499631222af6 F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e @@ -505,7 +505,7 @@ F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908 F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30 -F test/insert4.test c1469999a58e86a85b74df645a820f4cc7a8273b +F test/insert4.test b3e02648a5fc3075c29e13c369b5127bf859b5a2 F test/insert5.test 1f93cbe9742110119133d7e8e3ccfe6d7c249766 F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4 F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1 @@ -930,7 +930,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P d8b149f5e465f7794739ed0210e1e5c53110ee9a -R 46d4cc9c199137dd735f2ac252175f1e +P 0ab24b133e332ad7f4517b8e113e9c241ee9af9f +R 40e74cf200b39d155b455f390ce862eb U drh -Z 48df56ba9c3ee078a0d4702e2f08ce89 +Z 87bc3e585b95e6d3397bca153c02ab82 diff --git a/manifest.uuid b/manifest.uuid index 92d78b219d..6503aa6c35 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0ab24b133e332ad7f4517b8e113e9c241ee9af9f \ No newline at end of file +ddeea5ab5f6c0c4a86cdfbbb9f24d9d54bf8d301 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 588a84f36d..02456e776f 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1734,6 +1734,18 @@ static int xferOptimization( return 0; /* Tables have different CHECK constraints. Ticket #2252 */ } #endif +#ifndef SQLITE_OMIT_FOREIGN_KEY + /* Disallow the transfer optimization if the destination table constains + ** any foreign key constraints. This is more restrictive than necessary. + ** But the main beneficiary of the transfer optimization is the VACUUM + ** command, and the VACUUM command disables foreign key constraints. So + ** the extra complication to make this rule less restrictive is probably + ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] + */ + if( (pParse->db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ + return 0; + } +#endif /* If we get this far, it means either: ** diff --git a/test/insert4.test b/test/insert4.test index 0b069e996d..44b428a1c7 100644 --- a/test/insert4.test +++ b/test/insert4.test @@ -326,4 +326,64 @@ do_test insert4-6.7 { } } {1 {constraint failed}} +# Ticket [6284df89debdfa61db8073e062908af0c9b6118e] +# Disable the xfer optimization if the destination table contains +# a foreign key constraint +# +ifcapable foreignkey { + do_test insert4-7.1 { + set ::sqlite3_xferopt_count 0 + execsql { + CREATE TABLE t7a(x INTEGER PRIMARY KEY); INSERT INTO t7a VALUES(123); + CREATE TABLE t7b(y INTEGER REFERENCES t7a); + CREATE TABLE t7c(z INT); INSERT INTO t7c VALUES(234); + INSERT INTO t7b SELECT * FROM t7c; + SELECT * FROM t7b; + } + } {234} + do_test insert4-7.2 { + set ::sqlite3_xferopt_count + } {1} + do_test insert4-7.3 { + set ::sqlite3_xferopt_count 0 + execsql { + DELETE FROM t7b; + PRAGMA foreign_keys=ON; + } + catchsql { + INSERT INTO t7b SELECT * FROM t7c; + } + } {1 {foreign key constraint failed}} + do_test insert4-7.4 { + execsql {SELECT * FROM t7b} + } {} + do_test insert4-7.5 { + set ::sqlite3_xferopt_count + } {0} + do_test insert4-7.6 { + set ::sqlite3_xferopt_count 0 + execsql { + DELETE FROM t7b; DELETE FROM t7c; + INSERT INTO t7c VALUES(123); + INSERT INTO t7b SELECT * FROM t7c; + SELECT * FROM t7b; + } + } {123} + do_test insert4-7.7 { + set ::sqlite3_xferopt_count + } {0} + do_test insert4-7.7 { + set ::sqlite3_xferopt_count 0 + execsql { + PRAGMA foreign_keys=OFF; + DELETE FROM t7b; + INSERT INTO t7b SELECT * FROM t7c; + SELECT * FROM t7b; + } + } {123} + do_test insert4-7.8 { + set ::sqlite3_xferopt_count + } {1} +} + finish_test From 9a3baf10ca3bd1f8069c95832c07c0aafe0066d7 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 25 Apr 2011 18:01:27 +0000 Subject: [PATCH 05/22] Invoke the unix open() system call through a wrapper to avoid problems resulting from differing declarations to that function in various systems. FossilOrigin-Name: 4c7ff4dd352276e9c01cc536e188cbcd69396952 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/os_unix.c | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 8eaf915520..b78804e62d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Disable\sthe\stransfer\soptimization\sif\sthe\sdestination\stable\scontains\nany\sforeign\skey\sconstraint\sand\sforeign\skey\sconstraints\sare\senabled.\nTicket\s[6284df89debdf]. -D 2011-04-24T22:56:07.596 +C Invoke\sthe\sunix\sopen()\ssystem\scall\sthrough\sa\swrapper\sto\savoid\sproblems\s\nresulting\sfrom\sdiffering\sdeclarations\sto\sthat\sfunction\sin\svarious\ssystems. +D 2011-04-25T18:01:27.439 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -162,7 +162,7 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9 F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 -F src/os_unix.c d7889a0f9389c8c2e1d3b380f5aa1256c22a90e8 +F src/os_unix.c 2c67d126874b78eb427371db4793f0e8fbc7448b F src/os_win.c d149b9a7dfdd38de09afc054f8168cd3cd80630b F src/pager.c 055239dcdfe12b3f5d97f6f01f85da01e2d6d912 F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1 @@ -930,7 +930,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 0ab24b133e332ad7f4517b8e113e9c241ee9af9f -R 40e74cf200b39d155b455f390ce862eb +P ddeea5ab5f6c0c4a86cdfbbb9f24d9d54bf8d301 +R c3c570e59b4504f5792e40be1884b2ad U drh -Z 87bc3e585b95e6d3397bca153c02ab82 +Z 99b5b07687fe54475ef75b698d77b786 diff --git a/manifest.uuid b/manifest.uuid index 6503aa6c35..f4b8a8d726 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ddeea5ab5f6c0c4a86cdfbbb9f24d9d54bf8d301 \ No newline at end of file +4c7ff4dd352276e9c01cc536e188cbcd69396952 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 2d3a616373..a760e2c147 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -281,6 +281,18 @@ struct unixFile { #define threadid 0 #endif +/* +** Different Unix systems declare open() in different ways. Same use +** open(const char*,int,mode_t). Others use open(const char*,int,...). +** The difference is important when using a pointer to the function. +** +** The safest way to deal with the problem is to always use this wrapper +** which always has the same well-defined interface. +*/ +static int posixOpen(const char *zFile, int flags, int mode){ + return open(zFile, flags, mode); +} + /* ** Many system calls are accessed through pointer-to-functions so that ** they may be overridden at runtime to facilitate fault injection during @@ -292,8 +304,8 @@ static struct unix_syscall { sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ sqlite3_syscall_ptr pDefault; /* Default value */ } aSyscall[] = { - { "open", (sqlite3_syscall_ptr)open, 0 }, -#define osOpen ((int(*)(const char*,int,...))aSyscall[0].pCurrent) + { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, +#define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) { "close", (sqlite3_syscall_ptr)close, 0 }, #define osClose ((int(*)(int))aSyscall[1].pCurrent) From 3ca84ef62395d14bf5aa51a4bb945412ef10edbc Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 25 Apr 2011 18:03:10 +0000 Subject: [PATCH 06/22] Add the (deliberately undocumented) sqlite_log() SQL function as a built-in. FossilOrigin-Name: f7806e03995b314771aa72a08ce55d56d60096cf --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/func.c | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index b78804e62d..3f91515d1b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Invoke\sthe\sunix\sopen()\ssystem\scall\sthrough\sa\swrapper\sto\savoid\sproblems\s\nresulting\sfrom\sdiffering\sdeclarations\sto\sthat\sfunction\sin\svarious\ssystems. -D 2011-04-25T18:01:27.439 +C Add\sthe\s(deliberately\sundocumented)\ssqlite_log()\sSQL\sfunction\sas\sa\sbuilt-in. +D 2011-04-25T18:03:10.263 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -133,7 +133,7 @@ F src/delete.c 7a24fcc9a31664d145acb97ce56b6d9f249a25e4 F src/expr.c e3cf0957c6b8faaaf7386a3bc69e53c0dc9705be F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c a43ba8a005fb5efd1deeee06853e3a6120d46a91 -F src/func.c 3a8cb2fb2de3e3aed7f39106daf4878d9d17fcce +F src/func.c 6d907d397c9e6eded680f8946499efdf224d34bd F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 @@ -930,7 +930,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P ddeea5ab5f6c0c4a86cdfbbb9f24d9d54bf8d301 -R c3c570e59b4504f5792e40be1884b2ad +P 4c7ff4dd352276e9c01cc536e188cbcd69396952 +R 02826977cda64533dcdcab57c0092168 U drh -Z 99b5b07687fe54475ef75b698d77b786 +Z ae88889f134cbeb0e55dabbab9faed47 diff --git a/manifest.uuid b/manifest.uuid index f4b8a8d726..428479b63d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4c7ff4dd352276e9c01cc536e188cbcd69396952 \ No newline at end of file +f7806e03995b314771aa72a08ce55d56d60096cf \ No newline at end of file diff --git a/src/func.c b/src/func.c index 6a4f7c09c3..e75fa47e7a 100644 --- a/src/func.c +++ b/src/func.c @@ -774,6 +774,21 @@ static void sourceidFunc( sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC); } +/* +** Implementation of the sqlite_log() function. This is a wrapper around +** sqlite3_log(). The return value is NULL. The function exists purely for +** its side-effects. +*/ +static void logFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(context); + sqlite3_log(sqlite3_value_int(argv[0]), "%s", sqlite3_value_text(argv[1])); +} + /* ** Implementation of the sqlite_compileoption_used() function. ** The result is an integer that identifies if the compiler option @@ -1541,6 +1556,7 @@ void sqlite3RegisterGlobalFunctions(void){ FUNCTION(nullif, 2, 0, 1, nullifFunc ), FUNCTION(sqlite_version, 0, 0, 0, versionFunc ), FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), + FUNCTION(sqlite_log, 2, 0, 0, logFunc ), #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), From 53a9d15826ea9c0513a167585264437f805fa4ce Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 25 Apr 2011 18:20:04 +0000 Subject: [PATCH 07/22] Test case for the ".log" command to the command-line shell. FossilOrigin-Name: 7d0ff26a95cb1e9fcace4641245dda787f3522b4 --- manifest | 12 ++++++------ manifest.uuid | 2 +- tool/shell1.test | 5 +++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 3f91515d1b..cca88e6f6d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\s(deliberately\sundocumented)\ssqlite_log()\sSQL\sfunction\sas\sa\sbuilt-in. -D 2011-04-25T18:03:10.263 +C Test\scase\sfor\sthe\s".log"\scommand\sto\sthe\scommand-line\sshell. +D 2011-04-25T18:20:04.278 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -912,7 +912,7 @@ F tool/omittest.tcl b1dd290c1596e0f31fd335160a74ec5dfea3df4a F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/shell1.test fee04fce1bf55e6e081523545fd4e0e83490ff8e +F tool/shell1.test 44705d6078b37f58853005d2ad5f1e67bc9dbbed F tool/shell2.test 5dc76b8005b465f420fed8241621da7513060ff3 F tool/shell3.test 4fad469e8003938426355afdf34155f08c587836 F tool/shell4.test 35f9c3d452b4e76d5013c63e1fd07478a62f14ce @@ -930,7 +930,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 4c7ff4dd352276e9c01cc536e188cbcd69396952 -R 02826977cda64533dcdcab57c0092168 +P f7806e03995b314771aa72a08ce55d56d60096cf +R 90125b981bcf635951ddc9b0441cae0d U drh -Z ae88889f134cbeb0e55dabbab9faed47 +Z da6f87ac8d880cc9cef1dbf3763cd407 diff --git a/manifest.uuid b/manifest.uuid index 428479b63d..6f42c53a3b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f7806e03995b314771aa72a08ce55d56d60096cf \ No newline at end of file +7d0ff26a95cb1e9fcace4641245dda787f3522b4 \ No newline at end of file diff --git a/tool/shell1.test b/tool/shell1.test index 6980dab219..d066fc3c1a 100644 --- a/tool/shell1.test +++ b/tool/shell1.test @@ -711,4 +711,9 @@ do_test shell1-3.27.4 { catchcmd "test.db" ".timer OFF BAD" } {1 {Error: unknown command or invalid arguments: "timer". Enter ".help" for help}} +do_test shell1-3-28.1 { + catchcmd test.db \ + ".log stdout\nSELECT coalesce(sqlite_log(123,'hello'),'456');" +} "0 {(123) hello\n456}" + puts "CLI tests completed successfully" From b061d058cb618b2acd8492013356d4c325472a04 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 25 Apr 2011 18:49:57 +0000 Subject: [PATCH 08/22] Add support for on conflict clauses to fts3/fts4. FossilOrigin-Name: 6d2633a6d0a9bb88fb1a6adac0827dc51df2d4d2 --- ext/fts3/fts3.c | 2 + ext/fts3/fts3_write.c | 120 ++++++++++++++++++++++++++++++++---------- manifest | 36 +++++++------ manifest.uuid | 2 +- src/insert.c | 1 + src/sqlite.h.in | 20 +++++++ src/sqliteInt.h | 6 +++ src/update.c | 9 ++-- src/vdbe.c | 16 +++++- src/vtab.c | 70 +++++++++++++++++++++--- test/fts3atoken.test | 13 ++--- test/fts3aux1.test | 6 +-- test/fts3conf.test | 63 ++++++++++++++++++++++ 13 files changed, 297 insertions(+), 67 deletions(-) create mode 100644 test/fts3conf.test diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 20da05164d..c7e06d4bb6 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -524,6 +524,8 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){ char *zSql; /* SQL statement passed to declare_vtab() */ char *zCols; /* List of user defined columns */ + sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); + /* Create a list of user columns for the virtual table */ zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]); for(i=1; zCols && inColumn; i++){ diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 1a00f8a961..9d2bfaae8b 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -747,14 +747,14 @@ static int fts3DeleteAll(Fts3Table *p){ static void fts3DeleteTerms( int *pRC, /* Result code */ Fts3Table *p, /* The FTS table to delete from */ - sqlite3_value **apVal, /* apVal[] contains the docid to be deleted */ + sqlite3_value *pRowid, /* The docid to be deleted */ u32 *aSz /* Sizes of deleted document written here */ ){ int rc; sqlite3_stmt *pSelect; if( *pRC ) return; - rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, apVal); + rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pSelect) ){ int i; @@ -1894,16 +1894,16 @@ static void fts3SegWriterFree(SegmentWriter *pWriter){ ** The first value in the apVal[] array is assumed to contain an integer. ** This function tests if there exist any documents with docid values that ** are different from that integer. i.e. if deleting the document with docid -** apVal[0] would mean the FTS3 table were empty. +** pRowid would mean the FTS3 table were empty. ** ** If successful, *pisEmpty is set to true if the table is empty except for -** document apVal[0], or false otherwise, and SQLITE_OK is returned. If an +** document pRowid, or false otherwise, and SQLITE_OK is returned. If an ** error occurs, an SQLite error code is returned. */ -static int fts3IsEmpty(Fts3Table *p, sqlite3_value **apVal, int *pisEmpty){ +static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ sqlite3_stmt *pStmt; int rc; - rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, apVal); + rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pStmt) ){ *pisEmpty = sqlite3_column_int(pStmt, 0); @@ -2627,6 +2627,40 @@ int sqlite3Fts3DeferToken( return SQLITE_OK; } +/* +** SQLite value pRowid contains the rowid of a row that may or may not be +** present in the FTS3 table. If it is, delete it and adjust the contents +** of subsiduary data structures accordingly. +*/ +static int fts3DeleteByRowid( + Fts3Table *p, + sqlite3_value *pRowid, + int *pnDoc, + int *aSzDel +){ + int isEmpty = 0; + int rc = fts3IsEmpty(p, pRowid, &isEmpty); + if( rc==SQLITE_OK ){ + if( isEmpty ){ + /* Deleting this row means the whole table is empty. In this case + ** delete the contents of all three tables and throw away any + ** data in the pendingTerms hash table. */ + rc = fts3DeleteAll(p); + *pnDoc--; + }else{ + sqlite3_int64 iRemove = sqlite3_value_int64(pRowid); + rc = fts3PendingTermsDocid(p, iRemove); + fts3DeleteTerms(&rc, p, pRowid, aSzDel); + fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); + if( sqlite3_changes(p->db) ) *pnDoc--; + if( p->bHasDocsize ){ + fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); + } + } + } + + return rc; +} /* ** This function does the work for the xUpdate method of FTS3 virtual @@ -2645,46 +2679,74 @@ int sqlite3Fts3UpdateMethod( u32 *aSzIns; /* Sizes of inserted documents */ u32 *aSzDel; /* Sizes of deleted documents */ int nChng = 0; /* Net change in number of documents */ + int bInsertDone = 0; + int bReplace = 0; /* True if on conflict mode is REPLACE */ assert( p->pSegments==0 ); + /* Check for a "special" INSERT operation. One of the form: + ** + ** INSERT INTO xyz(xyz) VALUES('command'); + */ + if( nArg>1 + && sqlite3_value_type(apVal[0])==SQLITE_NULL + && sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL + ){ + return fts3SpecialInsert(p, apVal[p->nColumn+2]); + } + /* Allocate space to hold the change in document sizes */ aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 ); if( aSzIns==0 ) return SQLITE_NOMEM; aSzDel = &aSzIns[p->nColumn+1]; memset(aSzIns, 0, sizeof(aSzIns[0])*(p->nColumn+1)*2); - /* If this is a DELETE or UPDATE operation, remove the old record. */ - if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ - int isEmpty = 0; - rc = fts3IsEmpty(p, apVal, &isEmpty); - if( rc==SQLITE_OK ){ - if( isEmpty ){ - /* Deleting this row means the whole table is empty. In this case - ** delete the contents of all three tables and throw away any - ** data in the pendingTerms hash table. - */ - rc = fts3DeleteAll(p); + /* If this is an INSERT operation, or an UPDATE that modifies the rowid + ** value, then this operation requires constraint handling. + ** + ** If the on-conflict mode is REPLACE, this means that the existing row + ** should be deleted from the database before inserting the new row. Or, + ** if the on-conflict mode is other than REPLACE, then this method must + ** detect the conflict and return SQLITE_CONSTRAINT before beginning to + ** modify the database file. + */ + if( nArg>1 ){ + sqlite3_int64 iNewRowid; + sqlite3_value *pNewRowid = apVal[3+p->nColumn]; + if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ + pNewRowid = apVal[1]; + } + if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && ( + sqlite3_value_type(apVal[0])==SQLITE_NULL + || sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid) + )){ + if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ + rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel); }else{ - isRemove = 1; - iRemove = sqlite3_value_int64(apVal[0]); - rc = fts3PendingTermsDocid(p, iRemove); - fts3DeleteTerms(&rc, p, apVal, aSzDel); - fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, apVal); - if( p->bHasDocsize ){ - fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, apVal); - } - nChng--; + rc = fts3InsertData(p, apVal, pRowid); + bInsertDone = 1; } } - }else if( sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL ){ + } + if( rc!=SQLITE_OK ){ sqlite3_free(aSzIns); - return fts3SpecialInsert(p, apVal[p->nColumn+2]); + return rc; + } + + /* If this is a DELETE or UPDATE operation, remove the old record. */ + if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ + assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ); + rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel); + isRemove = 1; + iRemove = sqlite3_value_int64(apVal[0]); } /* If this is an INSERT or UPDATE operation, insert the new record. */ if( nArg>1 && rc==SQLITE_OK ){ - rc = fts3InsertData(p, apVal, pRowid); + if( bInsertDone==0 ){ + rc = fts3InsertData(p, apVal, pRowid); + if( rc==SQLITE_CONSTRAINT ) rc = SQLITE_CORRUPT; + } if( rc==SQLITE_OK && (!isRemove || *pRowid!=iRemove) ){ rc = fts3PendingTermsDocid(p, *pRowid); } diff --git a/manifest b/manifest index 8eaf915520..36dc26d0ca 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Disable\sthe\stransfer\soptimization\sif\sthe\sdestination\stable\scontains\nany\sforeign\skey\sconstraint\sand\sforeign\skey\sconstraints\sare\senabled.\nTicket\s[6284df89debdf]. -D 2011-04-24T22:56:07.596 +C Add\ssupport\sfor\son\sconflict\sclauses\sto\sfts3/fts4. +D 2011-04-25T18:49:57.773 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -61,7 +61,7 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 5653c5654ac9b65bf3646af7e1d695c7e9b991a0 +F ext/fts3/fts3.c 94fa15fc9d6290e2ba042c24fc83e272c86a40c6 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe F ext/fts3/fts3Int.h 945926ea4b6a686c3e9834640a252d9870b7191e F ext/fts3/fts3_aux.c 9e931f55eed8498dafe7bc1160f10cbb1a652fdf @@ -74,7 +74,7 @@ F ext/fts3/fts3_snippet.c e857c6a89d81d3b89df59f3b44b35c68d8ed5c62 F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3 F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d -F ext/fts3/fts3_write.c c0af09a04021926d7d84094fa950defc9213416d +F ext/fts3/fts3_write.c 388a7c7119f322d8fd4a5c19c9bd5793da47ccce F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9 @@ -138,7 +138,7 @@ F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c cdee360e5cea59db6c4a980e4360499631222af6 +F src/insert.c 3eea5a53d2644116fb865afaa4699fabe62b441c F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e @@ -178,9 +178,9 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff F src/shell.c 72e7e176bf46d5c6518d15ac4ad6847c4bb5df79 -F src/sqlite.h.in fe9a777d43276b4778e92b16a8b89ea6c38bb32b +F src/sqlite.h.in 92f2daa48c1926d79db79229fb583cdb22d2d4c5 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 -F src/sqliteInt.h ac8f3f5846275c634f6649969304a9e97f6f9854 +F src/sqliteInt.h 5facb244a286e5c9ecd2f59758019f24a9245c8e F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -231,11 +231,11 @@ F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080 F src/trigger.c 144cc18bb701f3286484aae4292a9531f09278c8 -F src/update.c 81911be16ece3c3e7716aa18565b4814ec41f8b9 +F src/update.c 5bcb56e5c7380a2eecb0e71891dbd4ad7437748f F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60 F src/util.c 465fe10aabf0ca7d7826a156dab919b0b65c525a F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e -F src/vdbe.c 05deeec6659f2579674a5e6510b3ada2a442f8d5 +F src/vdbe.c ac7aab1148964422b0a91ae5d50d31724fbd82ec F src/vdbe.h 8a675fefdf7119441fe817c800a9a52440c2e797 F src/vdbeInt.h fe8f58d305e629fff02f61f655aca1d299f1f6ae F src/vdbeapi.c e0e2672e0a96ae3f8575c8ecd02912a3e8a554a1 @@ -243,7 +243,7 @@ F src/vdbeaux.c 9ae5074b19bdff2d8806a278533956fb281510d5 F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 -F src/vtab.c b0abc931f95af94c9ffdf9f747eb191cda953123 +F src/vtab.c 0e89db3e7416ccdab5138883d69ed8006a7e992c F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794 F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f @@ -450,11 +450,12 @@ F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8 F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18 F test/fts3ao.test b83f99f70e9eec85f27d75801a974b3f820e01f9 -F test/fts3atoken.test bbb9e63a915f3df0e35d06e0add932b5bf2d54a9 -F test/fts3aux1.test 719c35cbbcc04dde8e5a54a6f69851a0af9ed1f2 +F test/fts3atoken.test 402ef2f7c2fb4b3d4fa0587df6441c1447e799b3 +F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0 F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c +F test/fts3conf.test 2dc3bce3fe20d1e9b0ecd27d4040d07a2b79d16b F test/fts3corrupt.test 7890cc202406858386ddf390a879dcf80bc10abf F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 @@ -930,7 +931,10 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 0ab24b133e332ad7f4517b8e113e9c241ee9af9f -R 40e74cf200b39d155b455f390ce862eb -U drh -Z 87bc3e585b95e6d3397bca153c02ab82 +P ddeea5ab5f6c0c4a86cdfbbb9f24d9d54bf8d301 +R ca5f1cf4bf0f7df53478a4e115a67980 +T *branch * vtab-conflict +T *sym-vtab-conflict * +T -sym-trunk * +U dan +Z dd80c4f8ae24b83ff1c8f809d0d54000 diff --git a/manifest.uuid b/manifest.uuid index 6503aa6c35..942ac84499 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ddeea5ab5f6c0c4a86cdfbbb9f24d9d54bf8d301 \ No newline at end of file +6d2633a6d0a9bb88fb1a6adac0827dc51df2d4d2 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 02456e776f..452939db94 100644 --- a/src/insert.c +++ b/src/insert.c @@ -969,6 +969,7 @@ void sqlite3Insert( const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB); + sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); sqlite3MayAbort(pParse); }else #endif diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 421da8e6bd..2c3b1a5031 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6389,6 +6389,26 @@ int sqlite3_wal_checkpoint_v2( #define SQLITE_CHECKPOINT_FULL 1 #define SQLITE_CHECKPOINT_RESTART 2 +/* +** CAPI3REF: Virtual Table Interface Configuration +*/ +int sqlite3_vtab_config(sqlite3*, int op, ...); + +/* +** CAPI3REF: Determine The Virtual Table Conflict Policy +*/ +#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 +int sqlite3_vtab_on_conflict(sqlite3 *); + +/* +** CAPI3REF: Virtual Table Conflict Policies +*/ +#define SQLITE_ROLLBACK 1 +/* #define SQLITE_IGNORE 2 */ +#define SQLITE_FAIL 3 +/* #define SQLITE_ABORT 4 */ +#define SQLITE_REPLACE 5 + /* ** Undo the hack that converts floating point types to integer for diff --git a/src/sqliteInt.h b/src/sqliteInt.h index ea0925e417..f000a228ca 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -632,6 +632,7 @@ typedef struct TriggerPrg TriggerPrg; typedef struct TriggerStep TriggerStep; typedef struct UnpackedRecord UnpackedRecord; typedef struct VTable VTable; +typedef struct VtabCtx VtabCtx; typedef struct Walker Walker; typedef struct WherePlan WherePlan; typedef struct WhereInfo WhereInfo; @@ -811,6 +812,7 @@ struct sqlite3 { u8 dfltLockMode; /* Default locking-mode for attached dbs */ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ u8 suppressErr; /* Do not issue error messages if true */ + u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ int nextPagesize; /* Pagesize after VACUUM if >0 */ int nTable; /* Number of tables in the database */ CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ @@ -869,7 +871,10 @@ struct sqlite3 { #endif #ifndef SQLITE_OMIT_VIRTUALTABLE Hash aModule; /* populated by sqlite3_create_module() */ +#if 0 Table *pVTab; /* vtab with active Connect/Create method */ +#endif + VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ VTable **aVTrans; /* Virtual tables with open transactions */ int nVTrans; /* Allocated size of aVTrans */ VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ @@ -1232,6 +1237,7 @@ struct VTable { Module *pMod; /* Pointer to module implementation */ sqlite3_vtab *pVtab; /* Pointer to vtab instance */ int nRef; /* Number of pointers to this structure */ + u8 bConstraint; /* True if constraints are supported */ VTable *pNext; /* Next in linked list (see above) */ }; diff --git a/src/update.c b/src/update.c index 315034d86f..aecf75cf35 100644 --- a/src/update.c +++ b/src/update.c @@ -23,7 +23,8 @@ static void updateVirtualTable( ExprList *pChanges, /* The columns to change in the UPDATE statement */ Expr *pRowidExpr, /* Expression used to recompute the rowid */ int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ - Expr *pWhere /* WHERE clause of the UPDATE statement */ + Expr *pWhere, /* WHERE clause of the UPDATE statement */ + int onError /* ON CONFLICT strategy */ ); #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -267,7 +268,7 @@ void sqlite3Update( /* Virtual tables must be handled separately */ if( IsVirtual(pTab) ){ updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, - pWhere); + pWhere, onError); pWhere = 0; pTabList = 0; goto update_cleanup; @@ -597,7 +598,8 @@ static void updateVirtualTable( ExprList *pChanges, /* The columns to change in the UPDATE statement */ Expr *pRowid, /* Expression used to recompute the rowid */ int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ - Expr *pWhere /* WHERE clause of the UPDATE statement */ + Expr *pWhere, /* WHERE clause of the UPDATE statement */ + int onError /* ON CONFLICT strategy */ ){ Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */ ExprList *pEList = 0; /* The result set of the SELECT statement */ @@ -654,6 +656,7 @@ static void updateVirtualTable( } sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB); + sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); sqlite3MayAbort(pParse); sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); sqlite3VdbeJumpHere(v, addr); diff --git a/src/vdbe.c b/src/vdbe.c index 5376b08a00..71756f8fca 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -5773,11 +5773,15 @@ case OP_VUpdate: { Mem **apArg; Mem *pX; + assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback + || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace + ); pVtab = pOp->p4.pVtab->pVtab; pModule = (sqlite3_module *)pVtab->pModule; nArg = pOp->p2; assert( pOp->p4type==P4_VTAB ); if( ALWAYS(pModule->xUpdate) ){ + u8 vtabOnConflict = db->vtabOnConflict; apArg = p->apArg; pX = &aMem[pOp->p3]; for(i=0; ivtabOnConflict = pOp->p5; rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid); + db->vtabOnConflict = vtabOnConflict; importVtabErrMsg(p, pVtab); if( rc==SQLITE_OK && pOp->p1 ){ assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); db->lastRowid = rowid; } - p->nChange++; + if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ + if( pOp->p5==OE_Ignore ){ + rc = SQLITE_OK; + }else{ + p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5); + } + }else{ + p->nChange++; + } } break; } diff --git a/src/vtab.c b/src/vtab.c index b052de23a5..51826e91f9 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -14,6 +14,18 @@ #ifndef SQLITE_OMIT_VIRTUALTABLE #include "sqliteInt.h" +/* +** Before a virtual table xCreate() or xConnect() method is invoked, the +** sqlite3.pVtabCtx member variable is set to point to an instance of +** this struct allocated on the stack. It is used by the implementation of +** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which +** are invoked only from within xCreate and xConnect methods. +*/ +struct VtabCtx { + Table *pTab; + VTable *pVTable; +}; + /* ** The actual function that does the work of creating a new module. ** This function implements the sqlite3_create_module() and @@ -434,6 +446,7 @@ static int vtabCallConstructor( int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), char **pzErr ){ + VtabCtx sCtx; VTable *pVTable; int rc; const char *const*azArg = (const char *const*)pTab->azModuleArg; @@ -453,12 +466,14 @@ static int vtabCallConstructor( pVTable->db = db; pVTable->pMod = pMod; - assert( !db->pVTab ); - assert( xConstruct ); - db->pVTab = pTab; - /* Invoke the virtual table constructor */ + assert( &db->pVtabCtx ); + assert( xConstruct ); + sCtx.pTab = pTab; + sCtx.pVTable = pVTable; + db->pVtabCtx = &sCtx; rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); + db->pVtabCtx = 0; if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; if( SQLITE_OK!=rc ){ @@ -474,7 +489,7 @@ static int vtabCallConstructor( ** the sqlite3_vtab object if successful. */ pVTable->pVtab->pModule = pMod->pModule; pVTable->nRef = 1; - if( db->pVTab ){ + if( sCtx.pTab ){ const char *zFormat = "vtable constructor did not declare schema: %s"; *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); sqlite3VtabUnlock(pVTable); @@ -522,7 +537,6 @@ static int vtabCallConstructor( } sqlite3DbFree(db, zModuleName); - db->pVTab = 0; return rc; } @@ -642,7 +656,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ char *zErr = 0; sqlite3_mutex_enter(db->mutex); - pTab = db->pVTab; + pTab = db->pVtabCtx->pTab; if( !pTab ){ sqlite3Error(db, SQLITE_MISUSE, 0); sqlite3_mutex_leave(db->mutex); @@ -670,7 +684,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ pParse->pNewTable->nCol = 0; pParse->pNewTable->aCol = 0; } - db->pVTab = 0; + db->pVtabCtx->pTab = 0; }else{ sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); @@ -937,4 +951,44 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ } } +int sqlite3_vtab_on_conflict(sqlite3 *db){ + int aMap[] = { + SQLITE_ROLLBACK, SQLITE_IGNORE, SQLITE_ABORT, SQLITE_FAIL, SQLITE_REPLACE + }; + assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 ); + assert( OE_Ignore==4 && OE_Replace==5 ); + assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 ); + return aMap[db->vtabOnConflict-1]; +} + + +int sqlite3_vtab_config(sqlite3 *db, int op, ...){ + va_list ap; + int rc = SQLITE_OK; + + sqlite3_mutex_enter(db->mutex); + + va_start(ap, op); + switch( op ){ + case SQLITE_VTAB_CONSTRAINT_SUPPORT: { + VtabCtx *p = db->pVtabCtx; + if( !p ){ + rc = SQLITE_MISUSE_BKPT; + }else{ + assert( (p->pTab->tabFlags & TF_Virtual)!=0 ); + p->pVTable->bConstraint = (u8)va_arg(ap, int); + } + break; + } + default: + rc = SQLITE_MISUSE_BKPT; + break; + } + va_end(ap); + + if( rc!=SQLITE_OK ) sqlite3Error(db, rc, 0); + sqlite3_mutex_leave(db->mutex); + return rc; +} + #endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/test/fts3atoken.test b/test/fts3atoken.test index d4c4825004..554259d0a5 100644 --- a/test/fts3atoken.test +++ b/test/fts3atoken.test @@ -167,14 +167,15 @@ ifcapable icu { do_icu_test fts3token-4.6 MiddleOfTheOcean $input $output do_icu_test fts3token-4.7 th_TH $input $output do_icu_test fts3token-4.8 en_US $input $output + + do_execsql_test 5.1 { + CREATE VIRTUAL TABLE x1 USING fts3(name,TOKENIZE icu en_US); + insert into x1 (name) values (NULL); + insert into x1 (name) values (NULL); + delete from x1; + } } -do_execsql_test 5.1 { - CREATE VIRTUAL TABLE x1 USING fts3(name,TOKENIZE icu en_US); - insert into x1 (name) values (NULL); - insert into x1 (name) values (NULL); - delete from x1; -} do_test fts3token-internal { execsql { SELECT fts3_tokenizer_internal_test() } diff --git a/test/fts3aux1.test b/test/fts3aux1.test index 5359521ab7..adda586353 100644 --- a/test/fts3aux1.test +++ b/test/fts3aux1.test @@ -38,10 +38,10 @@ do_execsql_test 1.2 { six 1 1 three 4 6 two 1 1 } -do_execsql_test 1.3 { - DELETE FROM t1; +do_execsql_test 1.3.1 { DELETE FROM t1; } +do_execsql_test 1.3.2 { SELECT term, documents, occurrences FROM terms WHERE col = '*'; -} {} +} do_execsql_test 1.4 { INSERT INTO t1 VALUES('a b a b a b a'); diff --git a/test/fts3conf.test b/test/fts3conf.test new file mode 100644 index 0000000000..c3f36d7ff9 --- /dev/null +++ b/test/fts3conf.test @@ -0,0 +1,63 @@ +# 2011 April 25 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the FTS3 module. + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fts3conf + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts3(x); + INSERT INTO t1(rowid, x) VALUES(1, 'a b c d'); + INSERT INTO t1(rowid, x) VALUES(2, 'e f g h'); + + CREATE TABLE source(a, b); + INSERT INTO source VALUES(4, 'z'); + INSERT INTO source VALUES(2, 'y'); +} +db_save_and_close + +set T1 "INTO t1(rowid, x) VALUES(1, 'x')" +set T2 "INTO t1(rowid, x) SELECT * FROM source" + +foreach {tn sql constraint data} [subst { + 1 "INSERT OR ROLLBACK $T1" 1 {{a b c d} {e f g h}} + 2 "INSERT OR ABORT $T1" 1 {{a b c d} {e f g h} {i j k l}} + 3 "INSERT OR FAIL $T1" 1 {{a b c d} {e f g h} {i j k l}} + 4 "INSERT OR IGNORE $T1" 0 {{a b c d} {e f g h} {i j k l}} + 5 "INSERT OR REPLACE $T1" 0 {x {e f g h} {i j k l}} + + 6 "INSERT OR ROLLBACK $T2" 1 {{a b c d} {e f g h}} + 7 "INSERT OR ABORT $T2" 1 {{a b c d} {e f g h} {i j k l}} + 8 "INSERT OR FAIL $T2" 1 {{a b c d} {e f g h} {i j k l} z} + 9 "INSERT OR IGNORE $T2" 0 {{a b c d} {e f g h} {i j k l} z} + 10 "INSERT OR REPLACE $T2" 0 {{a b c d} y {i j k l} z} +}] { + db_restore_and_reopen + execsql { + BEGIN; + INSERT INTO t1(rowid, x) VALUES(3, 'i j k l'); + } + set R(0) {0 {}} + set R(1) {1 {constraint failed}} + do_catchsql_test 1.$tn.1 $sql $R($constraint) + do_catchsql_test 1.$tn.2 { SELECT * FROM t1 } [list 0 $data] +} + +finish_test From a311b803925df71cb57d6741e87992009eb4e0e3 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 26 Apr 2011 19:21:34 +0000 Subject: [PATCH 09/22] Extra tests for fts3. And fixes for conflict-handling related problems in fts3. FossilOrigin-Name: fb4a355871d9482ccb28b6ba03b842b3cc87b696 --- ext/fts3/fts3.c | 21 ++- ext/fts3/fts3_term.c | 346 ++++++++++++++++++++++++++++++++++++++++++ ext/fts3/fts3_write.c | 18 ++- main.mk | 1 + manifest | 32 ++-- manifest.uuid | 2 +- src/sqlite.h.in | 5 + src/sqliteInt.h | 2 + src/vdbe.c | 6 +- src/vdbeaux.c | 9 ++ src/vtab.c | 27 +++- test/fts3conf.test | 57 ++++++- 12 files changed, 503 insertions(+), 23 deletions(-) create mode 100644 ext/fts3/fts3_term.c diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index c7e06d4bb6..52b853a9a2 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -3544,8 +3544,19 @@ static int fts3RenameMethod( return rc; } +static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ + return sqlite3Fts3PendingTermsFlush((Fts3Table *)pVtab); +} +static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ + return SQLITE_OK; +} +static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ + sqlite3Fts3PendingTermsClear((Fts3Table *)pVtab); + return SQLITE_OK; +} + static const sqlite3_module fts3Module = { - /* iVersion */ 0, + /* iVersion */ 1, /* xCreate */ fts3CreateMethod, /* xConnect */ fts3ConnectMethod, /* xBestIndex */ fts3BestIndexMethod, @@ -3565,6 +3576,9 @@ static const sqlite3_module fts3Module = { /* xRollback */ fts3RollbackMethod, /* xFindFunction */ fts3FindFunctionMethod, /* xRename */ fts3RenameMethod, + /* xSavepoint */ fts3SavepointMethod, + /* xRelease */ fts3ReleaseMethod, + /* xRollbackTo */ fts3RollbackToMethod, }; /* @@ -3611,6 +3625,11 @@ int sqlite3Fts3Init(sqlite3 *db){ sqlite3Fts3IcuTokenizerModule(&pIcu); #endif +#ifdef SQLITE_TEST + rc = sqlite3Fts3InitTerm(db); + if( rc!=SQLITE_OK ) return rc; +#endif + rc = sqlite3Fts3InitAux(db); if( rc!=SQLITE_OK ) return rc; diff --git a/ext/fts3/fts3_term.c b/ext/fts3/fts3_term.c new file mode 100644 index 0000000000..ce581633e1 --- /dev/null +++ b/ext/fts3/fts3_term.c @@ -0,0 +1,346 @@ +/* +** 2011 Jan 27 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +*/ + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) +#ifdef SQLITE_TEST + +#include "fts3Int.h" +#include +#include + +typedef struct Fts3termTable Fts3termTable; +typedef struct Fts3termCursor Fts3termCursor; + +struct Fts3termTable { + sqlite3_vtab base; /* Base class used by SQLite core */ + Fts3Table *pFts3Tab; +}; + +struct Fts3termCursor { + sqlite3_vtab_cursor base; /* Base class used by SQLite core */ + Fts3SegReaderCursor csr; /* Must be right after "base" */ + Fts3SegFilter filter; + + int isEof; /* True if cursor is at EOF */ + char *pNext; + + sqlite3_int64 iRowid; /* Current 'rowid' value */ + sqlite3_int64 iDocid; /* Current 'docid' value */ + int iCol; /* Current 'col' value */ + int iPos; /* Current 'pos' value */ +}; + +/* +** Schema of the terms table. +*/ +#define FTS3_TERMS_SCHEMA "CREATE TABLE x(term, docid, col, pos)" + +/* +** This function does all the work for both the xConnect and xCreate methods. +** These tables have no persistent representation of their own, so xConnect +** and xCreate are identical operations. +*/ +static int fts3termConnectMethod( + sqlite3 *db, /* Database connection */ + void *pUnused, /* Unused */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ + char **pzErr /* OUT: sqlite3_malloc'd error message */ +){ + char const *zDb; /* Name of database (e.g. "main") */ + char const *zFts3; /* Name of fts3 table */ + int nDb; /* Result of strlen(zDb) */ + int nFts3; /* Result of strlen(zFts3) */ + int nByte; /* Bytes of space to allocate here */ + int rc; /* value returned by declare_vtab() */ + Fts3termTable *p; /* Virtual table object to return */ + + UNUSED_PARAMETER(pUnused); + + /* The user should specify a single argument - the name of an fts3 table. */ + if( argc!=4 ){ + *pzErr = sqlite3_mprintf( + "wrong number of arguments to fts4term constructor" + ); + return SQLITE_ERROR; + } + + zDb = argv[1]; + nDb = strlen(zDb); + zFts3 = argv[3]; + nFts3 = strlen(zFts3); + + rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA); + if( rc!=SQLITE_OK ) return rc; + + nByte = sizeof(Fts3termTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; + p = (Fts3termTable *)sqlite3_malloc(nByte); + if( !p ) return SQLITE_NOMEM; + memset(p, 0, nByte); + + p->pFts3Tab = (Fts3Table *)&p[1]; + p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; + p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; + p->pFts3Tab->db = db; + + memcpy((char *)p->pFts3Tab->zDb, zDb, nDb); + memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); + sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); + + *ppVtab = (sqlite3_vtab *)p; + return SQLITE_OK; +} + +/* +** This function does the work for both the xDisconnect and xDestroy methods. +** These tables have no persistent representation of their own, so xDisconnect +** and xDestroy are identical operations. +*/ +static int fts3termDisconnectMethod(sqlite3_vtab *pVtab){ + Fts3termTable *p = (Fts3termTable *)pVtab; + Fts3Table *pFts3 = p->pFts3Tab; + int i; + + /* Free any prepared statements held */ + for(i=0; iaStmt); i++){ + sqlite3_finalize(pFts3->aStmt[i]); + } + sqlite3_free(pFts3->zSegmentsTbl); + sqlite3_free(p); + return SQLITE_OK; +} + +#define FTS4AUX_EQ_CONSTRAINT 1 +#define FTS4AUX_GE_CONSTRAINT 2 +#define FTS4AUX_LE_CONSTRAINT 4 + +/* +** xBestIndex - Analyze a WHERE and ORDER BY clause. +*/ +static int fts3termBestIndexMethod( + sqlite3_vtab *pVTab, + sqlite3_index_info *pInfo +){ + UNUSED_PARAMETER(pVTab); + UNUSED_PARAMETER(pInfo); + return SQLITE_OK; +} + +/* +** xOpen - Open a cursor. +*/ +static int fts3termOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ + Fts3termCursor *pCsr; /* Pointer to cursor object to return */ + + UNUSED_PARAMETER(pVTab); + + pCsr = (Fts3termCursor *)sqlite3_malloc(sizeof(Fts3termCursor)); + if( !pCsr ) return SQLITE_NOMEM; + memset(pCsr, 0, sizeof(Fts3termCursor)); + + *ppCsr = (sqlite3_vtab_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** xClose - Close a cursor. +*/ +static int fts3termCloseMethod(sqlite3_vtab_cursor *pCursor){ + Fts3Table *pFts3 = ((Fts3termTable *)pCursor->pVtab)->pFts3Tab; + Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; + + sqlite3Fts3SegmentsClose(pFts3); + sqlite3Fts3SegReaderFinish(&pCsr->csr); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** xNext - Advance the cursor to the next row, if any. +*/ +static int fts3termNextMethod(sqlite3_vtab_cursor *pCursor){ + Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; + Fts3Table *pFts3 = ((Fts3termTable *)pCursor->pVtab)->pFts3Tab; + int rc; + sqlite3_int64 v; + + /* Increment our pretend rowid value. */ + pCsr->iRowid++; + + /* Advance to the next term in the full-text index. */ + if( pCsr->csr.aDoclist==0 + || pCsr->pNext>=&pCsr->csr.aDoclist[pCsr->csr.nDoclist-1] + ){ + rc = sqlite3Fts3SegReaderStep(pFts3, &pCsr->csr); + if( rc!=SQLITE_ROW ){ + pCsr->isEof = 1; + return rc; + } + + pCsr->iCol = 0; + pCsr->iPos = 0; + pCsr->iDocid = 0; + pCsr->pNext = pCsr->csr.aDoclist; + + /* Read docid */ + pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &pCsr->iDocid); + } + + pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); + if( v==0 ){ + pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); + pCsr->iDocid += v; + pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); + pCsr->iCol = 0; + pCsr->iPos = 0; + } + + if( v==1 ){ + pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); + pCsr->iCol += v; + pCsr->iPos = 0; + pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); + } + + pCsr->iPos += (v - 2); + + return SQLITE_OK; +} + +/* +** xFilter - Initialize a cursor to point at the start of its data. +*/ +static int fts3termFilterMethod( + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ + int idxNum, /* Strategy index */ + const char *idxStr, /* Unused */ + int nVal, /* Number of elements in apVal */ + sqlite3_value **apVal /* Arguments for the indexing scheme */ +){ + Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; + Fts3Table *pFts3 = ((Fts3termTable *)pCursor->pVtab)->pFts3Tab; + int rc; + + UNUSED_PARAMETER(nVal); + UNUSED_PARAMETER(idxNum); + UNUSED_PARAMETER(idxStr); + UNUSED_PARAMETER(apVal); + + assert( idxStr==0 && idxNum==0 ); + + /* In case this cursor is being reused, close and zero it. */ + testcase(pCsr->filter.zTerm); + sqlite3Fts3SegReaderFinish(&pCsr->csr); + memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); + + pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; + pCsr->filter.flags |= FTS3_SEGMENT_SCAN; + + rc = sqlite3Fts3SegReaderCursor(pFts3, FTS3_SEGCURSOR_ALL, + pCsr->filter.zTerm, pCsr->filter.nTerm, 0, 1, &pCsr->csr + ); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter); + } + if( rc==SQLITE_OK ){ + rc = fts3termNextMethod(pCursor); + } + return rc; +} + +/* +** xEof - Return true if the cursor is at EOF, or false otherwise. +*/ +static int fts3termEofMethod(sqlite3_vtab_cursor *pCursor){ + Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; + return pCsr->isEof; +} + +/* +** xColumn - Return a column value. +*/ +static int fts3termColumnMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ + int iCol /* Index of column to read value from */ +){ + Fts3termCursor *p = (Fts3termCursor *)pCursor; + + assert( iCol>=0 && iCol<=3 ); + switch( iCol ){ + case 0: + sqlite3_result_text(pCtx, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT); + break; + case 1: + sqlite3_result_int64(pCtx, p->iDocid); + break; + case 2: + sqlite3_result_int64(pCtx, p->iCol); + break; + default: + sqlite3_result_int64(pCtx, p->iPos); + break; + } + + return SQLITE_OK; +} + +/* +** xRowid - Return the current rowid for the cursor. +*/ +static int fts3termRowidMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite_int64 *pRowid /* OUT: Rowid value */ +){ + Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; + *pRowid = pCsr->iRowid; + return SQLITE_OK; +} + +/* +** Register the fts3term module with database connection db. Return SQLITE_OK +** if successful or an error code if sqlite3_create_module() fails. +*/ +int sqlite3Fts3InitTerm(sqlite3 *db){ + static const sqlite3_module fts3term_module = { + 0, /* iVersion */ + fts3termConnectMethod, /* xCreate */ + fts3termConnectMethod, /* xConnect */ + fts3termBestIndexMethod, /* xBestIndex */ + fts3termDisconnectMethod, /* xDisconnect */ + fts3termDisconnectMethod, /* xDestroy */ + fts3termOpenMethod, /* xOpen */ + fts3termCloseMethod, /* xClose */ + fts3termFilterMethod, /* xFilter */ + fts3termNextMethod, /* xNext */ + fts3termEofMethod, /* xEof */ + fts3termColumnMethod, /* xColumn */ + fts3termRowidMethod, /* xRowid */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindFunction */ + 0 /* xRename */ + }; + int rc; /* Return code */ + + rc = sqlite3_create_module(db, "fts4term", &fts3term_module, 0); + return rc; +} + +#endif +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 9d2bfaae8b..425010a3d0 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -2711,15 +2711,31 @@ int sqlite3Fts3UpdateMethod( ** modify the database file. */ if( nArg>1 ){ - sqlite3_int64 iNewRowid; + /* Find the value object that holds the new rowid value. */ sqlite3_value *pNewRowid = apVal[3+p->nColumn]; if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ pNewRowid = apVal[1]; } + if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && ( sqlite3_value_type(apVal[0])==SQLITE_NULL || sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid) )){ + /* The new rowid is not NULL (in this case the rowid will be + ** automatically assigned and there is no chance of a conflict), and + ** the statement is either an INSERT or an UPDATE that modifies the + ** rowid column. So if the conflict mode is REPLACE, then delete any + ** existing row with rowid=pNewRowid. + ** + ** Or, if the conflict mode is not REPLACE, insert the new record into + ** the %_content table. If we hit the duplicate rowid constraint (or any + ** other error) while doing so, return immediately. + ** + ** This branch may also run if pNewRowid contains a value that cannot + ** be losslessly converted to an integer. In this case, the eventual + ** call to fts3InsertData() (either just below or further on in this + ** function) will return SQLITE_MISMATCH. + */ if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel); }else{ diff --git a/main.mk b/main.mk index e1df7a77f1..3df069a71d 100644 --- a/main.mk +++ b/main.mk @@ -299,6 +299,7 @@ TESTSRC2 = \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ + $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c diff --git a/manifest b/manifest index 36dc26d0ca..e810ed1767 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssupport\sfor\son\sconflict\sclauses\sto\sfts3/fts4. -D 2011-04-25T18:49:57.773 +C Extra\stests\sfor\sfts3.\sAnd\sfixes\sfor\sconflict-handling\srelated\sproblems\sin\sfts3. +D 2011-04-26T19:21:34.191 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -61,7 +61,7 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 94fa15fc9d6290e2ba042c24fc83e272c86a40c6 +F ext/fts3/fts3.c ce37973c86f15711a020fa629d8f95cfd642ebc3 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe F ext/fts3/fts3Int.h 945926ea4b6a686c3e9834640a252d9870b7191e F ext/fts3/fts3_aux.c 9e931f55eed8498dafe7bc1160f10cbb1a652fdf @@ -71,10 +71,11 @@ F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295 F ext/fts3/fts3_porter.c d61cfd81fb0fd8fbcb25adcaee0ba671aefaa5c2 F ext/fts3/fts3_snippet.c e857c6a89d81d3b89df59f3b44b35c68d8ed5c62 +F ext/fts3/fts3_term.c c1dbc904ab1c2d687b97643c671795456228ab22 F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3 F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d -F ext/fts3/fts3_write.c 388a7c7119f322d8fd4a5c19c9bd5793da47ccce +F ext/fts3/fts3_write.c b4dfd76d61adb183b87c56573a1bdd0e1d1501da F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9 @@ -101,7 +102,7 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 -F main.mk bd4e376deea4704b2bd9c77a4e6f0fa3de25c495 +F main.mk 496cec8b7890e39127532294e28e5e1d1b1beae1 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac @@ -178,9 +179,9 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff F src/shell.c 72e7e176bf46d5c6518d15ac4ad6847c4bb5df79 -F src/sqlite.h.in 92f2daa48c1926d79db79229fb583cdb22d2d4c5 +F src/sqlite.h.in 3dc514ef85adfdb6377abee4fb780b420fc43f5e F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 -F src/sqliteInt.h 5facb244a286e5c9ecd2f59758019f24a9245c8e +F src/sqliteInt.h 1ec9fa7b728c486e526ec012f73fdfb244238dfc F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -235,15 +236,15 @@ F src/update.c 5bcb56e5c7380a2eecb0e71891dbd4ad7437748f F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60 F src/util.c 465fe10aabf0ca7d7826a156dab919b0b65c525a F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e -F src/vdbe.c ac7aab1148964422b0a91ae5d50d31724fbd82ec +F src/vdbe.c b6396cb75bead0d163577b834cbcf4dcd0cea231 F src/vdbe.h 8a675fefdf7119441fe817c800a9a52440c2e797 F src/vdbeInt.h fe8f58d305e629fff02f61f655aca1d299f1f6ae F src/vdbeapi.c e0e2672e0a96ae3f8575c8ecd02912a3e8a554a1 -F src/vdbeaux.c 9ae5074b19bdff2d8806a278533956fb281510d5 +F src/vdbeaux.c 5c4cd4be10b8247061f97b77fa2b0a23728d43ed F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 -F src/vtab.c 0e89db3e7416ccdab5138883d69ed8006a7e992c +F src/vtab.c bcfd5a8b0a4951a60658cdd887a929f6c3816fdf F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794 F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f @@ -455,7 +456,7 @@ F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0 F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c -F test/fts3conf.test 2dc3bce3fe20d1e9b0ecd27d4040d07a2b79d16b +F test/fts3conf.test 03e5baecc3a1c82fc50fc75789bc1e13861f47fe F test/fts3corrupt.test 7890cc202406858386ddf390a879dcf80bc10abf F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 @@ -931,10 +932,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P ddeea5ab5f6c0c4a86cdfbbb9f24d9d54bf8d301 -R ca5f1cf4bf0f7df53478a4e115a67980 -T *branch * vtab-conflict -T *sym-vtab-conflict * -T -sym-trunk * +P 6d2633a6d0a9bb88fb1a6adac0827dc51df2d4d2 +R 3d729f606d16bb9d30fc86b95bfd6047 U dan -Z dd80c4f8ae24b83ff1c8f809d0d54000 +Z dd1f59cf11e82349f934a1bcc8d1254a diff --git a/manifest.uuid b/manifest.uuid index 942ac84499..923ce0ed96 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6d2633a6d0a9bb88fb1a6adac0827dc51df2d4d2 \ No newline at end of file +fb4a355871d9482ccb28b6ba03b842b3cc87b696 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 2c3b1a5031..0f18c07b40 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -4607,6 +4607,11 @@ struct sqlite3_module { void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg); int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); + /* The methods above are in version 0 of the sqlite_module object. Those + ** below are for version 1 and greater. */ + int (*xSavepoint)(sqlite3_vtab *pVTab, int); + int (*xRelease)(sqlite3_vtab *pVTab, int); + int (*xRollbackTo)(sqlite3_vtab *pVTab, int); }; /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f000a228ca..71cb368cc6 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3049,6 +3049,7 @@ void sqlite3AutoLoadExtensions(sqlite3*); # define sqlite3VtabLock(X) # define sqlite3VtabUnlock(X) # define sqlite3VtabUnlockList(X) +# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK #else void sqlite3VtabClear(sqlite3 *db, Table*); int sqlite3VtabSync(sqlite3 *db, char **); @@ -3057,6 +3058,7 @@ void sqlite3AutoLoadExtensions(sqlite3*); void sqlite3VtabLock(VTable *); void sqlite3VtabUnlock(VTable *); void sqlite3VtabUnlockList(sqlite3*); + int sqlite3VtabSavepoint(sqlite3 *, int, int); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif void sqlite3VtabMakeWritable(Parse*,Table*); diff --git a/src/vdbe.c b/src/vdbe.c index 71756f8fca..b348a397f4 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2821,7 +2821,11 @@ case OP_Transaction: { db->nStatement++; p->iStatement = db->nSavepoint + db->nStatement; } - rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); + + rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); + } /* Store the current value of the database handles deferred constraint ** counter. If the statement transaction needs to be rolled back, diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 4d4bb224f9..55e10eb70c 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2013,6 +2013,15 @@ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ db->nStatement--; p->iStatement = 0; + if( rc==SQLITE_OK ){ + if( eOp==SAVEPOINT_ROLLBACK ){ + rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint); + } + if( rc==SQLITE_OK ){ + rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint); + } + } + /* If the statement transaction is being rolled back, also restore the ** database handles deferred constraint counter to the value it had when ** the statement transaction was opened. */ diff --git a/src/vtab.c b/src/vtab.c index 51826e91f9..51ff9fd910 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -836,7 +836,6 @@ int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ if( pModule->xBegin ){ int i; - /* If pVtab is already in the aVTrans array, return early */ for(i=0; inVTrans; i++){ if( db->aVTrans[i]==pVTab ){ @@ -853,6 +852,32 @@ int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ return rc; } +int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ + int i; + int rc = SQLITE_OK; + + assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN ); + + for(i=0; rc==SQLITE_OK && inVTrans; i++){ + sqlite3_vtab *pVtab = db->aVTrans[i]->pVtab; + sqlite3_module *pMod = db->aVTrans[i]->pMod->pModule; + if( pMod->iVersion>=1 ){ + switch( op ){ + case SAVEPOINT_BEGIN: + rc = pMod->xSavepoint(pVtab, iSavepoint); + break; + case SAVEPOINT_ROLLBACK: + rc = pMod->xRollbackTo(pVtab, iSavepoint); + break; + default: + rc = pMod->xRelease(pVtab, iSavepoint); + break; + } + } + } + return rc; +} + /* ** The first parameter (pDef) is a function implementation. The ** second parameter (pExpr) is the first argument to this function. diff --git a/test/fts3conf.test b/test/fts3conf.test index c3f36d7ff9..7bcf66ef53 100644 --- a/test/fts3conf.test +++ b/test/fts3conf.test @@ -22,7 +22,43 @@ ifcapable !fts3 { return } -do_execsql_test 1.0 { + +proc fts3_integrity {tn db tbl} { + + if {[sqlite3_get_autocommit $db]==0} { + error "fts3_integrity does not work with an open transaction" + } + + set sql [db one {SELECT sql FROM sqlite_master WHERE name = $tbl}] + regexp -nocase {[^(]* using (.*)} $sql -> tail + set cols [list] + $db eval "PRAGMA table_info($tbl)" { + lappend cols $name + } + set cols [join [concat docid $cols] ,] + + $db eval [subst { + CREATE VIRTUAL TABLE fts3check USING fts4term($tbl); + CREATE VIRTUAL TABLE temp.fts3check2 USING $tail; + INSERT INTO temp.fts3check2($cols) SELECT docid, * FROM $tbl; + CREATE VIRTUAL TABLE temp.fts3check3 USING fts4term(fts3check2); + }] + + set m1 [$db one {SELECT md5sum(term, docid, col, pos) FROM fts3check}] + set m2 [$db one {SELECT md5sum(term, docid, col, pos) FROM fts3check3}] + + $db eval { + DROP TABLE fts3check; + DROP TABLE temp.fts3check2; + DROP TABLE temp.fts3check3; + } + + uplevel [list do_test $tn [list set {} $m1] $m2] +} + + + +do_execsql_test 1.0.1 { CREATE VIRTUAL TABLE t1 USING fts3(x); INSERT INTO t1(rowid, x) VALUES(1, 'a b c d'); INSERT INTO t1(rowid, x) VALUES(2, 'e f g h'); @@ -36,6 +72,9 @@ db_save_and_close set T1 "INTO t1(rowid, x) VALUES(1, 'x')" set T2 "INTO t1(rowid, x) SELECT * FROM source" +set T3 "t1 SET docid = 2 WHERE docid = 1" +set T4 "t1 SET docid = CASE WHEN docid = 1 THEN 4 ELSE 3 END WHERE docid <=2" + foreach {tn sql constraint data} [subst { 1 "INSERT OR ROLLBACK $T1" 1 {{a b c d} {e f g h}} 2 "INSERT OR ABORT $T1" 1 {{a b c d} {e f g h} {i j k l}} @@ -48,6 +87,18 @@ foreach {tn sql constraint data} [subst { 8 "INSERT OR FAIL $T2" 1 {{a b c d} {e f g h} {i j k l} z} 9 "INSERT OR IGNORE $T2" 0 {{a b c d} {e f g h} {i j k l} z} 10 "INSERT OR REPLACE $T2" 0 {{a b c d} y {i j k l} z} + + 11 "UPDATE OR ROLLBACK $T3" 1 {{a b c d} {e f g h}} + 12 "UPDATE OR ABORT $T3" 1 {{a b c d} {e f g h} {i j k l}} + 13 "UPDATE OR FAIL $T3" 1 {{a b c d} {e f g h} {i j k l}} + 14 "UPDATE OR IGNORE $T3" 0 {{a b c d} {e f g h} {i j k l}} + 15 "UPDATE OR REPLACE $T3" 0 {{a b c d} {i j k l}} + + 16 "UPDATE OR ROLLBACK $T4" 1 {{a b c d} {e f g h}} + 17 "UPDATE OR ABORT $T4" 1 {{a b c d} {e f g h} {i j k l}} + 18 "UPDATE OR FAIL $T4" 1 {{e f g h} {i j k l} {a b c d}} + 19 "UPDATE OR IGNORE $T4" 0 {{e f g h} {i j k l} {a b c d}} + 20 "UPDATE OR REPLACE $T4" 0 {{e f g h} {a b c d}} }] { db_restore_and_reopen execsql { @@ -58,6 +109,10 @@ foreach {tn sql constraint data} [subst { set R(1) {1 {constraint failed}} do_catchsql_test 1.$tn.1 $sql $R($constraint) do_catchsql_test 1.$tn.2 { SELECT * FROM t1 } [list 0 $data] + catchsql COMMIT + + fts3_integrity 1.$tn.3 db t1 } + finish_test From 5275d2ee6315eeb5b3ffa3c2569607d001cfd5cc Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 27 Apr 2011 01:00:17 +0000 Subject: [PATCH 10/22] Fix a comment typo. FossilOrigin-Name: 19c6625abd5b4e6a4406a8e421ae22527529e305 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbeaux.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index cca88e6f6d..fb51f7cc4a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Test\scase\sfor\sthe\s".log"\scommand\sto\sthe\scommand-line\sshell. -D 2011-04-25T18:20:04.278 +C Fix\sa\scomment\stypo. +D 2011-04-27T01:00:17.858 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -239,7 +239,7 @@ F src/vdbe.c 05deeec6659f2579674a5e6510b3ada2a442f8d5 F src/vdbe.h 8a675fefdf7119441fe817c800a9a52440c2e797 F src/vdbeInt.h fe8f58d305e629fff02f61f655aca1d299f1f6ae F src/vdbeapi.c e0e2672e0a96ae3f8575c8ecd02912a3e8a554a1 -F src/vdbeaux.c 9ae5074b19bdff2d8806a278533956fb281510d5 +F src/vdbeaux.c 5b8150112b490360fdf46f62f470a2ef75b0480a F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 @@ -930,7 +930,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P f7806e03995b314771aa72a08ce55d56d60096cf -R 90125b981bcf635951ddc9b0441cae0d +P 7d0ff26a95cb1e9fcace4641245dda787f3522b4 +R d24ac9411a98171848004eba2e415ab8 U drh -Z da6f87ac8d880cc9cef1dbf3763cd407 +Z 23b5de7727bb069a870fe57a3628ffd6 diff --git a/manifest.uuid b/manifest.uuid index 6f42c53a3b..4c573a5e04 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7d0ff26a95cb1e9fcace4641245dda787f3522b4 \ No newline at end of file +19c6625abd5b4e6a4406a8e421ae22527529e305 \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 4d4bb224f9..b594e13277 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2929,7 +2929,7 @@ int sqlite3VdbeRecordCompare( /* Compilers may complain that mem1.u.i is potentially uninitialized. ** We could initialize it, as shown here, to silence those complaints. - ** But in fact, mem1.u.i will never actually be used initialized, and doing + ** But in fact, mem1.u.i will never actually be used uninitialized, and doing ** the unnecessary initialization has a measurable negative performance ** impact, since this routine is a very high runner. And so, we choose ** to ignore the compiler warnings and leave this variable uninitialized. From d9495cd0c6813a359ee0c3cbd0e8a60ff56031b8 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 27 Apr 2011 12:08:04 +0000 Subject: [PATCH 11/22] Fix problems related to savepoint rollback and fts3. FossilOrigin-Name: ff69f823f23e6fb6e8b2857c4576d9c0732d9572 --- manifest | 20 +++++++-------- manifest.uuid | 2 +- src/sqliteInt.h | 3 --- src/test1.c | 28 +++++++++++++++++++++ src/vdbe.c | 13 ++++++++++ src/vtab.c | 52 +++++++++++++++++++++++++------------- test/fts3conf.test | 63 ++++++++++++++++++++++++++++++---------------- 7 files changed, 128 insertions(+), 53 deletions(-) diff --git a/manifest b/manifest index e810ed1767..525bcf35db 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Extra\stests\sfor\sfts3.\sAnd\sfixes\sfor\sconflict-handling\srelated\sproblems\sin\sfts3. -D 2011-04-26T19:21:34.191 +C Fix\sproblems\srelated\sto\ssavepoint\srollback\sand\sfts3. +D 2011-04-27T12:08:04.566 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -181,12 +181,12 @@ F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff F src/shell.c 72e7e176bf46d5c6518d15ac4ad6847c4bb5df79 F src/sqlite.h.in 3dc514ef85adfdb6377abee4fb780b420fc43f5e F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 -F src/sqliteInt.h 1ec9fa7b728c486e526ec012f73fdfb244238dfc +F src/sqliteInt.h e70a03bb66d209e279b3edeb57d4fdc42a1d9fda F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c 501c9a200fd998a268be475be5858febc90b725b -F src/test1.c 9ca440e80e16e53920904a0a5ac7feffb9b2c9a1 +F src/test1.c e0e4af306b678da05334c2ccaf0377ae8f06e911 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31 F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7 @@ -236,7 +236,7 @@ F src/update.c 5bcb56e5c7380a2eecb0e71891dbd4ad7437748f F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60 F src/util.c 465fe10aabf0ca7d7826a156dab919b0b65c525a F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e -F src/vdbe.c b6396cb75bead0d163577b834cbcf4dcd0cea231 +F src/vdbe.c 672ec2f41b95a6f35b5bbfe555689457dea4789e F src/vdbe.h 8a675fefdf7119441fe817c800a9a52440c2e797 F src/vdbeInt.h fe8f58d305e629fff02f61f655aca1d299f1f6ae F src/vdbeapi.c e0e2672e0a96ae3f8575c8ecd02912a3e8a554a1 @@ -244,7 +244,7 @@ F src/vdbeaux.c 5c4cd4be10b8247061f97b77fa2b0a23728d43ed F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 -F src/vtab.c bcfd5a8b0a4951a60658cdd887a929f6c3816fdf +F src/vtab.c 59db0620d682d34abb96860020429e77bb2b8ced F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794 F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f @@ -456,7 +456,7 @@ F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0 F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c -F test/fts3conf.test 03e5baecc3a1c82fc50fc75789bc1e13861f47fe +F test/fts3conf.test 7b71b8a5f21481dfae43b9f7a26f2506fc2f9e70 F test/fts3corrupt.test 7890cc202406858386ddf390a879dcf80bc10abf F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 @@ -932,7 +932,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 6d2633a6d0a9bb88fb1a6adac0827dc51df2d4d2 -R 3d729f606d16bb9d30fc86b95bfd6047 +P fb4a355871d9482ccb28b6ba03b842b3cc87b696 +R 7aaab6bc74b8e2e016b6645549f49c48 U dan -Z dd1f59cf11e82349f934a1bcc8d1254a +Z e77f5258c98bca31cf26e41c03abebcf diff --git a/manifest.uuid b/manifest.uuid index 923ce0ed96..c29bc677d9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fb4a355871d9482ccb28b6ba03b842b3cc87b696 \ No newline at end of file +ff69f823f23e6fb6e8b2857c4576d9c0732d9572 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 71cb368cc6..9c1bda7a76 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -871,9 +871,6 @@ struct sqlite3 { #endif #ifndef SQLITE_OMIT_VIRTUALTABLE Hash aModule; /* populated by sqlite3_create_module() */ -#if 0 - Table *pVTab; /* vtab with active Connect/Create method */ -#endif VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ VTable **aVTrans; /* Virtual tables with open transactions */ int nVTrans; /* Allocated size of aVTrans */ diff --git a/src/test1.c b/src/test1.c index 8a0d09a716..b79bbd0826 100644 --- a/src/test1.c +++ b/src/test1.c @@ -14,6 +14,7 @@ ** testing of the SQLite library. */ #include "sqliteInt.h" +#include "vdbeInt.h" #include "tcl.h" #include #include @@ -2326,6 +2327,32 @@ static int test_stmt_readonly( return TCL_OK; } +/* +** Usage: uses_stmt_journal STMT +** +** Return true if STMT uses a statement journal. +*/ +static int uses_stmt_journal( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_stmt *pStmt; + int rc; + + if( objc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetStringFromObj(objv[0], 0), " STMT", 0); + return TCL_ERROR; + } + + if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; + rc = sqlite3_stmt_readonly(pStmt); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(((Vdbe *)pStmt)->usesStmtJournal)); + return TCL_OK; +} + /* ** Usage: sqlite3_reset STMT @@ -5583,6 +5610,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_sql", test_sql ,0 }, { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, + { "uses_stmt_journal", uses_stmt_journal ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, diff --git a/src/vdbe.c b/src/vdbe.c index b348a397f4..996c649f88 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2580,6 +2580,14 @@ case OP_Savepoint: { }else{ nName = sqlite3Strlen30(zName); + /* This call is Ok even if this savepoint is actually a transaction + ** savepoint (and therefore should not prompt xSavepoint()) callbacks. + ** If this is a transaction savepoint being opened, it is guaranteed + ** that the db->aVTrans[] array is empty. */ + assert( db->autoCommit==0 || db->nVTrans==0 ); + rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + /* Create a new savepoint structure. */ pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+nName+1); if( pNew ){ @@ -2686,6 +2694,11 @@ case OP_Savepoint: { }else{ db->nDeferredCons = pSavepoint->nDeferredCons; } + + if( !isTransaction ){ + rc = sqlite3VtabSavepoint(db, p1, iSavepoint); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + } } } diff --git a/src/vtab.c b/src/vtab.c index 51ff9fd910..811d2e1640 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -656,8 +656,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ char *zErr = 0; sqlite3_mutex_enter(db->mutex); - pTab = db->pVtabCtx->pTab; - if( !pTab ){ + if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){ sqlite3Error(db, SQLITE_MISUSE, 0); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; @@ -852,26 +851,43 @@ int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ return rc; } +/* +** Invoke either the xSavepoint, xRollbackTo or xRelease method of all +** virtual tables that currently have an open transaction. Pass iSavepoint +** as the second argument to the virtual table method invoked. +** +** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is +** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is +** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with +** an open transaction is invoked. +** +** If any virtual table method returns an error code other than SQLITE_OK, +** processing is abandoned and the error returned to the caller of this +** function immediately. If all calls to virtual table methods are successful, +** SQLITE_OK is returned. +*/ int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ - int i; int rc = SQLITE_OK; assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN ); - - for(i=0; rc==SQLITE_OK && inVTrans; i++){ - sqlite3_vtab *pVtab = db->aVTrans[i]->pVtab; - sqlite3_module *pMod = db->aVTrans[i]->pMod->pModule; - if( pMod->iVersion>=1 ){ - switch( op ){ - case SAVEPOINT_BEGIN: - rc = pMod->xSavepoint(pVtab, iSavepoint); - break; - case SAVEPOINT_ROLLBACK: - rc = pMod->xRollbackTo(pVtab, iSavepoint); - break; - default: - rc = pMod->xRelease(pVtab, iSavepoint); - break; + if( db->aVTrans ){ + int i; + for(i=0; rc==SQLITE_OK && inVTrans; i++){ + const sqlite3_module *pMod = db->aVTrans[i]->pMod->pModule; + if( pMod->iVersion>=1 ){ + int (*xMethod)(sqlite3_vtab *, int); + switch( op ){ + case SAVEPOINT_BEGIN: + xMethod = pMod->xSavepoint; + break; + case SAVEPOINT_ROLLBACK: + xMethod = pMod->xRollbackTo; + break; + default: + xMethod = pMod->xRelease; + break; + } + if( xMethod ) rc = xMethod(db->aVTrans[i]->pVtab, iSavepoint); } } } diff --git a/test/fts3conf.test b/test/fts3conf.test index 7bcf66ef53..7557e96323 100644 --- a/test/fts3conf.test +++ b/test/fts3conf.test @@ -56,6 +56,14 @@ proc fts3_integrity {tn db tbl} { uplevel [list do_test $tn [list set {} $m1] $m2] } +proc sql_uses_stmt {db sql} { + set stmt [sqlite3_prepare db $sql -1 dummy] + set uses [uses_stmt_journal $stmt] + sqlite3_finalize $stmt + return $uses +} + + do_execsql_test 1.0.1 { @@ -75,30 +83,30 @@ set T2 "INTO t1(rowid, x) SELECT * FROM source" set T3 "t1 SET docid = 2 WHERE docid = 1" set T4 "t1 SET docid = CASE WHEN docid = 1 THEN 4 ELSE 3 END WHERE docid <=2" -foreach {tn sql constraint data} [subst { - 1 "INSERT OR ROLLBACK $T1" 1 {{a b c d} {e f g h}} - 2 "INSERT OR ABORT $T1" 1 {{a b c d} {e f g h} {i j k l}} - 3 "INSERT OR FAIL $T1" 1 {{a b c d} {e f g h} {i j k l}} - 4 "INSERT OR IGNORE $T1" 0 {{a b c d} {e f g h} {i j k l}} - 5 "INSERT OR REPLACE $T1" 0 {x {e f g h} {i j k l}} +foreach {tn sql uses constraint data} [subst { + 1 "INSERT OR ROLLBACK $T1" 0 1 {{a b c d} {e f g h}} + 2 "INSERT OR ABORT $T1" 0 1 {{a b c d} {e f g h} {i j k l}} + 3 "INSERT OR FAIL $T1" 0 1 {{a b c d} {e f g h} {i j k l}} + 4 "INSERT OR IGNORE $T1" 0 0 {{a b c d} {e f g h} {i j k l}} + 5 "INSERT OR REPLACE $T1" 0 0 {x {e f g h} {i j k l}} - 6 "INSERT OR ROLLBACK $T2" 1 {{a b c d} {e f g h}} - 7 "INSERT OR ABORT $T2" 1 {{a b c d} {e f g h} {i j k l}} - 8 "INSERT OR FAIL $T2" 1 {{a b c d} {e f g h} {i j k l} z} - 9 "INSERT OR IGNORE $T2" 0 {{a b c d} {e f g h} {i j k l} z} - 10 "INSERT OR REPLACE $T2" 0 {{a b c d} y {i j k l} z} + 6 "INSERT OR ROLLBACK $T2" 1 1 {{a b c d} {e f g h}} + 7 "INSERT OR ABORT $T2" 1 1 {{a b c d} {e f g h} {i j k l}} + 8 "INSERT OR FAIL $T2" 1 1 {{a b c d} {e f g h} {i j k l} z} + 9 "INSERT OR IGNORE $T2" 1 0 {{a b c d} {e f g h} {i j k l} z} + 10 "INSERT OR REPLACE $T2" 1 0 {{a b c d} y {i j k l} z} - 11 "UPDATE OR ROLLBACK $T3" 1 {{a b c d} {e f g h}} - 12 "UPDATE OR ABORT $T3" 1 {{a b c d} {e f g h} {i j k l}} - 13 "UPDATE OR FAIL $T3" 1 {{a b c d} {e f g h} {i j k l}} - 14 "UPDATE OR IGNORE $T3" 0 {{a b c d} {e f g h} {i j k l}} - 15 "UPDATE OR REPLACE $T3" 0 {{a b c d} {i j k l}} + 11 "UPDATE OR ROLLBACK $T3" 1 1 {{a b c d} {e f g h}} + 12 "UPDATE OR ABORT $T3" 1 1 {{a b c d} {e f g h} {i j k l}} + 13 "UPDATE OR FAIL $T3" 1 1 {{a b c d} {e f g h} {i j k l}} + 14 "UPDATE OR IGNORE $T3" 1 0 {{a b c d} {e f g h} {i j k l}} + 15 "UPDATE OR REPLACE $T3" 1 0 {{a b c d} {i j k l}} - 16 "UPDATE OR ROLLBACK $T4" 1 {{a b c d} {e f g h}} - 17 "UPDATE OR ABORT $T4" 1 {{a b c d} {e f g h} {i j k l}} - 18 "UPDATE OR FAIL $T4" 1 {{e f g h} {i j k l} {a b c d}} - 19 "UPDATE OR IGNORE $T4" 0 {{e f g h} {i j k l} {a b c d}} - 20 "UPDATE OR REPLACE $T4" 0 {{e f g h} {a b c d}} + 16 "UPDATE OR ROLLBACK $T4" 1 1 {{a b c d} {e f g h}} + 17 "UPDATE OR ABORT $T4" 1 1 {{a b c d} {e f g h} {i j k l}} + 18 "UPDATE OR FAIL $T4" 1 1 {{e f g h} {i j k l} {a b c d}} + 19 "UPDATE OR IGNORE $T4" 1 0 {{e f g h} {i j k l} {a b c d}} + 20 "UPDATE OR REPLACE $T4" 1 0 {{e f g h} {a b c d}} }] { db_restore_and_reopen execsql { @@ -112,7 +120,20 @@ foreach {tn sql constraint data} [subst { catchsql COMMIT fts3_integrity 1.$tn.3 db t1 + + do_test 1.$tn.4 [list sql_uses_stmt db $sql] $uses } +do_execsql_test 2.1.1 { + DELETE FROM t1; + BEGIN; + INSERT INTO t1 VALUES('a b c'); + SAVEPOINT a; + INSERT INTO t1 VALUES('x y z'); + ROLLBACK TO a; + COMMIT; +} +fts3_integrity 2.1.2 db t1 + finish_test From 3480a01dad92e286c85bbef2f125ec600879bac2 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 27 Apr 2011 16:02:46 +0000 Subject: [PATCH 12/22] Add documentation for the newly introduced sqlite3_vtab_config() and on_conflict() API functions. Test that encountering an SQLITE_MISMATCH in fts3 does not corrupt the full text index. FossilOrigin-Name: abdd70ae0424ccadb7edaf16e970c78b5257d23c --- ext/fts3/fts3_write.c | 4 +++- manifest | 16 ++++++------- manifest.uuid | 2 +- src/sqlite.h.in | 56 ++++++++++++++++++++++++++++++++++++++----- test/fts3conf.test | 16 ++++++++++--- 5 files changed, 75 insertions(+), 19 deletions(-) diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 425010a3d0..d42d4b3f26 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -2734,7 +2734,9 @@ int sqlite3Fts3UpdateMethod( ** This branch may also run if pNewRowid contains a value that cannot ** be losslessly converted to an integer. In this case, the eventual ** call to fts3InsertData() (either just below or further on in this - ** function) will return SQLITE_MISMATCH. + ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is + ** invoked, it will delete zero rows (since no row will have + ** docid=$pNewRowid if $pNewRowid is not an integer value). */ if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel); diff --git a/manifest b/manifest index 525bcf35db..86233879ca 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sproblems\srelated\sto\ssavepoint\srollback\sand\sfts3. -D 2011-04-27T12:08:04.566 +C Add\sdocumentation\sfor\sthe\snewly\sintroduced\ssqlite3_vtab_config()\sand\son_conflict()\sAPI\sfunctions.\sTest\sthat\sencountering\san\sSQLITE_MISMATCH\sin\sfts3\sdoes\snot\scorrupt\sthe\sfull\stext\sindex. +D 2011-04-27T16:02:46.459 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -75,7 +75,7 @@ F ext/fts3/fts3_term.c c1dbc904ab1c2d687b97643c671795456228ab22 F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3 F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d -F ext/fts3/fts3_write.c b4dfd76d61adb183b87c56573a1bdd0e1d1501da +F ext/fts3/fts3_write.c 21ddcc47906807fb9481a0cc161db73469645d68 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9 @@ -179,7 +179,7 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff F src/shell.c 72e7e176bf46d5c6518d15ac4ad6847c4bb5df79 -F src/sqlite.h.in 3dc514ef85adfdb6377abee4fb780b420fc43f5e +F src/sqlite.h.in 5d25d06b8ae0d624179dba9bebb7cce48ce831f0 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 F src/sqliteInt.h e70a03bb66d209e279b3edeb57d4fdc42a1d9fda F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d @@ -456,7 +456,7 @@ F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0 F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c -F test/fts3conf.test 7b71b8a5f21481dfae43b9f7a26f2506fc2f9e70 +F test/fts3conf.test 600b366bb658842d78ed72e05476d14c2409d539 F test/fts3corrupt.test 7890cc202406858386ddf390a879dcf80bc10abf F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 @@ -932,7 +932,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P fb4a355871d9482ccb28b6ba03b842b3cc87b696 -R 7aaab6bc74b8e2e016b6645549f49c48 +P ff69f823f23e6fb6e8b2857c4576d9c0732d9572 +R da0922898dc0b07ed5b043ad92b8294b U dan -Z e77f5258c98bca31cf26e41c03abebcf +Z fc25e1a6e640452f4b097e45b1091129 diff --git a/manifest.uuid b/manifest.uuid index c29bc677d9..d439dc7406 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ff69f823f23e6fb6e8b2857c4576d9c0732d9572 \ No newline at end of file +abdd70ae0424ccadb7edaf16e970c78b5257d23c \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 0f18c07b40..c93922f9df 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6389,6 +6389,9 @@ int sqlite3_wal_checkpoint_v2( ** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()] ** documentation for additional information about the meaning and use of ** each of these values. +** +**
SQLITE_CONFIG_GETMUTEX
+**
^(This option takes a single argument which is a pointer to an */ #define SQLITE_CHECKPOINT_PASSIVE 0 #define SQLITE_CHECKPOINT_FULL 1 @@ -6396,23 +6399,64 @@ int sqlite3_wal_checkpoint_v2( /* ** CAPI3REF: Virtual Table Interface Configuration +** +** This function is called by a virtual table implementation to configure +** various facets of the virtual table interface. At present, there is only +** one option that may be configured using this function. Further options +** may be added in the future. +** +**
+**
SQLITE_VTAB_CONSTRAINT_SUPPORT +**
If the second argument to sqlite3_vtab_config() is +** SQLITE_VTAB_CONSTRAINT_SUPPORT, then SQLite expects this function to +** have been called with three arguments, the third of which being of +** type 'int'. If the third argument is zero, then the virtual table +** is indicating that it does not support constraints. In this case if +** a call to the xUpdate method returns SQLITE_CONSTRAINT, the entire +** statement is rolled back as if [ON CONFLICT | OR ABORT] had been +** specified as part of the users SQL statement, regardless of the actual +** ON CONFLICT mode specified. +** +** If the third argument passed is non-zero, then the virtual table +** implementation must guarantee that if xUpdate returns +** SQLITE_CONSTRAINT, it does so before any modifications to internal +** or persistent data structures have been made. If the [ON CONFLICT] +** mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite is able to roll back +** a statement or database transaction, and abandon or continue processing +** the current SQL statement as appropriate. If the ON CONFLICT mode is +** REPLACE and the xUpdate method returns SQLITE_CONSTRAINT, SQLite +** handles this as if the ON CONFLICT mode had been ABORT. +** +** Virtual table implementations that are required to handle OR REPLACE +** must do so within the xUpdate method. If a call to the +** [sqlite3_vtab_on_conflict()] function indicates that the current ON +** CONFLICT policy is REPLACE, the virtual table implementation should +** silently replace the appropriate rows within the xUpdate callback and +** return SQLITE_OK. Or, if this is not possible, it may return +** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT +** constraint handling. +**
+** */ +#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 int sqlite3_vtab_config(sqlite3*, int op, ...); /* ** CAPI3REF: Determine The Virtual Table Conflict Policy -*/ -#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 -int sqlite3_vtab_on_conflict(sqlite3 *); - -/* -** CAPI3REF: Virtual Table Conflict Policies +** +** This function may only be called from within a call to the xUpdate method +** of a virtual table implementation for an INSERT or UPDATE operation. The +** value returned is one of SQLITE_ROLLBACK, SQLITE_IGNORE, SQLITE_FAIL, +** SQLITE_ABORT or SQLITE_REPLACE, according to the [ON CONFLICT] mode of the +** SQL statement that triggered the callback. */ #define SQLITE_ROLLBACK 1 /* #define SQLITE_IGNORE 2 */ #define SQLITE_FAIL 3 /* #define SQLITE_ABORT 4 */ #define SQLITE_REPLACE 5 +int sqlite3_vtab_on_conflict(sqlite3 *); + /* diff --git a/test/fts3conf.test b/test/fts3conf.test index 7557e96323..4f5478c064 100644 --- a/test/fts3conf.test +++ b/test/fts3conf.test @@ -56,6 +56,9 @@ proc fts3_integrity {tn db tbl} { uplevel [list do_test $tn [list set {} $m1] $m2] } +# Return true if the SQL statement passed as the second argument uses a +# statement transaction. +# proc sql_uses_stmt {db sql} { set stmt [sqlite3_prepare db $sql -1 dummy] set uses [uses_stmt_journal $stmt] @@ -63,9 +66,6 @@ proc sql_uses_stmt {db sql} { return $uses } - - - do_execsql_test 1.0.1 { CREATE VIRTUAL TABLE t1 USING fts3(x); INSERT INTO t1(rowid, x) VALUES(1, 'a b c d'); @@ -135,5 +135,15 @@ do_execsql_test 2.1.1 { } fts3_integrity 2.1.2 db t1 +do_catchsql_test 2.2.1 { + DELETE FROM t1; + BEGIN; + INSERT INTO t1(docid, x) VALUES(0, 'a b c'); + INSERT INTO t1(docid, x) VALUES(1, 'a b c'); + REPLACE INTO t1(docid, x) VALUES('zero', 'd e f'); +} {1 {datatype mismatch}} +do_execsql_test 2.2.2 { COMMIT } +do_execsql_test 2.2.3 { SELECT * FROM t1 } {{a b c} {a b c}} +fts3_integrity 2.2.4 db t1 finish_test From 5b92f192d9dcba108532d62488d8ce49330b85d5 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 27 Apr 2011 16:05:42 +0000 Subject: [PATCH 13/22] Expose the UTF8 to MBCS conversion routine in os_win.c to external applications. FossilOrigin-Name: 7b479b9bee93df909edecd44c7d6584d943b39c9 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/os_win.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index fb51f7cc4a..b4059728e0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\scomment\stypo. -D 2011-04-27T01:00:17.858 +C Expose\sthe\sUTF8\sto\sMBCS\sconversion\sroutine\sin\sos_win.c\sto\sexternal\napplications. +D 2011-04-27T16:05:42.346 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -163,7 +163,7 @@ F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9 F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 F src/os_unix.c 2c67d126874b78eb427371db4793f0e8fbc7448b -F src/os_win.c d149b9a7dfdd38de09afc054f8168cd3cd80630b +F src/os_win.c 0d2fb750f74e403b40286fd500882dcea93db275 F src/pager.c 055239dcdfe12b3f5d97f6f01f85da01e2d6d912 F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 @@ -930,7 +930,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 7d0ff26a95cb1e9fcace4641245dda787f3522b4 -R d24ac9411a98171848004eba2e415ab8 +P 19c6625abd5b4e6a4406a8e421ae22527529e305 +R fcd8fa82794547de86a43c56e868f9a6 U drh -Z 23b5de7727bb069a870fe57a3628ffd6 +Z f1379103c390c9054c004f3716fc6621 diff --git a/manifest.uuid b/manifest.uuid index 4c573a5e04..5cdcab0b2d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -19c6625abd5b4e6a4406a8e421ae22527529e305 \ No newline at end of file +7b479b9bee93df909edecd44c7d6584d943b39c9 \ No newline at end of file diff --git a/src/os_win.c b/src/os_win.c index 654a964468..cd7a69bce0 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -286,7 +286,7 @@ char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){ ** Convert UTF-8 to multibyte character string. Space to hold the ** returned string is obtained from malloc(). */ -static char *utf8ToMbcs(const char *zFilename){ +char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){ char *zFilenameMbcs; WCHAR *zTmpWide; @@ -2004,7 +2004,7 @@ static void *convertUtf8Filename(const char *zFilename){ */ #if SQLITE_OS_WINCE==0 }else{ - zConverted = utf8ToMbcs(zFilename); + zConverted = sqlite3_win32_utf8_to_mbcs(zFilename); #endif } /* caller will handle out of memory */ From 840561f2a4972438f4f867b86285efcda7353454 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 27 Apr 2011 18:08:42 +0000 Subject: [PATCH 14/22] Change the name of an internal function to avoid conflicts with the math library. FossilOrigin-Name: 1bd1484cd7e09709d87aa84b82e87597d00a4162 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/func.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index b4059728e0..33d8213904 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Expose\sthe\sUTF8\sto\sMBCS\sconversion\sroutine\sin\sos_win.c\sto\sexternal\napplications. -D 2011-04-27T16:05:42.346 +C Change\sthe\sname\sof\san\sinternal\sfunction\sto\savoid\sconflicts\swith\sthe\smath\nlibrary. +D 2011-04-27T18:08:42.071 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -133,7 +133,7 @@ F src/delete.c 7a24fcc9a31664d145acb97ce56b6d9f249a25e4 F src/expr.c e3cf0957c6b8faaaf7386a3bc69e53c0dc9705be F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c a43ba8a005fb5efd1deeee06853e3a6120d46a91 -F src/func.c 6d907d397c9e6eded680f8946499efdf224d34bd +F src/func.c b9117e40975245b8504cf3625d7e321d8d4b63dc F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 @@ -930,7 +930,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 19c6625abd5b4e6a4406a8e421ae22527529e305 -R fcd8fa82794547de86a43c56e868f9a6 +P 7b479b9bee93df909edecd44c7d6584d943b39c9 +R 896972878681caa8688ae0b699a33ade U drh -Z f1379103c390c9054c004f3716fc6621 +Z 901a5c52f94c833aabdd9b6dd2fd3b65 diff --git a/manifest.uuid b/manifest.uuid index 5cdcab0b2d..f22bfc0a4d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7b479b9bee93df909edecd44c7d6584d943b39c9 \ No newline at end of file +1bd1484cd7e09709d87aa84b82e87597d00a4162 \ No newline at end of file diff --git a/src/func.c b/src/func.c index e75fa47e7a..0b9b600d79 100644 --- a/src/func.c +++ b/src/func.c @@ -779,7 +779,7 @@ static void sourceidFunc( ** sqlite3_log(). The return value is NULL. The function exists purely for ** its side-effects. */ -static void logFunc( +static void errlogFunc( sqlite3_context *context, int argc, sqlite3_value **argv @@ -1556,7 +1556,7 @@ void sqlite3RegisterGlobalFunctions(void){ FUNCTION(nullif, 2, 0, 1, nullifFunc ), FUNCTION(sqlite_version, 0, 0, 0, versionFunc ), FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), - FUNCTION(sqlite_log, 2, 0, 0, logFunc ), + FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), From 4d953fd5b167908d16ede9f41a29087e98d57dc8 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 27 Apr 2011 19:54:44 +0000 Subject: [PATCH 15/22] In windows, ignore ERROR_NOT_LOCKED when calling the read-lock removal routine. FossilOrigin-Name: f55156c5194e85c47728b8a97fde3e5f0a5c9b56 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/os_win.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 33d8213904..51018c9381 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sname\sof\san\sinternal\sfunction\sto\savoid\sconflicts\swith\sthe\smath\nlibrary. -D 2011-04-27T18:08:42.071 +C In\swindows,\signore\sERROR_NOT_LOCKED\swhen\scalling\sthe\sread-lock\sremoval\nroutine. +D 2011-04-27T19:54:44.305 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -163,7 +163,7 @@ F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9 F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 F src/os_unix.c 2c67d126874b78eb427371db4793f0e8fbc7448b -F src/os_win.c 0d2fb750f74e403b40286fd500882dcea93db275 +F src/os_win.c 4271f0bf733c0b45635ddcfb41c935573de8284c F src/pager.c 055239dcdfe12b3f5d97f6f01f85da01e2d6d912 F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 @@ -930,7 +930,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 7b479b9bee93df909edecd44c7d6584d943b39c9 -R 896972878681caa8688ae0b699a33ade +P 1bd1484cd7e09709d87aa84b82e87597d00a4162 +R 9628f97d1cf37de85ec8d2f9df941216 U drh -Z 901a5c52f94c833aabdd9b6dd2fd3b65 +Z cb18bd6131d197c3ee5b628d2860f479 diff --git a/manifest.uuid b/manifest.uuid index f22bfc0a4d..68e76d018c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1bd1484cd7e09709d87aa84b82e87597d00a4162 \ No newline at end of file +f55156c5194e85c47728b8a97fde3e5f0a5c9b56 \ No newline at end of file diff --git a/src/os_win.c b/src/os_win.c index cd7a69bce0..4e91f7ab32 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -1052,7 +1052,7 @@ static int unlockReadLock(winFile *pFile){ res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0); #endif } - if( res == 0 ){ + if( res==0 && GetLastError()!=ERROR_NOT_LOCKED ){ pFile->lastErrno = GetLastError(); winLogError(SQLITE_IOERR_UNLOCK, "unlockReadLock", pFile->zPath); } From c6055c7374b5bd51f9acd47c0f26ad0d36011152 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 28 Apr 2011 18:46:46 +0000 Subject: [PATCH 16/22] Have r-tree virtual tables support on-conflict clauses. FossilOrigin-Name: 822ab52f1023b1c4973c806cc75454acd4e95fd0 --- ext/rtree/rtree.c | 241 ++++++++++++++++++++++++------------------ ext/rtree/rtree1.test | 81 ++++++++++++++ manifest | 18 ++-- manifest.uuid | 2 +- test/fts3conf.test | 10 -- test/tester.tcl | 11 ++ 6 files changed, 242 insertions(+), 121 deletions(-) diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index ebf430a98c..4529f3aabb 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -2625,6 +2625,90 @@ static int newRowid(Rtree *pRtree, i64 *piRowid){ return rc; } +/* +** Remove the entry with rowid=iDelete from the r-tree structure. +*/ +static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ + int rc; /* Return code */ + RtreeNode *pLeaf; /* Leaf node containing record iDelete */ + int iCell; /* Index of iDelete cell in pLeaf */ + RtreeNode *pRoot; /* Root node of rtree structure */ + + + /* Obtain a reference to the root node to initialise Rtree.iDepth */ + rc = nodeAcquire(pRtree, 1, 0, &pRoot); + + /* Obtain a reference to the leaf node that contains the entry + ** about to be deleted. + */ + if( rc==SQLITE_OK ){ + rc = findLeafNode(pRtree, iDelete, &pLeaf); + } + + /* Delete the cell in question from the leaf node. */ + if( rc==SQLITE_OK ){ + int rc2; + rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); + if( rc==SQLITE_OK ){ + rc = deleteCell(pRtree, pLeaf, iCell, 0); + } + rc2 = nodeRelease(pRtree, pLeaf); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + + /* Delete the corresponding entry in the _rowid table. */ + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete); + sqlite3_step(pRtree->pDeleteRowid); + rc = sqlite3_reset(pRtree->pDeleteRowid); + } + + /* Check if the root node now has exactly one child. If so, remove + ** it, schedule the contents of the child for reinsertion and + ** reduce the tree height by one. + ** + ** This is equivalent to copying the contents of the child into + ** the root node (the operation that Gutman's paper says to perform + ** in this scenario). + */ + if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ + int rc2; + RtreeNode *pChild; + i64 iChild = nodeGetRowid(pRtree, pRoot, 0); + rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); + if( rc==SQLITE_OK ){ + rc = removeNode(pRtree, pChild, pRtree->iDepth-1); + } + rc2 = nodeRelease(pRtree, pChild); + if( rc==SQLITE_OK ) rc = rc2; + if( rc==SQLITE_OK ){ + pRtree->iDepth--; + writeInt16(pRoot->zData, pRtree->iDepth); + pRoot->isDirty = 1; + } + } + + /* Re-insert the contents of any underfull nodes removed from the tree. */ + for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ + if( rc==SQLITE_OK ){ + rc = reinsertNodeContent(pRtree, pLeaf); + } + pRtree->pDeleted = pLeaf->pNext; + sqlite3_free(pLeaf); + } + + /* Release the reference to the root node. */ + if( rc==SQLITE_OK ){ + rc = nodeRelease(pRtree, pRoot); + }else{ + nodeRelease(pRtree, pRoot); + } + + return rc; +} + /* ** The xUpdate method for rtree module virtual tables. */ @@ -2636,103 +2720,25 @@ static int rtreeUpdate( ){ Rtree *pRtree = (Rtree *)pVtab; int rc = SQLITE_OK; + RtreeCell cell; /* New cell to insert if nData>1 */ + int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ rtreeReference(pRtree); - assert(nData>=1); - /* If azData[0] is not an SQL NULL value, it is the rowid of a - ** record to delete from the r-tree table. The following block does - ** just that. + /* Constraint handling. A write operation on an r-tree table may return + ** SQLITE_CONSTRAINT for two reasons: + ** + ** 1. A duplicate rowid value, or + ** 2. The supplied data violates the "x2>=x1" constraint. + ** + ** In the first case, if the conflict-handling mode is REPLACE, then + ** the conflicting row can be removed before proceeding. In the second + ** case, SQLITE_CONSTRAINT must be returned regardless of the + ** conflict-handling mode specified by the user. */ - if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){ - i64 iDelete; /* The rowid to delete */ - RtreeNode *pLeaf; /* Leaf node containing record iDelete */ - int iCell; /* Index of iDelete cell in pLeaf */ - RtreeNode *pRoot; - - /* Obtain a reference to the root node to initialise Rtree.iDepth */ - rc = nodeAcquire(pRtree, 1, 0, &pRoot); - - /* Obtain a reference to the leaf node that contains the entry - ** about to be deleted. - */ - if( rc==SQLITE_OK ){ - iDelete = sqlite3_value_int64(azData[0]); - rc = findLeafNode(pRtree, iDelete, &pLeaf); - } - - /* Delete the cell in question from the leaf node. */ - if( rc==SQLITE_OK ){ - int rc2; - rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); - if( rc==SQLITE_OK ){ - rc = deleteCell(pRtree, pLeaf, iCell, 0); - } - rc2 = nodeRelease(pRtree, pLeaf); - if( rc==SQLITE_OK ){ - rc = rc2; - } - } - - /* Delete the corresponding entry in the _rowid table. */ - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete); - sqlite3_step(pRtree->pDeleteRowid); - rc = sqlite3_reset(pRtree->pDeleteRowid); - } - - /* Check if the root node now has exactly one child. If so, remove - ** it, schedule the contents of the child for reinsertion and - ** reduce the tree height by one. - ** - ** This is equivalent to copying the contents of the child into - ** the root node (the operation that Gutman's paper says to perform - ** in this scenario). - */ - if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ - int rc2; - RtreeNode *pChild; - i64 iChild = nodeGetRowid(pRtree, pRoot, 0); - rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); - if( rc==SQLITE_OK ){ - rc = removeNode(pRtree, pChild, pRtree->iDepth-1); - } - rc2 = nodeRelease(pRtree, pChild); - if( rc==SQLITE_OK ) rc = rc2; - if( rc==SQLITE_OK ){ - pRtree->iDepth--; - writeInt16(pRoot->zData, pRtree->iDepth); - pRoot->isDirty = 1; - } - } - - /* Re-insert the contents of any underfull nodes removed from the tree. */ - for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ - if( rc==SQLITE_OK ){ - rc = reinsertNodeContent(pRtree, pLeaf); - } - pRtree->pDeleted = pLeaf->pNext; - sqlite3_free(pLeaf); - } - - /* Release the reference to the root node. */ - if( rc==SQLITE_OK ){ - rc = nodeRelease(pRtree, pRoot); - }else{ - nodeRelease(pRtree, pRoot); - } - } - - /* If the azData[] array contains more than one element, elements - ** (azData[2]..azData[argc-1]) contain a new record to insert into - ** the r-tree structure. - */ - if( rc==SQLITE_OK && nData>1 ){ - /* Insert a new record into the r-tree */ - RtreeCell cell; + if( nData>1 ){ int ii; - RtreeNode *pLeaf; /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */ assert( nData==(pRtree->nDim*2 + 3) ); @@ -2756,18 +2762,49 @@ static int rtreeUpdate( } } - /* Figure out the rowid of the new row. */ - if( sqlite3_value_type(azData[2])==SQLITE_NULL ){ - rc = newRowid(pRtree, &cell.iRowid); - }else{ + /* If a rowid value was supplied, check if it is already present in + ** the table. If so, the constraint has failed. */ + if( sqlite3_value_type(azData[2])!=SQLITE_NULL ){ cell.iRowid = sqlite3_value_int64(azData[2]); - sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); - if( SQLITE_ROW==sqlite3_step(pRtree->pReadRowid) ){ - sqlite3_reset(pRtree->pReadRowid); - rc = SQLITE_CONSTRAINT; - goto constraint; + if( sqlite3_value_type(azData[0])==SQLITE_NULL + || sqlite3_value_int64(azData[0])!=cell.iRowid + ){ + int steprc; + sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); + steprc = sqlite3_step(pRtree->pReadRowid); + rc = sqlite3_reset(pRtree->pReadRowid); + if( SQLITE_ROW==steprc ){ + if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ + rc = rtreeDeleteRowid(pRtree, cell.iRowid); + }else{ + rc = SQLITE_CONSTRAINT; + goto constraint; + } + } } - rc = sqlite3_reset(pRtree->pReadRowid); + bHaveRowid = 1; + } + } + + /* If azData[0] is not an SQL NULL value, it is the rowid of a + ** record to delete from the r-tree table. The following block does + ** just that. + */ + if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){ + rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(azData[0])); + } + + /* If the azData[] array contains more than one element, elements + ** (azData[2]..azData[argc-1]) contain a new record to insert into + ** the r-tree structure. + */ + if( rc==SQLITE_OK && nData>1 ){ + /* Insert the new record into the r-tree */ + RtreeNode *pLeaf; + + /* Figure out the rowid of the new row. */ + if( bHaveRowid==0 ){ + rc = newRowid(pRtree, &cell.iRowid); } *pRowid = cell.iRowid; @@ -3008,6 +3045,8 @@ static int rtreeInit( return SQLITE_ERROR; } + sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); + /* Allocate the sqlite3_vtab structure */ nDb = strlen(argv[1]); nName = strlen(argv[2]); diff --git a/ext/rtree/rtree1.test b/ext/rtree/rtree1.test index fe5fa0ae50..583b028507 100644 --- a/ext/rtree/rtree1.test +++ b/ext/rtree/rtree1.test @@ -31,6 +31,8 @@ source $testdir/tester.tcl # rtree-7.*: Test renaming an r-tree table. # rtree-8.*: Test constrained scans of r-tree data. # +# rtree-12.*: Test that on-conflict clauses are supported. +# ifcapable !rtree { finish_test @@ -416,4 +418,83 @@ do_test rtree-11.2 { } } {2} +#------------------------------------------------------------------------- +# Test on-conflict clause handling. +# +db_delete_and_reopen +do_execsql_test 12.0 { + CREATE VIRTUAL TABLE t1 USING rtree_i32(idx, x1, x2, y1, y2); + INSERT INTO t1 VALUES(1, 1, 2, 3, 4); + INSERT INTO t1 VALUES(2, 2, 3, 4, 5); + INSERT INTO t1 VALUES(3, 3, 4, 5, 6); + + CREATE TABLE source(idx, x1, x2, y1, y2); + INSERT INTO source VALUES(5, 8, 8, 8, 8); + INSERT INTO source VALUES(2, 7, 7, 7, 7); + +} +db_save_and_close +foreach {tn sql_template testdata} { + 1 "INSERT %CONF% INTO t1 VALUES(2, 7, 7, 7, 7)" { + ROLLBACK 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6} + ABORT 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + IGNORE 0 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + FAIL 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + REPLACE 0 0 {1 1 2 3 4 2 7 7 7 7 3 3 4 5 6 4 4 5 6 7} + } + + 2 "INSERT %CONF% INTO t1 SELECT * FROM source" { + ROLLBACK 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6} + ABORT 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + IGNORE 1 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7 5 8 8 8 8} + FAIL 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7 5 8 8 8 8} + REPLACE 1 0 {1 1 2 3 4 2 7 7 7 7 3 3 4 5 6 4 4 5 6 7 5 8 8 8 8} + } + + 3 "UPDATE %CONF% t1 SET idx = 2 WHERE idx = 4" { + ROLLBACK 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6} + ABORT 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + IGNORE 1 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + FAIL 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + REPLACE 1 0 {1 1 2 3 4 2 4 5 6 7 3 3 4 5 6} + } + + 3 "UPDATE %CONF% t1 SET idx = ((idx+1)%5)+1 WHERE idx > 2" { + ROLLBACK 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6} + ABORT 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + IGNORE 1 0 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} + FAIL 1 1 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} + REPLACE 1 0 {1 4 5 6 7 2 2 3 4 5 5 3 4 5 6} + } + + 4 "INSERT %CONF% INTO t1 VALUES(2, 7, 6, 7, 7)" { + ROLLBACK 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6} + ABORT 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + IGNORE 0 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + FAIL 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + REPLACE 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} + } + +} { + foreach {mode uses error data} $testdata { + db_restore_and_reopen + + set sql [string map [list %CONF% "OR $mode"] $sql_template] + set testname "12.$tn.[string tolower $mode]" + + execsql { + BEGIN; + INSERT INTO t1 VALUES(4, 4, 5, 6, 7); + } + + set res(0) {0 {}} + set res(1) {1 {constraint failed}} + do_catchsql_test $testname.1 $sql $res($error) + do_test $testname.2 [list sql_uses_stmt db $sql] $uses + do_execsql_test $testname.3 { SELECT * FROM t1 ORDER BY idx } $data + + do_test $testname.4 { rtree_check db t1 } 0 + db close + } +} finish_test diff --git a/manifest b/manifest index 86233879ca..bd7a00eb95 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sdocumentation\sfor\sthe\snewly\sintroduced\ssqlite3_vtab_config()\sand\son_conflict()\sAPI\sfunctions.\sTest\sthat\sencountering\san\sSQLITE_MISMATCH\sin\sfts3\sdoes\snot\scorrupt\sthe\sfull\stext\sindex. -D 2011-04-27T16:02:46.459 +C Have\sr-tree\svirtual\stables\ssupport\son-conflict\sclauses. +D 2011-04-28T18:46:46.861 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -82,9 +82,9 @@ F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9 F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/rtree.c f5fa951eba03c41d292958064604a033021acdee +F ext/rtree/rtree.c 829c6901a2b065ff93a68d431f9eaba8de7128e0 F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e -F ext/rtree/rtree1.test dbd4250ac0ad367a262eb9676f7e3080b0368206 +F ext/rtree/rtree1.test 28e1b8da4da98093ce3210187434dd760a8d89d8 F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc F ext/rtree/rtree4.test 0061e6f464fd3dc6a79f82454c5a1c3dadbe42af @@ -456,7 +456,7 @@ F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0 F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c -F test/fts3conf.test 600b366bb658842d78ed72e05476d14c2409d539 +F test/fts3conf.test 8e65ea56f88ced6cdd2252bdddb1a8327ae5af7e F test/fts3corrupt.test 7890cc202406858386ddf390a879dcf80bc10abf F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 @@ -688,7 +688,7 @@ F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05 -F test/tester.tcl 6fa3d2f581b479a3a088b1b5b0d145e548ebe662 +F test/tester.tcl d5139260aadd64f318ecbcf982316d5bbc254b1b F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca @@ -932,7 +932,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P ff69f823f23e6fb6e8b2857c4576d9c0732d9572 -R da0922898dc0b07ed5b043ad92b8294b +P abdd70ae0424ccadb7edaf16e970c78b5257d23c +R c8f4a330c2633adfb2862fa8f9efbab2 U dan -Z fc25e1a6e640452f4b097e45b1091129 +Z e17a424fc4dea753d2cbffe0969a3e63 diff --git a/manifest.uuid b/manifest.uuid index d439dc7406..e2827a6e32 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -abdd70ae0424ccadb7edaf16e970c78b5257d23c \ No newline at end of file +822ab52f1023b1c4973c806cc75454acd4e95fd0 \ No newline at end of file diff --git a/test/fts3conf.test b/test/fts3conf.test index 4f5478c064..ce410277ca 100644 --- a/test/fts3conf.test +++ b/test/fts3conf.test @@ -56,16 +56,6 @@ proc fts3_integrity {tn db tbl} { uplevel [list do_test $tn [list set {} $m1] $m2] } -# Return true if the SQL statement passed as the second argument uses a -# statement transaction. -# -proc sql_uses_stmt {db sql} { - set stmt [sqlite3_prepare db $sql -1 dummy] - set uses [uses_stmt_journal $stmt] - sqlite3_finalize $stmt - return $uses -} - do_execsql_test 1.0.1 { CREATE VIRTUAL TABLE t1 USING fts3(x); INSERT INTO t1(rowid, x) VALUES(1, 'a b c d'); diff --git a/test/tester.tcl b/test/tester.tcl index bae10530c6..7e15ab07d6 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -747,6 +747,17 @@ proc integrity_check {name {db db}} { } } + +# Return true if the SQL statement passed as the second argument uses a +# statement transaction. +# +proc sql_uses_stmt {db sql} { + set stmt [sqlite3_prepare $db $sql -1 dummy] + set uses [uses_stmt_journal $stmt] + sqlite3_finalize $stmt + return $uses +} + proc fix_ifcapable_expr {expr} { set ret "" set state 0 From 0f599faa294d3a7ee0316a5a249c87a3c94351a0 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 4 May 2011 12:52:59 +0000 Subject: [PATCH 17/22] Optimize "ORDER BY rowid/docid DESC/ASC" clauses on FTS tables. FossilOrigin-Name: 13395121e3d17ab6581dc5f6736ea324321a374c --- ext/fts3/fts3.c | 80 +++++++++++++++++++++++++++--- ext/fts3/fts3Int.h | 3 +- ext/fts3/fts3_snippet.c | 10 ++-- ext/fts3/fts3_term.c | 16 +++++- manifest | 19 +++---- manifest.uuid | 2 +- test/fts3sort.test | 107 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 213 insertions(+), 24 deletions(-) create mode 100644 test/fts3sort.test diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 52b853a9a2..faf497d9a0 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -419,6 +419,28 @@ static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){ *pVal += iVal; } +/* +** +*/ +static void fts3GetReverseDeltaVarint( + char **pp, + char *pStart, + sqlite3_int64 *pVal +){ + sqlite3_int64 iVal; + char *p = *pp; + + /* Pointer p now points at the first byte past the varint we are + ** interested in. So, unless the doclist is corrupt, the 0x80 bit is + ** clear on character p[-1]. */ + for(p = (*pp)-2; p>=pStart && *p&0x80; p--); + p++; + *pp = p; + + sqlite3Fts3GetVarint(p, &iVal); + *pVal -= iVal; +} + /* ** As long as *pp has not reached its end (pEnd), then do the same ** as fts3GetDeltaVarint(): read a single varint and add it to *pVal. @@ -1094,6 +1116,22 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ pInfo->aConstraintUsage[iCons].argvIndex = 1; pInfo->aConstraintUsage[iCons].omit = 1; } + + /* Regardless of the strategy selected, FTS can deliver rows in rowid (or + ** docid) order. Both ascending and descending are possible. + */ + if( pInfo->nOrderBy==1 ){ + struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0]; + if( pOrder->iColumn<0 || pOrder->iColumn==p->nColumn+1 ){ + if( pOrder->desc ){ + pInfo->idxStr = "DESC"; + }else{ + pInfo->idxStr = "ASC"; + } + } + pInfo->orderByConsumed = 1; + } + return SQLITE_OK; } @@ -2998,12 +3036,20 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){ } pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0); }else{ - if( pCsr->pNextId>=&pCsr->aDoclist[pCsr->nDoclist] ){ - pCsr->isEof = 1; - break; + if( pCsr->desc==0 ){ + if( pCsr->pNextId>=&pCsr->aDoclist[pCsr->nDoclist] ){ + pCsr->isEof = 1; + break; + } + fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId); + }else{ + fts3GetReverseDeltaVarint(&pCsr->pNextId,pCsr->aDoclist,&pCsr->iPrevId); + if( pCsr->pNextId<=pCsr->aDoclist ){ + pCsr->isEof = 1; + break; + } } sqlite3_reset(pCsr->pStmt); - fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId); pCsr->isRequireSeek = 1; pCsr->isMatchinfoNeeded = 1; } @@ -3036,8 +3082,8 @@ static int fts3FilterMethod( sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ const char *azSql[] = { - "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?", /* non-full-scan */ - "SELECT %s FROM %Q.'%q_content' AS x ", /* full-scan */ + "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?", /* non-full-scan */ + "SELECT %s FROM %Q.'%q_content' AS x ORDER BY docid %s", /* full-scan */ }; int rc; /* Return code */ char *zSql; /* SQL statement used to access %_content */ @@ -3093,7 +3139,9 @@ static int fts3FilterMethod( ** row by docid. */ zSql = (char *)azSql[idxNum==FTS3_FULLSCAN_SEARCH]; - zSql = sqlite3_mprintf(zSql, p->zReadExprlist, p->zDb, p->zName); + zSql = sqlite3_mprintf( + zSql, p->zReadExprlist, p->zDb, p->zName, (idxStr ? idxStr : "ASC") + ); if( !zSql ){ rc = SQLITE_NOMEM; }else{ @@ -3105,7 +3153,22 @@ static int fts3FilterMethod( } pCsr->eSearch = (i16)idxNum; + assert( pCsr->desc==0 ); if( rc!=SQLITE_OK ) return rc; + if( rc==SQLITE_OK && pCsr->nDoclist>0 && idxStr && idxStr[0]=='D' ){ + sqlite3_int64 iDocid = 0; + char *csr = pCsr->aDoclist; + while( csr<&pCsr->aDoclist[pCsr->nDoclist] ){ + fts3GetDeltaVarint(&csr, &iDocid); + } + pCsr->pNextId = csr; + pCsr->iPrevId = iDocid; + pCsr->desc = 1; + pCsr->isRequireSeek = 1; + pCsr->isMatchinfoNeeded = 1; + pCsr->eEvalmode = FTS3_EVAL_NEXT; + return SQLITE_OK; + } return fts3NextMethod(pCursor); } @@ -3264,6 +3327,7 @@ int sqlite3Fts3ExprLoadFtDoclist( ** stored in pExpr->aDoclist. */ char *sqlite3Fts3FindPositions( + Fts3Cursor *pCursor, /* Associate FTS3 cursor */ Fts3Expr *pExpr, /* Access this expressions doclist */ sqlite3_int64 iDocid, /* Docid associated with requested pos-list */ int iCol /* Column of requested pos-list */ @@ -3273,7 +3337,7 @@ char *sqlite3Fts3FindPositions( char *pEnd = &pExpr->aDoclist[pExpr->nDoclist]; char *pCsr; - if( pExpr->pCurrent==0 ){ + if( pExpr->pCurrent==0 || pCursor->desc ){ pExpr->pCurrent = pExpr->aDoclist; pExpr->iCurrent = 0; pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent,&pExpr->iCurrent); diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index b3f1ab55b1..b843fe9dc6 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -171,6 +171,7 @@ struct Fts3Cursor { char *pNextId; /* Pointer into the body of aDoclist */ char *aDoclist; /* List of docids for full-text queries */ int nDoclist; /* Size of buffer at aDoclist */ + int desc; /* True to sort in descending order */ int eEvalmode; /* An FTS3_EVAL_XX constant */ int nRowAvg; /* Average size of database rows, in pages */ @@ -353,7 +354,7 @@ int sqlite3Fts3GetVarint32(const char *, int *); int sqlite3Fts3VarintLen(sqlite3_uint64); void sqlite3Fts3Dequote(char *); -char *sqlite3Fts3FindPositions(Fts3Expr *, sqlite3_int64, int); +char *sqlite3Fts3FindPositions(Fts3Cursor *, Fts3Expr *, sqlite3_int64, int); int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *, Fts3Expr *); int sqlite3Fts3ExprLoadFtDoclist(Fts3Cursor *, Fts3Expr *, char **, int *); int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int); diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c index 6b74535079..99f9dd7174 100644 --- a/ext/fts3/fts3_snippet.c +++ b/ext/fts3/fts3_snippet.c @@ -415,7 +415,7 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){ pPhrase->nToken = pExpr->pPhrase->nToken; - pCsr = sqlite3Fts3FindPositions(pExpr, p->pCsr->iPrevId, p->iCol); + pCsr = sqlite3Fts3FindPositions(p->pCsr, pExpr, p->pCsr->iPrevId, p->iCol); if( pCsr ){ int iFirst = 0; pPhrase->pList = pCsr; @@ -888,7 +888,7 @@ static int fts3ExprLocalHitsCb( if( pExpr->aDoclist ){ char *pCsr; - pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1); + pCsr = sqlite3Fts3FindPositions(p->pCursor, pExpr, p->pCursor->iPrevId, -1); if( pCsr ){ fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0); } @@ -1055,7 +1055,7 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ LcsIterator *pIter = &aIter[i]; nToken -= pIter->pExpr->pPhrase->nToken; pIter->iPosOffset = nToken; - pIter->pRead = sqlite3Fts3FindPositions(pIter->pExpr, pCsr->iPrevId, -1); + pIter->pRead = sqlite3Fts3FindPositions(pCsr,pIter->pExpr,pCsr->iPrevId,-1); if( pIter->pRead ){ pIter->iPos = pIter->iPosOffset; fts3LcsIteratorAdvance(&aIter[i]); @@ -1408,6 +1408,7 @@ struct TermOffset { }; struct TermOffsetCtx { + Fts3Cursor *pCsr; int iCol; /* Column of table to populate aTerm for */ int iTerm; sqlite3_int64 iDocid; @@ -1425,7 +1426,7 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){ int iPos = 0; /* First position in position-list */ UNUSED_PARAMETER(iPhrase); - pList = sqlite3Fts3FindPositions(pExpr, p->iDocid, p->iCol); + pList = sqlite3Fts3FindPositions(p->pCsr, pExpr, p->iDocid, p->iCol); nTerm = pExpr->pPhrase->nToken; if( pList ){ fts3GetDeltaPosition(&pList, &iPos); @@ -1478,6 +1479,7 @@ void sqlite3Fts3Offsets( goto offsets_out; } sCtx.iDocid = pCsr->iPrevId; + sCtx.pCsr = pCsr; /* Loop through the table columns, appending offset information to ** string-buffer res for each column. diff --git a/ext/fts3/fts3_term.c b/ext/fts3/fts3_term.c index ce581633e1..e207ff870d 100644 --- a/ext/fts3/fts3_term.c +++ b/ext/fts3/fts3_term.c @@ -10,6 +10,9 @@ ** ****************************************************************************** ** +** This file is not part of the production FTS code. It is only used for +** testing. It contains a virtual table implementation that provides direct +** access to the full-text index of an FTS table. */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) @@ -134,7 +137,18 @@ static int fts3termBestIndexMethod( sqlite3_index_info *pInfo ){ UNUSED_PARAMETER(pVTab); - UNUSED_PARAMETER(pInfo); + + /* This vtab naturally does "ORDER BY term, docid, col, pos". */ + if( pInfo->nOrderBy ){ + int i; + for(i=0; inOrderBy; i++){ + if( pInfo->aOrderBy[i].iColumn!=i || pInfo->aOrderBy[i].desc ) break; + } + if( i==pInfo->nOrderBy ){ + pInfo->orderByConsumed = 1; + } + } + return SQLITE_OK; } diff --git a/manifest b/manifest index bd7a00eb95..fde6974ea3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Have\sr-tree\svirtual\stables\ssupport\son-conflict\sclauses. -D 2011-04-28T18:46:46.861 +C Optimize\s"ORDER\sBY\srowid/docid\sDESC/ASC"\sclauses\son\sFTS\stables. +D 2011-05-04T12:52:59.896 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -61,17 +61,17 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c ce37973c86f15711a020fa629d8f95cfd642ebc3 +F ext/fts3/fts3.c 47e4f4da599e0ccd7b7fea08aaf2c77544e278e3 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h 945926ea4b6a686c3e9834640a252d9870b7191e +F ext/fts3/fts3Int.h 8c2ac39ee17362571c58ab2c4f0667324c31f738 F ext/fts3/fts3_aux.c 9e931f55eed8498dafe7bc1160f10cbb1a652fdf F ext/fts3/fts3_expr.c 5f49e0deaf723724b08100bb3ff40aab02ad0c93 F ext/fts3/fts3_hash.c 3c8f6387a4a7f5305588b203fa7c887d753e1f1c F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295 F ext/fts3/fts3_porter.c d61cfd81fb0fd8fbcb25adcaee0ba671aefaa5c2 -F ext/fts3/fts3_snippet.c e857c6a89d81d3b89df59f3b44b35c68d8ed5c62 -F ext/fts3/fts3_term.c c1dbc904ab1c2d687b97643c671795456228ab22 +F ext/fts3/fts3_snippet.c a4a3c7d2ab15ca9188e2d9b51a5e3927bf76580d +F ext/fts3/fts3_term.c f115f5a5f4298303d3b22fc6c524b8d565c7b950 F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3 F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d @@ -475,6 +475,7 @@ F test/fts3query.test ef79d31fdb355d094baec1c1b24b60439a1fb8a2 F test/fts3rnd.test 2b1a579be557ab8ac54a51b39caa4aa8043cc4ad F test/fts3shared.test 8bb266521d7c5495c0ae522bb4d376ad5387d4a2 F test/fts3snippet.test a12f22a3ba4dd59751a57c79b031d07ab5f51ddd +F test/fts3sort.test b33d4650e8d4bff2dc00d14359a29cd1c25769f8 F test/fts4aa.test eadf85621c0a113d4c7ad3ccbf8441130e007b8f F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f @@ -932,7 +933,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P abdd70ae0424ccadb7edaf16e970c78b5257d23c -R c8f4a330c2633adfb2862fa8f9efbab2 +P 822ab52f1023b1c4973c806cc75454acd4e95fd0 +R bb599d547c2452f152daafa893566415 U dan -Z e17a424fc4dea753d2cbffe0969a3e63 +Z 8f8ca68f3fd8a51bab340e5fb86e9e14 diff --git a/manifest.uuid b/manifest.uuid index e2827a6e32..12102a8f27 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -822ab52f1023b1c4973c806cc75454acd4e95fd0 \ No newline at end of file +13395121e3d17ab6581dc5f6736ea324321a374c \ No newline at end of file diff --git a/test/fts3sort.test b/test/fts3sort.test new file mode 100644 index 0000000000..3f833a65cb --- /dev/null +++ b/test/fts3sort.test @@ -0,0 +1,107 @@ +# 2011 May 04 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the FTS3 module. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +set testprefix fts3sort + +proc build_database {nRow} { + db close + forcedelete test.db + sqlite3 db test.db + + set vocab [list aa ab ac ba bb bc ca cb cc da] + expr srand(0) + + execsql { CREATE VIRTUAL TABLE t1 USING fts4 } + for {set i 0} {$i < $nRow} {incr i} { + set v [expr int(rand()*1000000)] + set doc [list] + for {set div 1} {$div < 1000000} {set div [expr $div*10]} { + lappend doc [lindex $vocab [expr ($v/$div) % 10]] + } + execsql { INSERT INTO t1 VALUES($doc) } + } +} + +set nRow 1000 +do_test 1.0 { + build_database $nRow + execsql { SELECT count(*) FROM t1 } +} $nRow + +foreach {tn query} { + 1 "SELECT docid, * FROM t1" + 2 "SELECT docid, * FROM t1 WHERE t1 MATCH 'aa'" + 3 "SELECT docid, * FROM t1 WHERE t1 MATCH 'a*'" + 4 "SELECT docid, quote(matchinfo(t1)) FROM t1 WHERE t1 MATCH 'a*'" + 5 "SELECT docid, quote(matchinfo(t1,'pcnxals')) FROM t1 WHERE t1 MATCH 'b*'" + 6 "SELECT docid, * FROM t1 WHERE t1 MATCH 'a* b* c*'" + 7 "SELECT docid, * FROM t1 WHERE t1 MATCH 'aa OR da'" + 8 "SELECT docid, * FROM t1 WHERE t1 MATCH 'nosuchtoken'" + 9 "SELECT docid, snippet(t1) FROM t1 WHERE t1 MATCH 'aa OR da'" +} { + + unset -nocomplain A B C D + set A_list [list] + set B_list [list] + set C_list [list] + set D_list [list] + + unset -nocomplain X + db eval "$query ORDER BY rowid ASC" X { + set A($X(docid)) [array get X] + lappend A_list $X(docid) + } + unset -nocomplain X + db eval "$query ORDER BY rowid DESC" X { + set B($X(docid)) [array get X] + lappend B_list $X(docid) + } + unset -nocomplain X + db eval "$query ORDER BY docid ASC" X { + set C($X(docid)) [array get X] + lappend C_list $X(docid) + } + unset -nocomplain X + db eval "$query ORDER BY docid DESC" X { + set D($X(docid)) [array get X] + lappend D_list $X(docid) + } + + do_test 1.$tn.1 { set A_list } [lsort -integer -increasing $A_list] + do_test 1.$tn.2 { set B_list } [lsort -integer -decreasing $B_list] + do_test 1.$tn.3 { set C_list } [lsort -integer -increasing $C_list] + do_test 1.$tn.4 { set D_list } [lsort -integer -decreasing $D_list] + + unset -nocomplain DATA + unset -nocomplain X + db eval "$query" X { + set DATA($X(docid)) [array get X] + } + + do_test 1.$tn.5 { lsort [array get A] } [lsort [array get DATA]] + do_test 1.$tn.6 { lsort [array get B] } [lsort [array get DATA]] + do_test 1.$tn.7 { lsort [array get C] } [lsort [array get DATA]] + do_test 1.$tn.8 { lsort [array get D] } [lsort [array get DATA]] +} + +finish_test From e1c8e13bf679af279040c4f72275fabbb101dc9c Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 4 May 2011 15:41:18 +0000 Subject: [PATCH 18/22] Fix a performance problem in queries that use "ORDER BY rowid DESC" and one or more FTS auxiliary functions. FossilOrigin-Name: 95e09b20e9aad28f829c8950f3632debe473070a --- ext/fts3/fts3.c | 47 ++++++++++++++++++++++++++++++++++++++++------ manifest | 14 +++++++------- manifest.uuid | 2 +- test/fts3sort.test | 1 + 4 files changed, 50 insertions(+), 14 deletions(-) diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index faf497d9a0..5aba849137 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -3321,6 +3321,25 @@ int sqlite3Fts3ExprLoadFtDoclist( return rc; } + +/* +** When called, *ppPoslist must point to the byte immediately following the +** end of a position-list. i.e. ( (*ppPoslist)[-1]==POS_END ). This function +** moves *ppPoslist so that it instead points to the first byte of the +** position list. +*/ +static void fts3ReversePoslist(char *pStart, char **ppPoslist){ + char *p = &(*ppPoslist)[-3]; + char c = p[1]; + while( p>=pStart && (*p & 0x80) | c ){ + c = *p--; + } + if( p>pStart ){ p = &p[2]; } + while( *p++&0x80 ); + *ppPoslist = p; +} + + /* ** After ExprLoadDoclist() (see above) has been called, this function is ** used to iterate/search through the position lists that make up the doclist @@ -3337,21 +3356,37 @@ char *sqlite3Fts3FindPositions( char *pEnd = &pExpr->aDoclist[pExpr->nDoclist]; char *pCsr; - if( pExpr->pCurrent==0 || pCursor->desc ){ - pExpr->pCurrent = pExpr->aDoclist; - pExpr->iCurrent = 0; - pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent,&pExpr->iCurrent); + if( pExpr->pCurrent==0 ){ + if( pCursor->desc==0 ){ + pExpr->pCurrent = pExpr->aDoclist; + pExpr->iCurrent = 0; + fts3GetDeltaVarint(&pExpr->pCurrent, &pExpr->iCurrent); + }else{ + pCsr = pExpr->aDoclist; + while( pCsriCurrent); + fts3PoslistCopy(0, &pCsr); + } + fts3ReversePoslist(pExpr->aDoclist, &pCsr); + pExpr->pCurrent = pCsr; + } } pCsr = pExpr->pCurrent; assert( pCsr ); - while( pCsriCurrentdesc==0 && pCsrdesc && pCsr>pExpr->aDoclist) + ){ + if( pCursor->desc==0 && pExpr->iCurrentiCurrent); } pExpr->pCurrent = pCsr; + }else if( pCursor->desc && pExpr->iCurrent>iDocid ){ + fts3GetReverseDeltaVarint(&pCsr, pExpr->aDoclist, &pExpr->iCurrent); + fts3ReversePoslist(pExpr->aDoclist, &pCsr); + pExpr->pCurrent = pCsr; }else{ if( pExpr->iCurrent==iDocid ){ int iThis = 0; diff --git a/manifest b/manifest index fde6974ea3..6850c6a534 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Optimize\s"ORDER\sBY\srowid/docid\sDESC/ASC"\sclauses\son\sFTS\stables. -D 2011-05-04T12:52:59.896 +C Fix\sa\sperformance\sproblem\sin\squeries\sthat\suse\s"ORDER\sBY\srowid\sDESC"\sand\sone\sor\smore\sFTS\sauxiliary\sfunctions. +D 2011-05-04T15:41:18.367 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -61,7 +61,7 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 47e4f4da599e0ccd7b7fea08aaf2c77544e278e3 +F ext/fts3/fts3.c 18bf7e4eca7dcea86300ee4ead2427067c3b04c3 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe F ext/fts3/fts3Int.h 8c2ac39ee17362571c58ab2c4f0667324c31f738 F ext/fts3/fts3_aux.c 9e931f55eed8498dafe7bc1160f10cbb1a652fdf @@ -475,7 +475,7 @@ F test/fts3query.test ef79d31fdb355d094baec1c1b24b60439a1fb8a2 F test/fts3rnd.test 2b1a579be557ab8ac54a51b39caa4aa8043cc4ad F test/fts3shared.test 8bb266521d7c5495c0ae522bb4d376ad5387d4a2 F test/fts3snippet.test a12f22a3ba4dd59751a57c79b031d07ab5f51ddd -F test/fts3sort.test b33d4650e8d4bff2dc00d14359a29cd1c25769f8 +F test/fts3sort.test e6f24e9cffc46484bcc9fe63d3c2ce41afcaa6c9 F test/fts4aa.test eadf85621c0a113d4c7ad3ccbf8441130e007b8f F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f @@ -933,7 +933,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 822ab52f1023b1c4973c806cc75454acd4e95fd0 -R bb599d547c2452f152daafa893566415 +P 13395121e3d17ab6581dc5f6736ea324321a374c +R b72c70132342e56f35c0ae4fa3c076bd U dan -Z 8f8ca68f3fd8a51bab340e5fb86e9e14 +Z f70b0240fad2f490b24e91d4b974b53a diff --git a/manifest.uuid b/manifest.uuid index 12102a8f27..ce4b5a06e5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -13395121e3d17ab6581dc5f6736ea324321a374c \ No newline at end of file +95e09b20e9aad28f829c8950f3632debe473070a \ No newline at end of file diff --git a/test/fts3sort.test b/test/fts3sort.test index 3f833a65cb..001bef1135 100644 --- a/test/fts3sort.test +++ b/test/fts3sort.test @@ -58,6 +58,7 @@ foreach {tn query} { 7 "SELECT docid, * FROM t1 WHERE t1 MATCH 'aa OR da'" 8 "SELECT docid, * FROM t1 WHERE t1 MATCH 'nosuchtoken'" 9 "SELECT docid, snippet(t1) FROM t1 WHERE t1 MATCH 'aa OR da'" + 10 "SELECT docid, snippet(t1) FROM t1 WHERE t1 MATCH 'aa OR nosuchtoken'" } { unset -nocomplain A B C D From 62d6c7e32b559ad0fc6b4d07bdf4ec8ff4c6579d Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 4 May 2011 16:30:05 +0000 Subject: [PATCH 19/22] Fix a couple of compiler warnings in the FTS code. FossilOrigin-Name: 1a113359705d307efa1833b1dfa5542b045dae43 --- ext/fts3/fts3.c | 8 +++++++- ext/fts3/fts3_write.c | 7 +++---- manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 5aba849137..a32bf3d28c 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -420,7 +420,13 @@ static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){ } /* +** When this function is called, *pp points to the first byte following a +** varint that is part of a doclist (or position-list, or any other list +** of varints). This function moves *pp to point to the start of that varint, +** and decrements the value stored in *pVal by the varint value. ** +** Argument pStart points to the first byte of the doclist that the +** varint is part of. */ static void fts3GetReverseDeltaVarint( char **pp, @@ -3326,7 +3332,7 @@ int sqlite3Fts3ExprLoadFtDoclist( ** When called, *ppPoslist must point to the byte immediately following the ** end of a position-list. i.e. ( (*ppPoslist)[-1]==POS_END ). This function ** moves *ppPoslist so that it instead points to the first byte of the -** position list. +** same position list. */ static void fts3ReversePoslist(char *pStart, char **ppPoslist){ char *p = &(*ppPoslist)[-3]; diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index d42d4b3f26..025fb64a64 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -2636,7 +2636,7 @@ static int fts3DeleteByRowid( Fts3Table *p, sqlite3_value *pRowid, int *pnDoc, - int *aSzDel + u32 *aSzDel ){ int isEmpty = 0; int rc = fts3IsEmpty(p, pRowid, &isEmpty); @@ -2646,13 +2646,13 @@ static int fts3DeleteByRowid( ** delete the contents of all three tables and throw away any ** data in the pendingTerms hash table. */ rc = fts3DeleteAll(p); - *pnDoc--; + *pnDoc = *pnDoc - 1; }else{ sqlite3_int64 iRemove = sqlite3_value_int64(pRowid); rc = fts3PendingTermsDocid(p, iRemove); fts3DeleteTerms(&rc, p, pRowid, aSzDel); fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); - if( sqlite3_changes(p->db) ) *pnDoc--; + if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1; if( p->bHasDocsize ){ fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); } @@ -2680,7 +2680,6 @@ int sqlite3Fts3UpdateMethod( u32 *aSzDel; /* Sizes of deleted documents */ int nChng = 0; /* Net change in number of documents */ int bInsertDone = 0; - int bReplace = 0; /* True if on conflict mode is REPLACE */ assert( p->pSegments==0 ); diff --git a/manifest b/manifest index 6850c6a534..d29a4b2392 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sperformance\sproblem\sin\squeries\sthat\suse\s"ORDER\sBY\srowid\sDESC"\sand\sone\sor\smore\sFTS\sauxiliary\sfunctions. -D 2011-05-04T15:41:18.367 +C Fix\sa\scouple\sof\scompiler\swarnings\sin\sthe\sFTS\scode. +D 2011-05-04T16:30:05.506 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -61,7 +61,7 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 18bf7e4eca7dcea86300ee4ead2427067c3b04c3 +F ext/fts3/fts3.c 84dc693d123ae544ec68fc7b384960b759d93c8a F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe F ext/fts3/fts3Int.h 8c2ac39ee17362571c58ab2c4f0667324c31f738 F ext/fts3/fts3_aux.c 9e931f55eed8498dafe7bc1160f10cbb1a652fdf @@ -75,7 +75,7 @@ F ext/fts3/fts3_term.c f115f5a5f4298303d3b22fc6c524b8d565c7b950 F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3 F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d -F ext/fts3/fts3_write.c 21ddcc47906807fb9481a0cc161db73469645d68 +F ext/fts3/fts3_write.c 7d6d904b89333448eb968fc82470a74985d0b61e F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9 @@ -933,7 +933,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 13395121e3d17ab6581dc5f6736ea324321a374c -R b72c70132342e56f35c0ae4fa3c076bd +P 95e09b20e9aad28f829c8950f3632debe473070a +R 91dde4b8c1110da860391480e16cf257 U dan -Z f70b0240fad2f490b24e91d4b974b53a +Z 55ea31537da115eeaba601610bb50d13 diff --git a/manifest.uuid b/manifest.uuid index ce4b5a06e5..3ac9b0e756 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -95e09b20e9aad28f829c8950f3632debe473070a \ No newline at end of file +1a113359705d307efa1833b1dfa5542b045dae43 \ No newline at end of file From 134ec491c5f7f43fbfe73ee1f547b4f1cb2c937c Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 5 May 2011 13:53:46 +0000 Subject: [PATCH 20/22] Add a #include to test_demovfs.c in an effort to get it to compile on Solaris. FossilOrigin-Name: 8f06ea33c9070de8ea85368d76cf26237d1aee73 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/test_demovfs.c | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index cac930fd64..7c839e8448 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\svtab-conflict\sbranch\swith\strunk. -D 2011-05-04T17:23:19.296 +C Add\sa\s#include\sto\stest_demovfs.c\sin\san\seffort\sto\sget\sit\sto\scompile\son\sSolaris. +D 2011-05-05T13:53:46.541 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -200,7 +200,7 @@ F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2 F src/test_config.c d536042f27226b4639f0f87d4795fd37428a9ddf -F src/test_demovfs.c 31050680fa6925b4f677cfd4fa965b5f19195e50 +F src/test_demovfs.c 938d0f595f8bd310076e1c06cf7885a01ce7ce01 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5 F src/test_fuzzer.c f884f6f32e8513d34248d6e1ac8a32047fead254 @@ -933,7 +933,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P f55156c5194e85c47728b8a97fde3e5f0a5c9b56 1a113359705d307efa1833b1dfa5542b045dae43 -R ce8473bec0301287a61bbbfd48f07dff -U dan -Z 6d8393d5b7b8dbdcf9f90f047ce29665 +P 8f9666af5f9459cbd0305a86281d745ea6163acf +R 0b98a6dfe1bc7e5dd0540df1f35076f9 +U drh +Z 3320cc00343f9752f29938f9f9e325ca diff --git a/manifest.uuid b/manifest.uuid index fbb720f5ee..92ef709205 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8f9666af5f9459cbd0305a86281d745ea6163acf \ No newline at end of file +8f06ea33c9070de8ea85368d76cf26237d1aee73 \ No newline at end of file diff --git a/src/test_demovfs.c b/src/test_demovfs.c index e56e8065cf..d7bcd1f908 100644 --- a/src/test_demovfs.c +++ b/src/test_demovfs.c @@ -128,6 +128,7 @@ #include #include #include +#include /* ** Size of the write buffer used by journal files in bytes. From 7af72cf963863b97bb4ce4149f6dad8556046f89 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 5 May 2011 13:54:28 +0000 Subject: [PATCH 21/22] Change sqlite3_create_module() so that it avoids resetting the schema as long as preexisting modules are unchanged. FossilOrigin-Name: 8485855afc71fb8078d53719c3da75021890ce9e --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vtab.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 7c839e8448..71c47aa3e0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\s#include\sto\stest_demovfs.c\sin\san\seffort\sto\sget\sit\sto\scompile\son\sSolaris. -D 2011-05-05T13:53:46.541 +C Change\ssqlite3_create_module()\sso\sthat\sit\savoids\sresetting\sthe\sschema\sas\nlong\sas\spreexisting\smodules\sare\sunchanged. +D 2011-05-05T13:54:28.663 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -244,7 +244,7 @@ F src/vdbeaux.c 25aa5ba7d46b4fe7c8f33dc132d474242d5f9726 F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 -F src/vtab.c 59db0620d682d34abb96860020429e77bb2b8ced +F src/vtab.c cc56ae9512b65ac6b13b751ffa8649929831069d F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794 F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f @@ -933,7 +933,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 8f9666af5f9459cbd0305a86281d745ea6163acf -R 0b98a6dfe1bc7e5dd0540df1f35076f9 +P 8f06ea33c9070de8ea85368d76cf26237d1aee73 +R aff00e1334f6da4cf8292fcebfc844bd U drh -Z 3320cc00343f9752f29938f9f9e325ca +Z ad6da57164b98567e1b21b53456334e7 diff --git a/manifest.uuid b/manifest.uuid index 92ef709205..097842dbb9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8f06ea33c9070de8ea85368d76cf26237d1aee73 \ No newline at end of file +8485855afc71fb8078d53719c3da75021890ce9e \ No newline at end of file diff --git a/src/vtab.c b/src/vtab.c index 811d2e1640..72775fa3cb 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -54,13 +54,13 @@ static int createModule( pMod->xDestroy = xDestroy; pDel = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod); if( pDel && pDel->xDestroy ){ + sqlite3ResetInternalSchema(db, -1); pDel->xDestroy(pDel->pAux); } sqlite3DbFree(db, pDel); if( pDel==pMod ){ db->mallocFailed = 1; } - sqlite3ResetInternalSchema(db, -1); }else if( xDestroy ){ xDestroy(pAux); } From ef45bb75b305bcd231c069c84a9761660e7243b8 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 5 May 2011 15:39:50 +0000 Subject: [PATCH 22/22] Bump the version number to 3.7.7 on account of the new sqlite3_vtab_config() and sqlite3_vtab_on_conflict() interfaces. Updates to the documentation on those interfaces. FossilOrigin-Name: 930be6a1bdec8c150caafd790973f7a401fc1970 --- VERSION | 2 +- configure | 18 ++++++------- manifest | 20 +++++++-------- manifest.uuid | 2 +- src/sqlite.h.in | 67 +++++++++++++++++++++++++++++++++++------------- src/vtab.c | 17 +++++++++--- tool/shell1.test | 2 +- 7 files changed, 85 insertions(+), 43 deletions(-) diff --git a/VERSION b/VERSION index c90806c1a7..d2577d9756 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.7.6.1 +3.7.7 diff --git a/configure b/configure index c18e5d18ec..6cd191260f 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.62 for sqlite 3.7.6.1. +# Generated by GNU Autoconf 2.62 for sqlite 3.7.7. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. @@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.7.6.1' -PACKAGE_STRING='sqlite 3.7.6.1' +PACKAGE_VERSION='3.7.7' +PACKAGE_STRING='sqlite 3.7.7' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. @@ -1485,7 +1485,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures sqlite 3.7.6.1 to adapt to many kinds of systems. +\`configure' configures sqlite 3.7.7 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1550,7 +1550,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.7.6.1:";; + short | recursive ) echo "Configuration of sqlite 3.7.7:";; esac cat <<\_ACEOF @@ -1666,7 +1666,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.7.6.1 +sqlite configure 3.7.7 generated by GNU Autoconf 2.62 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1680,7 +1680,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by sqlite $as_me 3.7.6.1, which was +It was created by sqlite $as_me 3.7.7, which was generated by GNU Autoconf 2.62. Invocation command line was $ $0 $@ @@ -13942,7 +13942,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by sqlite $as_me 3.7.6.1, which was +This file was extended by sqlite $as_me 3.7.7, which was generated by GNU Autoconf 2.62. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13995,7 +13995,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ -sqlite config.status 3.7.6.1 +sqlite config.status 3.7.7 configured by $0, generated by GNU Autoconf 2.62, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/manifest b/manifest index 71c47aa3e0..edcbb7b26a 100644 --- a/manifest +++ b/manifest @@ -1,11 +1,11 @@ -C Change\ssqlite3_create_module()\sso\sthat\sit\savoids\sresetting\sthe\sschema\sas\nlong\sas\spreexisting\smodules\sare\sunchanged. -D 2011-05-05T13:54:28.663 +C Bump\sthe\sversion\snumber\sto\s3.7.7\son\saccount\sof\sthe\snew\ssqlite3_vtab_config()\nand\ssqlite3_vtab_on_conflict()\sinterfaces.\s\sUpdates\sto\sthe\sdocumentation\son\nthose\sinterfaces. +D 2011-05-05T15:39:50.869 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6 -F VERSION c97e5dcdea2407f4a94f9740294cdf39ce9e88c4 +F VERSION 3fcdd7fbe3eb282df3978fe77288544543767961 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531 F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248 @@ -22,7 +22,7 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.h.in 868fdb48c028421a203470e15c69ada15b9ba673 F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 -F configure 61dbf78cdc4d6a871333dc599c130be6cce865c5 x +F configure 1c31f231ba59b71ff81dbf5c7c7594fdc83803d5 x F configure.ac 87a3c71bbe9c925381c154413eea7f3cdc397244 F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 @@ -179,7 +179,7 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff F src/shell.c 72e7e176bf46d5c6518d15ac4ad6847c4bb5df79 -F src/sqlite.h.in 5d25d06b8ae0d624179dba9bebb7cce48ce831f0 +F src/sqlite.h.in 9bf19a5dcf6317b0f091c255edaed0b1fc01dcd0 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 F src/sqliteInt.h e70a03bb66d209e279b3edeb57d4fdc42a1d9fda F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d @@ -244,7 +244,7 @@ F src/vdbeaux.c 25aa5ba7d46b4fe7c8f33dc132d474242d5f9726 F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 -F src/vtab.c cc56ae9512b65ac6b13b751ffa8649929831069d +F src/vtab.c 1491acb3e0a67eafe69134fb65bfa0b7b7e82342 F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794 F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f @@ -915,7 +915,7 @@ F tool/omittest.tcl b1dd290c1596e0f31fd335160a74ec5dfea3df4a F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/shell1.test 44705d6078b37f58853005d2ad5f1e67bc9dbbed +F tool/shell1.test 5542ecdc952f91121a835ed817e6feaf8988b333 F tool/shell2.test 5dc76b8005b465f420fed8241621da7513060ff3 F tool/shell3.test 4fad469e8003938426355afdf34155f08c587836 F tool/shell4.test 35f9c3d452b4e76d5013c63e1fd07478a62f14ce @@ -933,7 +933,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 8f06ea33c9070de8ea85368d76cf26237d1aee73 -R aff00e1334f6da4cf8292fcebfc844bd +P 8485855afc71fb8078d53719c3da75021890ce9e +R d001197d2ada5bdc77fdb1803c900b72 U drh -Z ad6da57164b98567e1b21b53456334e7 +Z b6f82da815334ecd28dc3bea3383de2d diff --git a/manifest.uuid b/manifest.uuid index 097842dbb9..a54682b9ba 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8485855afc71fb8078d53719c3da75021890ce9e \ No newline at end of file +930be6a1bdec8c150caafd790973f7a401fc1970 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index c93922f9df..19b418b439 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -370,7 +370,8 @@ int sqlite3_exec( ** ** New error codes may be added in future versions of SQLite. ** -** See also: [SQLITE_IOERR_READ | extended result codes] +** See also: [SQLITE_IOERR_READ | extended result codes], +** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes]. */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ @@ -2198,6 +2199,9 @@ int sqlite3_set_authorizer( ** to signal SQLite whether or not the action is permitted. See the ** [sqlite3_set_authorizer | authorizer documentation] for additional ** information. +** +** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code] +** from the [sqlite3_vtab_on_conflict()] interface. */ #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ @@ -6400,31 +6404,46 @@ int sqlite3_wal_checkpoint_v2( /* ** CAPI3REF: Virtual Table Interface Configuration ** -** This function is called by a virtual table implementation to configure -** various facets of the virtual table interface. At present, there is only -** one option that may be configured using this function. Further options +** This function may be called by either the [xConnect] or [xCreate] method +** of a [virtual table] implementation to configure +** various facets of the virtual table interface. +** +** If this interface is invoked outside the context of an xConnect or +** xCreate virtual table method then the behavior is undefined. +** +** At present, there is only one option that may be configured using +** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options ** may be added in the future. +*/ +int sqlite3_vtab_config(sqlite3*, int op, ...); + +/* +** CAPI3REF: Virtual Table Configuration Options +** +** These macros define the various options to the +** [sqlite3_vtab_config()] interface that [virtual table] implementations +** can use to customize and optimize their behavior. ** **
**
SQLITE_VTAB_CONSTRAINT_SUPPORT -**
If the second argument to sqlite3_vtab_config() is +**
If the second argument to [sqlite3_vtab_config()] is ** SQLITE_VTAB_CONSTRAINT_SUPPORT, then SQLite expects this function to ** have been called with three arguments, the third of which being of ** type 'int'. If the third argument is zero, then the virtual table ** is indicating that it does not support constraints. In this case if -** a call to the xUpdate method returns SQLITE_CONSTRAINT, the entire +** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], the entire ** statement is rolled back as if [ON CONFLICT | OR ABORT] had been ** specified as part of the users SQL statement, regardless of the actual ** ON CONFLICT mode specified. ** ** If the third argument passed is non-zero, then the virtual table -** implementation must guarantee that if xUpdate returns -** SQLITE_CONSTRAINT, it does so before any modifications to internal +** implementation must guarantee that if [xUpdate] returns +** [SQLITE_CONSTRAINT], it does so before any modifications to internal ** or persistent data structures have been made. If the [ON CONFLICT] ** mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite is able to roll back ** a statement or database transaction, and abandon or continue processing ** the current SQL statement as appropriate. If the ON CONFLICT mode is -** REPLACE and the xUpdate method returns SQLITE_CONSTRAINT, SQLite +** REPLACE and the [xUpdate] method returns [SQLITE_CONSTRAINT], SQLite ** handles this as if the ON CONFLICT mode had been ABORT. ** ** Virtual table implementations that are required to handle OR REPLACE @@ -6439,23 +6458,35 @@ int sqlite3_wal_checkpoint_v2( ** */ #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 -int sqlite3_vtab_config(sqlite3*, int op, ...); /* ** CAPI3REF: Determine The Virtual Table Conflict Policy ** -** This function may only be called from within a call to the xUpdate method -** of a virtual table implementation for an INSERT or UPDATE operation. The -** value returned is one of SQLITE_ROLLBACK, SQLITE_IGNORE, SQLITE_FAIL, -** SQLITE_ABORT or SQLITE_REPLACE, according to the [ON CONFLICT] mode of the -** SQL statement that triggered the callback. +** This function may only be called from within a call to the [xUpdate] method +** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The +** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], +** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode +** of the SQL statement that triggered the call to the [xUpdate] method of the +** [virtual table]. +*/ +int sqlite3_vtab_on_conflict(sqlite3 *); + +/* +** CAPI3REF: Conflict resolution modes +** +** These constants are returned by [sqlite3_vtab_on_conflict()] to +** inform a [virtual table] implementation what the [ON CONFLICT] mode +** is for the SQL statement being evaluated. +** +** Note that the [SQLITE_IGNORE] constant is also used as a potential +** return value from the [sqlite3_set_authorizer()] callback and that +** [SQLITE_ABORT] is also a [result code]. */ #define SQLITE_ROLLBACK 1 -/* #define SQLITE_IGNORE 2 */ +/* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ #define SQLITE_FAIL 3 -/* #define SQLITE_ABORT 4 */ +/* #define SQLITE_ABORT 4 // Also an error code */ #define SQLITE_REPLACE 5 -int sqlite3_vtab_on_conflict(sqlite3 *); diff --git a/src/vtab.c b/src/vtab.c index 72775fa3cb..cac9c96064 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -992,17 +992,28 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ } } +/* +** Return the ON CONFLICT resolution mode in effect for the virtual +** table update operation currently in progress. +** +** The results of this routine are undefined unless it is called from +** within an xUpdate method. +*/ int sqlite3_vtab_on_conflict(sqlite3 *db){ - int aMap[] = { + static const unsigned char aMap[] = { SQLITE_ROLLBACK, SQLITE_IGNORE, SQLITE_ABORT, SQLITE_FAIL, SQLITE_REPLACE }; assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 ); assert( OE_Ignore==4 && OE_Replace==5 ); assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 ); - return aMap[db->vtabOnConflict-1]; + return (int)aMap[db->vtabOnConflict-1]; } - +/* +** Call from within the xCreate() or xConnect() methods to provide +** the SQLite core with additional information about the behavior +** of the virtual table being implemented. +*/ int sqlite3_vtab_config(sqlite3 *db, int op, ...){ va_list ap; int rc = SQLITE_OK; diff --git a/tool/shell1.test b/tool/shell1.test index d066fc3c1a..068f8ea25c 100644 --- a/tool/shell1.test +++ b/tool/shell1.test @@ -200,7 +200,7 @@ do_test shell1-1.15.3 { # -version show SQLite version do_test shell1-1.16.1 { catchcmd "-version test.db" "" -} {0 3.7.6.1} +} {0 3.7.7} #---------------------------------------------------------------------------- # Test cases shell1-2.*: Basic "dot" command token parsing.