From 90606b3d0374c3b07a9350ea83a7b553adb89e19 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 13 Jun 2014 16:18:02 -0500 Subject: [PATCH 01/59] Add PRAGMA cipher_store_pass PRAGMA cipher_store_pass allows the passphrase to remain in memory which will allow an ATTACH statement to succeed without providing the key value during ATTACH when both databases use the same passphrase, but have different salt values. Previously, in order to ATTACH with this scneario, calling ATTACH required providing the key value inline. --- src/crypto.c | 21 ++++++++++++++++----- src/crypto.h | 4 ++++ src/crypto_impl.c | 20 ++++++++++++++++++-- test/crypto.test | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index b9fb815..c9814e3 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -88,9 +88,16 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef } CODEC_TRACE(("sqlcipher_codec_pragma: entered db=%p iDb=%d pParse=%p zLeft=%s zRight=%s ctx=%p\n", db, iDb, pParse, zLeft, zRight, ctx)); - - - if( sqlite3StrICmp(zLeft, "cipher_profile")== 0 && zRight ){ + + if( sqlite3StrICmp(zLeft, "cipher_store_pass")==0 && zRight ) { + sqlcipher_codec_set_store_pass(ctx, sqlite3GetBoolean(zRight, 1)); + } else + if( sqlite3StrICmp(zLeft, "cipher_store_pass")==0 && !zRight ) { + char *store_pass_value = sqlite3_mprintf("%d", sqlcipher_codec_get_store_pass(ctx)); + codec_vdbe_return_static_string(pParse, "cipher_store_pass", store_pass_value); + sqlite3_free(store_pass_value); + } + if( sqlite3StrICmp(zLeft, "cipher_profile")== 0 && zRight ){ char *profile_status = sqlite3_mprintf("%d", sqlcipher_cipher_profile(db, zRight)); codec_vdbe_return_static_string(pParse, "cipher_profile", profile_status); sqlite3_free(profile_status); @@ -471,8 +478,12 @@ void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) { if( pDb->pBt ) { codec_ctx *ctx; sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx); - if(ctx) { /* if the codec has an attached codec_context user the raw key data */ - sqlcipher_codec_get_keyspec(ctx, zKey, nKey); + if(ctx) { + if(sqlcipher_codec_get_store_pass(ctx) == 1) { + sqlcipher_codec_get_pass(ctx, zKey, nKey); + } else { + sqlcipher_codec_get_keyspec(ctx, zKey, nKey); + } } else { *zKey = NULL; *nKey = 0; diff --git a/src/crypto.h b/src/crypto.h index d71f063..6d22ddf 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -216,6 +216,10 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx); int sqlcipher_codec_add_random(codec_ctx *ctx, const char *data, int random_sz); int sqlcipher_cipher_profile(sqlite3 *db, const char *destination); static void sqlcipher_profile_callback(void *file, const char *sql, sqlite3_uint64 run_time); +static int sqlcipher_codec_get_store_pass(codec_ctx *ctx); +static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey); +static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value); + #endif #endif /* END SQLCIPHER */ diff --git a/src/crypto_impl.c b/src/crypto_impl.c index d84f22b..2dc614b 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -47,6 +47,7 @@ to keep track of read / write state separately. The following struct and associated functions are defined here */ typedef struct { + int store_pass; int derive_key; int kdf_iter; int fast_kdf_iter; @@ -401,6 +402,19 @@ static int sqlcipher_cipher_ctx_set_keyspec(cipher_ctx *ctx, const unsigned char return SQLITE_OK; } +static int sqlcipher_codec_get_store_pass(codec_ctx *ctx) { + return ctx->read_ctx->store_pass; +} + +static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value) { + ctx->read_ctx->store_pass = value; +} + +static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) { + *zKey = ctx->read_ctx->pass; + *nKey = ctx->read_ctx->pass_sz; +} + /** * Set the passphrase for the cipher_ctx * @@ -897,8 +911,10 @@ int sqlcipher_codec_key_derive(codec_ctx *ctx) { } /* TODO: wipe and free passphrase after key derivation */ - sqlcipher_cipher_ctx_set_pass(ctx->read_ctx, NULL, 0); - sqlcipher_cipher_ctx_set_pass(ctx->write_ctx, NULL, 0); + if(ctx->read_ctx->store_pass != 1) { + sqlcipher_cipher_ctx_set_pass(ctx->read_ctx, NULL, 0); + sqlcipher_cipher_ctx_set_pass(ctx->write_ctx, NULL, 0); + } return SQLITE_OK; } diff --git a/test/crypto.test b/test/crypto.test index 825f034..04c957e 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -444,6 +444,49 @@ db2 close file delete -force test.db file delete -force test2.db +# attach an encrypted database +# without specifying key, verify it attaches +# correctly when PRAGMA cipher_store_pass = 1 +# is set. +do_test attach-database-with-default-key-using-cipher-store-pass { + + sqlite_orig db1 test.db + execsql { + PRAGMA key = 'testkey'; + CREATE TABLE t1(a,b); + INSERT INTO t1(a,b) VALUES('foo', 'bar'); + } db1 + db1 close + + sqlite_orig db2 test2.db + execsql { + PRAGMA key = 'testkey'; + CREATE TABLE t2(a,b); + INSERT INTO t2 VALUES ('test1', 'test2'); + } db2 + db2 close + + sqlite_orig db1 test.db + execsql { + PRAGMA key = 'testkey'; + PRAGMA cipher_store_pass = 1; + ATTACH DATABASE 'test2.db' as db2; + SELECT sqlcipher_export('db2'); + DETACH DATABASE db2; + } db1 + db1 close + + sqlite_orig db2 test2.db + execsql { + PRAGMA key = 'testkey'; + SELECT * FROM t1; + } db2 + +} {foo bar} +db2 close +file delete -force test.db +file delete -force test2.db + # attach an encrypted database # where both database have the same # key explicitly From c6072831d19bc251d5f534c724eb0f0c84a8997d Mon Sep 17 00:00:00 2001 From: Stephen Lombardo Date: Fri, 25 Jul 2014 11:40:49 -0400 Subject: [PATCH 02/59] fix redundant key derivation with common crypto provider --- src/crypto_cc.c | 2 +- src/crypto_impl.c | 44 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/crypto_cc.c b/src/crypto_cc.c index 707deca..1e18dc7 100644 --- a/src/crypto_cc.c +++ b/src/crypto_cc.c @@ -109,7 +109,7 @@ static int sqlcipher_cc_ctx_copy(void *target_ctx, void *source_ctx) { } static int sqlcipher_cc_ctx_cmp(void *c1, void *c2) { - return SQLITE_OK; + return 1; /* always indicate contexts are the same */ } static int sqlcipher_cc_ctx_init(void **ctx) { diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 2dc614b..9a77e0f 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -310,9 +310,7 @@ static void sqlcipher_cipher_ctx_free(cipher_ctx **iCtx) { * returns 1 otherwise */ static int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) { - CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered c1=%p c2=%p\n", c1, c2)); - - if( + int are_equal = ( c1->iv_sz == c2->iv_sz && c1->kdf_iter == c2->kdf_iter && c1->fast_kdf_iter == c2->fast_kdf_iter @@ -326,9 +324,43 @@ static int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) { || !sqlcipher_memcmp((const unsigned char*)c1->pass, (const unsigned char*)c2->pass, c1->pass_sz) - ) - ) return 0; - return 1; + )); + + CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered \ + c1=%p c2=%p \ + c1->iv_sz=%d c2->iv_sz=%d \ + c1->kdf_iter=%d c2->kdf_iter=%d \ + c1->fast_kdf_iter=%d c2->fast_kdf_iter=%d \ + c1->key_sz=%d c2->key_sz=%d \ + c1->pass_sz=%d c2->pass_sz=%d \ + c1->flags=%d c2->flags=%d \ + c1->hmac_sz=%d c2->hmac_sz=%d \ + c1->provider_ctx=%p c2->provider_ctx=%p \ + c1->pass=%p c2->pass=%p \ + c1->pass=%s c2->pass=%s \ + provider->ctx_cmp=%d \ + sqlcipher_memcmp=%d \ + are_equal=%d \ + \n", + c1, c2, + c1->iv_sz, c2->iv_sz, + c1->kdf_iter, c2->kdf_iter, + c1->fast_kdf_iter, c2->fast_kdf_iter, + c1->key_sz, c2->key_sz, + c1->pass_sz, c2->pass_sz, + c1->flags, c2->flags, + c1->hmac_sz, c2->hmac_sz, + c1->provider_ctx, c2->provider_ctx, + c1->pass, c2->pass, + c1->pass, c2->pass, + c1->provider->ctx_cmp(c1->provider_ctx, c2->provider_ctx), + sqlcipher_memcmp((const unsigned char*)c1->pass, + (const unsigned char*)c2->pass, + c1->pass_sz), + are_equal + )); + + return !are_equal; /* return 0 if they are the same, 1 otherwise */ } /** From 4e3ffe8c11a741288224673270edf1b30b0bebd4 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Wed, 23 Apr 2014 10:28:43 -0500 Subject: [PATCH 03/59] Adjust cipher version test --- test/crypto.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/crypto.test b/test/crypto.test index 04c957e..47086e3 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -1541,7 +1541,7 @@ do_test verify-pragma-cipher-version { execsql { PRAGMA cipher_version; } -} {3.0.1} +} {3.1.0} db close file delete -force test.db From 4ed24011b28c9d7abc331f7fd111e981b88af979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Helfensd=C3=B6rfer?= Date: Sat, 16 Aug 2014 10:46:29 +0200 Subject: [PATCH 04/59] Converted readme to valid markdown --- README.md | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 0378dad..552e9fa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -== SQLCipher == +## SQLCipher SQLCipher is an SQLite extension that provides transparent 256-bit AES encryption of database files. Pages are encrypted before being written to disk and are decrypted @@ -11,7 +11,7 @@ SQLCipher was initially developed by Stephen Lombardo at Zetetic LLC (sjlombardo@zetetic.net) as the encrypted database layer for Strip, an iPhone data vault and password manager (http://getstrip.com). -[Features] +## Features - Fast performance with as little as 5-15% overhead for encryption on many operations - 100% of data in the database file is encrypted @@ -20,7 +20,7 @@ an iPhone data vault and password manager (http://getstrip.com). - Algorithms provided by the peer reviewed OpenSSL crypto library. - Configurable crypto providers -[Compiling] +## Compiling Building SQLCipher is almost the same as compiling a regular version of SQLite with two small exceptions: @@ -30,57 +30,56 @@ SQLite with two small exceptions: Example Static linking (replace /opt/local/lib with the path to libcrypto.a) - $ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ - LDFLAGS="/opt/local/lib/libcrypto.a" - $ make + $ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ + LDFLAGS="/opt/local/lib/libcrypto.a" + $ make Example Dynamic linking - $ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ - LDFLAGS="-lcrypto" - $ make + $ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ + LDFLAGS="-lcrypto" + $ make -[Encrypting a database] +## Encrypting a database To specify an encryption passphrase for the database via the SQL interface you use a pragma. The passphrase you enter is passed through PBKDF2 key derivation to obtain the encryption key for the database - PRAGMA key = 'passphrase'; + PRAGMA key = 'passphrase'; Alternately, you can specify an exact byte sequence using a blob literal. If you use this method it is your responsibility to ensure that the data you provide a 64 character hex string, which will be converted directly to 32 bytes (256 bits) of key data without key derivation. - PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; To encrypt a database programatically you can use the sqlite3_key function. The data provided in pKey is converted to an encryption key according to the same rules as PRAGMA key. - - int sqlite3_key(sqlite3 *db, const void *pKey, int nKey); + int sqlite3_key(sqlite3 *db, const void *pKey, int nKey); PRAGMA key or sqlite3_key should be called as the first operation when a database is open. -[Changing a database key] +## Changing a database key To change the encryption passphrase for an existing database you may use the rekey pragma after you've supplied the correct database password; - PRAGMA key = 'passphrase'; -- start with the existing database passphrase - PRAGMA rekey = 'new-passphrase'; -- rekey will reencrypt with the new passphrase + PRAGMA key = 'passphrase'; -- start with the existing database passphrase + PRAGMA rekey = 'new-passphrase'; -- rekey will reencrypt with the new passphrase The hexrekey pragma may be used to rekey to a specific binary value - PRAGMA rekey = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + PRAGMA rekey = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; This can be accomplished programtically by using sqlite3_rekey; - sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) + sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) -[Support] +## Support The primary avenue for support and discussions is the SQLCipher users mailing list: @@ -97,7 +96,7 @@ posts about SQLCipher as we do not monitor them frequently. If you are using SQLCipher in your own software please let us know at support@zetetic.net! -[License] +## License Copyright (c) 2008, ZETETIC LLC All rights reserved. @@ -128,7 +127,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This directory contains source code to - SQLite: An Embeddable SQL Database Engine + SQLite: An Embeddable SQL Database Engine To compile the project, first create a directory in which to place the build products. It is recommended, but not required, that the @@ -138,7 +137,7 @@ script found at the root of the source tree. Then run "make". For example: - tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite" + tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite" mkdir bld ;# Build will occur in a sibling directory cd bld ;# Change to the build directory ../sqlite/configure ;# Run the configure script @@ -164,4 +163,4 @@ AWK. Contacts: - http://www.sqlite.org/ + http://www.sqlite.org/ From b67681a05fc0339cfc3f3b0f72950a30252d7d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Helfensd=C3=B6rfer?= Date: Sat, 16 Aug 2014 10:48:21 +0200 Subject: [PATCH 05/59] Fixed heading --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 552e9fa..a0f4cea 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -== End SQLCipher == +## End SQLCipher This directory contains source code to From 0b99d5d75c4d526311b08f1c34afc97a0a8145bb Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Tue, 30 Sep 2014 08:40:45 -0500 Subject: [PATCH 06/59] Snapshot of upstream SQLite 3.8.6 --- Makefile.in | 27 +- Makefile.msc | 161 +++- Makefile.vxworks | 4 + VERSION | 2 +- configure | 18 +- ext/fts3/fts3.c | 65 +- ext/fts3/fts3Int.h | 8 +- ext/fts3/fts3_expr.c | 205 ++--- ext/fts3/fts3_unicode.c | 16 +- ext/fts3/fts3_unicode2.c | 10 +- ext/fts3/fts3_write.c | 355 ++++++-- ext/fts3/tool/fts3view.c | 15 +- ext/fts3/unicode/mkunicode.tcl | 10 +- ext/misc/compress.c | 107 +++ ext/misc/fileio.c | 100 +++ ext/misc/spellfix.c | 4 +- ext/rtree/rtree.c | 1540 ++++++++++++++++---------------- ext/rtree/rtree1.test | 41 +- ext/rtree/rtree6.test | 26 +- ext/rtree/rtreeB.test | 2 +- ext/rtree/rtreeC.test | 125 ++- ext/rtree/rtreeE.test | 129 +++ ext/rtree/sqlite3rtree.h | 67 +- magic.txt | 1 + main.mk | 45 +- manifest | 370 ++++---- manifest.uuid | 2 +- src/alter.c | 1 + src/analyze.c | 262 ++++-- src/btree.c | 245 ++--- src/btree.h | 8 +- src/btreeInt.h | 25 +- src/build.c | 115 ++- src/callback.c | 4 +- src/delete.c | 18 +- src/expr.c | 417 +++++---- src/fkey.c | 6 +- src/func.c | 12 +- src/global.c | 13 +- src/insert.c | 24 +- src/legacy.c | 3 + src/main.c | 64 +- src/mem5.c | 2 +- src/mutex.c | 2 +- src/mutex_noop.c | 2 +- src/mutex_unix.c | 8 +- src/mutex_w32.c | 175 ++-- src/os.h | 79 +- src/os_setup.h | 57 ++ src/os_unix.c | 137 ++- src/os_win.c | 341 ++++--- src/os_win.h | 67 ++ src/pager.c | 67 +- src/parse.y | 27 + src/pragma.c | 93 +- src/printf.c | 162 ++-- src/resolve.c | 11 +- src/rowset.c | 6 +- src/select.c | 351 +++++--- src/shell.c | 535 ++++++++--- src/sqlite.h.in | 171 ++-- src/sqlite3.rc | 8 + src/sqliteInt.h | 171 +++- src/test1.c | 60 +- src/test2.c | 88 +- src/test_btree.c | 2 +- src/test_config.c | 6 +- src/test_multiplex.c | 21 +- src/test_multiplex.h | 2 +- src/test_osinst.c | 7 +- src/test_quota.c | 40 +- src/test_quota.h | 6 - src/test_rtree.c | 200 ++++- src/test_syscall.c | 49 +- src/test_vfs.c | 73 +- src/test_vfstrace.c | 2 +- src/tokenize.c | 6 + src/update.c | 5 +- src/utf.c | 4 +- src/util.c | 80 +- src/vdbe.c | 365 ++++++-- src/vdbe.h | 5 +- src/vdbeInt.h | 9 +- src/vdbeapi.c | 2 +- src/vdbeaux.c | 103 ++- src/vdbeblob.c | 4 +- src/vdbemem.c | 166 +++- src/vdbesort.c | 106 ++- src/wal.c | 6 +- src/where.c | 1447 +++++++++++++++++++++--------- src/whereInt.h | 9 +- test/alter.test | 38 + test/analyze3.test | 42 +- test/analyze6.test | 2 +- test/analyze9.test | 145 ++- test/analyzeC.test | 167 ++++ test/autoindex1.test | 2 + test/autoindex2.test | 271 ++++++ test/autoindex3.test | 58 ++ test/backcompat.test | 54 ++ test/capi3d.test | 37 + test/corruptG.test | 11 +- test/corruptI.test | 28 +- test/cost.test | 292 ++++++ test/distinct.test | 2 +- test/e_createtable.test | 11 +- test/e_expr.test | 9 +- test/e_fkey.test | 11 +- test/e_insert.test | 6 +- test/eqp.test | 56 +- test/extension01.test | 83 ++ test/fts3ao.test | 28 + test/fts3d.test | 30 +- test/fts3defer2.test | 1 + test/fts3expr.test | 5 + test/fts3expr4.test | 57 ++ test/fts4check.test | 28 + test/fts4growth.test | 437 +++++++++ test/fts4growth2.test | 93 ++ test/fts4merge4.test | 44 + test/fts4noti.test | 62 ++ test/func.test | 24 +- test/func3.test | 36 +- test/fuzz.test | 2 +- test/hexlit.test | 114 +++ test/in4.test | 177 ++++ test/incrblob_err.test | 1 + test/index6.test | 24 +- test/insert.test | 23 + test/join.test | 11 + test/limit.test | 20 + test/malloc.test | 1 + test/mallocK.test | 66 ++ test/mallocL.test | 43 + test/malloc_common.tcl | 1 + test/misc1.test | 16 + test/multiplex.test | 14 + test/nolock.test | 185 ++++ test/orderby1.test | 28 + test/orderby5.test | 22 +- test/orderby6.test | 183 ++++ test/orderby7.test | 106 +++ test/permutations.test | 24 + test/pragma.test | 27 +- test/rdonly.test | 6 + test/releasetest.tcl | 7 + test/selectA.test | 65 ++ test/shell1.test | 95 +- test/shell4.test | 4 +- test/shell5.test | 91 +- test/show_speedtest1_rtree.tcl | 57 ++ test/skipscan1.test | 2 +- test/skipscan2.test | 15 + test/skipscan5.test | 186 ++++ test/speedtest1.c | 229 ++++- test/syscall.test | 1 + test/table.test | 47 + test/tester.tcl | 1 + test/tkt-80e031a00f.test | 4 + test/tkt-9a8b09f8e6.test | 323 +++++++ test/tkt-a8a0d2996a.test | 93 ++ test/tkt-b75a9ca6b0.test | 77 ++ test/tkt-f67b41381a.test | 53 ++ test/tpch01.test | 7 +- test/trace2.test | 1 + test/unique2.test | 78 ++ test/unordered.test | 2 +- test/vtab_shared.test | 47 + test/wal.test | 13 + test/wal2.test | 8 +- test/wal64k.test | 51 ++ test/where2.test | 8 + test/where3.test | 3 +- test/where9.test | 5 + test/whereD.test | 53 ++ test/whereG.test | 69 +- test/whereH.test | 139 +++ test/whereI.test | 92 ++ test/whereJ.test | 375 ++++++++ test/win32lock.test | 50 +- test/with2.test | 27 + test/without_rowid1.test | 64 ++ tool/build-all-msvc.bat | 30 +- tool/lemon.c | 3 +- tool/logest.c | 69 +- tool/mkkeywordhash.c | 2 +- tool/mksqlite3c-noext.tcl | 2 + tool/mksqlite3c.tcl | 6 +- tool/mksqlite3internalh.tcl | 2 + tool/mkvsix.tcl | 258 ++++-- tool/showdb.c | 268 +++++- tool/showjournal.c | 19 +- tool/showstat4.c | 157 ++++ tool/showwal.c | 48 +- tool/warnings.sh | 2 +- tool/win/sqlite.vsix | Bin 32825 -> 32825 bytes 196 files changed, 13090 insertions(+), 3499 deletions(-) create mode 100644 ext/misc/compress.c create mode 100644 ext/misc/fileio.c create mode 100644 ext/rtree/rtreeE.test create mode 100644 src/os_setup.h create mode 100644 src/os_win.h create mode 100644 test/analyzeC.test create mode 100644 test/autoindex2.test create mode 100644 test/autoindex3.test create mode 100644 test/cost.test create mode 100644 test/extension01.test create mode 100644 test/fts3expr4.test create mode 100644 test/fts4growth.test create mode 100644 test/fts4growth2.test create mode 100644 test/hexlit.test create mode 100644 test/mallocL.test create mode 100644 test/nolock.test create mode 100644 test/orderby6.test create mode 100644 test/orderby7.test create mode 100644 test/show_speedtest1_rtree.tcl create mode 100644 test/skipscan5.test create mode 100644 test/tkt-9a8b09f8e6.test create mode 100644 test/tkt-a8a0d2996a.test create mode 100644 test/tkt-b75a9ca6b0.test create mode 100644 test/tkt-f67b41381a.test create mode 100644 test/unique2.test create mode 100644 test/wal64k.test create mode 100644 test/whereH.test create mode 100644 test/whereI.test create mode 100644 test/whereJ.test create mode 100644 tool/showstat4.c diff --git a/Makefile.in b/Makefile.in index 31e30ff..cf17b02 100644 --- a/Makefile.in +++ b/Makefile.in @@ -239,8 +239,10 @@ SRC = \ $(TOP)/src/os.c \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ + $(TOP)/src/os_setup.h \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ + $(TOP)/src/os_win.h \ $(TOP)/src/pager.c \ $(TOP)/src/pager.h \ $(TOP)/src/parse.y \ @@ -391,6 +393,7 @@ TESTSRC = \ TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ + $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ @@ -457,6 +460,8 @@ HDR = \ opcodes.h \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ + $(TOP)/src/os_setup.h \ + $(TOP)/src/os_win.h \ $(TOP)/src/pager.h \ $(TOP)/src/pcache.h \ parse.h \ @@ -934,8 +939,23 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c $(TO sqlite3_analyzer$(TEXE): sqlite3_analyzer.c $(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS) -showdb$(TEXE): $(TOP)/tool/showdb.c sqlite3.c - $(LTLINK) -o $@ $(TOP)/tool/showdb.c sqlite3.c $(TLIBS) +showdb$(TEXE): $(TOP)/tool/showdb.c sqlite3.lo + $(LTLINK) -o $@ $(TOP)/tool/showdb.c sqlite3.lo $(TLIBS) + +showstat4$(TEXE): $(TOP)/tool/showstat4.c sqlite3.lo + $(LTLINK) -o $@ $(TOP)/tool/showstat4.c sqlite3.lo $(TLIBS) + +showjournal$(TEXE): $(TOP)/tool/showjournal.c sqlite3.lo + $(LTLINK) -o $@ $(TOP)/tool/showjournal.c sqlite3.lo $(TLIBS) + +showwal$(TEXE): $(TOP)/tool/showwal.c sqlite3.lo + $(LTLINK) -o $@ $(TOP)/tool/showwal.c sqlite3.lo $(TLIBS) + +rollback-test$(TEXE): $(TOP)/tool/rollback-test.c sqlite3.lo + $(LTLINK) -o $@ $(TOP)/tool/rollback-test.c sqlite3.lo $(TLIBS) + +LogEst$(TEXE): $(TOP)/tool/logest.c sqlite3.h + $(LTLINK) -I. -o $@ $(TOP)/tool/logest.c wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.c $(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.c $(TLIBS) @@ -977,6 +997,9 @@ clean: rm -rf tsrc .target_source rm -f tclsqlite3$(TEXE) rm -f testfixture$(TEXE) test.db + rm -f LogEst$(TEXE) fts3view$(TEXE) rollback-test$(TEXE) showdb$(TEXE) + rm -f showjournal$(TEXE) showstat4$(TEXE) showwal$(TEXE) speedtest1$(TEXE) + rm -f wordcount$(TEXE) rm -f sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def rm -f sqlite3.c rm -f sqlite3rc.h diff --git a/Makefile.msc b/Makefile.msc index 5d6460b..3a9fa29 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -1,6 +1,9 @@ # # nmake Makefile for SQLite # +############################################################################### +############################## START OF OPTIONS ############################### +############################################################################### # The toplevel directory of the source tree. This is the directory # that contains this "Makefile.msc". @@ -13,6 +16,13 @@ TOP = . USE_AMALGAMATION = 1 !ENDIF +# Set this non-0 to use the library paths and other options necessary for +# Windows Phone 8.1. +# +!IFNDEF USE_WP81_OPTS +USE_WP81_OPTS = 0 +!ENDIF + # Set this non-0 to split the SQLite amalgamation file into chunks to # be used for debugging with Visual Studio. # @@ -116,6 +126,25 @@ DEBUG = 0 OPTIMIZATIONS = 2 !ENDIF +# These are the "standard" SQLite compilation options used when compiling for +# the Windows platform. +# +!IFNDEF OPT_FEATURE_FLAGS +OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 +OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 +OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 +!ENDIF + +############################################################################### +############################### END OF OPTIONS ################################ +############################################################################### + +# This assumes that MSVC is always installed in 32-bit Program Files directory +# and sets the variable for use in locating other 32-bit installs accordingly. +# +PROGRAMFILES_X86 = $(VCINSTALLDIR)\..\.. +PROGRAMFILES_X86 = $(PROGRAMFILES_X86:\\=\) + # Check for the predefined command macro CC. This should point to the compiler # binary for the target platform. If it is not defined, simply define it to # the legacy default value 'cl.exe'. @@ -140,6 +169,15 @@ LD = link.exe RC = rc.exe !ENDIF +# Check for the MSVC runtime library path macro. Othertise, this value will +# default to the 'lib' directory underneath the MSVC installation directory. +# +!IFNDEF CRTLIBPATH +CRTLIBPATH = $(VCINSTALLDIR)\lib +!ENDIF + +CRTLIBPATH = $(CRTLIBPATH:\\=\) + # Check for the command macro NCC. This should point to the compiler binary # for the platform the compilation process is taking place on. If it is not # defined, simply define it to have the same value as the CC macro. When @@ -168,8 +206,8 @@ NCC = $(NCC:\\=\) NCC = $(CC) !ENDIF -# Check for the MSVC runtime library path macro. Othertise, this -# value will default to the 'lib' directory underneath the MSVC +# Check for the MSVC native runtime library path macro. Othertise, +# this value will default to the 'lib' directory underneath the MSVC # installation directory. # !IFNDEF NCRTLIBPATH @@ -306,7 +344,6 @@ TCC = $(TCC) -DSQLITE_ENABLE_IOTRACE RCC = $(RCC) -DSQLITE_ENABLE_IOTRACE !ENDIF -# # Prevent warnings about "insecure" MSVC runtime library functions # being used. # @@ -314,28 +351,24 @@ TCC = $(TCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS BCC = $(BCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS RCC = $(RCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -# # Prevent warnings about "deprecated" POSIX functions being used. # TCC = $(TCC) -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS BCC = $(BCC) -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS RCC = $(RCC) -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -# # Use the SQLite debugging heap subsystem? # !IF $(MEMDEBUG)!=0 TCC = $(TCC) -DSQLITE_MEMDEBUG=1 RCC = $(RCC) -DSQLITE_MEMDEBUG=1 -# # Use native Win32 heap subsystem instead of malloc/free? # !ELSEIF $(WIN32HEAP)!=0 TCC = $(TCC) -DSQLITE_WIN32_MALLOC=1 RCC = $(RCC) -DSQLITE_WIN32_MALLOC=1 -# # Validate the heap on every call into the native Win32 heap subsystem? # !IF $(DEBUG)>2 @@ -430,25 +463,25 @@ RCC = $(RCC) -DSQLITE_TEMP_STORE=1 # The same set of OMIT and ENABLE flags should be passed to the # LEMON parser generator and the mkkeywordhash tool as well. -# BEGIN standard options -OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 -OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 -OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 -# END standard options +# These are the required SQLite compilation options used when compiling for +# the Windows platform. +# +REQ_FEATURE_FLAGS = $(REQ_FEATURE_FLAGS) -DSQLITE_MAX_TRIGGER_DEPTH=100 -# BEGIN required Windows option -OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_MAX_TRIGGER_DEPTH=100 -# END required Windows option +# Add the required and optional SQLite compilation options into the command +# lines used to invoke the MSVC code and resource compilers. +# +TCC = $(TCC) $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) +RCC = $(RCC) $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) -TCC = $(TCC) $(OPT_FEATURE_FLAGS) -RCC = $(RCC) $(OPT_FEATURE_FLAGS) - -# Add in any optional parameters specified on the make commane line -# ie. make "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1". +# Add in any optional parameters specified on the commane line, e.g. +# nmake /f Makefile.msc all "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1" +# TCC = $(TCC) $(OPTS) RCC = $(RCC) $(OPTS) # If compiling for debugging, add some defines. +# !IF $(DEBUG)>0 TCC = $(TCC) -D_DEBUG BCC = $(BCC) -D_DEBUG @@ -457,6 +490,7 @@ RCC = $(RCC) -D_DEBUG # If optimizations are enabled or disabled (either implicitly or # explicitly), add the necessary flags. +# !IF $(DEBUG)>0 || $(OPTIMIZATIONS)==0 TCC = $(TCC) -Od BCC = $(BCC) -Od @@ -472,12 +506,14 @@ BCC = $(BCC) -O1 !ENDIF # If symbols are enabled (or compiling for debugging), enable PDBs. +# !IF $(DEBUG)>0 || $(SYMBOLS)!=0 TCC = $(TCC) -Zi BCC = $(BCC) -Zi !ENDIF # If ICU support is enabled, add the compiler options for it. +# !IF $(USE_ICU)!=0 TCC = $(TCC) -DSQLITE_ENABLE_ICU=1 RCC = $(RCC) -DSQLITE_ENABLE_ICU=1 @@ -489,6 +525,7 @@ RCC = $(RCC) -I$(ICUINCDIR) # Command line prefixes for compiling code, compiling resources, # linking, etc. +# LTCOMPILE = $(TCC) -Fo$@ LTRCOMPILE = $(RCC) -r LTLIB = lib.exe @@ -510,36 +547,71 @@ LTLIBOPTS = /MACHINE:$(PLATFORM) !IF $(FOR_WINRT)!=0 LTLINKOPTS = $(LTLINKOPTS) /APPCONTAINER !IF "$(VISUALSTUDIOVERSION)"=="12.0" +!IFNDEF STORELIBPATH !IF "$(PLATFORM)"=="x86" -LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(VCINSTALLDIR)\lib\store" +STORELIBPATH = $(CRTLIBPATH)\store !ELSEIF "$(PLATFORM)"=="x64" -LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(VCINSTALLDIR)\lib\store\amd64" +STORELIBPATH = $(CRTLIBPATH)\store\amd64 !ELSEIF "$(PLATFORM)"=="ARM" -LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(VCINSTALLDIR)\lib\store\arm" +STORELIBPATH = $(CRTLIBPATH)\store\arm !ELSE -LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(VCINSTALLDIR)\lib\store" +STORELIBPATH = $(CRTLIBPATH)\store +!ENDIF +!ENDIF +STORELIBPATH = $(STORELIBPATH:\\=\) +LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(STORELIBPATH)" +!ENDIF +!ENDIF + +# When compiling for Windows Phone 8.1, an extra library path is +# required. +# +!IF $(USE_WP81_OPTS)!=0 +!IFNDEF WP81LIBPATH +!IF "$(PLATFORM)"=="x86" +WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86 +!ELSEIF "$(PLATFORM)"=="ARM" +WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\ARM +!ELSE +WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86 !ENDIF !ENDIF !ENDIF +# When compiling for Windows Phone 8.1, some extra linker options +# are also required. +# +!IF $(USE_WP81_OPTS)!=0 +!IFDEF WP81LIBPATH +LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)" +!ENDIF +LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE +LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib +LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib +!ENDIF + # If either debugging or symbols are enabled, enable PDBs. +# !IF $(DEBUG)>0 || $(SYMBOLS)!=0 LDFLAGS = /DEBUG !ENDIF # Start with the Tcl related linker options. +# !IF $(NO_TCL)==0 LTLIBPATHS = /LIBPATH:$(TCLLIBDIR) LTLIBS = $(LIBTCL) !ENDIF # If ICU support is enabled, add the linker options for it. +# !IF $(USE_ICU)!=0 LTLIBPATHS = $(LTLIBPATHS) /LIBPATH:$(ICULIBDIR) LTLIBS = $(LTLIBS) $(LIBICU) !ENDIF # nawk compatible awk. +# !IFNDEF NAWK NAWK = gawk.exe !ENDIF @@ -637,8 +709,10 @@ SRC = \ $(TOP)\src\os.c \ $(TOP)\src\os.h \ $(TOP)\src\os_common.h \ + $(TOP)\src\os_setup.h \ $(TOP)\src\os_unix.c \ $(TOP)\src\os_win.c \ + $(TOP)\src\os_win.h \ $(TOP)\src\pager.c \ $(TOP)\src\pager.h \ $(TOP)\src\parse.y \ @@ -788,6 +862,7 @@ TESTSRC = \ TESTEXT = \ $(TOP)\ext\misc\amatch.c \ $(TOP)\ext\misc\closure.c \ + $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ $(TOP)\ext\misc\ieee754.c \ $(TOP)\ext\misc\nextchar.c \ @@ -858,6 +933,8 @@ HDR = \ opcodes.h \ $(TOP)\src\os.h \ $(TOP)\src\os_common.h \ + $(TOP)\src\os_setup.h \ + $(TOP)\src\os_win.h \ $(TOP)\src\pager.h \ $(TOP)\src\pcache.h \ parse.h \ @@ -954,7 +1031,7 @@ lempar.c: $(TOP)\src\lempar.c copy $(TOP)\src\lempar.c . lemon.exe: $(TOP)\tool\lemon.c lempar.c - $(BCC) -Daccess=_access -Fe$@ $(TOP)\tool\lemon.c /link $(NLTLIBPATHS) + $(BCC) -Daccess=_access -Fe$@ $(TOP)\tool\lemon.c /link $(NLTLINKOPTS) $(NLTLIBPATHS) # Rules to build individual *.lo files from generated *.c files. This # applies to: @@ -1214,7 +1291,7 @@ parse.h: parse.c parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\addopcodes.awk del /Q parse.y parse.h parse.h.temp copy $(TOP)\src\parse.y . - .\lemon.exe $(OPT_FEATURE_FLAGS) $(OPTS) parse.y + .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(OPTS) parse.y move parse.h parse.h.temp $(NAWK) -f $(TOP)\addopcodes.awk parse.h.temp > parse.h @@ -1222,7 +1299,7 @@ sqlite3.h: $(TOP)\src\sqlite.h.in $(TOP)\manifest.uuid $(TOP)\VERSION $(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > sqlite3.h mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c - $(BCC) -Fe$@ $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)\tool\mkkeywordhash.c /link $(NLTLIBPATHS) + $(BCC) -Fe$@ $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)\tool\mkkeywordhash.c /link $(NLTLINKOPTS) $(NLTLIBPATHS) keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe .\mkkeywordhash.exe > keywordhash.h @@ -1358,6 +1435,29 @@ showdb.exe: $(TOP)\tool\showdb.c $(SQLITE3C) $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ $(TOP)\tool\showdb.c $(SQLITE3C) +showstat4.exe: $(TOP)\tool\showstat4.c $(SQLITE3C) + $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(TOP)\tool\showstat4.c $(SQLITE3C) + +showjournal.exe: $(TOP)\tool\showjournal.c $(SQLITE3C) + $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(TOP)\tool\showjournal.c $(SQLITE3C) + +showwal.exe: $(TOP)\tool\showwal.c $(SQLITE3C) + $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(TOP)\tool\showwal.c $(SQLITE3C) + +fts3view.exe: $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) + $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) + +rollback-test.exe: $(TOP)\tool\rollback-test.c $(SQLITE3C) + $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(TOP)\tool\rollback-test.c $(SQLITE3C) + +LogEst.exe: $(TOP)\tool\logest.c sqlite3.h + $(LTLINK) -Fe$@ $(TOP)\tool\LogEst.c + wordcount.exe: $(TOP)\test\wordcount.c $(SQLITE3C) $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ $(TOP)\test\wordcount.c $(SQLITE3C) @@ -1370,8 +1470,8 @@ clean: del /Q *.lo *.ilk *.lib *.obj *.pdb sqlite3.exe libsqlite3.lib del /Q *.cod *.da *.bb *.bbg gmon.out del /Q sqlite3.h opcodes.c opcodes.h - del /Q lemon.exe lempar.c parse.* - del /Q mkkeywordhash.exe keywordhash.h + del /Q lemon.* lempar.c parse.* + del /Q mkkeywordhash.* keywordhash.h del /Q notasharedlib.* -rmdir /Q/S .deps -rmdir /Q/S .libs @@ -1383,6 +1483,9 @@ clean: del /Q tclsqlite3.exe tclsqlite3.exp del /Q testloadext.dll testloadext.exp del /Q testfixture.exe testfixture.exp test.db + del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe + del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe + del /Q wordcount.exe del /Q sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def del /Q sqlite3.c sqlite3-*.c del /Q sqlite3rc.h diff --git a/Makefile.vxworks b/Makefile.vxworks index c9058da..0d9c27f 100644 --- a/Makefile.vxworks +++ b/Makefile.vxworks @@ -262,8 +262,10 @@ SRC = \ $(TOP)/src/os.c \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ + $(TOP)/src/os_setup.h \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ + $(TOP)/src/os_win.h \ $(TOP)/src/pager.c \ $(TOP)/src/pager.h \ $(TOP)/src/parse.y \ @@ -416,6 +418,8 @@ HDR = \ opcodes.h \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ + $(TOP)/src/os_setup.h \ + $(TOP)/src/os_win.h \ $(TOP)/src/pager.h \ $(TOP)/src/pcache.h \ parse.h \ diff --git a/VERSION b/VERSION index a6a2274..2e14a95 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.8.4.3 +3.8.6 diff --git a/configure b/configure index c6b4950..8748a98 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.8.4.3. +# Generated by GNU Autoconf 2.62 for sqlite 3.8.6. # # 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.8.4.3' -PACKAGE_STRING='sqlite 3.8.4.3' +PACKAGE_VERSION='3.8.6' +PACKAGE_STRING='sqlite 3.8.6' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. @@ -1483,7 +1483,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.8.4.3 to adapt to many kinds of systems. +\`configure' configures sqlite 3.8.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1548,7 +1548,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.8.4.3:";; + short | recursive ) echo "Configuration of sqlite 3.8.6:";; esac cat <<\_ACEOF @@ -1664,7 +1664,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.8.4.3 +sqlite configure 3.8.6 generated by GNU Autoconf 2.62 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1678,7 +1678,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.8.4.3, which was +It was created by sqlite $as_me 3.8.6, which was generated by GNU Autoconf 2.62. Invocation command line was $ $0 $@ @@ -14021,7 +14021,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.8.4.3, which was +This file was extended by sqlite $as_me 3.8.6, which was generated by GNU Autoconf 2.62. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14074,7 +14074,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ -sqlite config.status 3.8.4.3 +sqlite config.status 3.8.6 configured by $0, generated by GNU Autoconf 2.62, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 44b7f43..4f4b667 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -1333,7 +1333,7 @@ static int fts3InitVtab( p->bHasStat = isFts4; p->bFts4 = isFts4; p->bDescIdx = bDescIdx; - p->bAutoincrmerge = 0xff; /* 0xff means setting unknown */ + p->nAutoincrmerge = 0xff; /* 0xff means setting unknown */ p->zContentTbl = zContent; p->zLanguageid = zLanguageid; zContent = 0; @@ -1376,7 +1376,9 @@ static int fts3InitVtab( int n = (int)strlen(p->azColumn[iCol]); for(i=0; iazColumn[iCol], zNot, n) ){ + if( zNot && n==(int)strlen(zNot) + && 0==sqlite3_strnicmp(p->azColumn[iCol], zNot, n) + ){ p->abNotindexed[iCol] = 1; sqlite3_free(zNot); azNotindexed[i] = 0; @@ -1410,10 +1412,7 @@ static int fts3InitVtab( ** addition of a %_stat table so that it can use incremental merge. */ if( !isFts4 && !isCreate ){ - int rc2 = SQLITE_OK; - fts3DbExec(&rc2, db, "SELECT 1 FROM %Q.'%q_stat' WHERE id=2", - p->zDb, p->zName); - if( rc2==SQLITE_OK ) p->bHasStat = 1; + p->bHasStat = 2; } /* Figure out the page-size for the database. This is required in order to @@ -3305,7 +3304,10 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table*)pVtab; int rc = sqlite3Fts3PendingTermsFlush(p); - if( rc==SQLITE_OK && p->bAutoincrmerge==1 && p->nLeafAdd>(nMinMerge/16) ){ + if( rc==SQLITE_OK + && p->nLeafAdd>(nMinMerge/16) + && p->nAutoincrmerge && p->nAutoincrmerge!=0xff + ){ int mxLevel = 0; /* Maximum relative level value in db */ int A; /* Incr-merge parameter A */ @@ -3313,14 +3315,41 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){ assert( rc==SQLITE_OK || mxLevel==0 ); A = p->nLeafAdd * mxLevel; A += (A/2); - if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, 8); + if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge); } sqlite3Fts3SegmentsClose(p); return rc; } /* -** Implementation of xBegin() method. This is a no-op. +** If it is currently unknown whether or not the FTS table has an %_stat +** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat +** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code +** if an error occurs. +*/ +static int fts3SetHasStat(Fts3Table *p){ + int rc = SQLITE_OK; + if( p->bHasStat==2 ){ + const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'"; + char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName); + if( zSql ){ + sqlite3_stmt *pStmt = 0; + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + if( rc==SQLITE_OK ){ + int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW); + rc = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ) p->bHasStat = bHasStat; + } + sqlite3_free(zSql); + }else{ + rc = SQLITE_NOMEM; + } + } + return rc; +} + +/* +** Implementation of xBegin() method. */ static int fts3BeginMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table*)pVtab; @@ -3331,7 +3360,7 @@ static int fts3BeginMethod(sqlite3_vtab *pVtab){ TESTONLY( p->inTransaction = 1 ); TESTONLY( p->mxSavepoint = -1; ); p->nLeafAdd = 0; - return SQLITE_OK; + return fts3SetHasStat(p); } /* @@ -3580,6 +3609,10 @@ static int fts3RenameMethod( sqlite3 *db = p->db; /* Database connection */ int rc; /* Return Code */ + /* At this point it must be known if the %_stat table exists or not. + ** So bHasStat may not be 2. */ + rc = fts3SetHasStat(p); + /* As it happens, the pending terms table is always empty here. This is ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction ** always opens a savepoint transaction. And the xSavepoint() method @@ -3587,7 +3620,9 @@ static int fts3RenameMethod( ** PendingTermsFlush() in in case that changes. */ assert( p->nPendingData==0 ); - rc = sqlite3Fts3PendingTermsFlush(p); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3PendingTermsFlush(p); + } if( p->zContentTbl==0 ){ fts3DbExec(&rc, db, @@ -3715,7 +3750,7 @@ static void hashDestroy(void *p){ */ void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule); -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); #endif #ifdef SQLITE_ENABLE_ICU @@ -3733,7 +3768,7 @@ int sqlite3Fts3Init(sqlite3 *db){ Fts3Hash *pHash = 0; const sqlite3_tokenizer_module *pSimple = 0; const sqlite3_tokenizer_module *pPorter = 0; -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE const sqlite3_tokenizer_module *pUnicode = 0; #endif @@ -3742,7 +3777,7 @@ int sqlite3Fts3Init(sqlite3 *db){ sqlite3Fts3IcuTokenizerModule(&pIcu); #endif -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE sqlite3Fts3UnicodeTokenizer(&pUnicode); #endif @@ -3770,7 +3805,7 @@ int sqlite3Fts3Init(sqlite3 *db){ if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple) || sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter) -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE || sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode) #endif #ifdef SQLITE_ENABLE_ICU diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index 7f71736..b2827b7 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -210,20 +210,20 @@ struct Fts3Table { sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ char *zContentTbl; /* content=xxx option, or NULL */ char *zLanguageid; /* languageid=xxx option, or NULL */ - u8 bAutoincrmerge; /* True if automerge=1 */ + int nAutoincrmerge; /* Value configured by 'automerge' */ u32 nLeafAdd; /* Number of leaf blocks added this trans */ /* Precompiled statements used by the implementation. Each of these ** statements is run and reset within a single virtual table API call. */ - sqlite3_stmt *aStmt[37]; + sqlite3_stmt *aStmt[40]; char *zReadExprlist; char *zWriteExprlist; int nNodeSize; /* Soft limit for node size */ u8 bFts4; /* True for FTS4, false for FTS3 */ - u8 bHasStat; /* True if %_stat table exists */ + u8 bHasStat; /* True if %_stat table exists (2==unknown) */ u8 bHasDocsize; /* True if %_docsize table exists */ u8 bDescIdx; /* True if doclists are in reverse order */ u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */ @@ -585,7 +585,7 @@ int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *); /* fts3_unicode2.c (functions generated by parsing unicode text files) */ -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE int sqlite3FtsUnicodeFold(int, int); int sqlite3FtsUnicodeIsalnum(int); int sqlite3FtsUnicodeIsdiacritic(int); diff --git a/ext/fts3/fts3_expr.c b/ext/fts3/fts3_expr.c index 9c71f26..f5d28cb 100644 --- a/ext/fts3/fts3_expr.c +++ b/ext/fts3/fts3_expr.c @@ -185,40 +185,23 @@ static int getNextToken( int rc; sqlite3_tokenizer_cursor *pCursor; Fts3Expr *pRet = 0; - int nConsumed = 0; + int i = 0; - rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor); + /* Set variable i to the maximum number of bytes of input to tokenize. */ + for(i=0; iiLangid, z, i, &pCursor); if( rc==SQLITE_OK ){ const char *zToken; int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; int nByte; /* total space to allocate */ rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); - - if( (rc==SQLITE_OK || rc==SQLITE_DONE) && sqlite3_fts3_enable_parentheses ){ - int i; - if( rc==SQLITE_DONE ) iStart = n; - for(i=0; inNest++; - rc = fts3ExprParse(pParse, &z[i+1], n-i-1, &pRet, &nConsumed); - if( rc==SQLITE_OK && !pRet ){ - rc = SQLITE_DONE; - } - nConsumed = (int)(i + 1 + nConsumed); - break; - } - - if( z[i]==')' ){ - rc = SQLITE_DONE; - pParse->nNest--; - nConsumed = i+1; - break; - } - } - } - - if( nConsumed==0 && rc==SQLITE_OK ){ + if( rc==SQLITE_OK ){ nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; pRet = (Fts3Expr *)fts3MallocZero(nByte); if( !pRet ){ @@ -252,13 +235,14 @@ static int getNextToken( } } - nConsumed = iEnd; + *pnConsumed = iEnd; + }else if( i && rc==SQLITE_DONE ){ + rc = SQLITE_OK; } pModule->xClose(pCursor); } - *pnConsumed = nConsumed; *ppExpr = pRet; return rc; } @@ -508,6 +492,21 @@ static int getNextNode( return getNextString(pParse, &zInput[1], ii-1, ppExpr); } + if( sqlite3_fts3_enable_parentheses ){ + if( *zInput=='(' ){ + int nConsumed = 0; + pParse->nNest++; + rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed); + if( rc==SQLITE_OK && !*ppExpr ){ rc = SQLITE_DONE; } + *pnConsumed = (int)(zInput - z) + 1 + nConsumed; + return rc; + }else if( *zInput==')' ){ + pParse->nNest--; + *pnConsumed = (int)((zInput - z) + 1); + *ppExpr = 0; + return SQLITE_DONE; + } + } /* If control flows to this point, this must be a regular token, or ** the end of the input. Read a regular token using the sqlite3_tokenizer @@ -626,96 +625,100 @@ static int fts3ExprParse( while( rc==SQLITE_OK ){ Fts3Expr *p = 0; int nByte = 0; + rc = getNextNode(pParse, zIn, nIn, &p, &nByte); + assert( nByte>0 || (rc!=SQLITE_OK && p==0) ); if( rc==SQLITE_OK ){ - int isPhrase; + if( p ){ + int isPhrase; - if( !sqlite3_fts3_enable_parentheses - && p->eType==FTSQUERY_PHRASE && pParse->isNot - ){ - /* Create an implicit NOT operator. */ - Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr)); - if( !pNot ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_NOMEM; - goto exprparse_out; - } - pNot->eType = FTSQUERY_NOT; - pNot->pRight = p; - p->pParent = pNot; - if( pNotBranch ){ - pNot->pLeft = pNotBranch; - pNotBranch->pParent = pNot; - } - pNotBranch = pNot; - p = pPrev; - }else{ - int eType = p->eType; - isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); - - /* The isRequirePhrase variable is set to true if a phrase or - ** an expression contained in parenthesis is required. If a - ** binary operator (AND, OR, NOT or NEAR) is encounted when - ** isRequirePhrase is set, this is a syntax error. - */ - if( !isPhrase && isRequirePhrase ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_ERROR; - goto exprparse_out; - } - - if( isPhrase && !isRequirePhrase ){ - /* Insert an implicit AND operator. */ - Fts3Expr *pAnd; - assert( pRet && pPrev ); - pAnd = fts3MallocZero(sizeof(Fts3Expr)); - if( !pAnd ){ + if( !sqlite3_fts3_enable_parentheses + && p->eType==FTSQUERY_PHRASE && pParse->isNot + ){ + /* Create an implicit NOT operator. */ + Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr)); + if( !pNot ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; goto exprparse_out; } - pAnd->eType = FTSQUERY_AND; - insertBinaryOperator(&pRet, pPrev, pAnd); - pPrev = pAnd; - } + pNot->eType = FTSQUERY_NOT; + pNot->pRight = p; + p->pParent = pNot; + if( pNotBranch ){ + pNot->pLeft = pNotBranch; + pNotBranch->pParent = pNot; + } + pNotBranch = pNot; + p = pPrev; + }else{ + int eType = p->eType; + isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); - /* This test catches attempts to make either operand of a NEAR - ** operator something other than a phrase. For example, either of - ** the following: - ** - ** (bracketed expression) NEAR phrase - ** phrase NEAR (bracketed expression) - ** - ** Return an error in either case. - */ - if( pPrev && ( + /* The isRequirePhrase variable is set to true if a phrase or + ** an expression contained in parenthesis is required. If a + ** binary operator (AND, OR, NOT or NEAR) is encounted when + ** isRequirePhrase is set, this is a syntax error. + */ + if( !isPhrase && isRequirePhrase ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_ERROR; + goto exprparse_out; + } + + if( isPhrase && !isRequirePhrase ){ + /* Insert an implicit AND operator. */ + Fts3Expr *pAnd; + assert( pRet && pPrev ); + pAnd = fts3MallocZero(sizeof(Fts3Expr)); + if( !pAnd ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_NOMEM; + goto exprparse_out; + } + pAnd->eType = FTSQUERY_AND; + insertBinaryOperator(&pRet, pPrev, pAnd); + pPrev = pAnd; + } + + /* This test catches attempts to make either operand of a NEAR + ** operator something other than a phrase. For example, either of + ** the following: + ** + ** (bracketed expression) NEAR phrase + ** phrase NEAR (bracketed expression) + ** + ** Return an error in either case. + */ + if( pPrev && ( (eType==FTSQUERY_NEAR && !isPhrase && pPrev->eType!=FTSQUERY_PHRASE) || (eType!=FTSQUERY_PHRASE && isPhrase && pPrev->eType==FTSQUERY_NEAR) - )){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_ERROR; - goto exprparse_out; - } - - if( isPhrase ){ - if( pRet ){ - assert( pPrev && pPrev->pLeft && pPrev->pRight==0 ); - pPrev->pRight = p; - p->pParent = pPrev; - }else{ - pRet = p; + )){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_ERROR; + goto exprparse_out; } - }else{ - insertBinaryOperator(&pRet, pPrev, p); + + if( isPhrase ){ + if( pRet ){ + assert( pPrev && pPrev->pLeft && pPrev->pRight==0 ); + pPrev->pRight = p; + p->pParent = pPrev; + }else{ + pRet = p; + } + }else{ + insertBinaryOperator(&pRet, pPrev, p); + } + isRequirePhrase = !isPhrase; } - isRequirePhrase = !isPhrase; + pPrev = p; } assert( nByte>0 ); } assert( rc!=SQLITE_OK || (nByte>0 && nByte<=nIn) ); nIn -= nByte; zIn += nByte; - pPrev = p; } if( rc==SQLITE_DONE && pRet && isRequirePhrase ){ diff --git a/ext/fts3/fts3_unicode.c b/ext/fts3/fts3_unicode.c index 188358e..94fc27b 100644 --- a/ext/fts3/fts3_unicode.c +++ b/ext/fts3/fts3_unicode.c @@ -13,7 +13,7 @@ ** Implementation of the "unicode" full-text-search tokenizer. */ -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE #include "fts3Int.h" #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) @@ -231,7 +231,7 @@ static int unicodeCreate( for(i=0; rc==SQLITE_OK && ibRemoveDiacritic = 1; @@ -318,7 +318,7 @@ static int unicodeNext( ){ unicode_cursor *pCsr = (unicode_cursor *)pC; unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer); - int iCode; + int iCode = 0; char *zOut; const unsigned char *z = &pCsr->aInput[pCsr->iOff]; const unsigned char *zStart = z; @@ -363,11 +363,11 @@ static int unicodeNext( ); /* Set the output variables and return. */ - pCsr->iOff = (z - pCsr->aInput); + pCsr->iOff = (int)(z - pCsr->aInput); *paToken = pCsr->zToken; - *pnToken = zOut - pCsr->zToken; - *piStart = (zStart - pCsr->aInput); - *piEnd = (zEnd - pCsr->aInput); + *pnToken = (int)(zOut - pCsr->zToken); + *piStart = (int)(zStart - pCsr->aInput); + *piEnd = (int)(zEnd - pCsr->aInput); *piPos = pCsr->iToken++; return SQLITE_OK; } @@ -390,4 +390,4 @@ void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const **ppModule){ } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ -#endif /* ifndef SQLITE_ENABLE_FTS4_UNICODE61 */ +#endif /* ifndef SQLITE_DISABLE_FTS3_UNICODE */ diff --git a/ext/fts3/fts3_unicode2.c b/ext/fts3/fts3_unicode2.c index fba688f..20b7a25 100644 --- a/ext/fts3/fts3_unicode2.c +++ b/ext/fts3/fts3_unicode2.c @@ -15,7 +15,7 @@ ** DO NOT EDIT THIS MACHINE GENERATED FILE. */ -#if defined(SQLITE_ENABLE_FTS4_UNICODE61) +#ifndef SQLITE_DISABLE_FTS3_UNICODE #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) #include @@ -39,7 +39,7 @@ int sqlite3FtsUnicodeIsalnum(int c){ ** C. It is not possible to represent a range larger than 1023 codepoints ** using this format. */ - const static unsigned int aEntry[] = { + static const unsigned int aEntry[] = { 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07, 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01, 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401, @@ -131,7 +131,7 @@ int sqlite3FtsUnicodeIsalnum(int c){ return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 ); }else if( c<(1<<22) ){ unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; - int iRes; + int iRes = 0; int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; int iLo = 0; while( iHi>=iLo ){ @@ -202,7 +202,7 @@ static int remove_diacritic(int c){ } assert( key>=aDia[iRes] ); return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]); -}; +} /* @@ -362,4 +362,4 @@ int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ return ret; } #endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */ -#endif /* !defined(SQLITE_ENABLE_FTS4_UNICODE61) */ +#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */ diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 3564cf8..0da08c6 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -193,6 +193,7 @@ struct SegmentWriter { int nSize; /* Size of allocation at aData */ int nData; /* Bytes of data in aData */ char *aData; /* Pointer to block from malloc() */ + i64 nLeafData; /* Number of bytes of leaf data written */ }; /* @@ -268,6 +269,10 @@ struct SegmentNode { #define SQL_SELECT_INDEXES 35 #define SQL_SELECT_MXLEVEL 36 +#define SQL_SELECT_LEVEL_RANGE2 37 +#define SQL_UPDATE_LEVEL_IDX 38 +#define SQL_UPDATE_LEVEL 39 + /* ** This function is used to obtain an SQLite prepared statement handle ** for the statement identified by the second argument. If successful, @@ -369,7 +374,18 @@ static int fts3SqlStmt( /* SQL_SELECT_MXLEVEL ** Return the largest relative level in the FTS index or indexes. */ -/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'" +/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'", + + /* Return segments in order from oldest to newest.*/ +/* 37 */ "SELECT level, idx, end_block " + "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? " + "ORDER BY level DESC, idx ASC", + + /* Update statements used while promoting segments */ +/* 38 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=-1,idx=? " + "WHERE level=? AND idx=?", +/* 39 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=? WHERE level=-1" + }; int rc = SQLITE_OK; sqlite3_stmt *pStmt; @@ -1910,6 +1926,7 @@ static int fts3WriteSegdir( sqlite3_int64 iStartBlock, /* Value for "start_block" field */ sqlite3_int64 iLeafEndBlock, /* Value for "leaves_end_block" field */ sqlite3_int64 iEndBlock, /* Value for "end_block" field */ + sqlite3_int64 nLeafData, /* Bytes of leaf data in segment */ char *zRoot, /* Blob value for "root" field */ int nRoot /* Number of bytes in buffer zRoot */ ){ @@ -1920,7 +1937,13 @@ static int fts3WriteSegdir( sqlite3_bind_int(pStmt, 2, iIdx); sqlite3_bind_int64(pStmt, 3, iStartBlock); sqlite3_bind_int64(pStmt, 4, iLeafEndBlock); - sqlite3_bind_int64(pStmt, 5, iEndBlock); + if( nLeafData==0 ){ + sqlite3_bind_int64(pStmt, 5, iEndBlock); + }else{ + char *zEnd = sqlite3_mprintf("%lld %lld", iEndBlock, nLeafData); + if( !zEnd ) return SQLITE_NOMEM; + sqlite3_bind_text(pStmt, 5, zEnd, -1, sqlite3_free); + } sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); @@ -2246,6 +2269,9 @@ static int fts3SegWriterAdd( nDoclist; /* Doclist data */ } + /* Increase the total number of bytes written to account for the new entry. */ + pWriter->nLeafData += nReq; + /* If the buffer currently allocated is too small for this entry, realloc ** the buffer to make it large enough. */ @@ -2317,13 +2343,13 @@ static int fts3SegWriterFlush( pWriter->iFirst, pWriter->iFree, &iLast, &zRoot, &nRoot); } if( rc==SQLITE_OK ){ - rc = fts3WriteSegdir( - p, iLevel, iIdx, pWriter->iFirst, iLastLeaf, iLast, zRoot, nRoot); + rc = fts3WriteSegdir(p, iLevel, iIdx, + pWriter->iFirst, iLastLeaf, iLast, pWriter->nLeafData, zRoot, nRoot); } }else{ /* The entire tree fits on the root node. Write it to the segdir table. */ - rc = fts3WriteSegdir( - p, iLevel, iIdx, 0, 0, 0, pWriter->aData, pWriter->nData); + rc = fts3WriteSegdir(p, iLevel, iIdx, + 0, 0, 0, pWriter->nLeafData, pWriter->aData, pWriter->nData); } p->nLeafAdd++; return rc; @@ -2407,6 +2433,37 @@ static int fts3SegmentMaxLevel( return sqlite3_reset(pStmt); } +/* +** iAbsLevel is an absolute level that may be assumed to exist within +** the database. This function checks if it is the largest level number +** within its index. Assuming no error occurs, *pbMax is set to 1 if +** iAbsLevel is indeed the largest level, or 0 otherwise, and SQLITE_OK +** is returned. If an error occurs, an error code is returned and the +** final value of *pbMax is undefined. +*/ +static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){ + + /* Set pStmt to the compiled version of: + ** + ** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? + ** + ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). + */ + sqlite3_stmt *pStmt; + int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); + if( rc!=SQLITE_OK ) return rc; + sqlite3_bind_int64(pStmt, 1, iAbsLevel+1); + sqlite3_bind_int64(pStmt, 2, + ((iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL + ); + + *pbMax = 0; + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + *pbMax = sqlite3_column_type(pStmt, 0)==SQLITE_NULL; + } + return sqlite3_reset(pStmt); +} + /* ** Delete all entries in the %_segments table associated with the segment ** opened with seg-reader pSeg. This function does not affect the contents @@ -2942,6 +2999,140 @@ void sqlite3Fts3SegReaderFinish( } } +/* +** Decode the "end_block" field, selected by column iCol of the SELECT +** statement passed as the first argument. +** +** The "end_block" field may contain either an integer, or a text field +** containing the text representation of two non-negative integers separated +** by one or more space (0x20) characters. In the first case, set *piEndBlock +** to the integer value and *pnByte to zero before returning. In the second, +** set *piEndBlock to the first value and *pnByte to the second. +*/ +static void fts3ReadEndBlockField( + sqlite3_stmt *pStmt, + int iCol, + i64 *piEndBlock, + i64 *pnByte +){ + const unsigned char *zText = sqlite3_column_text(pStmt, iCol); + if( zText ){ + int i; + int iMul = 1; + i64 iVal = 0; + for(i=0; zText[i]>='0' && zText[i]<='9'; i++){ + iVal = iVal*10 + (zText[i] - '0'); + } + *piEndBlock = iVal; + while( zText[i]==' ' ) i++; + iVal = 0; + if( zText[i]=='-' ){ + i++; + iMul = -1; + } + for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){ + iVal = iVal*10 + (zText[i] - '0'); + } + *pnByte = (iVal * (i64)iMul); + } +} + + +/* +** A segment of size nByte bytes has just been written to absolute level +** iAbsLevel. Promote any segments that should be promoted as a result. +*/ +static int fts3PromoteSegments( + Fts3Table *p, /* FTS table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level just updated */ + sqlite3_int64 nByte /* Size of new segment at iAbsLevel */ +){ + int rc = SQLITE_OK; + sqlite3_stmt *pRange; + + rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE2, &pRange, 0); + + if( rc==SQLITE_OK ){ + int bOk = 0; + i64 iLast = (iAbsLevel/FTS3_SEGDIR_MAXLEVEL + 1) * FTS3_SEGDIR_MAXLEVEL - 1; + i64 nLimit = (nByte*3)/2; + + /* Loop through all entries in the %_segdir table corresponding to + ** segments in this index on levels greater than iAbsLevel. If there is + ** at least one such segment, and it is possible to determine that all + ** such segments are smaller than nLimit bytes in size, they will be + ** promoted to level iAbsLevel. */ + sqlite3_bind_int64(pRange, 1, iAbsLevel+1); + sqlite3_bind_int64(pRange, 2, iLast); + while( SQLITE_ROW==sqlite3_step(pRange) ){ + i64 nSize = 0, dummy; + fts3ReadEndBlockField(pRange, 2, &dummy, &nSize); + if( nSize<=0 || nSize>nLimit ){ + /* If nSize==0, then the %_segdir.end_block field does not not + ** contain a size value. This happens if it was written by an + ** old version of FTS. In this case it is not possible to determine + ** the size of the segment, and so segment promotion does not + ** take place. */ + bOk = 0; + break; + } + bOk = 1; + } + rc = sqlite3_reset(pRange); + + if( bOk ){ + int iIdx = 0; + sqlite3_stmt *pUpdate1; + sqlite3_stmt *pUpdate2; + + if( rc==SQLITE_OK ){ + rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0); + } + if( rc==SQLITE_OK ){ + rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL, &pUpdate2, 0); + } + + if( rc==SQLITE_OK ){ + + /* Loop through all %_segdir entries for segments in this index with + ** levels equal to or greater than iAbsLevel. As each entry is visited, + ** updated it to set (level = -1) and (idx = N), where N is 0 for the + ** oldest segment in the range, 1 for the next oldest, and so on. + ** + ** In other words, move all segments being promoted to level -1, + ** setting the "idx" fields as appropriate to keep them in the same + ** order. The contents of level -1 (which is never used, except + ** transiently here), will be moved back to level iAbsLevel below. */ + sqlite3_bind_int64(pRange, 1, iAbsLevel); + while( SQLITE_ROW==sqlite3_step(pRange) ){ + sqlite3_bind_int(pUpdate1, 1, iIdx++); + sqlite3_bind_int(pUpdate1, 2, sqlite3_column_int(pRange, 0)); + sqlite3_bind_int(pUpdate1, 3, sqlite3_column_int(pRange, 1)); + sqlite3_step(pUpdate1); + rc = sqlite3_reset(pUpdate1); + if( rc!=SQLITE_OK ){ + sqlite3_reset(pRange); + break; + } + } + } + if( rc==SQLITE_OK ){ + rc = sqlite3_reset(pRange); + } + + /* Move level -1 to level iAbsLevel */ + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pUpdate2, 1, iAbsLevel); + sqlite3_step(pUpdate2); + rc = sqlite3_reset(pUpdate2); + } + } + } + + + return rc; +} + /* ** Merge all level iLevel segments in the database into a single ** iLevel+1 segment. Or, if iLevel<0, merge all segments into a @@ -2966,6 +3157,7 @@ static int fts3SegmentMerge( Fts3SegFilter filter; /* Segment term filter condition */ Fts3MultiSegReader csr; /* Cursor to iterate through level(s) */ int bIgnoreEmpty = 0; /* True to ignore empty segments */ + i64 iMaxLevel = 0; /* Max level number for this index/langid */ assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel==FTS3_SEGCURSOR_PENDING @@ -2977,6 +3169,11 @@ static int fts3SegmentMerge( rc = sqlite3Fts3SegReaderCursor(p, iLangid, iIndex, iLevel, 0, 0, 1, 0, &csr); if( rc!=SQLITE_OK || csr.nSegment==0 ) goto finished; + if( iLevel!=FTS3_SEGCURSOR_PENDING ){ + rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iMaxLevel); + if( rc!=SQLITE_OK ) goto finished; + } + if( iLevel==FTS3_SEGCURSOR_ALL ){ /* This call is to merge all segments in the database to a single ** segment. The level of the new segment is equal to the numerically @@ -2986,21 +3183,21 @@ static int fts3SegmentMerge( rc = SQLITE_DONE; goto finished; } - rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iNewLevel); + iNewLevel = iMaxLevel; bIgnoreEmpty = 1; - }else if( iLevel==FTS3_SEGCURSOR_PENDING ){ - iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, 0); - rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, 0, &iIdx); }else{ /* This call is to merge all segments at level iLevel. find the next ** available segment index at level iLevel+1. The call to ** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to ** a single iLevel+2 segment if necessary. */ - rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx); + assert( FTS3_SEGCURSOR_PENDING==-1 ); iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1); + rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx); + bIgnoreEmpty = (iLevel!=FTS3_SEGCURSOR_PENDING) && (iNewLevel>iMaxLevel); } if( rc!=SQLITE_OK ) goto finished; + assert( csr.nSegment>0 ); assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) ); assert( iNewLevelnLeafData); + } + } + } finished: fts3SegWriterFree(pWriter); @@ -3035,7 +3239,7 @@ static int fts3SegmentMerge( /* -** Flush the contents of pendingTerms to level 0 segments. +** Flush the contents of pendingTerms to level 0 segments. */ int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ int rc = SQLITE_OK; @@ -3051,14 +3255,19 @@ int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ ** estimate the number of leaf blocks of content to be written */ if( rc==SQLITE_OK && p->bHasStat - && p->bAutoincrmerge==0xff && p->nLeafAdd>0 + && p->nAutoincrmerge==0xff && p->nLeafAdd>0 ){ sqlite3_stmt *pStmt = 0; rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); rc = sqlite3_step(pStmt); - p->bAutoincrmerge = (rc==SQLITE_ROW && sqlite3_column_int(pStmt, 0)); + if( rc==SQLITE_ROW ){ + p->nAutoincrmerge = sqlite3_column_int(pStmt, 0); + if( p->nAutoincrmerge==1 ) p->nAutoincrmerge = 8; + }else if( rc==SQLITE_DONE ){ + p->nAutoincrmerge = 0; + } rc = sqlite3_reset(pStmt); } } @@ -3426,6 +3635,8 @@ struct IncrmergeWriter { int iIdx; /* Index of *output* segment in iAbsLevel+1 */ sqlite3_int64 iStart; /* Block number of first allocated block */ sqlite3_int64 iEnd; /* Block number of last allocated block */ + sqlite3_int64 nLeafData; /* Bytes of leaf page data so far */ + u8 bNoLeafData; /* If true, store 0 for segment size */ NodeWriter aNodeWriter[FTS_MAX_APPENDABLE_HEIGHT]; }; @@ -3764,8 +3975,8 @@ static int fts3IncrmergeAppend( nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; } + pWriter->nLeafData += nSpace; blobGrowBuffer(&pLeaf->block, pLeaf->block.n + nSpace, &rc); - if( rc==SQLITE_OK ){ if( pLeaf->block.n==0 ){ pLeaf->block.n = 1; @@ -3864,6 +4075,7 @@ static void fts3IncrmergeRelease( pWriter->iStart, /* start_block */ pWriter->aNodeWriter[0].iBlock, /* leaves_end_block */ pWriter->iEnd, /* end_block */ + (pWriter->bNoLeafData==0 ? pWriter->nLeafData : 0), /* end_block */ pRoot->block.a, pRoot->block.n /* root */ ); } @@ -3965,7 +4177,11 @@ static int fts3IncrmergeLoad( if( sqlite3_step(pSelect)==SQLITE_ROW ){ iStart = sqlite3_column_int64(pSelect, 1); iLeafEnd = sqlite3_column_int64(pSelect, 2); - iEnd = sqlite3_column_int64(pSelect, 3); + fts3ReadEndBlockField(pSelect, 3, &iEnd, &pWriter->nLeafData); + if( pWriter->nLeafData<0 ){ + pWriter->nLeafData = pWriter->nLeafData * -1; + } + pWriter->bNoLeafData = (pWriter->nLeafData==0); nRoot = sqlite3_column_bytes(pSelect, 4); aRoot = sqlite3_column_blob(pSelect, 4); }else{ @@ -4566,11 +4782,11 @@ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){ /* ** Attempt an incremental merge that writes nMerge leaf blocks. ** -** Incremental merges happen nMin segments at a time. The two -** segments to be merged are the nMin oldest segments (the ones with -** the smallest indexes) in the highest level that contains at least -** nMin segments. Multiple merges might occur in an attempt to write the -** quota of nMerge leaf blocks. +** Incremental merges happen nMin segments at a time. The segments +** to be merged are the nMin oldest segments (the ones with the smallest +** values for the _segdir.idx field) in the highest level that contains +** at least nMin segments. Multiple merges might occur in an attempt to +** write the quota of nMerge leaf blocks. */ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ int rc; /* Return code */ @@ -4595,6 +4811,7 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex; sqlite3_stmt *pFindLevel = 0; /* SQL used to determine iAbsLevel */ int bUseHint = 0; /* True if attempting to append */ + int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */ /* Search the %_segdir table for the absolute level with the smallest ** relative level number that contains at least nMin segments, if any. @@ -4648,6 +4865,19 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ ** to start work on some other level. */ memset(pWriter, 0, nAlloc); pFilter->flags = FTS3_SEGMENT_REQUIRE_POS; + + if( rc==SQLITE_OK ){ + rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx); + assert( bUseHint==1 || bUseHint==0 ); + if( iIdx==0 || (bUseHint && iIdx==1) ){ + int bIgnore = 0; + rc = fts3SegmentIsMaxLevel(p, iAbsLevel+1, &bIgnore); + if( bIgnore ){ + pFilter->flags |= FTS3_SEGMENT_IGNORE_EMPTY; + } + } + } + if( rc==SQLITE_OK ){ rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr); } @@ -4655,16 +4885,12 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ && SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter)) && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr)) ){ - int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */ - rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx); - if( rc==SQLITE_OK ){ - if( bUseHint && iIdx>0 ){ - const char *zKey = pCsr->zTerm; - int nKey = pCsr->nTerm; - rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter); - }else{ - rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter); - } + if( bUseHint && iIdx>0 ){ + const char *zKey = pCsr->zTerm; + int nKey = pCsr->nTerm; + rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter); + }else{ + rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter); } if( rc==SQLITE_OK && pWriter->nLeafEst ){ @@ -4686,7 +4912,13 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ } } + if( nSeg!=0 ){ + pWriter->nLeafData = pWriter->nLeafData * -1; + } fts3IncrmergeRelease(p, pWriter, &rc); + if( nSeg==0 && pWriter->bNoLeafData==0 ){ + fts3PromoteSegments(p, iAbsLevel+1, pWriter->nLeafData); + } } sqlite3Fts3SegReaderFinish(pCsr); @@ -4773,7 +5005,10 @@ static int fts3DoAutoincrmerge( ){ int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; - p->bAutoincrmerge = fts3Getint(&zParam)!=0; + p->nAutoincrmerge = fts3Getint(&zParam); + if( p->nAutoincrmerge==1 || p->nAutoincrmerge>FTS3_MERGE_COUNT ){ + p->nAutoincrmerge = 8; + } if( !p->bHasStat ){ assert( p->bFts4==0 ); sqlite3Fts3CreateStatTable(&rc, p); @@ -4782,7 +5017,7 @@ static int fts3DoAutoincrmerge( rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0); if( rc ) return rc; sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); - sqlite3_bind_int(pStmt, 2, p->bAutoincrmerge); + sqlite3_bind_int(pStmt, 2, p->nAutoincrmerge); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); return rc; @@ -4939,34 +5174,36 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){ int iCol; for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ - const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1); - int nText = sqlite3_column_bytes(pStmt, iCol+1); - sqlite3_tokenizer_cursor *pT = 0; + if( p->abNotindexed[iCol]==0 ){ + const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1); + int nText = sqlite3_column_bytes(pStmt, iCol+1); + sqlite3_tokenizer_cursor *pT = 0; - rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText, &pT); - while( rc==SQLITE_OK ){ - char const *zToken; /* Buffer containing token */ - int nToken = 0; /* Number of bytes in token */ - int iDum1 = 0, iDum2 = 0; /* Dummy variables */ - int iPos = 0; /* Position of token in zText */ + rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText,&pT); + while( rc==SQLITE_OK ){ + char const *zToken; /* Buffer containing token */ + int nToken = 0; /* Number of bytes in token */ + int iDum1 = 0, iDum2 = 0; /* Dummy variables */ + int iPos = 0; /* Position of token in zText */ - rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos); - if( rc==SQLITE_OK ){ - int i; - cksum2 = cksum2 ^ fts3ChecksumEntry( - zToken, nToken, iLang, 0, iDocid, iCol, iPos - ); - for(i=1; inIndex; i++){ - if( p->aIndex[i].nPrefix<=nToken ){ - cksum2 = cksum2 ^ fts3ChecksumEntry( - zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos - ); + rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos); + if( rc==SQLITE_OK ){ + int i; + cksum2 = cksum2 ^ fts3ChecksumEntry( + zToken, nToken, iLang, 0, iDocid, iCol, iPos + ); + for(i=1; inIndex; i++){ + if( p->aIndex[i].nPrefix<=nToken ){ + cksum2 = cksum2 ^ fts3ChecksumEntry( + zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos + ); + } } } } + if( pT ) pModule->xClose(pT); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; } - if( pT ) pModule->xClose(pT); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; } } @@ -5271,6 +5508,10 @@ int sqlite3Fts3UpdateMethod( int nChng = 0; /* Net change in number of documents */ int bInsertDone = 0; + /* At this point it must be known if the %_stat table exists or not. + ** So bHasStat may not be 2. */ + assert( p->bHasStat==0 || p->bHasStat==1 ); + assert( p->pSegments==0 ); assert( nArg==1 /* DELETE operations */ diff --git a/ext/fts3/tool/fts3view.c b/ext/fts3/tool/fts3view.c index 479ae98..3dc1ba8 100644 --- a/ext/fts3/tool/fts3view.c +++ b/ext/fts3/tool/fts3view.c @@ -376,7 +376,7 @@ static void showSegmentStats(sqlite3 *db, const char *zTab){ sqlite3_finalize(pStmt); nLeaf = nSeg - nIdx; printf("Leaf segments larger than %5d bytes.... %9d %5.2f%%\n", - pgsz-45, n, n*100.0/nLeaf); + pgsz-45, n, nLeaf>0 ? n*100.0/nLeaf : 0.0); pStmt = prepare(db, "SELECT max(level%%1024) FROM '%q_segdir'", zTab); mxLevel = 0; @@ -554,7 +554,7 @@ static void decodeSegment( sqlite3_int64 n; sqlite3_int64 iDocsz; int iHeight; - int i = 0; + sqlite3_int64 i = 0; int cnt = 0; char zTerm[1000]; @@ -576,12 +576,12 @@ static void decodeSegment( fprintf(stderr, "term to long\n"); exit(1); } - memcpy(zTerm+iPrefix, aData+i, nTerm); + memcpy(zTerm+iPrefix, aData+i, (size_t)nTerm); zTerm[iPrefix+nTerm] = 0; i += nTerm; if( iHeight==0 ){ i += getVarint(aData+i, &iDocsz); - printf("term: %-25s doclist %7lld bytes offset %d\n", zTerm, iDocsz, i); + printf("term: %-25s doclist %7lld bytes offset %lld\n", zTerm, iDocsz, i); i += iDocsz; }else{ printf("term: %-25s child %lld\n", zTerm, ++iChild); @@ -749,18 +749,19 @@ static void decodeDoclist( */ static void showDoclist(sqlite3 *db, const char *zTab){ const unsigned char *aData; - sqlite3_int64 offset, nData; + sqlite3_int64 offset; + int nData; sqlite3_stmt *pStmt; offset = atoi64(azExtra[1]); - nData = atoi64(azExtra[2]); + nData = atoi(azExtra[2]); pStmt = prepareToGetSegment(db, zTab, azExtra[0]); if( sqlite3_step(pStmt)!=SQLITE_ROW ){ sqlite3_finalize(pStmt); return; } aData = sqlite3_column_blob(pStmt, 0); - printf("Doclist at %s offset %lld of size %lld bytes:\n", + printf("Doclist at %s offset %lld of size %d bytes:\n", azExtra[0], offset, nData); if( findOption("raw", 0, 0)!=0 ){ printBlob(aData+offset, nData); diff --git a/ext/fts3/unicode/mkunicode.tcl b/ext/fts3/unicode/mkunicode.tcl index 2da17c5..c3083ee 100644 --- a/ext/fts3/unicode/mkunicode.tcl +++ b/ext/fts3/unicode/mkunicode.tcl @@ -160,7 +160,7 @@ proc print_rd {map} { } assert( key>=aDia[iRes] ); return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);} - puts "\};" + puts "\}" } proc print_isdiacritic {zFunc map} { @@ -298,7 +298,7 @@ proc an_print_range_array {lRange} { ** using this format. */ }] - puts -nonewline " const static unsigned int aEntry\[\] = \{" + puts -nonewline " static const unsigned int aEntry\[\] = \{" set i 0 foreach range $lRange { foreach {iFirst nRange} $range {} @@ -349,7 +349,7 @@ proc print_isalnum {zFunc lRange} { return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 ); }else if( c<(1<<22) ){ unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; - int iRes; + int iRes = 0; int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; int iLo = 0; while( iHi>=iLo ){ @@ -732,7 +732,7 @@ proc print_fileheader {} { */ }] puts "" - puts "#if defined(SQLITE_ENABLE_FTS4_UNICODE61)" + puts "#ifndef SQLITE_DISABLE_FTS3_UNICODE" puts "#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)" puts "" puts "#include " @@ -808,4 +808,4 @@ if {$::generate_test_code} { } puts "#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */" -puts "#endif /* !defined(SQLITE_ENABLE_FTS4_UNICODE61) */" +puts "#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */" diff --git a/ext/misc/compress.c b/ext/misc/compress.c new file mode 100644 index 0000000..a405911 --- /dev/null +++ b/ext/misc/compress.c @@ -0,0 +1,107 @@ +/* +** 2014-06-13 +** +** 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 SQLite extension implements SQL compression functions +** compress() and uncompress() using ZLIB. +*/ +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 +#include + +/* +** Implementation of the "compress(X)" SQL function. The input X is +** compressed using zLib and the output is returned. +** +** The output is a BLOB that begins with a variable-length integer that +** is the input size in bytes (the size of X before compression). The +** variable-length integer is implemented as 1 to 5 bytes. There are +** seven bits per integer stored in the lower seven bits of each byte. +** More significant bits occur first. The most significant bit (0x80) +** is a flag to indicate the end of the integer. +*/ +static void compressFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *pIn; + unsigned char *pOut; + unsigned int nIn; + unsigned long int nOut; + unsigned char x[8]; + int i, j; + + pIn = sqlite3_value_blob(argv[0]); + nIn = sqlite3_value_bytes(argv[0]); + nOut = 13 + nIn + (nIn+999)/1000; + pOut = sqlite3_malloc( nOut+5 ); + for(i=4; i>=0; i--){ + x[i] = (nIn >> (7*(4-i)))&0x7f; + } + for(i=0; i<4 && x[i]==0; i++){} + for(j=0; i<=4; i++, j++) pOut[j] = x[i]; + pOut[j-1] |= 0x80; + compress(&pOut[j], &nOut, pIn, nIn); + sqlite3_result_blob(context, pOut, nOut+j, sqlite3_free); +} + +/* +** Implementation of the "uncompress(X)" SQL function. The argument X +** is a blob which was obtained from compress(Y). The output will be +** the value Y. +*/ +static void uncompressFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *pIn; + unsigned char *pOut; + unsigned int nIn; + unsigned long int nOut; + int rc; + int i; + + pIn = sqlite3_value_blob(argv[0]); + nIn = sqlite3_value_bytes(argv[0]); + nOut = 0; + for(i=0; i + +/* +** Implementation of the "readfile(X)" SQL function. The entire content +** of the file named X is read and returned as a BLOB. NULL is returned +** if the file does not exist or is unreadable. +*/ +static void readfileFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zName; + FILE *in; + long nIn; + void *pBuf; + + zName = (const char*)sqlite3_value_text(argv[0]); + if( zName==0 ) return; + in = fopen(zName, "rb"); + if( in==0 ) return; + fseek(in, 0, SEEK_END); + nIn = ftell(in); + rewind(in); + pBuf = sqlite3_malloc( nIn ); + if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ + sqlite3_result_blob(context, pBuf, nIn, sqlite3_free); + }else{ + sqlite3_free(pBuf); + } + fclose(in); +} + +/* +** Implementation of the "writefile(X,Y)" SQL function. The argument Y +** is written into file X. The number of bytes written is returned. Or +** NULL is returned if something goes wrong, such as being unable to open +** file X for writing. +*/ +static void writefileFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + FILE *out; + const char *z; + sqlite3_int64 rc; + const char *zFile; + + zFile = (const char*)sqlite3_value_text(argv[0]); + if( zFile==0 ) return; + out = fopen(zFile, "wb"); + if( out==0 ) return; + z = (const char*)sqlite3_value_blob(argv[1]); + if( z==0 ){ + rc = 0; + }else{ + rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out); + } + fclose(out); + sqlite3_result_int64(context, rc); +} + + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_fileio_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0, + readfileFunc, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0, + writefileFunc, 0, 0); + } + return rc; +} diff --git a/ext/misc/spellfix.c b/ext/misc/spellfix.c index a62d24c..2e6743e 100644 --- a/ext/misc/spellfix.c +++ b/ext/misc/spellfix.c @@ -1893,7 +1893,7 @@ static int spellfix1Init( char **pzErr ){ spellfix1_vtab *pNew = 0; - const char *zModule = argv[0]; + /* const char *zModule = argv[0]; // not used */ const char *zDbName = argv[1]; const char *zTableName = argv[2]; int nDbName; @@ -1947,7 +1947,7 @@ static int spellfix1Init( spellfix1DbExec(&rc, db, "CREATE INDEX IF NOT EXISTS \"%w\".\"%w_vocab_index_langid_k2\" " "ON \"%w_vocab\"(langid,k2);", - zDbName, zModule, zTableName + zDbName, zTableName, zTableName ); } for(i=3; rc==SQLITE_OK && i #include +#include #ifndef SQLITE_AMALGAMATION #include "sqlite3rtree.h" typedef sqlite3_int64 i64; typedef unsigned char u8; +typedef unsigned short u16; typedef unsigned int u32; #endif @@ -127,6 +87,7 @@ typedef struct RtreeConstraint RtreeConstraint; typedef struct RtreeMatchArg RtreeMatchArg; typedef struct RtreeGeomCallback RtreeGeomCallback; typedef union RtreeCoord RtreeCoord; +typedef struct RtreeSearchPoint RtreeSearchPoint; /* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */ #define RTREE_MAX_DIMENSIONS 5 @@ -135,7 +96,7 @@ typedef union RtreeCoord RtreeCoord; ** ever contain very many entries, so a fixed number of buckets is ** used. */ -#define HASHSIZE 128 +#define HASHSIZE 97 /* The xBestIndex method of this virtual table requires an estimate of ** the number of rows in the virtual table to calculate the costs of @@ -151,15 +112,15 @@ typedef union RtreeCoord RtreeCoord; ** An rtree virtual-table object. */ struct Rtree { - sqlite3_vtab base; + sqlite3_vtab base; /* Base class. Must be first */ sqlite3 *db; /* Host database connection */ int iNodeSize; /* Size in bytes of each node in the node table */ - int nDim; /* Number of dimensions */ - int nBytesPerCell; /* Bytes consumed per cell */ + u8 nDim; /* Number of dimensions */ + u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ + u8 nBytesPerCell; /* Bytes consumed per cell */ int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ - RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ int nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ @@ -186,10 +147,10 @@ struct Rtree { sqlite3_stmt *pWriteParent; sqlite3_stmt *pDeleteParent; - int eCoordType; + RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ }; -/* Possible values for eCoordType: */ +/* Possible values for Rtree.eCoordType: */ #define RTREE_COORD_REAL32 0 #define RTREE_COORD_INT32 1 @@ -201,11 +162,30 @@ struct Rtree { #ifdef SQLITE_RTREE_INT_ONLY typedef sqlite3_int64 RtreeDValue; /* High accuracy coordinate */ typedef int RtreeValue; /* Low accuracy coordinate */ +# define RTREE_ZERO 0 #else typedef double RtreeDValue; /* High accuracy coordinate */ typedef float RtreeValue; /* Low accuracy coordinate */ +# define RTREE_ZERO 0.0 #endif +/* +** When doing a search of an r-tree, instances of the following structure +** record intermediate results from the tree walk. +** +** The id is always a node-id. For iLevel>=1 the id is the node-id of +** the node that the RtreeSearchPoint represents. When iLevel==0, however, +** the id is of the parent node and the cell that RtreeSearchPoint +** represents is the iCell-th entry in the parent node. +*/ +struct RtreeSearchPoint { + RtreeDValue rScore; /* The score for this node. Smallest goes first. */ + sqlite3_int64 id; /* Node ID */ + u8 iLevel; /* 0=entries. 1=leaf node. 2+ for higher */ + u8 eWithin; /* PARTLY_WITHIN or FULLY_WITHIN */ + u8 iCell; /* Cell index within the node */ +}; + /* ** The minimum number of cells allowed for a node is a third of the ** maximum. In Gutman's notation: @@ -228,21 +208,44 @@ struct Rtree { */ #define RTREE_MAX_DEPTH 40 + +/* +** Number of entries in the cursor RtreeNode cache. The first entry is +** used to cache the RtreeNode for RtreeCursor.sPoint. The remaining +** entries cache the RtreeNode for the first elements of the priority queue. +*/ +#define RTREE_CACHE_SZ 5 + /* ** An rtree cursor object. */ struct RtreeCursor { - sqlite3_vtab_cursor base; - RtreeNode *pNode; /* Node cursor is currently pointing at */ - int iCell; /* Index of current cell in pNode */ + sqlite3_vtab_cursor base; /* Base class. Must be first */ + u8 atEOF; /* True if at end of search */ + u8 bPoint; /* True if sPoint is valid */ int iStrategy; /* Copy of idxNum search parameter */ int nConstraint; /* Number of entries in aConstraint */ RtreeConstraint *aConstraint; /* Search constraints. */ + int nPointAlloc; /* Number of slots allocated for aPoint[] */ + int nPoint; /* Number of slots used in aPoint[] */ + int mxLevel; /* iLevel value for root of the tree */ + RtreeSearchPoint *aPoint; /* Priority queue for search points */ + RtreeSearchPoint sPoint; /* Cached next search point */ + RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */ + u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */ }; +/* Return the Rtree of a RtreeCursor */ +#define RTREE_OF_CURSOR(X) ((Rtree*)((X)->base.pVtab)) + +/* +** A coordinate can be either a floating point number or a integer. All +** coordinates within a single R-Tree are always of the same time. +*/ union RtreeCoord { - RtreeValue f; - int i; + RtreeValue f; /* Floating point value */ + int i; /* Integer value */ + u32 u; /* Unsigned for byte-order conversions */ }; /* @@ -267,38 +270,67 @@ union RtreeCoord { struct RtreeConstraint { int iCoord; /* Index of constrained coordinate */ int op; /* Constraining operation */ - RtreeDValue rValue; /* Constraint value. */ - int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); - sqlite3_rtree_geometry *pGeom; /* Constraint callback argument for a MATCH */ + union { + RtreeDValue rValue; /* Constraint value. */ + int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*); + int (*xQueryFunc)(sqlite3_rtree_query_info*); + } u; + sqlite3_rtree_query_info *pInfo; /* xGeom and xQueryFunc argument */ }; /* Possible values for RtreeConstraint.op */ -#define RTREE_EQ 0x41 -#define RTREE_LE 0x42 -#define RTREE_LT 0x43 -#define RTREE_GE 0x44 -#define RTREE_GT 0x45 -#define RTREE_MATCH 0x46 +#define RTREE_EQ 0x41 /* A */ +#define RTREE_LE 0x42 /* B */ +#define RTREE_LT 0x43 /* C */ +#define RTREE_GE 0x44 /* D */ +#define RTREE_GT 0x45 /* E */ +#define RTREE_MATCH 0x46 /* F: Old-style sqlite3_rtree_geometry_callback() */ +#define RTREE_QUERY 0x47 /* G: New-style sqlite3_rtree_query_callback() */ + /* ** An rtree structure node. */ struct RtreeNode { - RtreeNode *pParent; /* Parent node */ - i64 iNode; - int nRef; - int isDirty; - u8 *zData; - RtreeNode *pNext; /* Next node in this hash chain */ + RtreeNode *pParent; /* Parent node */ + i64 iNode; /* The node number */ + int nRef; /* Number of references to this node */ + int isDirty; /* True if the node needs to be written to disk */ + u8 *zData; /* Content of the node, as should be on disk */ + RtreeNode *pNext; /* Next node in this hash collision chain */ }; + +/* Return the number of cells in a node */ #define NCELL(pNode) readInt16(&(pNode)->zData[2]) /* -** Structure to store a deserialized rtree record. +** A single cell from a node, deserialized */ struct RtreeCell { - i64 iRowid; - RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2]; + i64 iRowid; /* Node or entry ID */ + RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2]; /* Bounding box coordinates */ +}; + + +/* +** This object becomes the sqlite3_user_data() for the SQL functions +** that are created by sqlite3_rtree_geometry_callback() and +** sqlite3_rtree_query_callback() and which appear on the right of MATCH +** operators in order to constrain a search. +** +** xGeom and xQueryFunc are the callback functions. Exactly one of +** xGeom and xQueryFunc fields is non-NULL, depending on whether the +** SQL function was created using sqlite3_rtree_geometry_callback() or +** sqlite3_rtree_query_callback(). +** +** This object is deleted automatically by the destructor mechanism in +** sqlite3_create_function_v2(). +*/ +struct RtreeGeomCallback { + int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); + int (*xQueryFunc)(sqlite3_rtree_query_info*); + void (*xDestructor)(void*); + void *pContext; }; @@ -310,29 +342,16 @@ struct RtreeCell { #define RTREE_GEOMETRY_MAGIC 0x891245AB /* -** An instance of this structure must be supplied as a blob argument to -** the right-hand-side of an SQL MATCH operator used to constrain an -** r-tree query. +** An instance of this structure (in the form of a BLOB) is returned by +** the SQL functions that sqlite3_rtree_geometry_callback() and +** sqlite3_rtree_query_callback() create, and is read as the right-hand +** operand to the MATCH operator of an R-Tree. */ struct RtreeMatchArg { - u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ - int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue*, int *); - void *pContext; - int nParam; - RtreeDValue aParam[1]; -}; - -/* -** When a geometry callback is created (see sqlite3_rtree_geometry_callback), -** a single instance of the following structure is allocated. It is used -** as the context for the user-function created by by s_r_g_c(). The object -** is eventually deleted by the destructor mechanism provided by -** sqlite3_create_function_v2() (which is called by s_r_g_c() to create -** the geometry callback function). -*/ -struct RtreeGeomCallback { - int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); - void *pContext; + u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ + RtreeGeomCallback cb; /* Info about the callback functions */ + int nParam; /* Number of parameters to the SQL function */ + RtreeDValue aParam[1]; /* Values for parameters to the SQL function */ }; #ifndef MAX @@ -426,10 +445,7 @@ static void nodeZero(Rtree *pRtree, RtreeNode *p){ ** in the Rtree.aHash table. */ static int nodeHash(i64 iNode){ - return ( - (iNode>>56) ^ (iNode>>48) ^ (iNode>>40) ^ (iNode>>32) ^ - (iNode>>24) ^ (iNode>>16) ^ (iNode>> 8) ^ (iNode>> 0) - ) % HASHSIZE; + return iNode % HASHSIZE; } /* @@ -489,8 +505,7 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ /* ** Obtain a reference to an r-tree node. */ -static int -nodeAcquire( +static int nodeAcquire( Rtree *pRtree, /* R-tree structure */ i64 iNode, /* Node number to load */ RtreeNode *pParent, /* Either the parent node or NULL */ @@ -579,10 +594,10 @@ nodeAcquire( ** Overwrite cell iCell of node pNode with the contents of pCell. */ static void nodeOverwriteCell( - Rtree *pRtree, - RtreeNode *pNode, - RtreeCell *pCell, - int iCell + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node into which the cell is to be written */ + RtreeCell *pCell, /* The cell to write */ + int iCell /* Index into pNode into which pCell is written */ ){ int ii; u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; @@ -594,7 +609,7 @@ static void nodeOverwriteCell( } /* -** Remove cell the cell with index iCell from node pNode. +** Remove the cell with index iCell from node pNode. */ static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){ u8 *pDst = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; @@ -611,11 +626,10 @@ static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){ ** ** If there is not enough free space in pNode, return SQLITE_FULL. */ -static int -nodeInsertCell( - Rtree *pRtree, - RtreeNode *pNode, - RtreeCell *pCell +static int nodeInsertCell( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* Write new cell into this node */ + RtreeCell *pCell /* The cell to be inserted */ ){ int nCell; /* Current number of cells in pNode */ int nMaxCell; /* Maximum number of cells for pNode */ @@ -636,8 +650,7 @@ nodeInsertCell( /* ** If the node is dirty, write it out to the database. */ -static int -nodeWrite(Rtree *pRtree, RtreeNode *pNode){ +static int nodeWrite(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; if( pNode->isDirty ){ sqlite3_stmt *p = pRtree->pWriteNode; @@ -662,8 +675,7 @@ nodeWrite(Rtree *pRtree, RtreeNode *pNode){ ** Release a reference to a node. If the node is dirty and the reference ** count drops to zero, the node data is written to the database. */ -static int -nodeRelease(Rtree *pRtree, RtreeNode *pNode){ +static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; if( pNode ){ assert( pNode->nRef>0 ); @@ -691,9 +703,9 @@ nodeRelease(Rtree *pRtree, RtreeNode *pNode){ ** an internal node, then the 64-bit integer is a child page number. */ static i64 nodeGetRowid( - Rtree *pRtree, - RtreeNode *pNode, - int iCell + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node from which to extract the ID */ + int iCell /* The cell index from which to extract the ID */ ){ assert( iCellzData[4 + pRtree->nBytesPerCell*iCell]); @@ -703,11 +715,11 @@ static i64 nodeGetRowid( ** Return coordinate iCoord from cell iCell in node pNode. */ static void nodeGetCoord( - Rtree *pRtree, - RtreeNode *pNode, - int iCell, - int iCoord, - RtreeCoord *pCoord /* Space to write result to */ + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node from which to extract a coordinate */ + int iCell, /* The index of the cell within the node */ + int iCoord, /* Which coordinate to extract */ + RtreeCoord *pCoord /* OUT: Space to write result to */ ){ readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord); } @@ -717,15 +729,20 @@ static void nodeGetCoord( ** to by pCell with the results. */ static void nodeGetCell( - Rtree *pRtree, - RtreeNode *pNode, - int iCell, - RtreeCell *pCell + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node containing the cell to be read */ + int iCell, /* Index of the cell within the node */ + RtreeCell *pCell /* OUT: Write the cell contents here */ ){ - int ii; + u8 *pData; + u8 *pEnd; + RtreeCoord *pCoord; pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell); - for(ii=0; iinDim*2; ii++){ - nodeGetCoord(pRtree, pNode, iCell, ii, &pCell->aCoord[ii]); + pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell); + pEnd = pData + pRtree->nDim*8; + pCoord = pCell->aCoord; + for(; pDataaConstraint ){ int i; /* Used to iterate through constraint array */ for(i=0; inConstraint; i++){ - sqlite3_rtree_geometry *pGeom = pCsr->aConstraint[i].pGeom; - if( pGeom ){ - if( pGeom->xDelUser ) pGeom->xDelUser(pGeom->pUser); - sqlite3_free(pGeom); + sqlite3_rtree_query_info *pInfo = pCsr->aConstraint[i].pInfo; + if( pInfo ){ + if( pInfo->xDelUser ) pInfo->xDelUser(pInfo->pUser); + sqlite3_free(pInfo); } } sqlite3_free(pCsr->aConstraint); @@ -867,12 +884,13 @@ static void freeCursorConstraints(RtreeCursor *pCsr){ */ static int rtreeClose(sqlite3_vtab_cursor *cur){ Rtree *pRtree = (Rtree *)(cur->pVtab); - int rc; + int ii; RtreeCursor *pCsr = (RtreeCursor *)cur; freeCursorConstraints(pCsr); - rc = nodeRelease(pRtree, pCsr->pNode); + sqlite3_free(pCsr->aPoint); + for(ii=0; iiaNode[ii]); sqlite3_free(pCsr); - return rc; + return SQLITE_OK; } /* @@ -883,196 +901,166 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){ */ static int rtreeEof(sqlite3_vtab_cursor *cur){ RtreeCursor *pCsr = (RtreeCursor *)cur; - return (pCsr->pNode==0); + return pCsr->atEOF; } /* -** The r-tree constraint passed as the second argument to this function is -** guaranteed to be a MATCH constraint. -*/ -static int testRtreeGeom( - Rtree *pRtree, /* R-Tree object */ - RtreeConstraint *pConstraint, /* MATCH constraint to test */ - RtreeCell *pCell, /* Cell to test */ - int *pbRes /* OUT: Test result */ -){ - int i; - RtreeDValue aCoord[RTREE_MAX_DIMENSIONS*2]; - int nCoord = pRtree->nDim*2; - - assert( pConstraint->op==RTREE_MATCH ); - assert( pConstraint->pGeom ); - - for(i=0; iaCoord[i]); - } - return pConstraint->xGeom(pConstraint->pGeom, nCoord, aCoord, pbRes); -} - -/* -** Cursor pCursor currently points to a cell in a non-leaf page. -** Set *pbEof to true if the sub-tree headed by the cell is filtered -** (excluded) by the constraints in the pCursor->aConstraint[] -** array, or false otherwise. +** Convert raw bits from the on-disk RTree record into a coordinate value. +** The on-disk format is big-endian and needs to be converted for little- +** endian platforms. The on-disk record stores integer coordinates if +** eInt is true and it stores 32-bit floating point records if eInt is +** false. a[] is the four bytes of the on-disk record to be decoded. +** Store the results in "r". ** -** Return SQLITE_OK if successful or an SQLite error code if an error -** occurs within a geometry callback. +** There are three versions of this macro, one each for little-endian and +** big-endian processors and a third generic implementation. The endian- +** specific implementations are much faster and are preferred if the +** processor endianness is known at compile-time. The SQLITE_BYTEORDER +** macro is part of sqliteInt.h and hence the endian-specific +** implementation will only be used if this module is compiled as part +** of the amalgamation. */ -static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){ - RtreeCell cell; - int ii; - int bRes = 0; - int rc = SQLITE_OK; - - nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); - for(ii=0; bRes==0 && iinConstraint; ii++){ - RtreeConstraint *p = &pCursor->aConstraint[ii]; - RtreeDValue cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]); - RtreeDValue cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]); - - assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE - || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH - ); - - switch( p->op ){ - case RTREE_LE: case RTREE_LT: - bRes = p->rValuerValue>cell_max; - break; - - case RTREE_EQ: - bRes = (p->rValue>cell_max || p->rValueop==RTREE_MATCH ); - rc = testRtreeGeom(pRtree, p, &cell, &bRes); - bRes = !bRes; - break; - } - } - } - - *pbEof = bRes; - return rc; +#if defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==1234 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + memcpy(&c.u,a,4); \ + c.u = ((c.u>>24)&0xff)|((c.u>>8)&0xff00)| \ + ((c.u&0xff)<<24)|((c.u&0xff00)<<8); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ } - -/* -** Test if the cell that cursor pCursor currently points to -** would be filtered (excluded) by the constraints in the -** pCursor->aConstraint[] array. If so, set *pbEof to true before -** returning. If the cell is not filtered (excluded) by the constraints, -** set pbEof to zero. -** -** Return SQLITE_OK if successful or an SQLite error code if an error -** occurs within a geometry callback. -** -** This function assumes that the cell is part of a leaf node. -*/ -static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){ - RtreeCell cell; - int ii; - *pbEof = 0; - - nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); - for(ii=0; iinConstraint; ii++){ - RtreeConstraint *p = &pCursor->aConstraint[ii]; - RtreeDValue coord = DCOORD(cell.aCoord[p->iCoord]); - int res; - assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE - || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH - ); - switch( p->op ){ - case RTREE_LE: res = (coord<=p->rValue); break; - case RTREE_LT: res = (coordrValue); break; - case RTREE_GE: res = (coord>=p->rValue); break; - case RTREE_GT: res = (coord>p->rValue); break; - case RTREE_EQ: res = (coord==p->rValue); break; - default: { - int rc; - assert( p->op==RTREE_MATCH ); - rc = testRtreeGeom(pRtree, p, &cell, &res); - if( rc!=SQLITE_OK ){ - return rc; - } - break; - } - } - - if( !res ){ - *pbEof = 1; - return SQLITE_OK; - } - } - - return SQLITE_OK; +#elif defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==4321 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + memcpy(&c.u,a,4); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ } +#else +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + c.u = ((u32)a[0]<<24) + ((u32)a[1]<<16) \ + +((u32)a[2]<<8) + a[3]; \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#endif /* -** Cursor pCursor currently points at a node that heads a sub-tree of -** height iHeight (if iHeight==0, then the node is a leaf). Descend -** to point to the left-most cell of the sub-tree that matches the -** configured constraints. +** Check the RTree node or entry given by pCellData and p against the MATCH +** constraint pConstraint. */ -static int descendToCell( - Rtree *pRtree, - RtreeCursor *pCursor, - int iHeight, - int *pEof /* OUT: Set to true if cannot descend */ +static int rtreeCallbackConstraint( + RtreeConstraint *pConstraint, /* The constraint to test */ + int eInt, /* True if RTree holding integer coordinates */ + u8 *pCellData, /* Raw cell content */ + RtreeSearchPoint *pSearch, /* Container of this cell */ + sqlite3_rtree_dbl *prScore, /* OUT: score for the cell */ + int *peWithin /* OUT: visibility of the cell */ ){ - int isEof; - int rc; - int ii; - RtreeNode *pChild; - sqlite3_int64 iRowid; + int i; /* Loop counter */ + sqlite3_rtree_query_info *pInfo = pConstraint->pInfo; /* Callback info */ + int nCoord = pInfo->nCoord; /* No. of coordinates */ + int rc; /* Callback return code */ + sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2]; /* Decoded coordinates */ - RtreeNode *pSavedNode = pCursor->pNode; - int iSavedCell = pCursor->iCell; + assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY ); + assert( nCoord==2 || nCoord==4 || nCoord==6 || nCoord==8 || nCoord==10 ); - assert( iHeight>=0 ); - - if( iHeight==0 ){ - rc = testRtreeEntry(pRtree, pCursor, &isEof); + if( pConstraint->op==RTREE_QUERY && pSearch->iLevel==1 ){ + pInfo->iRowid = readInt64(pCellData); + } + pCellData += 8; + for(i=0; iop==RTREE_MATCH ){ + rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo, + nCoord, aCoord, &i); + if( i==0 ) *peWithin = NOT_WITHIN; + *prScore = RTREE_ZERO; }else{ - rc = testRtreeCell(pRtree, pCursor, &isEof); - } - if( rc!=SQLITE_OK || isEof || iHeight==0 ){ - goto descend_to_cell_out; - } - - iRowid = nodeGetRowid(pRtree, pCursor->pNode, pCursor->iCell); - rc = nodeAcquire(pRtree, iRowid, pCursor->pNode, &pChild); - if( rc!=SQLITE_OK ){ - goto descend_to_cell_out; - } - - nodeRelease(pRtree, pCursor->pNode); - pCursor->pNode = pChild; - isEof = 1; - for(ii=0; isEof && iiiCell = ii; - rc = descendToCell(pRtree, pCursor, iHeight-1, &isEof); - if( rc!=SQLITE_OK ){ - goto descend_to_cell_out; + pInfo->aCoord = aCoord; + pInfo->iLevel = pSearch->iLevel - 1; + pInfo->rScore = pInfo->rParentScore = pSearch->rScore; + pInfo->eWithin = pInfo->eParentWithin = pSearch->eWithin; + rc = pConstraint->u.xQueryFunc(pInfo); + if( pInfo->eWithin<*peWithin ) *peWithin = pInfo->eWithin; + if( pInfo->rScore<*prScore || *prScorerScore; } } - - if( isEof ){ - assert( pCursor->pNode==pChild ); - nodeReference(pSavedNode); - nodeRelease(pRtree, pChild); - pCursor->pNode = pSavedNode; - pCursor->iCell = iSavedCell; - } - -descend_to_cell_out: - *pEof = isEof; return rc; } +/* +** Check the internal RTree node given by pCellData against constraint p. +** If this constraint cannot be satisfied by any child within the node, +** set *peWithin to NOT_WITHIN. +*/ +static void rtreeNonleafConstraint( + RtreeConstraint *p, /* The constraint to test */ + int eInt, /* True if RTree holds integer coordinates */ + u8 *pCellData, /* Raw cell content as appears on disk */ + int *peWithin /* Adjust downward, as appropriate */ +){ + sqlite3_rtree_dbl val; /* Coordinate value convert to a double */ + + /* p->iCoord might point to either a lower or upper bound coordinate + ** in a coordinate pair. But make pCellData point to the lower bound. + */ + pCellData += 8 + 4*(p->iCoord&0xfe); + + assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE + || p->op==RTREE_GT || p->op==RTREE_EQ ); + switch( p->op ){ + case RTREE_LE: + case RTREE_LT: + case RTREE_EQ: + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the lower bound of the coordinate pair */ + if( p->u.rValue>=val ) return; + if( p->op!=RTREE_EQ ) break; /* RTREE_LE and RTREE_LT end here */ + /* Fall through for the RTREE_EQ case */ + + default: /* RTREE_GT or RTREE_GE, or fallthrough of RTREE_EQ */ + pCellData += 4; + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the upper bound of the coordinate pair */ + if( p->u.rValue<=val ) return; + } + *peWithin = NOT_WITHIN; +} + +/* +** Check the leaf RTree cell given by pCellData against constraint p. +** If this constraint is not satisfied, set *peWithin to NOT_WITHIN. +** If the constraint is satisfied, leave *peWithin unchanged. +** +** The constraint is of the form: xN op $val +** +** The op is given by p->op. The xN is p->iCoord-th coordinate in +** pCellData. $val is given by p->u.rValue. +*/ +static void rtreeLeafConstraint( + RtreeConstraint *p, /* The constraint to test */ + int eInt, /* True if RTree holds integer coordinates */ + u8 *pCellData, /* Raw cell content as appears on disk */ + int *peWithin /* Adjust downward, as appropriate */ +){ + RtreeDValue xN; /* Coordinate value converted to a double */ + + assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE + || p->op==RTREE_GT || p->op==RTREE_EQ ); + pCellData += 8 + p->iCoord*4; + RTREE_DECODE_COORD(eInt, pCellData, xN); + switch( p->op ){ + case RTREE_LE: if( xN <= p->u.rValue ) return; break; + case RTREE_LT: if( xN < p->u.rValue ) return; break; + case RTREE_GE: if( xN >= p->u.rValue ) return; break; + case RTREE_GT: if( xN > p->u.rValue ) return; break; + default: if( xN == p->u.rValue ) return; break; + } + *peWithin = NOT_WITHIN; +} + /* ** One of the cells in node pNode is guaranteed to have a 64-bit ** integer value equal to iRowid. Return the index of this cell. @@ -1085,6 +1073,7 @@ static int nodeRowidIndex( ){ int ii; int nCell = NCELL(pNode); + assert( nCell<200 ); for(ii=0; iirScorerScore ) return -1; + if( pA->rScore>pB->rScore ) return +1; + if( pA->iLeveliLevel ) return -1; + if( pA->iLevel>pB->iLevel ) return +1; + return 0; +} + +/* +** Interchange to search points in a cursor. +*/ +static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){ + RtreeSearchPoint t = p->aPoint[i]; + assert( iaPoint[i] = p->aPoint[j]; + p->aPoint[j] = t; + i++; j++; + if( i=RTREE_CACHE_SZ ){ + nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); + p->aNode[i] = 0; + }else{ + RtreeNode *pTemp = p->aNode[i]; + p->aNode[i] = p->aNode[j]; + p->aNode[j] = pTemp; + } + } +} + +/* +** Return the search point with the lowest current score. +*/ +static RtreeSearchPoint *rtreeSearchPointFirst(RtreeCursor *pCur){ + return pCur->bPoint ? &pCur->sPoint : pCur->nPoint ? pCur->aPoint : 0; +} + +/* +** Get the RtreeNode for the search point with the lowest score. +*/ +static RtreeNode *rtreeNodeOfFirstSearchPoint(RtreeCursor *pCur, int *pRC){ + sqlite3_int64 id; + int ii = 1 - pCur->bPoint; + assert( ii==0 || ii==1 ); + assert( pCur->bPoint || pCur->nPoint ); + if( pCur->aNode[ii]==0 ){ + assert( pRC!=0 ); + id = ii ? pCur->aPoint[0].id : pCur->sPoint.id; + *pRC = nodeAcquire(RTREE_OF_CURSOR(pCur), id, 0, &pCur->aNode[ii]); + } + return pCur->aNode[ii]; +} + +/* +** Push a new element onto the priority queue +*/ +static RtreeSearchPoint *rtreeEnqueue( + RtreeCursor *pCur, /* The cursor */ + RtreeDValue rScore, /* Score for the new search point */ + u8 iLevel /* Level for the new search point */ +){ + int i, j; + RtreeSearchPoint *pNew; + if( pCur->nPoint>=pCur->nPointAlloc ){ + int nNew = pCur->nPointAlloc*2 + 8; + pNew = sqlite3_realloc(pCur->aPoint, nNew*sizeof(pCur->aPoint[0])); + if( pNew==0 ) return 0; + pCur->aPoint = pNew; + pCur->nPointAlloc = nNew; + } + i = pCur->nPoint++; + pNew = pCur->aPoint + i; + pNew->rScore = rScore; + pNew->iLevel = iLevel; + assert( iLevel>=0 && iLevel<=RTREE_MAX_DEPTH ); + while( i>0 ){ + RtreeSearchPoint *pParent; + j = (i-1)/2; + pParent = pCur->aPoint + j; + if( rtreeSearchPointCompare(pNew, pParent)>=0 ) break; + rtreeSearchPointSwap(pCur, j, i); + i = j; + pNew = pParent; + } + return pNew; +} + +/* +** Allocate a new RtreeSearchPoint and return a pointer to it. Return +** NULL if malloc fails. +*/ +static RtreeSearchPoint *rtreeSearchPointNew( + RtreeCursor *pCur, /* The cursor */ + RtreeDValue rScore, /* Score for the new search point */ + u8 iLevel /* Level for the new search point */ +){ + RtreeSearchPoint *pNew, *pFirst; + pFirst = rtreeSearchPointFirst(pCur); + pCur->anQueue[iLevel]++; + if( pFirst==0 + || pFirst->rScore>rScore + || (pFirst->rScore==rScore && pFirst->iLevel>iLevel) + ){ + if( pCur->bPoint ){ + int ii; + pNew = rtreeEnqueue(pCur, rScore, iLevel); + if( pNew==0 ) return 0; + ii = (int)(pNew - pCur->aPoint) + 1; + if( iiaNode[ii]==0 ); + pCur->aNode[ii] = pCur->aNode[0]; + }else{ + nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]); + } + pCur->aNode[0] = 0; + *pNew = pCur->sPoint; + } + pCur->sPoint.rScore = rScore; + pCur->sPoint.iLevel = iLevel; + pCur->bPoint = 1; + return &pCur->sPoint; + }else{ + return rtreeEnqueue(pCur, rScore, iLevel); + } +} + +#if 0 +/* Tracing routines for the RtreeSearchPoint queue */ +static void tracePoint(RtreeSearchPoint *p, int idx, RtreeCursor *pCur){ + if( idx<0 ){ printf(" s"); }else{ printf("%2d", idx); } + printf(" %d.%05lld.%02d %g %d", + p->iLevel, p->id, p->iCell, p->rScore, p->eWithin + ); + idx++; + if( idxaNode[idx]); + }else{ + printf("\n"); + } +} +static void traceQueue(RtreeCursor *pCur, const char *zPrefix){ + int ii; + printf("=== %9s ", zPrefix); + if( pCur->bPoint ){ + tracePoint(&pCur->sPoint, -1, pCur); + } + for(ii=0; iinPoint; ii++){ + if( ii>0 || pCur->bPoint ) printf(" "); + tracePoint(&pCur->aPoint[ii], ii, pCur); + } +} +# define RTREE_QUEUE_TRACE(A,B) traceQueue(A,B) +#else +# define RTREE_QUEUE_TRACE(A,B) /* no-op */ +#endif + +/* Remove the search point with the lowest current score. +*/ +static void rtreeSearchPointPop(RtreeCursor *p){ + int i, j, k, n; + i = 1 - p->bPoint; + assert( i==0 || i==1 ); + if( p->aNode[i] ){ + nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); + p->aNode[i] = 0; + } + if( p->bPoint ){ + p->anQueue[p->sPoint.iLevel]--; + p->bPoint = 0; + }else if( p->nPoint ){ + p->anQueue[p->aPoint[0].iLevel]--; + n = --p->nPoint; + p->aPoint[0] = p->aPoint[n]; + if( naNode[1] = p->aNode[n+1]; + p->aNode[n+1] = 0; + } + i = 0; + while( (j = i*2+1)aPoint[k], &p->aPoint[j])<0 ){ + if( rtreeSearchPointCompare(&p->aPoint[k], &p->aPoint[i])<0 ){ + rtreeSearchPointSwap(p, i, k); + i = k; + }else{ + break; + } + }else{ + if( rtreeSearchPointCompare(&p->aPoint[j], &p->aPoint[i])<0 ){ + rtreeSearchPointSwap(p, i, j); + i = j; + }else{ + break; + } + } + } + } +} + + +/* +** Continue the search on cursor pCur until the front of the queue +** contains an entry suitable for returning as a result-set row, +** or until the RtreeSearchPoint queue is empty, indicating that the +** query has completed. +*/ +static int rtreeStepToLeaf(RtreeCursor *pCur){ + RtreeSearchPoint *p; + Rtree *pRtree = RTREE_OF_CURSOR(pCur); + RtreeNode *pNode; + int eWithin; + int rc = SQLITE_OK; + int nCell; + int nConstraint = pCur->nConstraint; + int ii; + int eInt; + RtreeSearchPoint x; + + eInt = pRtree->eCoordType==RTREE_COORD_INT32; + while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){ + pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc); + if( rc ) return rc; + nCell = NCELL(pNode); + assert( nCell<200 ); + while( p->iCellzData + (4+pRtree->nBytesPerCell*p->iCell); + eWithin = FULLY_WITHIN; + for(ii=0; iiaConstraint + ii; + if( pConstraint->op>=RTREE_MATCH ){ + rc = rtreeCallbackConstraint(pConstraint, eInt, pCellData, p, + &rScore, &eWithin); + if( rc ) return rc; + }else if( p->iLevel==1 ){ + rtreeLeafConstraint(pConstraint, eInt, pCellData, &eWithin); + }else{ + rtreeNonleafConstraint(pConstraint, eInt, pCellData, &eWithin); + } + if( eWithin==NOT_WITHIN ) break; + } + p->iCell++; + if( eWithin==NOT_WITHIN ) continue; + x.iLevel = p->iLevel - 1; + if( x.iLevel ){ + x.id = readInt64(pCellData); + x.iCell = 0; + }else{ + x.id = p->id; + x.iCell = p->iCell - 1; + } + if( p->iCell>=nCell ){ + RTREE_QUEUE_TRACE(pCur, "POP-S:"); + rtreeSearchPointPop(pCur); + } + if( rScoreeWithin = eWithin; + p->id = x.id; + p->iCell = x.iCell; + RTREE_QUEUE_TRACE(pCur, "PUSH-S:"); + break; + } + if( p->iCell>=nCell ){ + RTREE_QUEUE_TRACE(pCur, "POP-Se:"); + rtreeSearchPointPop(pCur); + } + } + pCur->atEOF = p==0; + return SQLITE_OK; +} + /* ** Rtree virtual table module xNext method. */ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ - Rtree *pRtree = (Rtree *)(pVtabCursor->pVtab); RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; int rc = SQLITE_OK; - /* RtreeCursor.pNode must not be NULL. If is is NULL, then this cursor is - ** already at EOF. It is against the rules to call the xNext() method of - ** a cursor that has already reached EOF. - */ - assert( pCsr->pNode ); - - if( pCsr->iStrategy==1 ){ - /* This "scan" is a direct lookup by rowid. There is no next entry. */ - nodeRelease(pRtree, pCsr->pNode); - pCsr->pNode = 0; - }else{ - /* Move to the next entry that matches the configured constraints. */ - int iHeight = 0; - while( pCsr->pNode ){ - RtreeNode *pNode = pCsr->pNode; - int nCell = NCELL(pNode); - for(pCsr->iCell++; pCsr->iCelliCell++){ - int isEof; - rc = descendToCell(pRtree, pCsr, iHeight, &isEof); - if( rc!=SQLITE_OK || !isEof ){ - return rc; - } - } - pCsr->pNode = pNode->pParent; - rc = nodeParentIndex(pRtree, pNode, &pCsr->iCell); - if( rc!=SQLITE_OK ){ - return rc; - } - nodeReference(pCsr->pNode); - nodeRelease(pRtree, pNode); - iHeight++; - } - } - + /* Move to the next entry that matches the configured constraints. */ + RTREE_QUEUE_TRACE(pCsr, "POP-Nx:"); + rtreeSearchPointPop(pCsr); + rc = rtreeStepToLeaf(pCsr); return rc; } @@ -1156,13 +1399,14 @@ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ ** Rtree virtual table module xRowid method. */ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ - Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; - - assert(pCsr->pNode); - *pRowid = nodeGetRowid(pRtree, pCsr->pNode, pCsr->iCell); - - return SQLITE_OK; + RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); + int rc = SQLITE_OK; + RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); + if( rc==SQLITE_OK && p ){ + *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); + } + return rc; } /* @@ -1171,13 +1415,18 @@ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ Rtree *pRtree = (Rtree *)cur->pVtab; RtreeCursor *pCsr = (RtreeCursor *)cur; + RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); + RtreeCoord c; + int rc = SQLITE_OK; + RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); + if( rc ) return rc; + if( p==0 ) return SQLITE_OK; if( i==0 ){ - i64 iRowid = nodeGetRowid(pRtree, pCsr->pNode, pCsr->iCell); - sqlite3_result_int64(ctx, iRowid); + sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); }else{ - RtreeCoord c; - nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c); + if( rc ) return rc; + nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ sqlite3_result_double(ctx, c.f); @@ -1188,7 +1437,6 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ sqlite3_result_int(ctx, c.i); } } - return SQLITE_OK; } @@ -1199,12 +1447,18 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ ** *ppLeaf to 0 and return SQLITE_OK. If an error occurs, set *ppLeaf ** to zero and return an SQLite error code. */ -static int findLeafNode(Rtree *pRtree, i64 iRowid, RtreeNode **ppLeaf){ +static int findLeafNode( + Rtree *pRtree, /* RTree to search */ + i64 iRowid, /* The rowid searching for */ + RtreeNode **ppLeaf, /* Write the node here */ + sqlite3_int64 *piNode /* Write the node-id here */ +){ int rc; *ppLeaf = 0; sqlite3_bind_int64(pRtree->pReadRowid, 1, iRowid); if( sqlite3_step(pRtree->pReadRowid)==SQLITE_ROW ){ i64 iNode = sqlite3_column_int64(pRtree->pReadRowid, 0); + if( piNode ) *piNode = iNode; rc = nodeAcquire(pRtree, iNode, 0, ppLeaf); sqlite3_reset(pRtree->pReadRowid); }else{ @@ -1220,9 +1474,10 @@ static int findLeafNode(Rtree *pRtree, i64 iRowid, RtreeNode **ppLeaf){ ** operator. */ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ - RtreeMatchArg *p; - sqlite3_rtree_geometry *pGeom; - int nBlob; + RtreeMatchArg *pBlob; /* BLOB returned by geometry function */ + sqlite3_rtree_query_info *pInfo; /* Callback information */ + int nBlob; /* Size of the geometry function blob */ + int nExpected; /* Expected size of the BLOB */ /* Check that value is actually a blob. */ if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR; @@ -1235,27 +1490,29 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ return SQLITE_ERROR; } - pGeom = (sqlite3_rtree_geometry *)sqlite3_malloc( - sizeof(sqlite3_rtree_geometry) + nBlob - ); - if( !pGeom ) return SQLITE_NOMEM; - memset(pGeom, 0, sizeof(sqlite3_rtree_geometry)); - p = (RtreeMatchArg *)&pGeom[1]; + pInfo = (sqlite3_rtree_query_info*)sqlite3_malloc( sizeof(*pInfo)+nBlob ); + if( !pInfo ) return SQLITE_NOMEM; + memset(pInfo, 0, sizeof(*pInfo)); + pBlob = (RtreeMatchArg*)&pInfo[1]; - memcpy(p, sqlite3_value_blob(pValue), nBlob); - if( p->magic!=RTREE_GEOMETRY_MAGIC - || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(RtreeDValue)) - ){ - sqlite3_free(pGeom); + memcpy(pBlob, sqlite3_value_blob(pValue), nBlob); + nExpected = (int)(sizeof(RtreeMatchArg) + + (pBlob->nParam-1)*sizeof(RtreeDValue)); + if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){ + sqlite3_free(pInfo); return SQLITE_ERROR; } + pInfo->pContext = pBlob->cb.pContext; + pInfo->nParam = pBlob->nParam; + pInfo->aParam = pBlob->aParam; - pGeom->pContext = p->pContext; - pGeom->nParam = p->nParam; - pGeom->aParam = p->aParam; - - pCons->xGeom = p->xGeom; - pCons->pGeom = pGeom; + if( pBlob->cb.xGeom ){ + pCons->u.xGeom = pBlob->cb.xGeom; + }else{ + pCons->op = RTREE_QUERY; + pCons->u.xQueryFunc = pBlob->cb.xQueryFunc; + } + pCons->pInfo = pInfo; return SQLITE_OK; } @@ -1269,44 +1526,59 @@ static int rtreeFilter( ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; - RtreeNode *pRoot = 0; int ii; int rc = SQLITE_OK; + int iCell = 0; rtreeReference(pRtree); + /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ freeCursorConstraints(pCsr); - pCsr->iStrategy = idxNum; + sqlite3_free(pCsr->aPoint); + memset(pCsr, 0, sizeof(RtreeCursor)); + pCsr->base.pVtab = (sqlite3_vtab*)pRtree; + pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ + RtreeSearchPoint *p; /* Search point for the the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); - rc = findLeafNode(pRtree, iRowid, &pLeaf); - pCsr->pNode = pLeaf; - if( pLeaf ){ - assert( rc==SQLITE_OK ); - rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &pCsr->iCell); + i64 iNode = 0; + rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); + if( rc==SQLITE_OK && pLeaf!=0 ){ + p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); + assert( p!=0 ); /* Always returns pCsr->sPoint */ + pCsr->aNode[0] = pLeaf; + p->id = iNode; + p->eWithin = PARTLY_WITHIN; + rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); + p->iCell = iCell; + RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); + }else{ + pCsr->atEOF = 1; } }else{ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array ** with the configured constraints. */ - if( argc>0 ){ + rc = nodeAcquire(pRtree, 1, 0, &pRoot); + if( rc==SQLITE_OK && argc>0 ){ pCsr->aConstraint = sqlite3_malloc(sizeof(RtreeConstraint)*argc); pCsr->nConstraint = argc; if( !pCsr->aConstraint ){ rc = SQLITE_NOMEM; }else{ memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc); + memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); assert( (idxStr==0 && argc==0) || (idxStr && (int)strlen(idxStr)==argc*2) ); for(ii=0; iiaConstraint[ii]; p->op = idxStr[ii*2]; - p->iCoord = idxStr[ii*2+1]-'a'; - if( p->op==RTREE_MATCH ){ + p->iCoord = idxStr[ii*2+1]-'0'; + if( p->op>=RTREE_MATCH ){ /* A MATCH operator. The right-hand-side must be a blob that ** can be cast into an RtreeMatchArg object. One created using ** an sqlite3_rtree_geometry_callback() SQL user function. @@ -1315,41 +1587,35 @@ static int rtreeFilter( if( rc!=SQLITE_OK ){ break; } + p->pInfo->nCoord = pRtree->nDim*2; + p->pInfo->anQueue = pCsr->anQueue; + p->pInfo->mxLevel = pRtree->iDepth + 1; }else{ #ifdef SQLITE_RTREE_INT_ONLY - p->rValue = sqlite3_value_int64(argv[ii]); + p->u.rValue = sqlite3_value_int64(argv[ii]); #else - p->rValue = sqlite3_value_double(argv[ii]); + p->u.rValue = sqlite3_value_double(argv[ii]); #endif } } } } - if( rc==SQLITE_OK ){ - pCsr->pNode = 0; - rc = nodeAcquire(pRtree, 1, 0, &pRoot); - } - if( rc==SQLITE_OK ){ - int isEof = 1; - int nCell = NCELL(pRoot); - pCsr->pNode = pRoot; - for(pCsr->iCell=0; rc==SQLITE_OK && pCsr->iCelliCell++){ - assert( pCsr->pNode==pRoot ); - rc = descendToCell(pRtree, pCsr, pRtree->iDepth, &isEof); - if( !isEof ){ - break; - } - } - if( rc==SQLITE_OK && isEof ){ - assert( pCsr->pNode==pRoot ); - nodeRelease(pRtree, pRoot); - pCsr->pNode = 0; - } - assert( rc!=SQLITE_OK || !pCsr->pNode || pCsr->iCellpNode) ); + RtreeSearchPoint *pNew; + pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, pRtree->iDepth+1); + if( pNew==0 ) return SQLITE_NOMEM; + pNew->id = 1; + pNew->iCell = 0; + pNew->eWithin = PARTLY_WITHIN; + assert( pCsr->bPoint==1 ); + pCsr->aNode[0] = pRoot; + pRoot = 0; + RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); + rc = rtreeStepToLeaf(pCsr); } } + nodeRelease(pRtree, pRoot); rtreeRelease(pRtree); return rc; } @@ -1451,7 +1717,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ break; } zIdxStr[iIdx++] = op; - zIdxStr[iIdx++] = p->iColumn - 1 + 'a'; + zIdxStr[iIdx++] = p->iColumn - 1 + '0'; pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); pIdxInfo->aConstraintUsage[ii].omit = 1; } @@ -1544,62 +1810,32 @@ static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){ return (cellArea(pRtree, &cell)-area); } -#if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLIT static RtreeDValue cellOverlap( Rtree *pRtree, RtreeCell *p, RtreeCell *aCell, - int nCell, - int iExclude + int nCell ){ int ii; - RtreeDValue overlap = 0.0; + RtreeDValue overlap = RTREE_ZERO; for(ii=0; iinDim*2); jj+=2){ - RtreeDValue x1, x2; - - x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); - x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); - - if( x2nDim*2); jj+=2){ + RtreeDValue x1, x2; + x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); + x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); + if( x2iDepth-1) ){ - int jj; - aCell = sqlite3_malloc(sizeof(RtreeCell)*nCell); - if( !aCell ){ - rc = SQLITE_NOMEM; - nodeRelease(pRtree, pNode); - pNode = 0; - continue; - } - for(jj=0; jjiDepth-1) ){ - overlap = cellOverlapEnlargement(pRtree,&cell,pCell,aCell,nCell,iCell); - }else{ - overlap = 0.0; - } - if( (iCell==0) - || (overlapnDim; i++){ - RtreeDValue x1 = DCOORD(aCell[0].aCoord[i*2]); - RtreeDValue x2 = DCOORD(aCell[0].aCoord[i*2+1]); - RtreeDValue x3 = x1; - RtreeDValue x4 = x2; - int jj; - - int iCellLeft = 0; - int iCellRight = 0; - - for(jj=1; jjx4 ) x4 = right; - if( left>x3 ){ - x3 = left; - iCellRight = jj; - } - if( rightmaxNormalInnerWidth ){ - iLeftSeed = iCellLeft; - iRightSeed = iCellRight; - } - } - } - - *piLeftSeed = iLeftSeed; - *piRightSeed = iRightSeed; -} -#endif /* VARIANT_GUTTMAN_LINEAR_SPLIT */ - -#if VARIANT_GUTTMAN_QUADRATIC_SPLIT -/* -** Implementation of the quadratic variant of the PickNext() function from -** Guttman[84]. -*/ -static RtreeCell *QuadraticPickNext( - Rtree *pRtree, - RtreeCell *aCell, - int nCell, - RtreeCell *pLeftBox, - RtreeCell *pRightBox, - int *aiUsed -){ - #define FABS(a) ((a)<0.0?-1.0*(a):(a)) - - int iSelect = -1; - RtreeDValue fDiff; - int ii; - for(ii=0; iifDiff ){ - fDiff = diff; - iSelect = ii; - } - } - } - aiUsed[iSelect] = 1; - return &aCell[iSelect]; -} - -/* -** Implementation of the quadratic variant of the PickSeeds() function from -** Guttman[84]. -*/ -static void QuadraticPickSeeds( - Rtree *pRtree, - RtreeCell *aCell, - int nCell, - int *piLeftSeed, - int *piRightSeed -){ - int ii; - int jj; - - int iLeftSeed = 0; - int iRightSeed = 1; - RtreeDValue fWaste = 0.0; - - for(ii=0; iifWaste ){ - iLeftSeed = ii; - iRightSeed = jj; - fWaste = waste; - } - } - } - - *piLeftSeed = iLeftSeed; - *piRightSeed = iRightSeed; -} -#endif /* VARIANT_GUTTMAN_QUADRATIC_SPLIT */ /* ** Arguments aIdx, aDistance and aSpare all point to arrays of size @@ -2040,7 +2090,6 @@ static void SortByDimension( } } -#if VARIANT_RSTARTREE_SPLIT /* ** Implementation of the R*-tree variant of SplitNode from Beckman[1990]. */ @@ -2059,7 +2108,7 @@ static int splitNodeStartree( int iBestDim = 0; int iBestSplit = 0; - RtreeDValue fBestMargin = 0.0; + RtreeDValue fBestMargin = RTREE_ZERO; int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int)); @@ -2080,9 +2129,9 @@ static int splitNodeStartree( } for(ii=0; iinDim; ii++){ - RtreeDValue margin = 0.0; - RtreeDValue fBestOverlap = 0.0; - RtreeDValue fBestArea = 0.0; + RtreeDValue margin = RTREE_ZERO; + RtreeDValue fBestOverlap = RTREE_ZERO; + RtreeDValue fBestArea = RTREE_ZERO; int iBestLeft = 0; int nLeft; @@ -2108,7 +2157,7 @@ static int splitNodeStartree( } margin += cellMargin(pRtree, &left); margin += cellMargin(pRtree, &right); - overlap = cellOverlap(pRtree, &left, &right, 1, -1); + overlap = cellOverlap(pRtree, &left, &right, 1); area = cellArea(pRtree, &left) + cellArea(pRtree, &right); if( (nLeft==RTREE_MINCELLS(pRtree)) || (overlap0; i--){ - RtreeCell *pNext; - pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed); - RtreeDValue diff = - cellGrowth(pRtree, pBboxLeft, pNext) - - cellGrowth(pRtree, pBboxRight, pNext) - ; - if( (RTREE_MINCELLS(pRtree)-NCELL(pRight)==i) - || (diff>0.0 && (RTREE_MINCELLS(pRtree)-NCELL(pLeft)!=i)) - ){ - nodeInsertCell(pRtree, pRight, pNext); - cellUnion(pRtree, pBboxRight, pNext); - }else{ - nodeInsertCell(pRtree, pLeft, pNext); - cellUnion(pRtree, pBboxLeft, pNext); - } - } - - sqlite3_free(aiUsed); - return SQLITE_OK; -} -#endif static int updateMapping( Rtree *pRtree, @@ -2274,7 +2267,8 @@ static int SplitNode( memset(pLeft->zData, 0, pRtree->iNodeSize); memset(pRight->zData, 0, pRtree->iNodeSize); - rc = AssignCells(pRtree, aCell, nCell, pLeft, pRight, &leftbbox, &rightbbox); + rc = splitNodeStartree(pRtree, aCell, nCell, pLeft, pRight, + &leftbbox, &rightbbox); if( rc!=SQLITE_OK ){ goto splitnode_out; } @@ -2557,7 +2551,7 @@ static int Reinsert( } for(ii=0; iinDim; iDim++){ RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) - DCOORD(aCell[ii].aCoord[iDim*2])); @@ -2623,16 +2617,12 @@ static int rtreeInsertCell( } } if( nodeInsertCell(pRtree, pNode, pCell) ){ -#if VARIANT_RSTARTREE_REINSERT if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){ rc = SplitNode(pRtree, pNode, pCell, iHeight); }else{ pRtree->iReinsertHeight = iHeight; rc = Reinsert(pRtree, pNode, pCell, iHeight); } -#else - rc = SplitNode(pRtree, pNode, pCell, iHeight); -#endif }else{ rc = AdjustTree(pRtree, pNode, pCell); if( rc==SQLITE_OK ){ @@ -2702,7 +2692,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ ** about to be deleted. */ if( rc==SQLITE_OK ){ - rc = findLeafNode(pRtree, iDelete, &pLeaf); + rc = findLeafNode(pRtree, iDelete, &pLeaf, 0); } /* Delete the cell in question from the leaf node. */ @@ -2947,26 +2937,32 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){ ** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST. */ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ - const char *zSql = "SELECT stat FROM sqlite_stat1 WHERE tbl= ? || '_rowid'"; + const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; + char *zSql; sqlite3_stmt *p; int rc; i64 nRow = 0; - rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_text(p, 1, pRtree->zName, -1, SQLITE_STATIC); - if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); - rc = sqlite3_finalize(p); - }else if( rc!=SQLITE_NOMEM ){ - rc = SQLITE_OK; - } - - if( rc==SQLITE_OK ){ - if( nRow==0 ){ - pRtree->nRowEst = RTREE_DEFAULT_ROWEST; - }else{ - pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); + zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); + if( rc==SQLITE_OK ){ + if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); + rc = sqlite3_finalize(p); + }else if( rc!=SQLITE_NOMEM ){ + rc = SQLITE_OK; } + + if( rc==SQLITE_OK ){ + if( nRow==0 ){ + pRtree->nRowEst = RTREE_DEFAULT_ROWEST; + }else{ + pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); + } + } + sqlite3_free(zSql); } return rc; @@ -3033,7 +3029,8 @@ static int rtreeSqlInit( char *zCreate = sqlite3_mprintf( "CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY, data BLOB);" "CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY, nodeno INTEGER);" -"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY, parentnode INTEGER);" +"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY," + " parentnode INTEGER);" "INSERT INTO '%q'.'%q_node' VALUES(1, zeroblob(%d))", zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, pRtree->iNodeSize ); @@ -3235,6 +3232,8 @@ static int rtreeInit( if( rc==SQLITE_OK ){ *ppVtab = (sqlite3_vtab *)pRtree; }else{ + assert( *ppVtab==0 ); + assert( pRtree->nBusy==1 ); rtreeRelease(pRtree); } return rc; @@ -3245,10 +3244,10 @@ static int rtreeInit( ** Implementation of a scalar function that decodes r-tree nodes to ** human readable strings. This can be used for debugging and analysis. ** -** The scalar function takes two arguments, a blob of data containing -** an r-tree node, and the number of dimensions the r-tree indexes. -** For a two-dimensional r-tree structure called "rt", to deserialize -** all nodes, a statement like: +** The scalar function takes two arguments: (1) the number of dimensions +** to the rtree (between 1 and 5, inclusive) and (2) a blob of data containing +** an r-tree node. For a two-dimensional r-tree structure called "rt", to +** deserialize all nodes, a statement like: ** ** SELECT rtreenode(2, data) FROM rt_node; ** @@ -3281,7 +3280,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ nCell = (int)strlen(zCell); for(jj=0; jjxDestructor ) pInfo->xDestructor(pInfo->pContext); sqlite3_free(p); } /* -** Each call to sqlite3_rtree_geometry_callback() creates an ordinary SQLite -** scalar user function. This C function is the callback used for all such -** registered SQL functions. +** Each call to sqlite3_rtree_geometry_callback() or +** sqlite3_rtree_query_callback() creates an ordinary SQLite +** scalar function that is implemented by this routine. ** -** The scalar user functions return a blob that is interpreted by r-tree -** table MATCH operators. +** All this function does is construct an RtreeMatchArg object that +** contains the geometry-checking callback routines and a list of +** parameters to this function, then return that RtreeMatchArg object +** as a BLOB. +** +** The R-Tree MATCH operator will read the returned BLOB, deserialize +** the RtreeMatchArg object, and use the RtreeMatchArg object to figure +** out which elements of the R-Tree should be returned by the query. */ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx); @@ -3373,8 +3390,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ }else{ int i; pBlob->magic = RTREE_GEOMETRY_MAGIC; - pBlob->xGeom = pGeomCtx->xGeom; - pBlob->pContext = pGeomCtx->pContext; + pBlob->cb = pGeomCtx[0]; pBlob->nParam = nArg; for(i=0; iaParam[i] = sqlite3_value_double(aArg[i]); #endif } - sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free); + sqlite3_result_blob(ctx, pBlob, nBlob, sqlite3_free); } } @@ -3391,10 +3407,10 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ ** Register a new geometry function for use with the r-tree MATCH operator. */ int sqlite3_rtree_geometry_callback( - sqlite3 *db, - const char *zGeom, - int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue *, int *), - void *pContext + sqlite3 *db, /* Register SQL function on this connection */ + const char *zGeom, /* Name of the new SQL function */ + int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*), /* Callback */ + void *pContext /* Extra data associated with the callback */ ){ RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ @@ -3402,12 +3418,36 @@ int sqlite3_rtree_geometry_callback( pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); if( !pGeomCtx ) return SQLITE_NOMEM; pGeomCtx->xGeom = xGeom; + pGeomCtx->xQueryFunc = 0; + pGeomCtx->xDestructor = 0; pGeomCtx->pContext = pContext; - - /* Create the new user-function. Register a destructor function to delete - ** the context object when it is no longer required. */ return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY, - (void *)pGeomCtx, geomCallback, 0, 0, doSqlite3Free + (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback + ); +} + +/* +** Register a new 2nd-generation geometry function for use with the +** r-tree MATCH operator. +*/ +int sqlite3_rtree_query_callback( + sqlite3 *db, /* Register SQL function on this connection */ + const char *zQueryFunc, /* Name of new SQL function */ + int (*xQueryFunc)(sqlite3_rtree_query_info*), /* Callback */ + void *pContext, /* Extra data passed into the callback */ + void (*xDestructor)(void*) /* Destructor for the extra data */ +){ + RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ + + /* Allocate and populate the context object. */ + pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); + if( !pGeomCtx ) return SQLITE_NOMEM; + pGeomCtx->xGeom = 0; + pGeomCtx->xQueryFunc = xQueryFunc; + pGeomCtx->xDestructor = xDestructor; + pGeomCtx->pContext = pContext; + return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY, + (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback ); } diff --git a/ext/rtree/rtree1.test b/ext/rtree/rtree1.test index 275b132..0beb16c 100644 --- a/ext/rtree/rtree1.test +++ b/ext/rtree/rtree1.test @@ -33,6 +33,7 @@ set testprefix rtree1 # rtree-8.*: Test constrained scans of r-tree data. # # rtree-12.*: Test that on-conflict clauses are supported. +# rtree-13.*: Test that bug [d2889096e7bdeac6d] has been fixed. # ifcapable !rtree { @@ -120,12 +121,13 @@ proc execsql_intout {sql} { # Test that it is possible to open an existing database that contains # r-tree tables. # -do_test rtree-1.4.1 { - execsql { - CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2); - INSERT INTO t1 VALUES(1, 5.0, 10.0); - INSERT INTO t1 VALUES(2, 15.0, 20.0); - } +do_execsql_test rtree-1.4.1a { + CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2); + INSERT INTO t1 VALUES(1, 5.0, 10.0); + SELECT substr(hex(data),1,40) FROM t1_node; +} {00000001000000000000000140A0000041200000} +do_execsql_test rtree-1.4.1b { + INSERT INTO t1 VALUES(2, 15.0, 20.0); } {} do_test rtree-1.4.2 { db close @@ -435,16 +437,18 @@ do_test rtree-11.2 { # Test on-conflict clause handling. # db_delete_and_reopen -do_execsql_test 12.0 { +do_execsql_test 12.0.1 { CREATE VIRTUAL TABLE t1 USING rtree_i32(idx, x1, x2, y1, y2); INSERT INTO t1 VALUES(1, 1, 2, 3, 4); + SELECT substr(hex(data),1,56) FROM t1_node; +} {00000001000000000000000100000001000000020000000300000004} +do_execsql_test 12.0.2 { 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} { @@ -510,4 +514,25 @@ foreach {tn sql_template testdata} { db close } } + +#------------------------------------------------------------------------- +# Test that bug [d2889096e7bdeac6d] has been fixed. +# +reset_db +do_execsql_test 13.1 { + CREATE VIRTUAL TABLE t9 USING rtree(id, xmin, xmax); + INSERT INTO t9 VALUES(1,0,0); + INSERT INTO t9 VALUES(2,0,0); + SELECT * FROM t9 WHERE id IN (1, 2); +} {1 0.0 0.0 2 0.0 0.0} + +do_execsql_test 13.2 { + WITH r(x) AS ( + SELECT 1 UNION ALL + SELECT 2 UNION ALL + SELECT 3 + ) + SELECT * FROM r CROSS JOIN t9 WHERE id=x; +} {1 1 0.0 0.0 2 2 0.0 0.0} + finish_test diff --git a/ext/rtree/rtree6.test b/ext/rtree/rtree6.test index bdc9bb4..cec3a8d 100644 --- a/ext/rtree/rtree6.test +++ b/ext/rtree/rtree6.test @@ -57,31 +57,31 @@ do_test rtree6-1.1 { do_test rtree6-1.2 { rtree_strategy {SELECT * FROM t1 WHERE x1>10} -} {Ea} +} {E0} do_test rtree6-1.3 { rtree_strategy {SELECT * FROM t1 WHERE x1<10} -} {Ca} +} {C0} do_test rtree6-1.4 { rtree_strategy {SELECT * FROM t1,t2 WHERE k=ii AND x1<10} -} {Ca} +} {C0} do_test rtree6-1.5 { rtree_strategy {SELECT * FROM t1,t2 WHERE k=+ii AND x1<10} -} {Ca} +} {C0} do_eqp_test rtree6.2.1 { SELECT * FROM t1,t2 WHERE k=+ii AND x1<10 } { - 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca} + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0} 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test rtree6.2.2 { SELECT * FROM t1,t2 WHERE k=ii AND x1<10 } { - 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca} + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0} 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } @@ -92,10 +92,16 @@ do_eqp_test rtree6.2.3 { 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } -do_eqp_test rtree6.2.4 { +do_eqp_test rtree6.2.4.1 { + SELECT * FROM t1,t2 WHERE v=+ii and x1<10 and x2>10 +} { + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1} + 0 1 1 {SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?)} +} +do_eqp_test rtree6.2.4.2 { SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10 } { - 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:CaEb} + 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1} 0 1 1 {SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?)} } @@ -126,7 +132,7 @@ do_test rtree6.3.2 { x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 } -} {EaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEa} +} {E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0} do_test rtree6.3.3 { rtree_strategy { SELECT * FROM t3 WHERE @@ -137,7 +143,7 @@ do_test rtree6.3.3 { x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 } -} {EaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEa} +} {E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0} do_execsql_test rtree6-3.4 { SELECT * FROM t3 WHERE x1>0.5 AND x1>0.8 AND x1>1.1 diff --git a/ext/rtree/rtreeB.test b/ext/rtree/rtreeB.test index 7cb445c..aeb308e 100644 --- a/ext/rtree/rtreeB.test +++ b/ext/rtree/rtreeB.test @@ -41,7 +41,7 @@ ifcapable rtree_int_only { INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400); SELECT rtreenode(2, data) FROM t1_node; } - } {{{1073741824 0.000000 0.000000 100.000000 100.000000} {2147483646 0.000000 0.000000 200.000000 200.000000} {4294967296 0.000000 0.000000 300.000000 300.000000} {8589934592 20.000000 20.000000 150.000000 150.000000} {9223372036854775807 150.000000 150.000000 400.000000 400.000000}}} + } {{{1073741824 0 0 100 100} {2147483646 0 0 200 200} {4294967296 0 0 300 300} {8589934592 20 20 150 150} {9223372036854775807 150 150 400 400}}} } finish_test diff --git a/ext/rtree/rtreeC.test b/ext/rtree/rtreeC.test index 2e5bede..94db05a 100644 --- a/ext/rtree/rtreeC.test +++ b/ext/rtree/rtreeC.test @@ -29,7 +29,7 @@ do_eqp_test 1.1 { WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { 0 0 1 {SCAN TABLE t} - 0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa} + 0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 1.2 { @@ -37,7 +37,7 @@ do_eqp_test 1.2 { WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { 0 0 0 {SCAN TABLE t} - 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa} + 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 1.3 { @@ -45,7 +45,7 @@ do_eqp_test 1.3 { WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y } { 0 0 0 {SCAN TABLE t} - 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa} + 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 1.5 { @@ -82,7 +82,7 @@ do_eqp_test 2.1 { WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { 0 0 1 {SCAN TABLE t} - 0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa} + 0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 2.2 { @@ -90,7 +90,7 @@ do_eqp_test 2.2 { WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { 0 0 0 {SCAN TABLE t} - 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa} + 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 2.3 { @@ -98,7 +98,7 @@ do_eqp_test 2.3 { WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y } { 0 0 0 {SCAN TABLE t} - 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa} + 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 2.5 { @@ -158,5 +158,116 @@ do_execsql_test 4.3 { SELECT b, a FROM t2 LEFT JOIN t1 ON (+a = +b); } {1 1 3 {}} -finish_test +#-------------------------------------------------------------------- +# Test that the sqlite_stat1 data is used correctly. +# +reset_db +do_execsql_test 5.1 { + CREATE TABLE t1(x PRIMARY KEY, y); + CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2); + INSERT INTO t1(x) VALUES(1); + INSERT INTO t1(x) SELECT x+1 FROM t1; -- 2 + INSERT INTO t1(x) SELECT x+2 FROM t1; -- 4 + INSERT INTO t1(x) SELECT x+4 FROM t1; -- 8 + INSERT INTO t1(x) SELECT x+8 FROM t1; -- 16 + INSERT INTO t1(x) SELECT x+16 FROM t1; -- 32 + INSERT INTO t1(x) SELECT x+32 FROM t1; -- 64 + INSERT INTO t1(x) SELECT x+64 FROM t1; -- 128 + INSERT INTO t1(x) SELECT x+128 FROM t1; -- 256 + INSERT INTO t1(x) SELECT x+256 FROM t1; -- 512 + INSERT INTO t1(x) SELECT x+512 FROM t1; --1024 + + INSERT INTO rt SELECT x, x, x+1 FROM t1 WHERE x<=5; +} + +# First test a query with no ANALYZE data at all. The outer loop is +# real table "t1". +# +do_eqp_test 5.2 { + SELECT * FROM t1, rt WHERE x==id; +} { + 0 0 0 {SCAN TABLE t1} + 0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:} +} + +# Now create enough ANALYZE data to tell SQLite that virtual table "rt" +# contains very few rows. This causes it to move "rt" to the outer loop. +# +do_execsql_test 5.3 { + ANALYZE; + DELETE FROM sqlite_stat1 WHERE tbl='t1'; +} +db close +sqlite3 db test.db +do_eqp_test 5.4 { + SELECT * FROM t1, rt WHERE x==id; +} { + 0 0 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:} + 0 1 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (x=?)} +} + +# Delete the ANALYZE data. "t1" should be the outer loop again. +# +do_execsql_test 5.5 { DROP TABLE sqlite_stat1; } +db close +sqlite3 db test.db +do_eqp_test 5.6 { + SELECT * FROM t1, rt WHERE x==id; +} { + 0 0 0 {SCAN TABLE t1} + 0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:} +} + +# This time create and attach a database that contains ANALYZE data for +# tables of the same names as those used internally by virtual table +# "rt". Check that the rtree module is not fooled into using this data. +# Table "t1" should remain the outer loop. +# +do_test 5.7 { + db backup test.db2 + sqlite3 db2 test.db2 + db2 eval { + ANALYZE; + DELETE FROM sqlite_stat1 WHERE tbl='t1'; + } + db2 close + db close + sqlite3 db test.db + execsql { ATTACH 'test.db2' AS aux; } +} {} +do_eqp_test 5.8 { + SELECT * FROM t1, rt WHERE x==id; +} { + 0 0 0 {SCAN TABLE t1} + 0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:} +} + +#-------------------------------------------------------------------- +# Test that having a second connection drop the sqlite_stat1 table +# before it is required by rtreeConnect() does not cause problems. +# +ifcapable rtree { + reset_db + do_execsql_test 6.1 { + CREATE TABLE t1(x); + CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2); + INSERT INTO t1 VALUES(1); + INSERT INTO rt VALUES(1,2,3); + ANALYZE; + } + db close + sqlite3 db test.db + do_execsql_test 6.2 { SELECT * FROM t1 } {1} + + do_test 6.3 { + sqlite3 db2 test.db + db2 eval { DROP TABLE sqlite_stat1 } + db2 close + execsql { SELECT * FROM rt } + } {1 2.0 3.0} + db close +} + + +finish_test diff --git a/ext/rtree/rtreeE.test b/ext/rtree/rtreeE.test new file mode 100644 index 0000000..c450623 --- /dev/null +++ b/ext/rtree/rtreeE.test @@ -0,0 +1,129 @@ +# 2010 August 28 +# +# 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 contains tests for the r-tree module. Specifically, it tests +# that new-style custom r-tree queries (geometry callbacks) work. +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source $testdir/tester.tcl +ifcapable !rtree { finish_test ; return } +ifcapable rtree_int_only { finish_test; return } + + +#------------------------------------------------------------------------- +# Test the example 2d "circle" geometry callback. +# +register_circle_geom db + +do_execsql_test rtreeE-1.1 { + PRAGMA page_size=512; + CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1); + + /* A tight pattern of small boxes near 0,0 */ + WITH RECURSIVE + x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4), + y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4) + INSERT INTO rt1 SELECT x+5*y, x, x+2, y, y+2 FROM x, y; + + /* A looser pattern of small boxes near 100, 0 */ + WITH RECURSIVE + x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4), + y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4) + INSERT INTO rt1 SELECT 100+x+5*y, x*3+100, x*3+102, y*3, y*3+2 FROM x, y; + + /* A looser pattern of larger boxes near 0, 200 */ + WITH RECURSIVE + x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4), + y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4) + INSERT INTO rt1 SELECT 200+x+5*y, x*7, x*7+15, y*7+200, y*7+215 FROM x, y; +} {} + +# Queries against each of the three clusters */ +do_execsql_test rtreeE-1.1 { + SELECT id FROM rt1 WHERE id MATCH Qcircle(0.0, 0.0, 50.0, 3) ORDER BY id; +} {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24} +do_execsql_test rtreeE-1.2 { + SELECT id FROM rt1 WHERE id MATCH Qcircle(100.0, 0.0, 50.0, 3) ORDER BY id; +} {100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124} +do_execsql_test rtreeE-1.3 { + SELECT id FROM rt1 WHERE id MATCH Qcircle(0.0, 200.0, 50.0, 3) ORDER BY id; +} {200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224} + +# The Qcircle geometry function gives a lower score to larger leaf-nodes. +# This causes the 200s to sort before the 100s and the 0s to sort before +# last. +# +do_execsql_test rtreeE-1.4 { + SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,3) AND id%100==0 +} {200 100 0} + +# Exclude odd rowids on a depth-first search +do_execsql_test rtreeE-1.5 { + SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,4) ORDER BY +id +} {0 2 4 6 8 10 12 14 16 18 20 22 24 100 102 104 106 108 110 112 114 116 118 120 122 124 200 202 204 206 208 210 212 214 216 218 220 222 224} + +# Exclude odd rowids on a breadth-first search. +do_execsql_test rtreeE-1.6 { + SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,5) ORDER BY +id +} {0 2 4 6 8 10 12 14 16 18 20 22 24 100 102 104 106 108 110 112 114 116 118 120 122 124 200 202 204 206 208 210 212 214 216 218 220 222 224} + +# Construct a large 2-D RTree with thousands of random entries. +# +do_test rtreeE-2.1 { + db eval { + CREATE TABLE t2(id,x0,x1,y0,y1); + CREATE VIRTUAL TABLE rt2 USING rtree(id,x0,x1,y0,y1); + BEGIN; + } + expr srand(0) + for {set i 1} {$i<=10000} {incr i} { + set dx [expr {int(rand()*40)+1}] + set dy [expr {int(rand()*40)+1}] + set x0 [expr {int(rand()*(10000 - $dx))}] + set x1 [expr {$x0+$dx}] + set y0 [expr {int(rand()*(10000 - $dy))}] + set y1 [expr {$y0+$dy}] + set id [expr {$i+10000}] + db eval {INSERT INTO t2 VALUES($id,$x0,$x1,$y0,$y1)} + } + db eval { + INSERT INTO rt2 SELECT * FROM t2; + COMMIT; + } +} {} + +for {set i 1} {$i<=200} {incr i} { + set dx [expr {int(rand()*100)}] + set dy [expr {int(rand()*100)}] + set x0 [expr {int(rand()*(10000 - $dx))}] + set x1 [expr {$x0+$dx}] + set y0 [expr {int(rand()*(10000 - $dy))}] + set y1 [expr {$y0+$dy}] + set ans [db eval {SELECT id FROM t2 WHERE x1>=$x0 AND x0<=$x1 AND y1>=$y0 AND y0<=$y1 ORDER BY id}] + do_execsql_test rtreeE-2.2.$i { + SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch($x0,$x1,$y0,$y1) ORDER BY id + } $ans +} + +# Run query that have very deep priority queues +# +set ans [db eval {SELECT id FROM t2 WHERE x1>=0 AND x0<=5000 AND y1>=0 AND y0<=5000 ORDER BY id}] +do_execsql_test rtreeE-2.3 { + SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch(0,5000,0,5000) ORDER BY id +} $ans +set ans [db eval {SELECT id FROM t2 WHERE x1>=0 AND x0<=10000 AND y1>=0 AND y0<=10000 ORDER BY id}] +do_execsql_test rtreeE-2.4 { + SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch(0,10000,0,10000) ORDER BY id +} $ans + +finish_test diff --git a/ext/rtree/sqlite3rtree.h b/ext/rtree/sqlite3rtree.h index c849091..5de0508 100644 --- a/ext/rtree/sqlite3rtree.h +++ b/ext/rtree/sqlite3rtree.h @@ -21,6 +21,16 @@ extern "C" { #endif typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; +typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; + +/* The double-precision datatype used by RTree depends on the +** SQLITE_RTREE_INT_ONLY compile-time option. +*/ +#ifdef SQLITE_RTREE_INT_ONLY + typedef sqlite3_int64 sqlite3_rtree_dbl; +#else + typedef double sqlite3_rtree_dbl; +#endif /* ** Register a geometry callback named zGeom that can be used as part of an @@ -31,11 +41,7 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, -#ifdef SQLITE_RTREE_INT_ONLY - int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes), -#else - int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes), -#endif + int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), void *pContext ); @@ -47,11 +53,60 @@ int sqlite3_rtree_geometry_callback( struct sqlite3_rtree_geometry { void *pContext; /* Copy of pContext passed to s_r_g_c() */ int nParam; /* Size of array aParam[] */ - double *aParam; /* Parameters passed to SQL geom function */ + sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */ void *pUser; /* Callback implementation user data */ void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ }; +/* +** Register a 2nd-generation geometry callback named zScore that can be +** used as part of an R-Tree geometry query as follows: +** +** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) +*/ +int sqlite3_rtree_query_callback( + sqlite3 *db, + const char *zQueryFunc, + int (*xQueryFunc)(sqlite3_rtree_query_info*), + void *pContext, + void (*xDestructor)(void*) +); + + +/* +** A pointer to a structure of the following type is passed as the +** argument to scored geometry callback registered using +** sqlite3_rtree_query_callback(). +** +** Note that the first 5 fields of this structure are identical to +** sqlite3_rtree_geometry. This structure is a subclass of +** sqlite3_rtree_geometry. +*/ +struct sqlite3_rtree_query_info { + void *pContext; /* pContext from when function registered */ + int nParam; /* Number of function parameters */ + sqlite3_rtree_dbl *aParam; /* value of function parameters */ + void *pUser; /* callback can use this, if desired */ + void (*xDelUser)(void*); /* function to free pUser */ + sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */ + unsigned int *anQueue; /* Number of pending entries in the queue */ + int nCoord; /* Number of coordinates */ + int iLevel; /* Level of current node or entry */ + int mxLevel; /* The largest iLevel value in the tree */ + sqlite3_int64 iRowid; /* Rowid for current entry */ + sqlite3_rtree_dbl rParentScore; /* Score of parent node */ + int eParentWithin; /* Visibility of parent node */ + int eWithin; /* OUT: Visiblity */ + sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ +}; + +/* +** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin. +*/ +#define NOT_WITHIN 0 /* Object completely outside of query region */ +#define PARTLY_WITHIN 1 /* Object partially overlaps query region */ +#define FULLY_WITHIN 2 /* Object fully contained within query region */ + #ifdef __cplusplus } /* end of the 'extern "C"' block */ diff --git a/magic.txt b/magic.txt index add96a7..6562268 100644 --- a/magic.txt +++ b/magic.txt @@ -28,4 +28,5 @@ >68 belong =0x47504b47 OGC GeoPackage file - >68 belong =0x47503130 OGC GeoPackage version 1.0 file - >68 belong =0x45737269 Esri Spatially-Enabled Database - +>68 belong =0x4d504258 MBTiles tileset - >0 string =SQLite SQLite3 database diff --git a/main.mk b/main.mk index ebd508a..718cf5c 100644 --- a/main.mk +++ b/main.mk @@ -121,8 +121,10 @@ SRC = \ $(TOP)/src/os.c \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ + $(TOP)/src/os_setup.h \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ + $(TOP)/src/os_win.h \ $(TOP)/src/pager.c \ $(TOP)/src/pager.h \ $(TOP)/src/parse.y \ @@ -208,6 +210,7 @@ SRC += \ $(TOP)/ext/icu/sqliteicu.h \ $(TOP)/ext/icu/icu.c SRC += \ + $(TOP)/ext/rtree/sqlite3rtree.h \ $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/rtree.c @@ -274,6 +277,7 @@ TESTSRC = \ TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ + $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ @@ -339,6 +343,8 @@ HDR = \ opcodes.h \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ + $(TOP)/src/os_setup.h \ + $(TOP)/src/os_win.h \ $(TOP)/src/pager.h \ $(TOP)/src/pcache.h \ parse.h \ @@ -476,7 +482,7 @@ parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk mv parse.h parse.h.temp $(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h -sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION +sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION $(TOP)/ext/rtree/sqlite3rtree.h tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h keywordhash.h: $(TOP)/tool/mkkeywordhash.c @@ -622,9 +628,32 @@ $(TEST_EXTENSION): $(TOP)/src/test_loadext.c extensiontest: testfixture$(EXE) $(TEST_EXTENSION) ./testfixture$(EXE) $(TOP)/test/loadext.test -showdb$(EXE): $(TOP)/tool/showdb.c sqlite3.c +showdb$(EXE): $(TOP)/tool/showdb.c sqlite3.o $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o showdb$(EXE) \ - $(TOP)/tool/showdb.c sqlite3.c + $(TOP)/tool/showdb.c sqlite3.o $(THREADLIB) + +showstat4$(EXE): $(TOP)/tool/showstat4.c sqlite3.o + $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o showstat4$(EXE) \ + $(TOP)/tool/showstat4.c sqlite3.o $(THREADLIB) + +showjournal$(EXE): $(TOP)/tool/showjournal.c sqlite3.o + $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o showjournal$(EXE) \ + $(TOP)/tool/showjournal.c sqlite3.o $(THREADLIB) + +showwal$(EXE): $(TOP)/tool/showwal.c sqlite3.o + $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o showwal$(EXE) \ + $(TOP)/tool/showwal.c sqlite3.o $(THREADLIB) + +fts3view$(EXE): $(TOP)/ext/fts3/tool/fts3view.c sqlite3.o + $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o fts3view$(EXE) \ + $(TOP)/ext/fts3/tool/fts3view.c sqlite3.o $(THREADLIB) + +rollback-test$(EXE): $(TOP)/tool/rollback-test.c sqlite3.o + $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o rollback-test$(EXE) \ + $(TOP)/tool/rollback-test.c sqlite3.o $(THREADLIB) + +LogEst$(EXE): $(TOP)/tool/logest.c sqlite3.h + $(TCC) -o LogEst$(EXE) $(TOP)/tool/logest.c wordcount$(EXE): $(TOP)/test/wordcount.c sqlite3.c $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o wordcount$(EXE) \ @@ -666,10 +695,18 @@ clean: rm -f fts3-testfixture fts3-testfixture.exe rm -f testfixture testfixture.exe rm -f threadtest3 threadtest3.exe + rm -f LogEst LogEst.exe + rm -f fts3view fts3view.exe + rm -f rollback-test rollback-test.exe + rm -f showdb showdb.exe + rm -f showjournal showjournal.exe + rm -f showstat4 showstat4.exe + rm -f showwal showwal.exe + rm -f speedtest1 speedtest1.exe + rm -f wordcount wordcount.exe rm -f sqlite3.c sqlite3-*.c fts?amal.c tclsqlite3.c rm -f sqlite3rc.h rm -f shell.c sqlite3ext.h rm -f sqlite3_analyzer sqlite3_analyzer.exe sqlite3_analyzer.c rm -f sqlite-*-output.vsix rm -f mptester mptester.exe - rm -f showdb diff --git a/manifest b/manifest index 1ce80fb..28b547a 100644 --- a/manifest +++ b/manifest @@ -1,12 +1,12 @@ -C Version\s3.8.4.3 -D 2014-04-03T16:53:12.416 +C Version\s3.8.6 +D 2014-08-15T11:46:33.931 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 +F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc fdacba6fb574868c71fde6db6b77789a383a4c19 -F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315 +F Makefile.msc 5b04e657cf08a9ac7fc47d876c5c8be962c47d6b +F Makefile.vxworks 034289efa9d591b04b1a73598623119c306cbba0 F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8 -F VERSION f2e148dd23e570d315c957fee69bd5d302242840 +F VERSION 1c877615a9db323e3cd301e3d57d853f9d5c4a07 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 @@ -38,7 +38,7 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 -F configure 215e976e24f3a008409277800f29dac638b2b3e8 x +F configure 513f1e2464c3673bcdb5471b13d98e7eeb6f5ca2 x F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1 @@ -78,11 +78,11 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 3fe91e36a0304ad4b35020f0e22ff37e95873166 +F ext/fts3/fts3.c 2f5e925bdb9d6d3e488c5a981af60cad4f9cdfe7 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h eb5f8029589f3d8f1dc7fd50c773326a640388b1 +F ext/fts3/fts3Int.h 53d4eca1fb23eab00681fb028fb82eb5705c1e21 F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365 -F ext/fts3/fts3_expr.c 5165c365cb5a035f5be8bb296f7aa3211d43e4ac +F ext/fts3/fts3_expr.c 351395fad6fcb16ecfc61db0861008a70101330c F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60 F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5 @@ -94,56 +94,59 @@ F ext/fts3/fts3_tokenize_vtab.c 011170fe9eba5ff062f1a31d3188e00267716706 F ext/fts3/fts3_tokenizer.c bbdc731bc91338050675c6d1da9ab82147391e16 F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3 F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004 -F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9 -F ext/fts3/fts3_unicode2.c 0113d3acf13429e6dc38e0647d1bc71211c31a4d -F ext/fts3/fts3_write.c cdebe72171a217b1465032dec103f8d17f7dad4d +F ext/fts3/fts3_unicode.c a93f5edc0aff44ef8b06d7cb55b52026541ca145 +F ext/fts3/fts3_unicode2.c c3d01968d497bd7001e7dc774ba75b372738c057 +F ext/fts3/fts3_write.c 8260388626516a7005d06a9dce94f9e55c6c2a41 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 -F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197 +F ext/fts3/tool/fts3view.c 3986531f2fc0ceca0c89c31ec7d0589b6adb19d6 F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7 -F ext/fts3/unicode/mkunicode.tcl dc6f268eb526710e2c6e496c372471d773d0c368 +F ext/fts3/unicode/mkunicode.tcl a2567f9d6ad6779879a2e394c120ad8718557e65 F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 F ext/icu/icu.c d415ccf984defeb9df2c0e1afcfaa2f6dc05eacb F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/misc/amatch.c 678056a4bfcd83c4e82dea81d37543cd1d6dbee1 F ext/misc/closure.c 636024302cde41b2bf0c542f81c40c624cfb7012 +F ext/misc/compress.c 76e45655f4046e756064ab10c62e18f2eb846b9f +F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f F ext/misc/fuzzer.c 136533c53cfce0957f0b48fa11dba27e21c5c01d F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342 F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63 F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a -F ext/misc/spellfix.c 93f3961074cebe63c31fcefe62ca2a032ee8dfed +F ext/misc/spellfix.c cb016c2dab951ffd7b819a7bc8a750ebd6c26c0f F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512 F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95 F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/rtree.c a4e18b2c150adad20aecbeb3408cd235a0a57441 +F ext/rtree/rtree.c 57bec53e1a677ab74217fe1f20a58c3a47261d6b F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e -F ext/rtree/rtree1.test cf679265ecafff494a768ac9c2f43a70915a6290 +F ext/rtree/rtree1.test 541bbcab74613907fea08b2ecdcdd5b7aa724cc9 F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0 F ext/rtree/rtree5.test 6a510494f12454bf57ef28f45bc7764ea279431e -F ext/rtree/rtree6.test fe0bd377a21c68ce2826129d14354c884cb1f354 +F ext/rtree/rtree6.test 0cfbdf27ee086bf16a3da2c6f2d5b3d6473cb27e F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971 F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a F ext/rtree/rtree9.test d86ebf08ff6328895613ed577dd8a2a37c472c34 F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf -F ext/rtree/rtreeB.test 983e567b49b5dca165940f66b87e161aa30e82b2 -F ext/rtree/rtreeC.test 03975565f40a0bee165f613143e4dec716dd5a59 +F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e +F ext/rtree/rtreeC.test df158dcc81f1a43ce7eef361af03c48ec91f1e06 F ext/rtree/rtreeD.test 636630357638f5983701550b37f0f5867130d2ca +F ext/rtree/rtreeE.test 388c1c8602c3ce55c15f03b509e9cf545fb7c41f F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195 F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea -F ext/rtree/sqlite3rtree.h c34c1e41d1ab80bb8ad09aae402c9c956871a765 +F ext/rtree/sqlite3rtree.h 83349d519fe5f518b3ea025d18dd1fe51b1684bd F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 -F magic.txt f439556c5ce01ced70987e5ee86549a45165d9ff -F main.mk 3ae543fa446525c1dec55f58de67f41b78651812 +F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 +F main.mk 036a65c9042b2f5013baf85c82629d700fe031c4 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -157,78 +160,80 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c 5d99edbac5bc416032772b723ee30182ee6e5de0 -F src/analyze.c 663e0b291d27eb03c9fd6b421e2d61ba348a2389 +F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1 +F src/analyze.c f98a351908da29f7b44741cfeb9eb20dda648ba0 F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c 4d28fb15543f0e071b1780b2af8cd2ee489de32d -F src/btree.h 9e0f97c01b972f779eb7655cfb4f8727fd6dc26f -F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4 -F src/build.c 0d50ef95aad63f4c4fc47f3fa2670d4557c45db0 -F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98 +F src/btree.c fa057e30794bfd867963b44a3a42710a45c335a1 +F src/btree.h 4245a349bfe09611d7ff887dbc3a80cee8b7955a +F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3 +F src/build.c 5abf794fe8a605f2005b422e98a3cedad9b9ef5b +F src/callback.c fcff28cf0df2403dd2f313bb8d1b8f31f6f3cd64 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 -F src/delete.c cdd57149543bb28304d8f717c243f2a86b1fc280 -F src/expr.c 014b8087a15c4c314bdd798cb1cb0b32693f8b40 +F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf +F src/expr.c f749009cf4a8534efb5e0d5cd7c9fb1fb0f2836c F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb -F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf -F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811 -F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486 +F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 +F src/func.c bbb724b74ed96ca42675a7274646a71dd52bcda7 +F src/global.c 1e4bd956dc2f608f87d2a929abc4a20db65f30e4 F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c d8bb30535c8c0785876025a4a07f9074640a15d1 +F src/insert.c 991e4964e9295da3993e2c0f81c7faf642371848 F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d -F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 +F src/legacy.c febc2a9e7ad6c1a6191c7b5b9170b325d263f343 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303 -F src/main.c e054917b1beb3081b0f23e8bdd3d6c0e12933dd3 +F src/main.c 1cf92c5c6468f2b6ed99b638706781ccc9c60b42 F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534 -F src/mem5.c aeb019f271ea53de83d651ec526877e6ba863450 +F src/mem5.c 74670012946c4adc8a6ad84d03acc80959c3e529 F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785 -F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc +F src/mutex.c 84a073c9a23a8d7bdd2ea832522d1730df18812c F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea -F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553 -F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc -F src/mutex_w32.c 6108c88e1cb38d8fbb3534b170793815cbedbf97 +F src/mutex_noop.c f3f09fd7a2eb4287cfc799753ffc30380e7b71a1 +F src/mutex_unix.c 1b10d5413dfc794364a8adf3eb3a192926b43fa3 +F src/mutex_w32.c c50939b72368f1cfbddb58520372081a50558548 F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace -F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f +F src/os.h 60d419395e32a8029fa380a80a3da2e9030f635e F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 -F src/os_unix.c 18f7f95dc6bcb9cf4d4a238d8e2de96611bc2ae5 -F src/os_win.c e71678ac927d0a0fb11d993db20a9748eabf808e -F src/pager.c 97a8908bf4e6e7c3adea09d3597cfa48ae33ab4e +F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa +F src/os_unix.c bd7df3094a60915c148517504c76df4fca24e542 +F src/os_win.c 1c936c7b0659d0eb12b868e2cd710a570e78873e +F src/os_win.h 057344a6720b4c8405d9bd98f58cb37a6ee46c25 +F src/pager.c f6bb1fa6cdf2062f2d8aec3e64db302bca519ab8 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 -F src/parse.y 2613ca5d609c2f3d71dd297351f010bcec16e1e0 +F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0 F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c -F src/pragma.c e78b4bf2a267de2c17ee09f90b6807cf8d40e6a3 +F src/pragma.c d10ef67c4de79f78188b965b4b7988aff1d66f2e F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337 -F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269 +F src/printf.c af06f66927919730f03479fed6ae9854f73419f4 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece -F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66 -F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 -F src/select.c 0adf172d33cc610ff5ffe26edfd2ba67c3551655 -F src/shell.c bab4de12b441369491812ecc93212ff4deda68fa -F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80 -F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e +F src/resolve.c 0ea356d32a5e884add23d1b9b4e8736681dd5697 +F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be +F src/select.c ea48e891406ccdf748f3eb02893e056d134a0fea +F src/shell.c 75bb7bd2c80bb44861598f322a417c4bafe98fd7 +F src/sqlite.h.in ed9d35990c61f0388ca6405706455c4095310553 +F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h fa7161b3de18a9c355d4148233f3563c92311fcc +F src/sqliteInt.h 641f8fbb65ca2084c8df95b525f6f82c7a1e91ae F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c e87c99e28a145943666b51b212dacae35fcea0bd -F src/test1.c 2401eee14a4309a7cfe2aeb2f30ad517a1d9c299 -F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35 +F src/test1.c 14409a611e9c27c6c522c610bbff5561f05c1558 +F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df F src/test5.c 5a34feec76d9b3a86aab30fd4f6cc9c48cbab4c1 @@ -239,8 +244,8 @@ F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60 F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8 F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12 F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e -F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16 -F src/test_config.c 0336e0bdbe541b4af89d7e3dd0656e8e6b51e585 +F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f +F src/test_config.c 42fb068a038c8684741522f551325228b1389e63 F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f @@ -252,68 +257,69 @@ F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64 F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4 F src/test_malloc.c 1ff5b1243d96124c9a180f3b89424820a1f337f3 -F src/test_multiplex.c 9f304bf04170c91c0318238d512df2da039eb1c8 -F src/test_multiplex.h 110a8c4d356e0aa464ca8730375608a9a0b61ae1 +F src/test_multiplex.c ca90057438b63bf0840ebb84d0ef050624519a76 +F src/test_multiplex.h c08e4e8f8651f0c5e0509b138ff4d5b43ed1f5d3 F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f F src/test_onefile.c 0396f220561f3b4eedc450cef26d40c593c69a25 -F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba +F src/test_osinst.c 3d0340bc31a9f3d8a3547e0272373e80f78dde25 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c 30c64f0ef84734f2231a686df41ed882b0c59bc0 -F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb -F src/test_rtree.c f3d1d12538dccb75fd916e3fa58f250edbdd3b47 +F src/test_quota.c 65f6348fec0f2b3020c907247fb47556b214abb9 +F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d +F src/test_rtree.c fdd8d29ca5165c7857987a2ba263fac5c69e231f F src/test_schema.c cd12a2223c3a394f4d07bb93bdf6d344c5c121b6 F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e F src/test_stat.c 9898687a6c2beca733b0dd6fe19163d987826d31 F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd -F src/test_syscall.c 16dbe79fb320fadb5acd7a0a59f49e52ab2d2091 +F src/test_syscall.c 2e21ca7f7dc54a028f1967b63f1e76155c356f9b F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb -F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9 -F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78 +F src/test_vfs.c f84075a388527892ff184988f43b69ce69b8083c +F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 -F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7 +F src/tokenize.c ae45399d6252b4d736af43bee1576ce7bff86aec F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb -F src/update.c 5b3e74a03b3811e586b4f2b4cbd7c49f01c93115 -F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c -F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf +F src/update.c ea336ce7b8b3fc5e316ba8f082e6445babf81059 +F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05 +F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c 5f0fffa9bf49a90c05dc3d46d8217603fd0ee00e -F src/vdbe.h fb2c48c198300a7c632f09fc940011d2ad2fc2ae -F src/vdbeInt.h e54fc4f289fce48e81b3371128446033d097733b -F src/vdbeapi.c 0ed6053f947edd0b30f64ce5aeb811872a3450a4 -F src/vdbeaux.c 714df4e1c82f629d39602fd5a0b6cace9b8832d6 -F src/vdbeblob.c 15377abfb59251bccedd5a9c7d014a895f0c04aa -F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447 -F src/vdbesort.c 46801acb342e5e4c07ba1777fe58880c143abb59 +F src/vdbe.c f7f4066e4d6e3858878d76ce9288ea603e12ddf6 +F src/vdbe.h c63fad052c9e7388d551e556e119c0bcf6bebdf8 +F src/vdbeInt.h f5513f2b5ac1e2c5128996c7ea23add256a301df +F src/vdbeapi.c 24e40422382beb774daab11fe9fe9d37e8a04949 +F src/vdbeaux.c 25d62ef82cf1be2a1255eacac636fa0d943d8b3d +F src/vdbeblob.c 9205ce9d3b064d9600f8418a897fc88b5687d9ac +F src/vdbemem.c d90a1e8acf8b63dc9d14cbbea12bfec6cec31394 +F src/vdbesort.c f7f5563bf7d4695ca8f3203f3bf9de96d04ed0b3 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd -F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8 +F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45 -F src/where.c 7e56746cb33715baf3c2e78ea6216aaf7229a535 -F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138 +F src/where.c ab20f9c24a422ee8900831b343c3d1e5e7aca87b +F src/whereInt.h 923820bee9726033a501a08d2fc69b9c1ee4feb3 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783 -F test/alter.test e88dfa77e020c2b48e52a8020c70171ab828e079 +F test/alter.test 547dc2d292644301ac9a7dda22b319b74f9c08d2 F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060 F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d F test/alter4.test d6c011fa0d6227abba762498cafbb607c9609e93 F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4 -F test/analyze3.test 412f690dfe95b337475e3e78a84a85d25f6f125d +F test/analyze3.test bf41f0f680dd1e0d44eed5e769531e93a5320275 F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213 F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4 -F test/analyze6.test d31defa011a561b938b4608d3538c1b4e0b5e92c +F test/analyze6.test f1c552ce39cca4ec922a7e4e0e5d0203d6b3281f F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88 -F test/analyze9.test e072a5172d55afcba98d6ca6a219ce8878c2f5c9 +F test/analyze9.test 3ef1b471247308e710a794b6e50a6ab536c5604b F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944 F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d +F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93 F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7 @@ -329,11 +335,13 @@ F test/auth.test 5bdf154eb28c0e4bbc0473f335858c0d96171768 F test/auth2.test c3b415b76c033bedb81292118fb7c01f5f10cbcd F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 F test/autoinc.test c58912526998a39e11f66b533e23cfabea7f25b7 -F test/autoindex1.test d4dfe14001dfcb74cfbd7107f45a79fc1ab6183e +F test/autoindex1.test 762ff3f8e25d852aae55c6462ca166a80c0cde61 +F test/autoindex2.test 60d2fc6f38364308ce73a9beb01b47ded38697de +F test/autoindex3.test 8254f689c3241081fad52b7bea18ba53e07e14a2 F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 -F test/backcompat.test 5f8ad58b3eaebc78cd2c66c65476a42e6f32b2ad +F test/backcompat.test 19a1f337c68419b020a7481dd272a472c4ad8ef4 F test/backup.test c9cdd23a495864b9edf75a9fa66f5cb7e10fcf62 F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf F test/backup4.test 2a2e4a64388090b152de753fd9e123f28f6a3bd4 @@ -365,7 +373,7 @@ F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738 F test/capi3.test 71bcf2fbd36a9732f617766dfd752552c8e491b5 F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 F test/capi3c.test a21869e4d50d5dbb7e566e328fc0bc7c2efa6a32 -F test/capi3d.test 6d0fc0a86d73f42dd19a7d8b7761ab9bc02277d0 +F test/capi3d.test c84af0c49267f9c3fbf4c1c46aa647646023811e F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 F test/check.test 5831ddb6f2c687782eaf2e1a07b6e17f24c4f763 @@ -403,9 +411,10 @@ F test/corruptC.test 02405cf7ed0c1e989060e1aab6d02ffbc3906fbb F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040 F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4 -F test/corruptG.test 58ec333a01997fe655e34e5bea52b7a2a6b9704d +F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804 F test/corruptH.test 88ed71a086e13591c917aac6de32750e7c7281cb -F test/corruptI.test 1b796461e5b635e0a74e3c4ecb1121c82d319dff +F test/corruptI.test 0afbba50bfae006094cc548b4605f521c1179502 +F test/cost.test 19d314526616ce4473eb4e4e450fcb94499ce318 F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5 F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62 F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f @@ -431,16 +440,16 @@ F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240 F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2 F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e -F test/distinct.test c7b194ef95dbddb32d77acbbab2e023c6eed0cb2 +F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 -F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada +F test/e_createtable.test 181653f6f45e3adde73f8686600ce5ad7515466b F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412 F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306 -F test/e_expr.test 5c71d183fbf519a4769fd2e2124afdc70b5b1f42 -F test/e_fkey.test 630597377549af579d34faaf64c6959a5a68ef76 +F test/e_expr.test 8f5fdd7261e2d746813b0c6a1c0e34824ad3c5ad +F test/e_fkey.test a1783fe1f759e1990e6a11adfcf0702dac4d0707 F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459 -F test/e_insert.test 1e44f84d2abe44d66e4fbf198be4b20e3cc724a0 +F test/e_insert.test 7b2fa9cd1456f83474d6c5d27db3abaeb8be2023 F test/e_reindex.test 396b7b4f0a66863b4e95116a67d93b227193e589 F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6 F test/e_select.test 52692ff3849541e828ad4661fe3773a9b8711763 @@ -452,7 +461,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473 F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40 F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020 -F test/eqp.test 57c6c604c2807fb5531731c5323133453c24afac +F test/eqp.test 85873fa5816c48915c82c4e74cb5c35a5b48160f F test/errmsg.test f31592a594b44ee121371d25ddd5d63497bb3401 F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3 F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75 @@ -460,6 +469,7 @@ F test/exclusive2.test 32798111aae78a5deec980eee383213f189df308 F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30 F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d +F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9 F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7 F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146 @@ -523,7 +533,7 @@ F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8 F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18 -F test/fts3ao.test 71b0675e3df5c512a5a03daaa95ee1916de23dda +F test/fts3ao.test 3e4e3d5e75c076520341d0bdf4eb17c00e8cbde2 F test/fts3atoken.test fca30fd86db9241d571c637751e9a8a2f50f1451 F test/fts3auto.test b981fea19b132b4e6878f50d7c1f369b28f68eb9 F test/fts3aux1.test f8f287a4a73f381f8fa15b6a70f36245f903d221 @@ -535,15 +545,16 @@ F test/fts3conf.test ee8500c86dd58ec075e8831a1e216a79989436de F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 -F test/fts3d.test c8a193513a269ec4c205ca09645e26e0bc71b860 +F test/fts3d.test 95c17d1b67b33a5eac0bf5a0d11116a0c0ac7a3a F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963 -F test/fts3defer2.test a3b6cbeabaf28c9398652a4d101ea224d9358479 +F test/fts3defer2.test e880e3b65bdf999f4746cdaefa65f14a98b9b724 F test/fts3defer3.test dd53fc13223c6d8264a98244e9b19abd35ed71cd F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297 F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851 -F test/fts3expr.test 06f1a96facc8f3e4b1ad5cc001dc5c8e83e68b9f +F test/fts3expr.test 3401d47b229c4504424caf362cc4ff704cad4162 F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a F test/fts3expr3.test 9e91b8edbcb197bf2e92161aa7696446d96dce5f +F test/fts3expr4.test 0713d94ab951ed88a8c3629a4889a48c55c4067c F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660 F test/fts3fault2.test 3198eef2804deea7cac8403e771d9cbcb752d887 F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641 @@ -562,25 +573,27 @@ F test/fts3tok1.test c551043de056b0b1582a54e878991f57bad074bc F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d F test/fts3varint.test 752c08ed5d32c5d7dc211b056f4ed68a76b7e36e F test/fts4aa.test 0c3152322c7f0b548cc942ad763eaba0da87ccca -F test/fts4check.test 66fa274cab2b615f2fb338b257713aba8fad88a8 +F test/fts4check.test 74d77f6cdb768ac49df5afda575cef14ae3d239a F test/fts4content.test 2e7252557d6d24afa101d9ba1de710d6140e6d06 F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01 +F test/fts4growth.test df10fde9f47cf5c71861e63fd8efcd573c4f7e53 +F test/fts4growth2.test 2f063be1902a73cd087355837c52fed42ac11a5d F test/fts4incr.test 361960ed3550e781f3f313e17e2182ef9cefc0e9 F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7 F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891 F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7 -F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584 -F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057 +F test/fts4merge4.test d895b1057a7798b67e03455d0fa50e9ea836c47b +F test/fts4noti.test 524807f0c36d49deea7920cdd4cd687408b58849 F test/fts4unicode.test 01ec3fe2a7c3cfff3b4c0581b83caa11b33efa36 F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d -F test/func.test a21814945d32137412b553d98ad2107f9b2173a9 +F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f -F test/func3.test dbccee9133cfef1473c59ec07b5f0262b9d72f9a +F test/func3.test d202a7606d23f90988a664e88e268aed1087c11c F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f F test/func5.test cdd224400bc3e48d891827cc913a57051a426fa4 F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74 -F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6 +F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1 F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167 F test/fuzz3.test efd384b896c647b61a2c1848ba70d42aad60a7b3 F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b @@ -588,18 +601,19 @@ F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26 F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36 F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536 F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98 +F test/hexlit.test f9ecde8145bfc2341573473256c74ae37a200497 F test/hook.test 162d7cef7a2d2b04839fe14402934e6a1b79442f F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 -F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617 +F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068 F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3 F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328 F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600 F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4 F test/incrblob4.test f26502a5697893e5acea268c910f16478c2f0fab -F test/incrblob_err.test d2562d2771ebffd4b3af89ef64c140dd44371597 +F test/incrblob_err.test af1f12ba60d220c9752073ff2bda2ad59e88960d F test/incrblobfault.test 280474078f6da9e732cd2a215d3d854969014b6e F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32 F test/incrvacuum2.test 379eeb8740b0ef60c372c439ad4cbea20b34bb9b @@ -610,12 +624,12 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index3.test 55a90cff99834305e8141df7afaef39674b57062 F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33 -F test/index6.test 936979c3a1e87b81feaed2d00505665bf142d764 +F test/index6.test fb370966ac3cd0989053dd5385757b5c3e24ab6a F test/index7.test a3baf9a625bda7fd49471e99aeae04095fbfeecf F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 -F test/insert.test acf909b067b838eb55338d619e800e148c17f1f5 +F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371 F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30 F test/insert4.test 4791662c50518bdd37d394cae9a7a8014e845bb3 @@ -631,7 +645,7 @@ F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b -F test/join.test 559b81eb56ae350246f9c25986aa52c81c725c7e +F test/join.test 52d4d49f86d0cf46926672878c4eaf0da399104a F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 @@ -648,7 +662,7 @@ F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 F test/like.test e191e536d0fcd722a6b965e7cd1ee0bfd12a5991 F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da -F test/limit.test cc0ab63385239b63c72452b0e93700bf5e8f0b99 +F test/limit.test 3d7df19c35ac672a11f7de406cd3205d592babbb F test/loadext.test 648cb95f324d1775c54a55c12271b2d1156b633b F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7 F test/lock.test 87af515b0c4cf928576d0f89946d67d7c265dfb4 @@ -662,7 +676,7 @@ F test/lock_common.tcl 0c270b121d40959fa2f3add382200c27045b3d95 F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2 F test/main.test 39c4bb8a157f57298ed1659d6df89d9f35aaf2c8 F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9 -F test/malloc.test fd368e31fe98d4779ed80442f311ed9f03bcd1f7 +F test/malloc.test 4eb83876dfe4915766c179b687b8640437f14abf F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a F test/malloc4.test 957337613002b7058a85116493a262f679f3a261 F test/malloc5.test fafce0aa9157060445cd1a56ad50fc79d82f28c3 @@ -681,8 +695,9 @@ F test/mallocG.test 0ff91b65c50bdaba680fb75d87fe4ad35bb7934f F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6 F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e -F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9 -F test/malloc_common.tcl 58e54229c4132ef882a11fab6419ec4cd3073589 +F test/mallocK.test 3cff7c0f64735f6883bacdd294e45a6ed5714817 +F test/mallocL.test 252ddc7eb4fbf75364eab17b938816085ff1fc17 +F test/malloc_common.tcl 3663f9001ce3e29bbaa9677ffe15cd468e3ec7e3 F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f F test/memdb.test fcb5297b321b562084fc79d64d5a12a1cd2b639b @@ -693,7 +708,7 @@ F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax4.test 536a3360470633a177e42fbc19660d146b51daef -F test/misc1.test 441a0fafc7087f841db09fbfca54e7aea9f5a84c +F test/misc1.test 1201a037c24f982cc0e956cdaa34fcaf6439c417 F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 @@ -705,12 +720,13 @@ F test/mmap1.test 93d167b328255cbe6679fe1e1a23be1b1197d07b F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3 -F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256 +F test/multiplex.test efd015ca0b5b4a57dc9535b8feb1273eebeadb60 F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41 F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660 F test/nan.test e9648b9d007c7045242af35e11a984d4b169443a +F test/nolock.test 0540dd96f39b8876e3ffdd8814fad0ea425efeee F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf F test/notify2.test ce23eb522c9e1fff6443f96376fe67872202061c F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934 @@ -718,11 +734,13 @@ F test/notnull.test f8fcf58669ddba79274daa2770d61dfad8274f62 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 -F test/orderby1.test 9b524aff9147288da43a6d7ddfdcff47fa2303c6 +F test/orderby1.test 12426f99518cde45f34215ca6a0ebc0e9bc5c77a F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04 F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99 F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4 -F test/orderby5.test 0eb82d5890c3f3d0563966560cfdc984ea69e30c +F test/orderby5.test 8f08a54836d21fb7c70245360751aedd1c2286fb +F test/orderby6.test 8b38138ab0972588240b3fca0985d2e400432859 +F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3 F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71 @@ -736,8 +754,8 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54 -F test/permutations.test 40add071ba71aefe1c04f5845308cf46f7de8d04 -F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0 +F test/permutations.test bc474bafb022cc5014ef3a9c3d5ab61d6d6f587c +F test/pragma.test 19d0241a007bcdd77fc2606ec60fc60357e7fc8b F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1 @@ -751,11 +769,11 @@ F test/quota2.test 7dc12e08b11cbc4c16c9ba2aa2e040ea8d8ab4b8 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df -F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d +F test/rdonly.test dd30a4858d8e0fbad2304c2bd74a33d4df36412a F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a -F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce +F test/releasetest.tcl a0df0dfc5e3ee83ade87b9cc96db41b52d590b9e F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a F test/rollback.test e9504a009a202c3ed711da2e6879ff60c5a4669c F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 @@ -785,7 +803,7 @@ F test/select6.test e76bd10a56988f15726c097a5d5a7966fe82d3b2 F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95 -F test/selectA.test 77adaffe9704cb80e301ebaeff4b107b58d435c5 +F test/selectA.test 64b88a80271c1710966e50e633380696b60a12a4 F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25 F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977 F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394 @@ -803,16 +821,18 @@ F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21 F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5 F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 -F test/shell1.test f2a1d471e5cd2b42f7a65b166dc1ace2b8d11583 +F test/shell1.test d60946b5fde4d85fe06db7331dfe89011f564350 F test/shell2.test c57da3a381c099b02c813ba156298d5c2f5c93a3 F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29 -F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9 -F test/shell5.test bb755ea9144b8078a752fc56223582627070b5f1 +F test/shell4.test 8a9c08976291e6c6c808b4d718f4a8b299f339f5 +F test/shell5.test 15a419cc1df21c892ed64f5596ae7a501f2816f2 F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 +F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5 F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868 F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 -F test/skipscan1.test bed8cbe9d554c8c27afb6c88500f704c86a9196f -F test/skipscan2.test 5a4db0799c338ddbacb154aaa5589c0254b36a8d +F test/skipscan1.test 28c7faa41a0d7265040ecb0a0abd90c0904270b2 +F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a +F test/skipscan5.test d8b9692b702745a0e41c23f9da6beac81df01196 F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5 @@ -824,7 +844,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523 F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715 F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b -F test/speedtest1.c 1603da7b4897716f9df15bd71b0310f56ec3181e +F test/speedtest1.c d29c8048beb7ea9254191f3fde9414709166a920 F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298 F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de @@ -835,16 +855,16 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4 F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85 -F test/syscall.test a653783d985108c4912cc64d341ffbbb55ad2806 +F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6 -F test/table.test 580d23530187026d4502fae74a490f0408cf2cc7 +F test/table.test 2a1d2fa52c531de5915f28023747d9a8c27b6f31 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 -F test/tester.tcl f31bea1483ea1d39620f982130026e76f872d744 +F test/tester.tcl b4ff83a8b069633f4aca788236d10a7086112a49 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -882,18 +902,21 @@ F test/tkt-78e04e52ea.test 813779f8888f3ca226df656c4eef078f9635f3c9 F test/tkt-7a31705a7e6.test e75a2bba4eec801b92c8040eb22096ac6d35e844 F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18 F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8 -F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7 +F test/tkt-80e031a00f.test f50046f474ecf67ad5c50cd9200da04ff887d7cd F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356 F test/tkt-8c63ff0ec.test 258b7fc8d7e4e1cb5362c7d65c143528b9c4cbed F test/tkt-91e2e8ba6f.test 08c4f94ae07696b05c9b822da0b4e5337a2f54c5 F test/tkt-94c04eaadb.test f738c57c7f68ab8be1c054415af7774617cb6223 +F test/tkt-9a8b09f8e6.test b2ef151d0984b2ebf237760dbeaa50724e5a0667 F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67 F test/tkt-9f2eb3abac.test 85bc63e749f050e6a61c8f9207f1eee65c9d3395 F test/tkt-a7b7803e.test 159ef554234fa1f9fb318c751b284bd1cf858da4 +F test/tkt-a8a0d2996a.test eb597379dbcefa24765763d7f682c00cb5924fa9 F test/tkt-b1d3a2e531.test 8f7576e41ca179289ee1a8fee28386fd8e4b0550 F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0 F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3 +F test/tkt-b75a9ca6b0.test 97cc2d5eeaf82799eb42138c0a1ff64370238ce4 F test/tkt-bd484a090c.test 60460bf946f79a79712b71f202eda501ca99b898 F test/tkt-bdc6bbbb38.test fc38bb09bdd440e3513a1f5f98fc60a075182d7d F test/tkt-c48d99d690.test ba61977d62ab612fc515b3c488a6fbd6464a2447 @@ -902,6 +925,7 @@ F test/tkt-d11f09d36e.test d999b548fef885d1d1afa49a0e8544ecf436869d F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09 F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30 F test/tkt-f3e5abed55.test d5a0126118142d13e27f6ce9f4c47096e9321c00 +F test/tkt-f67b41381a.test a23bc124c981662db712167bacd0ed8ad11abac9 F test/tkt-f777251dc7a.test af6531446c64bfd268416f07b4df7be7f9c749d2 F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7 F test/tkt-f973c7ac31.test 28ef85c7f015477916795246d8286aeda39d4ead @@ -992,9 +1016,9 @@ F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1 F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7 -F test/tpch01.test 8f4ac52f62f3e9f6bce0889105aecdf0275e331b +F test/tpch01.test 04adbf8d8300fa60a222f28d901abd76e7be6dd4 F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5 -F test/trace2.test e7a988fdd982cdec62f1f1f34b0360e6476d01a0 +F test/trace2.test 93b47ca6996c66b47f57224cfb146f34e07df382 F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6 F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76 F test/trans3.test 373ac5183cc56be69f48ae44090e7f672939f732 @@ -1018,8 +1042,9 @@ F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264 +F test/unique2.test 41e7f83c6827605991160a31380148a9fc5f1339 F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825 -F test/unordered.test ef85ac8f2f3c93ed2b9e811b684de73175fc464c +F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8 F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae @@ -1047,13 +1072,14 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61 F test/vtabF.test fd5ad376f5a34fe0891df1f3cddb4fe7c3eb077e F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 -F test/vtab_shared.test 6acafaae7126c9f49be72c2f57eb8bef3024f1cb -F test/wal.test 40073e54359d43354925b2b700b7eebd5e207285 -F test/wal2.test a8e3963abf6b232cf0b852b09b53665ef34007af +F test/vtab_shared.test ea8778d5b0df200adef2ca7c00c3c37d4375f772 +F test/wal.test 885f32b2b390b30b4aa3dbb0e568f8f78d40f5cc +F test/wal2.test 1f841d2048080d32f552942e333fd99ce541dada F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0 F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c F test/wal5.test 8f888b50f66b78821e61ed0e233ded5de378224b F test/wal6.test 527581f5527bf9c24394991e2be83000aace5f9e +F test/wal64k.test 163655ecd2cb8afef4737cac2a40fdd2eeaf20b8 F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd F test/wal8.test 75c42e1bc4545c277fed212f8fc9b7723cd02216 F test/wal9.test 378e76a9ad09cd9bee06c172ad3547b0129a6750 @@ -1074,31 +1100,34 @@ F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417 F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e F test/where.test 28b64e93428961b07b0d486778d63fd672948f6b -F test/where2.test 455a2eb2666e66c1e84e2cb5815173a85e6237db -F test/where3.test d28c51f257e60be30f74308fa385ceeddfb54a6e +F test/where2.test 23fdb5d8e756554aad4ca7ae03de9dd8367a2c6e +F test/where3.test 1ad55ba900bd7747f98b6082e65bd3e442c5004e F test/where4.test d8420ceeb8323a41ceff1f1841fc528e824e1ecf F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8 F test/where8.test 806f1dcec4088be2b826b33f757fe6e17c3236a1 F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739 -F test/where9.test 4f3eab951353a3ae164befc521c777dfa903e46c +F test/where9.test 729c3ba9b47e8f9f1aab96bae7dad2a524f1d1a2 F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a -F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62 +F test/whereD.test fd9120e262f9da3c45940f52aefeef4d15b904e5 F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7 -F test/whereG.test 2a3d5181decc801b36600fa1c40b0dad2ccc267f +F test/whereG.test 69f5ec4b15760a8c860f80e2d55525669390aab3 +F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2 +F test/whereI.test 1d89199697919d4930be05a71e7fe620f114e622 +F test/whereJ.test 35a40a50d0e13aa6b0de7cc5d4b204e5f9f9669f F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c -F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361 +F test/win32lock.test 71642fa56e9b06e5cfffe6bad67cb8c1eb2c555a F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d F test/with1.test 268081a6b14817a262ced4d0ee34d4d2a1dd2068 -F test/with2.test 2fe78fcd8deef2a0f9cfc49bfc755911d0b3fd64 +F test/with2.test ee227a663586aa09771cafd4fa269c5217eaf775 F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991 -F test/without_rowid1.test e00a0a9dc9f0be651f011d61e8a32b7add5afb30 +F test/without_rowid1.test 7862e605753c8d25329f665fa09072e842183151 F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99 F test/without_rowid3.test eac3d5c8a1924725b58503a368f2cbd24fd6c8a0 F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a @@ -1106,7 +1135,7 @@ F test/without_rowid5.test b4a639a367f04d382d20e8f44fc1be4f2d57d107 F test/wordcount.c 9915e06cb33d8ca8109b8700791afe80d305afda F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F test/zerodamage.test cf6748bad89553cc1632be51a6f54e487e4039ac -F tool/build-all-msvc.bat e0917e787df675b020d250d60a00de8abaa4e30a x +F tool/build-all-msvc.bat a0534c971b86fe95f1983f445db5b896d3394818 x F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367 F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2 F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b @@ -1116,28 +1145,29 @@ F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce -F tool/lemon.c 07aba6270d5a5016ba8107b09e431eea4ecdc123 +F tool/lemon.c 3ff0fec22f92dfb54e62eeb48772eddffdbeb0d6 F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc -F tool/logest.c 7ad625cac3d54012b27d468b7af6612f78b9ba75 +F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/mkautoconfamal.sh f8d8dbf7d62f409ebed5134998bf5b51d7266383 -F tool/mkkeywordhash.c c9e05e4a7bcab8fab9f583d5b321fb72f565ad97 +F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e F tool/mkpragmatab.tcl 78a77b2c554d534c6f2dc903130186ed15715460 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 -F tool/mksqlite3c-noext.tcl 8bce31074e4cbe631bb7676526a048335f4c9f02 -F tool/mksqlite3c.tcl ed5b4e9ca8bf209ff401059a16362f37710fd8b8 +F tool/mksqlite3c-noext.tcl 1712d3d71256ca1f297046619c89e77a4d7c8f6d +F tool/mksqlite3c.tcl ba274df71f5e6534b0a913c7c48eabfcbd0934b6 F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12 -F tool/mksqlite3internalh.tcl 3dca7bb5374cee003379b8cbac73714f610ef795 -F tool/mkvsix.tcl 6477fb9dab838b7eea1eed50658ff1cda04850b5 +F tool/mksqlite3internalh.tcl b6514145a7d5321b47e64e19b8116cc44f973eb1 +F tool/mkvsix.tcl 52a4c613707ac34ae9c226e5ccc69cb948556105 F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091 F tool/omittest.tcl 34d7ac01fe4fd18e3637f64abe12c40eca0f6b97 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/showdb.c 1f3fe634d6f690b8d39ab1b9fd34583d468921e1 -F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02 -F tool/showwal.c 3f7f7da5ec0cba51b1449a75f700493377da57b5 +F tool/showdb.c b9ee6b6c81a094bf33badbf7e9da34cdbc0cce25 +F tool/showjournal.c 053eb1cc774710c6890b7dd6293300cc297b16a5 +F tool/showstat4.c c39279d6bd37cb999b634f0064f6f86ad7af008f +F tool/showwal.c 3209120269cdf9380f091459e47b776b4f81dfd3 F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b F tool/spaceanal.tcl 8e50b217c56a6a086a1b47eac9d09c5cd65b996f @@ -1154,12 +1184,12 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891 F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 -F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 -F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P f05a49b6e006475c5b2678a1195bf67c6f2f07a4 -R d2e6a9f3fa74174124bde3b843da1650 +F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 +F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f +P 3f45b8192dad7fb1f027cbaa694046e3c1b3e278 +R be8bb3bca247e348b90f7388fee24972 T +bgcolor * #d0c0ff T +sym-release * -T +sym-version-3.8.4.3 * +T +sym-version-3.8.6 * U drh -Z 9dec8c048dfa23d9d6583a61b396f9d3 +Z 74d8dd4d4aac0ae87245b4bcefd8b172 diff --git a/manifest.uuid b/manifest.uuid index f9539f2..910d8f9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a611fa96c4a848614efe899130359c9f6fb889c3 +9491ba7d738528f168657adb43a198238abde19e diff --git a/src/alter.c b/src/alter.c index 1a83e57..64204b7 100644 --- a/src/alter.c +++ b/src/alter.c @@ -116,6 +116,7 @@ static void renameParentFunc( int token; /* Type of token */ UNUSED_PARAMETER(NotUsed); + if( zInput==0 || zOld==0 ) return; for(z=zInput; *z; z=z+n){ n = sqlite3GetToken(z, &token); if( token==TK_REFERENCES ){ diff --git a/src/analyze.c b/src/analyze.c index 2a03e29..f9c03dc 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -246,6 +246,7 @@ static void openStatTable( assert( i1 ); /* >1 because it includes the rowid column */ + assert( nCol>0 ); nColUp = sizeof(tRowcnt)<8 ? (nCol+1)&~1 : nCol; + nKeyCol = sqlite3_value_int(argv[1]); + assert( nKeyCol<=nCol ); + assert( nKeyCol>0 ); /* Allocate the space required for the Stat4Accum object */ n = sizeof(*p) @@ -415,6 +434,7 @@ static void statInit( p->db = db; p->nRow = 0; p->nCol = nCol; + p->nKeyCol = nKeyCol; p->current.anDLt = (tRowcnt*)&p[1]; p->current.anEq = &p->current.anDLt[nColUp]; @@ -425,9 +445,9 @@ static void statInit( p->iGet = -1; p->mxSample = mxSample; - p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[1])/(mxSample/3+1) + 1); + p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1); p->current.anLt = &p->current.anEq[nColUp]; - p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[1])*0xd0944565; + p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[2])*0xd0944565; /* Set up the Stat4Accum.a[] and aBest[] arrays */ p->a = (struct Stat4Sample*)&p->current.anLt[nColUp]; @@ -450,7 +470,7 @@ static void statInit( sqlite3_result_blob(context, p, sizeof(p), stat4Destructor); } static const FuncDef statInitFuncdef = { - 1+IsStat34, /* nArg */ + 2+IsStat34, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ @@ -674,7 +694,10 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){ ** R Rowid for the current row. Might be a key record for ** WITHOUT ROWID tables. ** -** The SQL function always returns NULL. +** This SQL function always returns NULL. It's purpose it to accumulate +** statistical data and/or samples in the Stat4Accum object about the +** index being analyzed. The stat_get() SQL function will later be used to +** extract relevant information for constructing the sqlite_statN tables. ** ** The R parameter is only used for STAT3 and STAT4 */ @@ -691,7 +714,7 @@ static void statPush( UNUSED_PARAMETER( argc ); UNUSED_PARAMETER( context ); - assert( p->nCol>1 ); /* Includes rowid field */ + assert( p->nCol>0 ); assert( iChngnCol ); if( p->nRow==0 ){ @@ -768,7 +791,10 @@ static const FuncDef statPushFuncdef = { /* ** Implementation of the stat_get(P,J) SQL function. This routine is -** used to query the results. Content is returned for parameter J +** used to query statistical information that has been gathered into +** the Stat4Accum object by prior calls to stat_push(). The P parameter +** is a BLOB which is decoded into a pointer to the Stat4Accum objects. +** The content to returned is determined by the parameter J ** which is one of the STAT_GET_xxxx values defined above. ** ** If neither STAT3 nor STAT4 are enabled, then J is always @@ -819,7 +845,7 @@ static void statGet( char *z; int i; - char *zRet = sqlite3MallocZero(p->nCol * 25); + char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 ); if( zRet==0 ){ sqlite3_result_error_nomem(context); return; @@ -827,7 +853,7 @@ static void statGet( sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow); z = zRet + sqlite3Strlen30(zRet); - for(i=0; i<(p->nCol-1); i++){ + for(i=0; inKeyCol; i++){ u64 nDistinct = p->current.anDLt[i] + 1; u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; sqlite3_snprintf(24, z, " %llu", iVal); @@ -987,27 +1013,27 @@ static void analyzeOneTable( sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - int nCol; /* Number of columns indexed by pIdx */ - int *aGotoChng; /* Array of jump instruction addresses */ + int nCol; /* Number of columns in pIdx. "N" */ int addrRewind; /* Address of "OP_Rewind iIdxCur" */ - int addrGotoChng0; /* Address of "Goto addr_chng_0" */ int addrNextRow; /* Address of "next_row:" */ const char *zIdxName; /* Name of the index */ + int nColTest; /* Number of columns to test for changes */ if( pOnlyIdx && pOnlyIdx!=pIdx ) continue; if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0; - VdbeNoopComment((v, "Begin analysis of %s", pIdx->zName)); - nCol = pIdx->nKeyCol; - aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*(nCol+1)); - if( aGotoChng==0 ) continue; + if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIdx) ){ + nCol = pIdx->nKeyCol; + zIdxName = pTab->zName; + nColTest = nCol - 1; + }else{ + nCol = pIdx->nColumn; + zIdxName = pIdx->zName; + nColTest = pIdx->uniqNotNull ? pIdx->nKeyCol-1 : nCol-1; + } /* Populate the register containing the index name. */ - if( pIdx->autoIndex==2 && !HasRowid(pTab) ){ - zIdxName = pTab->zName; - }else{ - zIdxName = pIdx->zName; - } sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, zIdxName, 0); + VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName)); /* ** Pseudo-code for loop that calls stat_push(): @@ -1032,7 +1058,7 @@ static void analyzeOneTable( ** regPrev(1) = idx(1) ** ... ** - ** chng_addr_N: + ** endDistinctTest: ** regRowid = idx(rowid) ** stat_push(P, regChng, regRowid) ** Next csr @@ -1045,7 +1071,7 @@ static void analyzeOneTable( ** the regPrev array and a trailing rowid (the rowid slot is required ** when building a record to insert into the sample column of ** the sqlite_stat4 table. */ - pParse->nMem = MAX(pParse->nMem, regPrev+nCol); + pParse->nMem = MAX(pParse->nMem, regPrev+nColTest); /* Open a read-only cursor on the index being analyzed. */ assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) ); @@ -1055,18 +1081,22 @@ static void analyzeOneTable( /* Invoke the stat_init() function. The arguments are: ** - ** (1) the number of columns in the index including the rowid, - ** (2) the number of rows in the index, + ** (1) the number of columns in the index including the rowid + ** (or for a WITHOUT ROWID table, the number of PK columns), + ** (2) the number of columns in the key without the rowid/pk + ** (3) the number of rows in the index, ** - ** The second argument is only used for STAT3 and STAT4 + ** + ** The third argument is only used for STAT3 and STAT4 */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+2); + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3); #endif - sqlite3VdbeAddOp2(v, OP_Integer, nCol+1, regStat4+1); + sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1); + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2); sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4+1, regStat4); sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, 1+IsStat34); + sqlite3VdbeChangeP5(v, 2+IsStat34); /* Implementation of the following: ** @@ -1079,44 +1109,62 @@ static void analyzeOneTable( addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng); - addrGotoChng0 = sqlite3VdbeAddOp0(v, OP_Goto); - - /* - ** next_row: - ** regChng = 0 - ** if( idx(0) != regPrev(0) ) goto chng_addr_0 - ** regChng = 1 - ** if( idx(1) != regPrev(1) ) goto chng_addr_1 - ** ... - ** regChng = N - ** goto chng_addr_N - */ addrNextRow = sqlite3VdbeCurrentAddr(v); - for(i=0; iazColl[i]); - sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); - sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp); - aGotoChng[i] = - sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ); - sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); - VdbeCoverage(v); - } - sqlite3VdbeAddOp2(v, OP_Integer, nCol, regChng); - aGotoChng[nCol] = sqlite3VdbeAddOp0(v, OP_Goto); - /* - ** chng_addr_0: - ** regPrev(0) = idx(0) - ** chng_addr_1: - ** regPrev(1) = idx(1) - ** ... - */ - sqlite3VdbeJumpHere(v, addrGotoChng0); - for(i=0; i0 ){ + int endDistinctTest = sqlite3VdbeMakeLabel(v); + int *aGotoChng; /* Array of jump instruction addresses */ + aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*nColTest); + if( aGotoChng==0 ) continue; + /* + ** next_row: + ** regChng = 0 + ** if( idx(0) != regPrev(0) ) goto chng_addr_0 + ** regChng = 1 + ** if( idx(1) != regPrev(1) ) goto chng_addr_1 + ** ... + ** regChng = N + ** goto endDistinctTest + */ + sqlite3VdbeAddOp0(v, OP_Goto); + addrNextRow = sqlite3VdbeCurrentAddr(v); + if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){ + /* For a single-column UNIQUE index, once we have found a non-NULL + ** row, we know that all the rest will be distinct, so skip + ** subsequent distinctness tests. */ + sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest); + VdbeCoverage(v); + } + for(i=0; iazColl[i]); + sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp); + aGotoChng[i] = + sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + VdbeCoverage(v); + } + sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng); + sqlite3VdbeAddOp2(v, OP_Goto, 0, endDistinctTest); + + + /* + ** chng_addr_0: + ** regPrev(0) = idx(0) + ** chng_addr_1: + ** regPrev(1) = idx(1) + ** ... + */ + sqlite3VdbeJumpHere(v, addrNextRow-1); + for(i=0; inMem = MAX(pParse->nMem, regCol+nCol+1); + pParse->nMem = MAX(pParse->nMem, regCol+nCol); addrNext = sqlite3VdbeCurrentAddr(v); callStatGet(v, regStat4, STAT_GET_ROWID, regSampleRowid); @@ -1190,7 +1237,7 @@ static void analyzeOneTable( i16 iCol = pIdx->aiColumn[i]; sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i); } - sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol+1, regSample); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample); #endif sqlite3VdbeAddOp3(v, OP_MakeRecord, regTabname, 6, regTemp); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid); @@ -1202,7 +1249,6 @@ static void analyzeOneTable( /* End of analysis */ sqlite3VdbeJumpHere(v, addrRewind); - sqlite3DbFree(db, aGotoChng); } @@ -1303,6 +1349,7 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ Table *pTab; Index *pIdx; Token *pTableName; + Vdbe *v; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ @@ -1350,6 +1397,8 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ } } } + v = sqlite3GetVdbe(pParse); + if( v ) sqlite3VdbeAddOp0(v, OP_Expire); } /* @@ -1371,6 +1420,7 @@ static void decodeIntArray( char *zIntArray, /* String containing int array to decode */ int nOut, /* Number of slots in aOut[] */ tRowcnt *aOut, /* Store integers here */ + LogEst *aLog, /* Or, if aOut==0, here */ Index *pIndex /* Handle extra flags for this index, if not NULL */ ){ char *z = zIntArray; @@ -1389,7 +1439,17 @@ static void decodeIntArray( v = v*10 + c - '0'; z++; } - aOut[i] = v; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( aOut ){ + aOut[i] = v; + }else +#else + assert( aOut==0 ); + UNUSED_PARAMETER(aOut); +#endif + { + aLog[i] = sqlite3LogEst(v); + } if( *z==' ' ) z++; } #ifndef SQLITE_ENABLE_STAT3_OR_STAT4 @@ -1397,14 +1457,19 @@ static void decodeIntArray( #else if( pIndex ) #endif - { - if( strcmp(z, "unordered")==0 ){ + while( z[0] ){ + if( sqlite3_strglob("unordered*", z)==0 ){ pIndex->bUnordered = 1; }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){ - int v32 = 0; - sqlite3GetInt32(z+3, &v32); - pIndex->szIdxRow = sqlite3LogEst(v32); + pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3)); } +#ifdef SQLITE_ENABLE_COSTMULT + else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){ + pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9)); + } +#endif + while( z[0]!=0 && z[0]!=' ' ) z++; + while( z[0]==' ' ) z++; } } @@ -1445,12 +1510,16 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ z = argv[2]; if( pIndex ){ - decodeIntArray((char*)z, pIndex->nKeyCol+1, pIndex->aiRowEst, pIndex); - if( pIndex->pPartIdxWhere==0 ) pTable->nRowEst = pIndex->aiRowEst[0]; + pIndex->bUnordered = 0; + decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex); + if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0]; }else{ Index fakeIdx; fakeIdx.szIdxRow = pTable->szTabRow; - decodeIntArray((char*)z, 1, &pTable->nRowEst, &fakeIdx); +#ifdef SQLITE_ENABLE_COSTMULT + fakeIdx.pTable = pTable; +#endif + decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx); pTable->szTabRow = fakeIdx.szIdxRow; } @@ -1491,7 +1560,16 @@ static void initAvgEq(Index *pIdx){ IndexSample *aSample = pIdx->aSample; IndexSample *pFinal = &aSample[pIdx->nSample-1]; int iCol; - for(iCol=0; iColnKeyCol; iCol++){ + int nCol = 1; + if( pIdx->nSampleCol>1 ){ + /* If this is stat4 data, then calculate aAvgEq[] values for all + ** sample columns except the last. The last is always set to 1, as + ** once the trailing PK fields are considered all index keys are + ** unique. */ + nCol = pIdx->nSampleCol-1; + pIdx->aAvgEq[nCol] = 1; + } + for(iCol=0; iColaAvgEq[iCol] = avgEq; - if( pIdx->nSampleCol==1 ) break; } } } @@ -1573,7 +1650,6 @@ static int loadStatTbl( while( sqlite3_step(pStmt)==SQLITE_ROW ){ int nIdxCol = 1; /* Number of columns in stat4 records */ - int nAvgCol = 1; /* Number of entries in Index.aAvgEq */ char *zIndex; /* Index name */ Index *pIdx; /* Pointer to the index object */ @@ -1591,13 +1667,17 @@ static int loadStatTbl( ** loaded from the stat4 table. In this case ignore stat3 data. */ if( pIdx==0 || pIdx->nSample ) continue; if( bStat3==0 ){ - nIdxCol = pIdx->nKeyCol+1; - nAvgCol = pIdx->nKeyCol; + assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 ); + if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){ + nIdxCol = pIdx->nKeyCol; + }else{ + nIdxCol = pIdx->nColumn; + } } pIdx->nSampleCol = nIdxCol; nByte = sizeof(IndexSample) * nSample; nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample; - nByte += nAvgCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ + nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ pIdx->aSample = sqlite3DbMallocZero(db, nByte); if( pIdx->aSample==0 ){ @@ -1605,7 +1685,7 @@ static int loadStatTbl( return SQLITE_NOMEM; } pSpace = (tRowcnt*)&pIdx->aSample[nSample]; - pIdx->aAvgEq = pSpace; pSpace += nAvgCol; + pIdx->aAvgEq = pSpace; pSpace += nIdxCol; for(i=0; iaSample[i].anEq = pSpace; pSpace += nIdxCol; pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol; @@ -1642,9 +1722,9 @@ static int loadStatTbl( pPrevIdx = pIdx; } pSample = &pIdx->aSample[pIdx->nSample]; - decodeIntArray((char*)sqlite3_column_text(pStmt,1), nCol, pSample->anEq, 0); - decodeIntArray((char*)sqlite3_column_text(pStmt,2), nCol, pSample->anLt, 0); - decodeIntArray((char*)sqlite3_column_text(pStmt,3), nCol, pSample->anDLt,0); + decodeIntArray((char*)sqlite3_column_text(pStmt,1),nCol,pSample->anEq,0,0); + decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0); + decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0); /* Take a copy of the sample. Add two 0x00 bytes the end of the buffer. ** This is in case the sample record is corrupted. In that case, the diff --git a/src/btree.c b/src/btree.c index 29ead1c..60bc7de 100644 --- a/src/btree.c +++ b/src/btree.c @@ -162,7 +162,7 @@ static int hasSharedCacheTableLock( ** the correct locks are held. So do not bother - just return true. ** This case does not come up very often anyhow. */ - if( isIndex && (!pSchema || (pSchema->flags&DB_SchemaLoaded)==0) ){ + if( isIndex && (!pSchema || (pSchema->schemaFlags&DB_SchemaLoaded)==0) ){ return 1; } @@ -446,16 +446,11 @@ static int cursorHoldsMutex(BtCursor *p){ } #endif - -#ifndef SQLITE_OMIT_INCRBLOB /* -** Invalidate the overflow page-list cache for cursor pCur, if any. +** Invalidate the overflow cache of the cursor passed as the first argument. +** on the shared btree structure pBt. */ -static void invalidateOverflowCache(BtCursor *pCur){ - assert( cursorHoldsMutex(pCur) ); - sqlite3_free(pCur->aOverflow); - pCur->aOverflow = 0; -} +#define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl) /* ** Invalidate the overflow page-list cache for all cursors opened @@ -469,6 +464,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){ } } +#ifndef SQLITE_OMIT_INCRBLOB /* ** This function is called before modifying the contents of a table ** to invalidate any incrblob cursors that are open on the @@ -491,16 +487,14 @@ static void invalidateIncrblobCursors( BtShared *pBt = pBtree->pBt; assert( sqlite3BtreeHoldsMutex(pBtree) ); for(p=pBt->pCursor; p; p=p->pNext){ - if( p->isIncrblobHandle && (isClearTable || p->info.nKey==iRow) ){ + if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){ p->eState = CURSOR_INVALID; } } } #else - /* Stub functions when INCRBLOB is omitted */ - #define invalidateOverflowCache(x) - #define invalidateAllOverflowCache(x) + /* Stub function when INCRBLOB is omitted */ #define invalidateIncrblobCursors(x,y,z) #endif /* SQLITE_OMIT_INCRBLOB */ @@ -746,20 +740,32 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){ ** at is deleted out from under them. ** ** This routine returns an error code if something goes wrong. The -** integer *pHasMoved is set to one if the cursor has moved and 0 if not. +** integer *pHasMoved is set as follows: +** +** 0: The cursor is unchanged +** 1: The cursor is still pointing at the same row, but the pointers +** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch() +** might now be invalid because of a balance() or other change to the +** b-tree. +** 2: The cursor is no longer pointing to the row. The row might have +** been deleted out from under the cursor. */ int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){ int rc; + if( pCur->eState==CURSOR_VALID ){ + *pHasMoved = 0; + return SQLITE_OK; + } rc = restoreCursorPosition(pCur); if( rc ){ - *pHasMoved = 1; + *pHasMoved = 2; return rc; } if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){ - *pHasMoved = 1; + *pHasMoved = 2; }else{ - *pHasMoved = 0; + *pHasMoved = 1; } return SQLITE_OK; } @@ -1626,7 +1632,7 @@ static Pgno btreePagecount(BtShared *pBt){ u32 sqlite3BtreeLastPage(Btree *p){ assert( sqlite3BtreeHoldsMutex(p) ); assert( ((p->pBt->nPage)&0x8000000)==0 ); - return (int)btreePagecount(p->pBt); + return btreePagecount(p->pBt); } /* @@ -2161,6 +2167,7 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ return SQLITE_OK; } +#if SQLITE_MAX_MMAP_SIZE>0 /* ** Change the limit on the amount of the database file that may be ** memory mapped. @@ -2173,6 +2180,7 @@ int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){ sqlite3BtreeLeave(p); return SQLITE_OK; } +#endif /* SQLITE_MAX_MMAP_SIZE>0 */ /* ** Change the way data is synced to disk in order to increase or decrease @@ -2549,7 +2557,8 @@ static int countValidCursors(BtShared *pBt, int wrOnly){ BtCursor *pCur; int r = 0; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ - if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++; + if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0) + && pCur->eState!=CURSOR_FAULT ) r++; } return r; } @@ -3624,7 +3633,8 @@ static int btreeCursor( pCur->pKeyInfo = pKeyInfo; pCur->pBtree = p; pCur->pBt = pBt; - pCur->wrFlag = (u8)wrFlag; + assert( wrFlag==0 || wrFlag==BTCF_WriteFlag ); + pCur->curFlags = wrFlag; pCur->pNext = pBt->pCursor; if( pCur->pNext ){ pCur->pNext->pPrev = pCur; @@ -3694,7 +3704,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ releasePage(pCur->apPage[i]); } unlockBtreeIfUnused(pBt); - invalidateOverflowCache(pCur); + sqlite3DbFree(pBtree->db, pCur->aOverflow); /* sqlite3_free(pCur); */ sqlite3BtreeLeave(pBtree); } @@ -3733,7 +3743,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ if( pCur->info.nSize==0 ){ int iPage = pCur->iPage; btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); - pCur->validNKey = 1; + pCur->curFlags |= BTCF_ValidNKey; }else{ assertCellInfo(pCur); } @@ -3743,8 +3753,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ #define getCellInfo(pCur) \ if( pCur->info.nSize==0 ){ \ int iPage = pCur->iPage; \ - btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \ - pCur->validNKey = 1; \ + btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \ + pCur->curFlags |= BTCF_ValidNKey; \ }else{ \ assertCellInfo(pCur); \ } @@ -3915,10 +3925,12 @@ static int copyPayload( /* ** This function is used to read or overwrite payload information -** for the entry that the pCur cursor is pointing to. If the eOp -** parameter is 0, this is a read operation (data copied into -** buffer pBuf). If it is non-zero, a write (data copied from -** buffer pBuf). +** for the entry that the pCur cursor is pointing to. The eOp +** argument is interpreted as follows: +** +** 0: The operation is a read. Populate the overflow cache. +** 1: The operation is a write. Populate the overflow cache. +** 2: The operation is a read. Do not populate the overflow cache. ** ** A total of "amt" bytes are read or written beginning at "offset". ** Data is read to or from the buffer pBuf. @@ -3926,11 +3938,11 @@ static int copyPayload( ** The content being read or written might appear on the main page ** or be scattered out on multiple overflow pages. ** -** If the BtCursor.isIncrblobHandle flag is set, and the current -** cursor entry uses one or more overflow pages, this function -** allocates space for and lazily popluates the overflow page-list -** cache array (BtCursor.aOverflow). Subsequent calls use this -** cache to make seeking to the supplied offset more efficient. +** If the current cursor entry uses one or more overflow pages and the +** eOp argument is not 2, this function may allocate space for and lazily +** popluates the overflow page-list cache array (BtCursor.aOverflow). +** Subsequent calls use this cache to make seeking to the supplied offset +** more efficient. ** ** Once an overflow page-list cache has been allocated, it may be ** invalidated if some other cursor writes to the same table, or if @@ -3954,15 +3966,22 @@ static int accessPayload( int iIdx = 0; MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ +#ifdef SQLITE_DIRECT_OVERFLOW_READ + int bEnd; /* True if reading to end of data */ +#endif assert( pPage ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->aiIdx[pCur->iPage]nCell ); assert( cursorHoldsMutex(pCur) ); + assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */ getCellInfo(pCur); aPayload = pCur->info.pCell + pCur->info.nHeader; nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey); +#ifdef SQLITE_DIRECT_OVERFLOW_READ + bEnd = (offset+amt==nKey+pCur->info.nData); +#endif if( NEVER(offset+amt > nKey+pCur->info.nData) || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] @@ -3977,7 +3996,7 @@ static int accessPayload( if( a+offset>pCur->info.nLocal ){ a = pCur->info.nLocal - offset; } - rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage); + rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage); offset = 0; pBuf += a; amt -= a; @@ -3991,21 +4010,30 @@ static int accessPayload( nextPage = get4byte(&aPayload[pCur->info.nLocal]); -#ifndef SQLITE_OMIT_INCRBLOB - /* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[] - ** has not been allocated, allocate it now. The array is sized at - ** one entry for each overflow page in the overflow chain. The - ** page number of the first overflow page is stored in aOverflow[0], - ** etc. A value of 0 in the aOverflow[] array means "not yet known" - ** (the cache is lazily populated). + /* If the BtCursor.aOverflow[] has not been allocated, allocate it now. + ** Except, do not allocate aOverflow[] for eOp==2. + ** + ** The aOverflow[] array is sized at one entry for each overflow page + ** in the overflow chain. The page number of the first overflow page is + ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array + ** means "not yet known" (the cache is lazily populated). */ - if( pCur->isIncrblobHandle && !pCur->aOverflow ){ + if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; - pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl); - /* nOvfl is always positive. If it were zero, fetchPayload would have - ** been used instead of this routine. */ - if( ALWAYS(nOvfl) && !pCur->aOverflow ){ - rc = SQLITE_NOMEM; + if( nOvfl>pCur->nOvflAlloc ){ + Pgno *aNew = (Pgno*)sqlite3DbRealloc( + pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno) + ); + if( aNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + pCur->nOvflAlloc = nOvfl*2; + pCur->aOverflow = aNew; + } + } + if( rc==SQLITE_OK ){ + memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno)); + pCur->curFlags |= BTCF_ValidOvfl; } } @@ -4013,22 +4041,19 @@ static int accessPayload( ** entry for the first required overflow page is valid, skip ** directly to it. */ - if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){ + if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){ iIdx = (offset/ovflSize); nextPage = pCur->aOverflow[iIdx]; offset = (offset%ovflSize); } -#endif for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){ -#ifndef SQLITE_OMIT_INCRBLOB /* If required, populate the overflow page-list cache. */ - if( pCur->aOverflow ){ + if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){ assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage); pCur->aOverflow[iIdx] = nextPage; } -#endif if( offset>=ovflSize ){ /* The only reason to read this page is to obtain the page @@ -4036,13 +4061,17 @@ static int accessPayload( ** data is not required. So first try to lookup the overflow ** page-list cache, if any, then fall back to the getOverflowPage() ** function. + ** + ** Note that the aOverflow[] array must be allocated because eOp!=2 + ** here. If eOp==2, then offset==0 and this branch is never taken. */ -#ifndef SQLITE_OMIT_INCRBLOB - if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){ + assert( eOp!=2 ); + assert( pCur->curFlags & BTCF_ValidOvfl ); + if( pCur->aOverflow[iIdx+1] ){ nextPage = pCur->aOverflow[iIdx+1]; - } else -#endif + }else{ rc = getOverflowPage(pBt, nextPage, 0, &nextPage); + } offset -= ovflSize; }else{ /* Need to read this page properly. It contains some of the @@ -4064,13 +4093,15 @@ static int accessPayload( ** 3) the database is file-backed, and ** 4) there is no open write-transaction, and ** 5) the database is not a WAL database, + ** 6) all data from the page is being read. ** ** then data can be read directly from the database file into the ** output buffer, bypassing the page-cache altogether. This speeds ** up loading large records that span many overflow pages. */ - if( eOp==0 /* (1) */ + if( (eOp&0x01)==0 /* (1) */ && offset==0 /* (2) */ + && (bEnd || a==ovflSize) /* (6) */ && pBt->inTransaction==TRANS_READ /* (4) */ && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */ && pBt->pPage1->aData[19]==0x01 /* (5) */ @@ -4087,12 +4118,12 @@ static int accessPayload( { DbPage *pDbPage; rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage, - (eOp==0 ? PAGER_GET_READONLY : 0) + ((eOp&0x01)==0 ? PAGER_GET_READONLY : 0) ); if( rc==SQLITE_OK ){ aPayload = sqlite3PagerGetData(pDbPage); nextPage = get4byte(aPayload); - rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); + rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage); sqlite3PagerUnref(pDbPage); offset = 0; } @@ -4186,10 +4217,7 @@ static const void *fetchPayload( assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorHoldsMutex(pCur) ); assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); - if( pCur->info.nSize==0 ){ - btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage], - &pCur->info); - } + assert( pCur->info.nSize>0 ); *pAmt = pCur->info.nLocal; return (void*)(pCur->info.pCell + pCur->info.nHeader); } @@ -4240,14 +4268,14 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, newPgno, &pNewPage, - pCur->wrFlag==0 ? PAGER_GET_READONLY : 0); + (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0); if( rc ) return rc; pCur->apPage[i+1] = pNewPage; pCur->aiIdx[i+1] = 0; pCur->iPage++; pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){ return SQLITE_CORRUPT_BKPT; } @@ -4305,7 +4333,7 @@ static void moveToParent(BtCursor *pCur){ releasePage(pCur->apPage[pCur->iPage]); pCur->iPage--; pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); } /* @@ -4352,7 +4380,7 @@ static int moveToRoot(BtCursor *pCur){ return SQLITE_OK; }else{ rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0], - pCur->wrFlag==0 ? PAGER_GET_READONLY : 0); + (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; return rc; @@ -4379,8 +4407,7 @@ static int moveToRoot(BtCursor *pCur){ pCur->aiIdx[0] = 0; pCur->info.nSize = 0; - pCur->atLast = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); if( pRoot->nCell>0 ){ pCur->eState = CURSOR_VALID; @@ -4443,7 +4470,7 @@ static int moveToRightmost(BtCursor *pCur){ if( rc==SQLITE_OK ){ pCur->aiIdx[pCur->iPage] = pPage->nCell-1; pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~BTCF_ValidNKey; } return rc; } @@ -4482,7 +4509,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); /* If the cursor already points to the last entry, this is a no-op. */ - if( CURSOR_VALID==pCur->eState && pCur->atLast ){ + if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){ #ifdef SQLITE_DEBUG /* This block serves to assert() that the cursor really does point ** to the last entry in the b-tree. */ @@ -4505,7 +4532,12 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ assert( pCur->eState==CURSOR_VALID ); *pRes = 0; rc = moveToRightmost(pCur); - pCur->atLast = rc==SQLITE_OK ?1:0; + if( rc==SQLITE_OK ){ + pCur->curFlags |= BTCF_AtLast; + }else{ + pCur->curFlags &= ~BTCF_AtLast; + } + } } return rc; @@ -4556,14 +4588,14 @@ int sqlite3BtreeMovetoUnpacked( /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ - if( pCur->eState==CURSOR_VALID && pCur->validNKey + if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 && pCur->apPage[0]->intKey ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; } - if( pCur->atLast && pCur->info.nKeycurFlags & BTCF_AtLast)!=0 && pCur->info.nKeyisCorrupt = 0; assert( pIdxKey->default_rc==1 || pIdxKey->default_rc==0 || pIdxKey->default_rc==-1 @@ -4629,7 +4662,7 @@ int sqlite3BtreeMovetoUnpacked( if( lwr>upr ){ c = +1; break; } }else{ assert( nCellKey==intKey ); - pCur->validNKey = 1; + pCur->curFlags |= BTCF_ValidNKey; pCur->info.nKey = nCellKey; pCur->aiIdx[pCur->iPage] = (u16)idx; if( !pPage->leaf ){ @@ -4686,7 +4719,7 @@ int sqlite3BtreeMovetoUnpacked( goto moveto_finish; } pCur->aiIdx[pCur->iPage] = (u16)idx; - rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); + rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2); if( rc ){ sqlite3_free(pCellKey); goto moveto_finish; @@ -4694,6 +4727,7 @@ int sqlite3BtreeMovetoUnpacked( c = xRecordCompare(nCell, pCellKey, pIdxKey, 0); sqlite3_free(pCellKey); } + assert( pIdxKey->isCorrupt==0 || c==0 ); if( c<0 ){ lwr = idx+1; }else if( c>0 ){ @@ -4703,6 +4737,7 @@ int sqlite3BtreeMovetoUnpacked( *pRes = 0; rc = SQLITE_OK; pCur->aiIdx[pCur->iPage] = (u16)idx; + if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT; goto moveto_finish; } if( lwr>upr ) break; @@ -4731,7 +4766,7 @@ moveto_next_layer: } moveto_finish: pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); return rc; } @@ -4776,6 +4811,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ assert( *pRes==0 || *pRes==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); if( pCur->eState!=CURSOR_VALID ){ + invalidateOverflowCache(pCur); rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ *pRes = 0; @@ -4809,7 +4845,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ testcase( idx>pPage->nCell ); pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); if( idx>=pPage->nCell ){ if( !pPage->leaf ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); @@ -4870,7 +4906,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ assert( pRes!=0 ); assert( *pRes==0 || *pRes==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); - pCur->atLast = 0; + pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl); if( pCur->eState!=CURSOR_VALID ){ if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){ rc = btreeRestoreCursorPosition(pCur); @@ -4915,7 +4951,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ moveToParent(pCur); } pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); pCur->aiIdx[pCur->iPage]--; pPage = pCur->apPage[pCur->iPage]; @@ -5705,7 +5741,8 @@ static void insertCell( if( *pRC ) return; assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); - assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=10921 ); + assert( MX_CELL(pPage->pBt)<=10921 ); + assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB ); assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) ); assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); @@ -6940,7 +6977,7 @@ int sqlite3BtreeInsert( } assert( cursorHoldsMutex(pCur) ); - assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE + assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE && (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); @@ -6973,7 +7010,7 @@ int sqlite3BtreeInsert( /* If the cursor is currently on the last row and we are appending a ** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto() ** call */ - if( pCur->validNKey && nKey>0 && pCur->info.nKey==nKey-1 ){ + if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){ loc = -1; } } @@ -7026,7 +7063,7 @@ int sqlite3BtreeInsert( /* If no error has occurred and pPage has an overflow cell, call balance() ** to redistribute the cells within the tree. Since balance() may move - ** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey + ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey ** variables. ** ** Previous versions of SQLite called moveToRoot() to move the cursor @@ -7046,7 +7083,7 @@ int sqlite3BtreeInsert( */ pCur->info.nSize = 0; if( rc==SQLITE_OK && pPage->nOverflow ){ - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey); rc = balance(pCur); /* Must make sure nOverflow is reset to zero even if the balance() @@ -7078,7 +7115,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); - assert( pCur->wrFlag ); + assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); @@ -7423,6 +7460,15 @@ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ return rc; } +/* +** Delete all information from the single table that pCur is open on. +** +** This routine only work for pCur on an ephemeral table. +*/ +int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){ + return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0); +} + /* ** Erase all information in a table and add the root of the table to ** the freelist. Except, the root of the principle table (the one on @@ -8382,7 +8428,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ int rc; assert( cursorHoldsMutex(pCsr) ); assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); - assert( pCsr->isIncrblobHandle ); + assert( pCsr->curFlags & BTCF_Incrblob ); rc = restoreCursorPosition(pCsr); if( rc!=SQLITE_OK ){ @@ -8411,7 +8457,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ ** (d) there are no conflicting read-locks, and ** (e) the cursor points at a valid row of an intKey table. */ - if( !pCsr->wrFlag ){ + if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){ return SQLITE_READONLY; } assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0 @@ -8424,20 +8470,10 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ } /* -** Set a flag on this cursor to cache the locations of pages from the -** overflow list for the current row. This is used by cursors opened -** for incremental blob IO only. -** -** This function sets a flag only. The actual page location cache -** (stored in BtCursor.aOverflow[]) is allocated and used by function -** accessPayload() (the worker function for sqlite3BtreeData() and -** sqlite3BtreePutData()). +** Mark this cursor as an incremental blob cursor. */ -void sqlite3BtreeCacheOverflow(BtCursor *pCur){ - assert( cursorHoldsMutex(pCur) ); - assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); - invalidateOverflowCache(pCur); - pCur->isIncrblobHandle = 1; +void sqlite3BtreeIncrblobCursor(BtCursor *pCur){ + pCur->curFlags |= BTCF_Incrblob; } #endif @@ -8485,3 +8521,10 @@ void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){ assert( mask==BTREE_BULKLOAD || mask==0 ); pCsr->hints = mask; } + +/* +** Return true if the given Btree is read-only. +*/ +int sqlite3BtreeIsReadonly(Btree *p){ + return (p->pBt->btsFlags & BTS_READ_ONLY)!=0; +} diff --git a/src/btree.h b/src/btree.h index eda7bef..7118534 100644 --- a/src/btree.h +++ b/src/btree.h @@ -63,7 +63,9 @@ int sqlite3BtreeOpen( int sqlite3BtreeClose(Btree*); int sqlite3BtreeSetCacheSize(Btree*,int); -int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); +#if SQLITE_MAX_MMAP_SIZE>0 + int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); +#endif int sqlite3BtreeSetPagerFlags(Btree*,unsigned); int sqlite3BtreeSyncDisabled(Btree*); int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); @@ -113,6 +115,7 @@ int sqlite3BtreeIncrVacuum(Btree *); int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, int*); +int sqlite3BtreeClearTableOfCursor(BtCursor*); void sqlite3BtreeTripAllCursors(Btree*, int); void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); @@ -187,10 +190,11 @@ char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); struct Pager *sqlite3BtreePager(Btree*); int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); -void sqlite3BtreeCacheOverflow(BtCursor *); +void sqlite3BtreeIncrblobCursor(BtCursor *); void sqlite3BtreeClearCursor(BtCursor *); int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask); +int sqlite3BtreeIsReadonly(Btree *pBt); #ifndef NDEBUG int sqlite3BtreeCursorIsValid(BtCursor*); diff --git a/src/btreeInt.h b/src/btreeInt.h index 87b4181..d1cdd46 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -496,27 +496,30 @@ struct BtCursor { BtShared *pBt; /* The BtShared this cursor points to */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */ -#ifndef SQLITE_OMIT_INCRBLOB Pgno *aOverflow; /* Cache of overflow page locations */ -#endif - Pgno pgnoRoot; /* The root page of this tree */ CellInfo info; /* A parse of the cell we are pointing at */ - i64 nKey; /* Size of pKey, or last integer key */ - void *pKey; /* Saved key that was cursor's last known position */ + i64 nKey; /* Size of pKey, or last integer key */ + void *pKey; /* Saved key that was cursor last known position */ + Pgno pgnoRoot; /* The root page of this tree */ + int nOvflAlloc; /* Allocated size of aOverflow[] array */ int skipNext; /* Prev() is noop if negative. Next() is noop if positive */ - u8 wrFlag; /* True if writable */ - u8 atLast; /* Cursor pointing to the last entry */ - u8 validNKey; /* True if info.nKey is valid */ + u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 eState; /* One of the CURSOR_XXX constants (see below) */ -#ifndef SQLITE_OMIT_INCRBLOB - u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */ -#endif u8 hints; /* As configured by CursorSetHints() */ i16 iPage; /* Index of current page in apPage */ u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */ MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ }; +/* +** Legal values for BtCursor.curFlags +*/ +#define BTCF_WriteFlag 0x01 /* True if a write cursor */ +#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */ +#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */ +#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */ +#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */ + /* ** Potential values for BtCursor.eState. ** diff --git a/src/build.c b/src/build.c index 10077e5..a9a8f21 100644 --- a/src/build.c +++ b/src/build.c @@ -113,6 +113,19 @@ static void codeTableLocks(Parse *pParse){ #define codeTableLocks(x) #endif +/* +** Return TRUE if the given yDbMask object is empty - if it contains no +** 1 bits. This routine is used by the DbMaskAllZero() and DbMaskNotZero() +** macros when SQLITE_MAX_ATTACHED is greater than 30. +*/ +#if SQLITE_MAX_ATTACHED>30 +int sqlite3DbMaskAllZero(yDbMask m){ + int i; + for(i=0; imallocFailed==0 && (pParse->cookieMask || pParse->pConstExpr) ){ - yDbMask mask; + if( db->mallocFailed==0 + && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr) + ){ int iDb, i; assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init ); sqlite3VdbeJumpHere(v, 0); - for(iDb=0, mask=1; iDbnDb; mask<<=1, iDb++){ - if( (mask & pParse->cookieMask)==0 ) continue; + for(iDb=0; iDbnDb; iDb++){ + if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue; sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeAddOp4Int(v, OP_Transaction, /* Opcode */ iDb, /* P1 */ - (mask & pParse->writeMask)!=0, /* P2 */ + DbMaskTest(pParse->writeMask,iDb), /* P2 */ pParse->cookieValue[iDb], /* P3 */ db->aDb[iDb].pSchema->iGeneration /* P4 */ ); @@ -216,7 +230,7 @@ void sqlite3FinishCoding(Parse *pParse){ pParse->nMem = 0; pParse->nSet = 0; pParse->nVar = 0; - pParse->cookieMask = 0; + DbMaskZero(pParse->cookieMask); } /* @@ -757,7 +771,7 @@ int sqlite3CheckObjectName(Parse *pParse, const char *zName){ */ Index *sqlite3PrimaryKeyIndex(Table *pTab){ Index *p; - for(p=pTab->pIndex; p && p->autoIndex!=2; p=p->pNext){} + for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){} return p; } @@ -905,7 +919,7 @@ void sqlite3StartTable( pTable->iPKey = -1; pTable->pSchema = db->aDb[iDb].pSchema; pTable->nRef = 1; - pTable->nRowEst = 1048576; + pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; @@ -1286,7 +1300,7 @@ void sqlite3AddPrimaryKey( p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0); if( p ){ - p->autoIndex = 2; + p->idxType = SQLITE_IDXTYPE_PRIMARYKEY; if( v ) sqlite3VdbeJumpHere(v, pParse->addrSkipPK); } pList = 0; @@ -1306,7 +1320,10 @@ void sqlite3AddCheckConstraint( ){ #ifndef SQLITE_OMIT_CHECK Table *pTab = pParse->pNewTable; - if( pTab && !IN_DECLARE_VTAB ){ + sqlite3 *db = pParse->db; + if( pTab && !IN_DECLARE_VTAB + && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt) + ){ pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); if( pParse->constraintName.n ){ sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1); @@ -1658,7 +1675,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ assert( pParse->pNewTable==pTab ); pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0); if( pPk==0 ) return; - pPk->autoIndex = 2; + pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY; pTab->iPKey = -1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); @@ -1681,7 +1698,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int n; - if( pIdx->autoIndex==2 ) continue; + if( IsPrimaryKeyIndex(pIdx) ) continue; for(i=n=0; iaiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++; } @@ -2113,7 +2130,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ pSelTab->aCol = 0; sqlite3DeleteTable(db, pSelTab); assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); - pTable->pSchema->flags |= DB_UnresetViews; + pTable->pSchema->schemaFlags |= DB_UnresetViews; }else{ pTable->nCol = 0; nErr++; @@ -2680,7 +2697,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); - sqlite3VdbeResolveLabel(v, iPartIdxLabel); + sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); @@ -2690,12 +2707,12 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); assert( pKey!=0 || db->mallocFailed || pParse->nErr ); - if( pIndex->onError!=OE_None && pKey!=0 ){ + if( IsUniqueIndex(pIndex) && pKey!=0 ){ int j2 = sqlite3VdbeCurrentAddr(v) + 3; sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, - pKey->nField - pIndex->nKeyCol); VdbeCoverage(v); + pIndex->nKeyCol); VdbeCoverage(v); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); }else{ addr2 = sqlite3VdbeCurrentAddr(v); @@ -2730,15 +2747,15 @@ Index *sqlite3AllocateIndexObject( nByte = ROUND8(sizeof(Index)) + /* Index structure */ ROUND8(sizeof(char*)*nCol) + /* Index.azColl */ - ROUND8(sizeof(tRowcnt)*(nCol+1) + /* Index.aiRowEst */ + ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */ sizeof(i16)*nCol + /* Index.aiColumn */ sizeof(u8)*nCol); /* Index.aSortOrder */ p = sqlite3DbMallocZero(db, nByte + nExtra); if( p ){ char *pExtra = ((char*)p)+ROUND8(sizeof(Index)); - p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol); - p->aiRowEst = (tRowcnt*)pExtra; pExtra += sizeof(tRowcnt)*(nCol+1); - p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol; + p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol); + p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1); + p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol; p->aSortOrder = (u8*)pExtra; p->nColumn = nCol; p->nKeyCol = nCol - 1; @@ -2761,7 +2778,7 @@ Index *sqlite3AllocateIndexObject( ** ** If the index is created successfully, return a pointer to the new Index ** structure. This is used by sqlite3AddPrimaryKey() to mark the index -** as the tables primary key (Index.autoIndex==2). +** as the tables primary key (Index.idxType==SQLITE_IDXTYPE_PRIMARYKEY) */ Index *sqlite3CreateIndex( Parse *pParse, /* All information about this parse */ @@ -2968,7 +2985,7 @@ Index *sqlite3CreateIndex( if( db->mallocFailed ){ goto exit_create_index; } - assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowEst) ); + assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst) ); assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) ); pIndex->zName = zExtra; zExtra += nName + 1; @@ -2976,7 +2993,7 @@ Index *sqlite3CreateIndex( pIndex->pTable = pTab; pIndex->onError = (u8)onError; pIndex->uniqNotNull = onError!=OE_None; - pIndex->autoIndex = (u8)(pName==0); + pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE; pIndex->pSchema = db->aDb[iDb].pSchema; pIndex->nKeyCol = pList->nExpr; if( pPIWhere ){ @@ -3087,9 +3104,9 @@ Index *sqlite3CreateIndex( Index *pIdx; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int k; - assert( pIdx->onError!=OE_None ); - assert( pIdx->autoIndex ); - assert( pIndex->onError!=OE_None ); + assert( IsUniqueIndex(pIdx) ); + assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF ); + assert( IsUniqueIndex(pIndex) ); if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue; for(k=0; knKeyCol; k++){ @@ -3249,7 +3266,7 @@ exit_create_index: ** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the ** number of rows in the table that match any particular value of the ** first column of the index. aiRowEst[2] is an estimate of the number -** of rows that match any particular combiniation of the first 2 columns +** of rows that match any particular combination of the first 2 columns ** of the index. And so forth. It must always be the case that * ** aiRowEst[N]<=aiRowEst[N-1] @@ -3260,20 +3277,27 @@ exit_create_index: ** are based on typical values found in actual indices. */ void sqlite3DefaultRowEst(Index *pIdx){ - tRowcnt *a = pIdx->aiRowEst; + /* 10, 9, 8, 7, 6 */ + LogEst aVal[] = { 33, 32, 30, 28, 26 }; + LogEst *a = pIdx->aiRowLogEst; + int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); int i; - tRowcnt n; - assert( a!=0 ); - a[0] = pIdx->pTable->nRowEst; - if( a[0]<10 ) a[0] = 10; - n = 10; - for(i=1; i<=pIdx->nKeyCol; i++){ - a[i] = n; - if( n>5 ) n--; - } - if( pIdx->onError!=OE_None ){ - a[pIdx->nKeyCol] = 1; + + /* Set the first entry (number of rows in the index) to the estimated + ** number of rows in the table. Or 10, if the estimated number of rows + ** in the table is less than that. */ + a[0] = pIdx->pTable->nRowLogEst; + if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); + + /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is + ** 6 and each subsequent value (if any) is 5. */ + memcpy(&a[1], aVal, nCopy*sizeof(LogEst)); + for(i=nCopy+1; i<=pIdx->nKeyCol; i++){ + a[i] = 23; assert( 23==sqlite3LogEst(5) ); } + + assert( 0==sqlite3LogEst(1) ); + if( IsUniqueIndex(pIdx) ) a[pIdx->nKeyCol] = 0; } /* @@ -3304,7 +3328,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ pParse->checkSchema = 1; goto exit_drop_index; } - if( pIndex->autoIndex ){ + if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){ sqlite3ErrorMsg(pParse, "index associated with UNIQUE " "or PRIMARY KEY constraint cannot be dropped", 0); goto exit_drop_index; @@ -3833,15 +3857,13 @@ int sqlite3OpenTempDatabase(Parse *pParse){ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); sqlite3 *db = pToplevel->db; - yDbMask mask; assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pBt!=0 || iDb==1 ); assert( iDbcookieMask & mask)==0 ){ - pToplevel->cookieMask |= mask; + if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){ + DbMaskSet(pToplevel->cookieMask, iDb); pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie; if( !OMIT_TEMPDB && iDb==1 ){ sqlite3OpenTempDatabase(pToplevel); @@ -3880,7 +3902,7 @@ void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); sqlite3CodeVerifySchema(pParse, iDb); - pToplevel->writeMask |= ((yDbMask)1)<writeMask, iDb); pToplevel->isMultiWrite |= setStatement; } @@ -3963,7 +3985,8 @@ void sqlite3UniqueConstraint( } zErr = sqlite3StrAccumFinish(&errMsg); sqlite3HaltConstraint(pParse, - (pIdx->autoIndex==2)?SQLITE_CONSTRAINT_PRIMARYKEY:SQLITE_CONSTRAINT_UNIQUE, + IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY + : SQLITE_CONSTRAINT_UNIQUE, onError, zErr, P4_DYNAMIC, P5_ConstraintUnique); } diff --git a/src/callback.c b/src/callback.c index 260fe80..46fbe2c 100644 --- a/src/callback.c +++ b/src/callback.c @@ -447,9 +447,9 @@ void sqlite3SchemaClear(void *p){ sqlite3HashClear(&temp1); sqlite3HashClear(&pSchema->fkeyHash); pSchema->pSeqTab = 0; - if( pSchema->flags & DB_SchemaLoaded ){ + if( pSchema->schemaFlags & DB_SchemaLoaded ){ pSchema->iGeneration++; - pSchema->flags &= ~DB_SchemaLoaded; + pSchema->schemaFlags &= ~DB_SchemaLoaded; } } diff --git a/src/delete.c b/src/delete.c index 79e83ca..c74d8ea 100644 --- a/src/delete.c +++ b/src/delete.c @@ -739,7 +739,7 @@ void sqlite3GenerateRowIndexDelete( &iPartIdxLabel, pPrior, r1); sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); - sqlite3VdbeResolveLabel(v, iPartIdxLabel); + sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); pPrior = pIdx; } } @@ -758,10 +758,11 @@ void sqlite3GenerateRowIndexDelete( ** ** If *piPartIdxLabel is not NULL, fill it in with a label and jump ** to that label if pIdx is a partial index that should be skipped. +** The label should be resolved using sqlite3ResolvePartIdxLabel(). ** A partial index should be skipped if its WHERE clause evaluates ** to false or null. If pIdx is not a partial index, *piPartIdxLabel ** will be set to zero which is an empty label that is ignored by -** sqlite3VdbeResolveLabel(). +** sqlite3ResolvePartIdxLabel(). ** ** The pPrior and regPrior parameters are used to implement a cache to ** avoid unnecessary register loads. If pPrior is not NULL, then it is @@ -794,6 +795,7 @@ int sqlite3GenerateIndexKey( if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(v); pParse->iPartIdxTab = iDataCur; + sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); }else{ @@ -821,3 +823,15 @@ int sqlite3GenerateIndexKey( sqlite3ReleaseTempRange(pParse, regBase, nCol); return regBase; } + +/* +** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label +** because it was a partial index, then this routine should be called to +** resolve that label. +*/ +void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ + if( iLabel ){ + sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel); + sqlite3ExprCachePop(pParse); + } +} diff --git a/src/expr.c b/src/expr.c index 722a77d..0d2292e 100644 --- a/src/expr.c +++ b/src/expr.c @@ -33,6 +33,7 @@ char sqlite3ExprAffinity(Expr *pExpr){ int op; pExpr = sqlite3ExprSkipCollate(pExpr); + if( pExpr->flags & EP_Generic ) return 0; op = pExpr->op; if( op==TK_SELECT ){ assert( pExpr->flags&EP_xIsSelect ); @@ -65,7 +66,11 @@ char sqlite3ExprAffinity(Expr *pExpr){ ** If a memory allocation error occurs, that fact is recorded in pParse->db ** and the pExpr parameter is returned unchanged. */ -Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){ +Expr *sqlite3ExprAddCollateToken( + Parse *pParse, /* Parsing context */ + Expr *pExpr, /* Add the "COLLATE" clause to this expression */ + const Token *pCollName /* Name of collating sequence */ +){ if( pCollName->n>0 ){ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1); if( pNew ){ @@ -118,6 +123,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ Expr *p = pExpr; while( p ){ int op = p->op; + if( p->flags & EP_Generic ) break; if( op==TK_CAST || op==TK_UPLUS ){ p = p->pLeft; continue; @@ -949,7 +955,6 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ if( p==0 ) return 0; pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); if( pNew==0 ) return 0; - pNew->iECursor = 0; pNew->nExpr = i = p->nExpr; if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; inExpr; i+=i){} pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) ); @@ -1062,7 +1067,6 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; - pNew->addrOpenEphm[2] = -1; pNew->nSelectRow = p->nSelectRow; pNew->pWith = withDup(db, p->pWith); return pNew; @@ -1364,6 +1368,9 @@ int sqlite3ExprCanBeNull(const Expr *p){ case TK_FLOAT: case TK_BLOB: return 0; + case TK_COLUMN: + assert( p->pTab!=0 ); + return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0; default: return 1; } @@ -1471,6 +1478,40 @@ int sqlite3CodeOnce(Parse *pParse){ return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++); } +/* +** Generate code that checks the left-most column of index table iCur to see if +** it contains any NULL entries. Cause the register at regHasNull to be set +** to a non-NULL value if iCur contains no NULLs. Cause register regHasNull +** to be set to NULL if iCur contains one or more NULL values. +*/ +static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ + int j1; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull); + j1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + VdbeComment((v, "first_entry_in(%d)", iCur)); + sqlite3VdbeJumpHere(v, j1); +} + + +#ifndef SQLITE_OMIT_SUBQUERY +/* +** The argument is an IN operator with a list (not a subquery) on the +** right-hand side. Return TRUE if that list is constant. +*/ +static int sqlite3InRhsIsConstant(Expr *pIn){ + Expr *pLHS; + int res; + assert( !ExprHasProperty(pIn, EP_xIsSelect) ); + pLHS = pIn->pLeft; + pIn->pLeft = 0; + res = sqlite3ExprIsConstant(pIn); + pIn->pLeft = pLHS; + return res; +} +#endif + /* ** This function is used by the implementation of the IN (...) operator. ** The pX parameter is the expression on the RHS of the IN operator, which @@ -1480,7 +1521,7 @@ int sqlite3CodeOnce(Parse *pParse){ ** be used either to test for membership in the RHS set or to iterate through ** all members of the RHS set, skipping duplicates. ** -** A cursor is opened on the b-tree object that the RHS of the IN operator +** A cursor is opened on the b-tree object that is the RHS of the IN operator ** and pX->iTable is set to the index of that cursor. ** ** The returned value of this function indicates the b-tree type, as follows: @@ -1490,6 +1531,8 @@ int sqlite3CodeOnce(Parse *pParse){ ** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index. ** IN_INDEX_EPH - The cursor was opened on a specially created and ** populated epheremal table. +** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be +** implemented as a sequence of comparisons. ** ** An existing b-tree might be used if the RHS expression pX is a simple ** subquery such as: @@ -1499,51 +1542,56 @@ int sqlite3CodeOnce(Parse *pParse){ ** If the RHS of the IN operator is a list or a more complex subquery, then ** an ephemeral table might need to be generated from the RHS and then ** pX->iTable made to point to the ephermeral table instead of an -** existing table. +** existing table. ** -** If the prNotFound parameter is 0, then the b-tree will be used to iterate -** through the set members, skipping any duplicates. In this case an -** epheremal table must be used unless the selected is guaranteed +** The inFlags parameter must contain exactly one of the bits +** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP. If inFlags contains +** IN_INDEX_MEMBERSHIP, then the generated table will be used for a +** fast membership test. When the IN_INDEX_LOOP bit is set, the +** IN index will be used to loop over all values of the RHS of the +** IN operator. +** +** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate +** through the set members) then the b-tree must not contain duplicates. +** An epheremal table must be used unless the selected is guaranteed ** to be unique - either because it is an INTEGER PRIMARY KEY or it ** has a UNIQUE constraint or UNIQUE index. ** -** If the prNotFound parameter is not 0, then the b-tree will be used -** for fast set membership tests. In this case an epheremal table must +** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used +** for fast set membership tests) then an epheremal table must ** be used unless is an INTEGER PRIMARY KEY or an index can ** be found with as its left-most column. ** +** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and +** if the RHS of the IN operator is a list (not a subquery) then this +** routine might decide that creating an ephemeral b-tree for membership +** testing is too expensive and return IN_INDEX_NOOP. In that case, the +** calling routine should implement the IN operator using a sequence +** of Eq or Ne comparison operations. +** ** When the b-tree is being used for membership tests, the calling function -** needs to know whether or not the structure contains an SQL NULL -** value in order to correctly evaluate expressions like "X IN (Y, Z)". -** If there is any chance that the (...) might contain a NULL value at +** might need to know whether or not the RHS side of the IN operator +** contains a NULL. If prRhsHasNull is not a NULL pointer and +** if there is any chance that the (...) might contain a NULL value at ** runtime, then a register is allocated and the register number written -** to *prNotFound. If there is no chance that the (...) contains a -** NULL value, then *prNotFound is left unchanged. +** to *prRhsHasNull. If there is no chance that the (...) contains a +** NULL value, then *prRhsHasNull is left unchanged. ** -** If a register is allocated and its location stored in *prNotFound, then -** its initial value is NULL. If the (...) does not remain constant -** for the duration of the query (i.e. the SELECT within the (...) -** is a correlated subquery) then the value of the allocated register is -** reset to NULL each time the subquery is rerun. This allows the -** caller to use vdbe code equivalent to the following: -** -** if( register==NULL ){ -** has_null = -** register = 1 -** } -** -** in order to avoid running the -** test more often than is necessary. +** If a register is allocated and its location stored in *prRhsHasNull, then +** the value in that register will be NULL if the b-tree contains one or more +** NULL values, and it will be some non-NULL value if the b-tree contains no +** NULL values. */ #ifndef SQLITE_OMIT_SUBQUERY -int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ +int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){ Select *p; /* SELECT to the right of IN operator */ int eType = 0; /* Type of RHS table. IN_INDEX_* */ int iTab = pParse->nTab++; /* Cursor of the RHS table */ - int mustBeUnique = (prNotFound==0); /* True if RHS must be unique */ + int mustBeUnique; /* True if RHS must be unique */ Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */ assert( pX->op==TK_IN ); + mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0; /* Check to see if an existing table or index can be used to ** satisfy the query. This is preferable to generating a new @@ -1600,7 +1648,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){ if( (pIdx->aiColumn[0]==iCol) && sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq - && (!mustBeUnique || (pIdx->nKeyCol==1 && pIdx->onError!=OE_None)) + && (!mustBeUnique || (pIdx->nKeyCol==1 && IsUniqueIndex(pIdx))) ){ int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); @@ -1609,9 +1657,9 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; - if( prNotFound && !pTab->aCol[iCol].notNull ){ - *prNotFound = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); + if( prRhsHasNull && !pTab->aCol[iCol].notNull ){ + *prRhsHasNull = ++pParse->nMem; + sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull); } sqlite3VdbeJumpHere(v, iAddr); } @@ -1619,22 +1667,36 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ } } + /* If no preexisting index is available for the IN clause + ** and IN_INDEX_NOOP is an allowed reply + ** and the RHS of the IN operator is a list, not a subquery + ** and the RHS is not contant or has two or fewer terms, + ** then it is not worth creating an ephermeral table to evaluate + ** the IN operator so return IN_INDEX_NOOP. + */ + if( eType==0 + && (inFlags & IN_INDEX_NOOP_OK) + && !ExprHasProperty(pX, EP_xIsSelect) + && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) + ){ + eType = IN_INDEX_NOOP; + } + + if( eType==0 ){ - /* Could not found an existing table or index to use as the RHS b-tree. + /* Could not find an existing table or index to use as the RHS b-tree. ** We will have to generate an ephemeral table to do the job. */ u32 savedNQueryLoop = pParse->nQueryLoop; int rMayHaveNull = 0; eType = IN_INDEX_EPH; - if( prNotFound ){ - *prNotFound = rMayHaveNull = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); - }else{ - testcase( pParse->nQueryLoop>0 ); + if( inFlags & IN_INDEX_LOOP ){ pParse->nQueryLoop = 0; if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ eType = IN_INDEX_ROWID; } + }else if( prRhsHasNull ){ + *prRhsHasNull = rMayHaveNull = ++pParse->nMem; } sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID); pParse->nQueryLoop = savedNQueryLoop; @@ -1665,15 +1727,9 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ ** ** If rMayHaveNull is non-zero, that means that the operation is an IN ** (not a SELECT or EXISTS) and that the RHS might contains NULLs. -** Furthermore, the IN is in a WHERE clause and that we really want -** to iterate over the RHS of the IN operator in order to quickly locate -** all corresponding LHS elements. All this routine does is initialize -** the register given by rMayHaveNull to NULL. Calling routines will take -** care of changing this register value to non-NULL if the RHS is NULL-free. -** -** If rMayHaveNull is zero, that means that the subquery is being used -** for membership testing only. There is no need to initialize any -** registers to indicate the presence or absence of NULLs on the RHS. +** All this routine does is initialize the register given by rMayHaveNull +** to NULL. Calling routines will take care of changing this register +** value to non-NULL if the RHS is NULL-free. ** ** For a SELECT or EXISTS operator, return the register that holds the ** result. For IN operators or if an error occurs, the return value is 0. @@ -1682,10 +1738,10 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ int sqlite3CodeSubselect( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The IN, SELECT, or EXISTS operator */ - int rMayHaveNull, /* Register that records whether NULLs exist in RHS */ + int rHasNullFlag, /* Register that records whether NULLs exist in RHS */ int isRowid /* If true, LHS of IN operator is a rowid */ ){ - int testAddr = -1; /* One-time test address */ + int jmpIfDynamic = -1; /* One-time test address */ int rReg = 0; /* Register storing resulting */ Vdbe *v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return 0; @@ -1702,13 +1758,13 @@ int sqlite3CodeSubselect( ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasProperty(pExpr, EP_VarSelect) ){ - testAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); + jmpIfDynamic = sqlite3CodeOnce(pParse); VdbeCoverage(v); } #ifndef SQLITE_OMIT_EXPLAIN if( pParse->explain==2 ){ char *zMsg = sqlite3MPrintf( - pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr>=0?"":"CORRELATED ", + pParse->db, "EXECUTE %s%s SUBQUERY %d", jmpIfDynamic>=0?"":"CORRELATED ", pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId ); sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); @@ -1722,10 +1778,6 @@ int sqlite3CodeSubselect( Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */ KeyInfo *pKeyInfo = 0; /* Key information */ - if( rMayHaveNull ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull); - } - affinity = sqlite3ExprAffinity(pLeft); /* Whether this is an 'x IN(SELECT...)' or an 'x IN()' @@ -1751,6 +1803,7 @@ int sqlite3CodeSubselect( ** Generate code to write the results of the select into the temporary ** table allocated and opened above. */ + Select *pSelect = pExpr->x.pSelect; SelectDest dest; ExprList *pEList; @@ -1758,13 +1811,15 @@ int sqlite3CodeSubselect( sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); dest.affSdst = (u8)affinity; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); - pExpr->x.pSelect->iLimit = 0; + pSelect->iLimit = 0; + testcase( pSelect->selFlags & SF_Distinct ); + pSelect->selFlags &= ~SF_Distinct; testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ - if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){ + if( sqlite3Select(pParse, pSelect, &dest) ){ sqlite3KeyInfoUnref(pKeyInfo); return 0; } - pEList = pExpr->x.pSelect->pEList; + pEList = pSelect->pEList; assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ assert( pEList!=0 ); assert( pEList->nExpr>0 ); @@ -1795,7 +1850,7 @@ int sqlite3CodeSubselect( /* Loop through each expression in . */ r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp2(v, OP_Null, 0, r2); + if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2); for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ Expr *pE2 = pItem->pExpr; int iValToIns; @@ -1805,9 +1860,9 @@ int sqlite3CodeSubselect( ** this code only executes once. Because for a non-constant ** expression we need to rerun this code each time. */ - if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){ - sqlite3VdbeChangeToNoop(v, testAddr); - testAddr = -1; + if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){ + sqlite3VdbeChangeToNoop(v, jmpIfDynamic); + jmpIfDynamic = -1; } /* Evaluate the expression and insert it into the temp table */ @@ -1877,10 +1932,14 @@ int sqlite3CodeSubselect( } } - if( testAddr>=0 ){ - sqlite3VdbeJumpHere(v, testAddr); + if( rHasNullFlag ){ + sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag); } - sqlite3ExprCachePop(pParse, 1); + + if( jmpIfDynamic>=0 ){ + sqlite3VdbeJumpHere(v, jmpIfDynamic); + } + sqlite3ExprCachePop(pParse); return rReg; } @@ -1899,7 +1958,7 @@ int sqlite3CodeSubselect( ** if the LHS is NULL or if the LHS is not contained within the RHS and the ** RHS contains one or more NULL values. ** -** This routine generates code will jump to destIfFalse if the LHS is not +** This routine generates code that jumps to destIfFalse if the LHS is not ** contained within the RHS. If due to NULLs we cannot determine if the LHS ** is contained in the RHS then jump to destIfNull. If the LHS is contained ** within the RHS then fall through. @@ -1922,7 +1981,9 @@ static void sqlite3ExprCodeIN( v = pParse->pVdbe; assert( v!=0 ); /* OOM detected prior to this routine */ VdbeNoopComment((v, "begin IN expr")); - eType = sqlite3FindInIndex(pParse, pExpr, &rRhsHasNull); + eType = sqlite3FindInIndex(pParse, pExpr, + IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK, + destIfFalse==destIfNull ? 0 : &rRhsHasNull); /* Figure out the affinity to use to create a key from the results ** of the expression. affinityStr stores a static string suitable for @@ -1936,86 +1997,118 @@ static void sqlite3ExprCodeIN( r1 = sqlite3GetTempReg(pParse); sqlite3ExprCode(pParse, pExpr->pLeft, r1); - /* If the LHS is NULL, then the result is either false or NULL depending - ** on whether the RHS is empty or not, respectively. + /* If sqlite3FindInIndex() did not find or create an index that is + ** suitable for evaluating the IN operator, then evaluate using a + ** sequence of comparisons. */ - if( destIfNull==destIfFalse ){ - /* Shortcut for the common case where the false and NULL outcomes are - ** the same. */ - sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); + if( eType==IN_INDEX_NOOP ){ + ExprList *pList = pExpr->x.pList; + CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + int labelOk = sqlite3VdbeMakeLabel(v); + int r2, regToFree; + int regCkNull = 0; + int ii; + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + if( destIfNull!=destIfFalse ){ + regCkNull = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_BitAnd, r1, r1, regCkNull); + } + for(ii=0; iinExpr; ii++){ + r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree); + if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){ + sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull); + } + if( iinExpr-1 || destIfNull!=destIfFalse ){ + sqlite3VdbeAddOp4(v, OP_Eq, r1, labelOk, r2, + (void*)pColl, P4_COLLSEQ); + VdbeCoverageIf(v, iinExpr-1); + VdbeCoverageIf(v, ii==pList->nExpr-1); + sqlite3VdbeChangeP5(v, affinity); + }else{ + assert( destIfNull==destIfFalse ); + sqlite3VdbeAddOp4(v, OP_Ne, r1, destIfFalse, r2, + (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, affinity | SQLITE_JUMPIFNULL); + } + sqlite3ReleaseTempReg(pParse, regToFree); + } + if( regCkNull ){ + sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); + } + sqlite3VdbeResolveLabel(v, labelOk); + sqlite3ReleaseTempReg(pParse, regCkNull); }else{ - int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); - sqlite3VdbeJumpHere(v, addr1); - } - - if( eType==IN_INDEX_ROWID ){ - /* In this case, the RHS is the ROWID of table b-tree + + /* If the LHS is NULL, then the result is either false or NULL depending + ** on whether the RHS is empty or not, respectively. */ - sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1); - VdbeCoverage(v); - }else{ - /* In this case, the RHS is an index b-tree. - */ - sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); - - /* If the set membership test fails, then the result of the - ** "x IN (...)" expression must be either 0 or NULL. If the set - ** contains no NULL values, then the result is 0. If the set - ** contains one or more NULL values, then the result of the - ** expression is also NULL. - */ - if( rRhsHasNull==0 || destIfFalse==destIfNull ){ - /* This branch runs if it is known at compile time that the RHS - ** cannot contain NULL values. This happens as the result - ** of a "NOT NULL" constraint in the database schema. - ** - ** Also run this branch if NULL is equivalent to FALSE - ** for this particular IN operator. + if( sqlite3ExprCanBeNull(pExpr->pLeft) ){ + if( destIfNull==destIfFalse ){ + /* Shortcut for the common case where the false and NULL outcomes are + ** the same. */ + sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); + }else{ + int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); + sqlite3VdbeJumpHere(v, addr1); + } + } + + if( eType==IN_INDEX_ROWID ){ + /* In this case, the RHS is the ROWID of table b-tree */ - sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1); + sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1); VdbeCoverage(v); }else{ - /* In this branch, the RHS of the IN might contain a NULL and - ** the presence of a NULL on the RHS makes a difference in the - ** outcome. + /* In this case, the RHS is an index b-tree. */ - int j1, j2; - - /* First check to see if the LHS is contained in the RHS. If so, - ** then the presence of NULLs in the RHS does not matter, so jump - ** over all of the code that follows. + sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); + + /* If the set membership test fails, then the result of the + ** "x IN (...)" expression must be either 0 or NULL. If the set + ** contains no NULL values, then the result is 0. If the set + ** contains one or more NULL values, then the result of the + ** expression is also NULL. */ - j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1); - VdbeCoverage(v); - - /* Here we begin generating code that runs if the LHS is not - ** contained within the RHS. Generate additional code that - ** tests the RHS for NULLs. If the RHS contains a NULL then - ** jump to destIfNull. If there are no NULLs in the RHS then - ** jump to destIfFalse. - */ - sqlite3VdbeAddOp2(v, OP_If, rRhsHasNull, destIfNull); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_IfNot, rRhsHasNull, destIfFalse); VdbeCoverage(v); - j2 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, rRhsHasNull, 1); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Integer, 0, rRhsHasNull); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); - sqlite3VdbeJumpHere(v, j2); - sqlite3VdbeAddOp2(v, OP_Integer, 1, rRhsHasNull); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); - - /* The OP_Found at the top of this branch jumps here when true, - ** causing the overall IN expression evaluation to fall through. - */ - sqlite3VdbeJumpHere(v, j1); + assert( destIfFalse!=destIfNull || rRhsHasNull==0 ); + if( rRhsHasNull==0 ){ + /* This branch runs if it is known at compile time that the RHS + ** cannot contain NULL values. This happens as the result + ** of a "NOT NULL" constraint in the database schema. + ** + ** Also run this branch if NULL is equivalent to FALSE + ** for this particular IN operator. + */ + sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1); + VdbeCoverage(v); + }else{ + /* In this branch, the RHS of the IN might contain a NULL and + ** the presence of a NULL on the RHS makes a difference in the + ** outcome. + */ + int j1; + + /* First check to see if the LHS is contained in the RHS. If so, + ** then the answer is TRUE the presence of NULLs in the RHS does + ** not matter. If the LHS is not contained in the RHS, then the + ** answer is NULL if the RHS contains NULLs and the answer is + ** FALSE if the RHS is NULL-free. + */ + j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); + sqlite3VdbeJumpHere(v, j1); + } } } sqlite3ReleaseTempReg(pParse, r1); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); VdbeComment((v, "end IN expr")); } #endif /* SQLITE_OMIT_SUBQUERY */ @@ -2072,7 +2165,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ i64 value; const char *z = pExpr->u.zToken; assert( z!=0 ); - c = sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); + c = sqlite3DecOrHexToI64(z, &value); if( c==0 || (c==2 && negFlag) ){ char *zV; if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; } @@ -2082,7 +2175,14 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ #ifdef SQLITE_OMIT_FLOATING_POINT sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); #else - codeReal(v, z, negFlag, iMem); +#ifndef SQLITE_OMIT_HEX_INTEGER + if( sqlite3_strnicmp(z,"0x",2)==0 ){ + sqlite3ErrorMsg(pParse, "hex literal too big: %s", z); + }else +#endif + { + codeReal(v, z, negFlag, iMem); + } #endif } } @@ -2198,15 +2298,14 @@ void sqlite3ExprCachePush(Parse *pParse){ /* ** Remove from the column cache any entries that were added since the -** the previous N Push operations. In other words, restore the cache -** to the state it was in N Pushes ago. +** the previous sqlite3ExprCachePush operation. In other words, restore +** the cache to the state it was in prior the most recent Push. */ -void sqlite3ExprCachePop(Parse *pParse, int N){ +void sqlite3ExprCachePop(Parse *pParse){ int i; struct yColCache *p; - assert( N>0 ); - assert( pParse->iCacheLevel>=N ); - pParse->iCacheLevel -= N; + assert( pParse->iCacheLevel>=1 ); + pParse->iCacheLevel--; #ifdef SQLITE_DEBUG if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ printf("POP to %d\n", pParse->iCacheLevel); @@ -2335,7 +2434,7 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ int i; struct yColCache *p; assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo ); - sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1); + sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); for(i=0, p=pParse->aColCache; iiReg; if( x>=iFrom && xu.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0); - if( pDef==0 ){ + if( pDef==0 || pDef->xFunc==0 ){ sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId); break; } @@ -2684,7 +2783,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ sqlite3ExprCacheRemove(pParse, target, 1); sqlite3ExprCachePush(pParse); sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); } sqlite3VdbeResolveLabel(v, endCoalesce); break; @@ -2736,9 +2835,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ } sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */ - sqlite3ExprCodeExprList(pParse, pFarg, r1, + sqlite3ExprCodeExprList(pParse, pFarg, r1, SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR); - sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */ + sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */ }else{ r1 = 0; } @@ -2958,13 +3057,13 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ testcase( aListelem[i+1].pExpr->op==TK_COLUMN ); sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); sqlite3VdbeResolveLabel(v, nextCase); } if( (nExpr&1)!=0 ){ sqlite3ExprCachePush(pParse); sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } @@ -3543,7 +3642,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ sqlite3ExprCachePush(pParse); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); break; } case TK_OR: { @@ -3551,7 +3650,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprCachePush(pParse); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); break; } case TK_NOT: { @@ -3697,7 +3796,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); break; } case TK_OR: { @@ -3707,7 +3806,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); break; } case TK_NOT: { diff --git a/src/fkey.c b/src/fkey.c index 336256e..50c10da 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -225,7 +225,7 @@ int sqlite3FkLocateIndex( } for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->nKeyCol==nCol && pIdx->onError!=OE_None ){ + if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){ /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number ** of columns. If each indexed column corresponds to a foreign key ** column of pFKey, then this index is a winner. */ @@ -233,8 +233,8 @@ int sqlite3FkLocateIndex( if( zKey==0 ){ /* If zKey is NULL, then this foreign key is implicitly mapped to ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be - ** identified by the test (Index.autoIndex==2). */ - if( pIdx->autoIndex==2 ){ + ** identified by the test. */ + if( IsPrimaryKeyIndex(pIdx) ){ if( aiCol ){ int i; for(i=0; iaCol[i].iFrom; diff --git a/src/func.c b/src/func.c index 6be9635..dbc8375 100644 --- a/src/func.c +++ b/src/func.c @@ -9,12 +9,9 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file contains the C functions that implement various SQL -** functions of SQLite. -** -** There is only one exported symbol in this file - the function -** sqliteRegisterBuildinFunctions() found at the bottom of the file. -** All other code has file scope. +** This file contains the C-language implementions for many of the SQL +** functions of SQLite. (Some function, and in particular the date and +** time functions, are implemented separately.) */ #include "sqliteInt.h" #include @@ -1541,7 +1538,7 @@ static void groupConcatStep( } zVal = (char*)sqlite3_value_text(argv[0]); nVal = sqlite3_value_bytes(argv[0]); - if( nVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal); + if( zVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal); } } static void groupConcatFinalize(sqlite3_context *context){ @@ -1691,6 +1688,7 @@ void sqlite3RegisterGlobalFunctions(void){ FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), + FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), FUNCTION(nullif, 2, 0, 1, nullifFunc ), diff --git a/src/global.c b/src/global.c index 1ee3f64..2c14b58 100644 --- a/src/global.c +++ b/src/global.c @@ -173,15 +173,22 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0, /* isMutexInit */ 0, /* isMallocInit */ 0, /* isPCacheInit */ - 0, /* pInitMutex */ 0, /* nRefInitMutex */ + 0, /* pInitMutex */ 0, /* xLog */ 0, /* pLogArg */ - 0, /* bLocaltimeFault */ #ifdef SQLITE_ENABLE_SQLLOG 0, /* xSqllog */ - 0 /* pSqllogArg */ + 0, /* pSqllogArg */ #endif +#ifdef SQLITE_VDBE_COVERAGE + 0, /* xVdbeBranch */ + 0, /* pVbeBranchArg */ +#endif +#ifndef SQLITE_OMIT_BUILTIN_TEST + 0, /* xTestCallback */ +#endif + 0 /* bLocaltimeFault */ }; /* diff --git a/src/insert.c b/src/insert.c index abdf1ad..5964b91 100644 --- a/src/insert.c +++ b/src/insert.c @@ -614,6 +614,7 @@ void sqlite3Insert( if( j>=pTab->nCol ){ if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){ ipkColumn = i; + bIdListInOrder = 0; }else{ sqlite3ErrorMsg(pParse, "table %S has no column named %s", pTabList, 0, pColumn->a[i].zName); @@ -1462,7 +1463,7 @@ void sqlite3GenerateConstraintChecks( ** KEY values of this row before the update. */ int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol; int op = OP_Ne; - int regCmp = (pIdx->autoIndex==2 ? regIdx : regR); + int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR); for(i=0; inKeyCol; i++){ char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]); @@ -1563,7 +1564,7 @@ void sqlite3CompleteInsertion( sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]); pik_flags = 0; if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT; - if( pIdx->autoIndex==2 && !HasRowid(pTab) ){ + if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ assert( pParse->nested==0 ); pik_flags |= OPFLAG_NCHANGE; } @@ -1649,7 +1650,7 @@ int sqlite3OpenTableAndIndices( for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ int iIdxCur = iBase++; assert( pIdx->pSchema==pTab->pSchema ); - if( pIdx->autoIndex==2 && !HasRowid(pTab) && piDataCur ){ + if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){ *piDataCur = iIdxCur; } if( aToOpen==0 || aToOpen[i+1] ){ @@ -1865,18 +1866,27 @@ static int xferOptimization( return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ } for(i=0; inCol; i++){ - if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){ + Column *pDestCol = &pDest->aCol[i]; + Column *pSrcCol = &pSrc->aCol[i]; + if( pDestCol->affinity!=pSrcCol->affinity ){ return 0; /* Affinity must be the same on all columns */ } - if( !xferCompatibleCollation(pDest->aCol[i].zColl, pSrc->aCol[i].zColl) ){ + if( !xferCompatibleCollation(pDestCol->zColl, pSrcCol->zColl) ){ return 0; /* Collating sequence must be the same on all columns */ } - if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){ + if( pDestCol->notNull && !pSrcCol->notNull ){ return 0; /* tab2 must be NOT NULL if tab1 is */ } + /* Default values for second and subsequent columns need to match. */ + if( i>0 + && ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0) + || (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0)) + ){ + return 0; /* Default values must be the same for all columns */ + } } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ - if( pDestIdx->onError!=OE_None ){ + if( IsUniqueIndex(pDestIdx) ){ destHasUniqueIdx = 1; } for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){ diff --git a/src/legacy.c b/src/legacy.c index 94649ae..1913f0b 100644 --- a/src/legacy.c +++ b/src/legacy.c @@ -96,6 +96,9 @@ int sqlite3_exec( } } if( xCallback(pArg, nCol, azVals, azCols) ){ + /* EVIDENCE-OF: R-38229-40159 If the callback function to + ** sqlite3_exec() returns non-zero, then sqlite3_exec() will + ** return SQLITE_ABORT. */ rc = SQLITE_ABORT; sqlite3VdbeFinalize((Vdbe *)pStmt); pStmt = 0; diff --git a/src/main.c b/src/main.c index 8b7495d..cea7282 100644 --- a/src/main.c +++ b/src/main.c @@ -800,6 +800,7 @@ static void disconnectAllVtab(sqlite3 *db){ } } } + sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); #else UNUSED_PARAMETER(db); @@ -826,6 +827,8 @@ static int connectionIsBusy(sqlite3 *db){ */ static int sqlite3Close(sqlite3 *db, int forceZombie){ if( !db ){ + /* EVIDENCE-OF: R-63257-11740 Calling sqlite3_close() or + ** sqlite3_close_v2() with a NULL pointer argument is a harmless no-op. */ return SQLITE_OK; } if( !sqlite3SafetyCheckSickOrOk(db) ){ @@ -1055,7 +1058,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ ** Return a static string containing the name corresponding to the error code ** specified in the argument. */ -#if defined(SQLITE_TEST) +#if (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) || defined(SQLITE_TEST) const char *sqlite3ErrName(int rc){ const char *zName = 0; int i, origRc = rc; @@ -1090,7 +1093,6 @@ const char *sqlite3ErrName(int rc){ case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break; case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break; case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break; - case SQLITE_IOERR_BLOCKED: zName = "SQLITE_IOERR_BLOCKED"; break; case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break; case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break; case SQLITE_IOERR_CHECKRESERVEDLOCK: @@ -2075,7 +2077,7 @@ static const int aHardLimit[] = { SQLITE_MAX_FUNCTION_ARG, SQLITE_MAX_ATTACHED, SQLITE_MAX_LIKE_PATTERN_LENGTH, - SQLITE_MAX_VARIABLE_NUMBER, + SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ SQLITE_MAX_TRIGGER_DEPTH, }; @@ -2100,8 +2102,8 @@ static const int aHardLimit[] = { #if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000 # error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000 #endif -#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>62 -# error SQLITE_MAX_ATTACHED must be between 0 and 62 +#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125 +# error SQLITE_MAX_ATTACHED must be between 0 and 125 #endif #if SQLITE_MAX_LIKE_PATTERN_LENGTH<1 # error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1 @@ -3113,6 +3115,28 @@ int sqlite3_test_control(int op, ...){ break; } + /* + ** sqlite3_test_control(FAULT_INSTALL, xCallback) + ** + ** Arrange to invoke xCallback() whenever sqlite3FaultSim() is called, + ** if xCallback is not NULL. + ** + ** As a test of the fault simulator mechanism itself, sqlite3FaultSim(0) + ** is called immediately after installing the new callback and the return + ** value from sqlite3FaultSim(0) becomes the return from + ** sqlite3_test_control(). + */ + case SQLITE_TESTCTRL_FAULT_INSTALL: { + /* MSVC is picky about pulling func ptrs from va lists. + ** http://support.microsoft.com/kb/47961 + ** sqlite3GlobalConfig.xTestCallback = va_arg(ap, int(*)(int)); + */ + typedef int(*TESTCALLBACKFUNC_t)(int); + sqlite3GlobalConfig.xTestCallback = va_arg(ap, TESTCALLBACKFUNC_t); + rc = sqlite3FaultSim(0); + break; + } + /* ** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd) ** @@ -3204,6 +3228,22 @@ int sqlite3_test_control(int op, ...){ break; } + /* + ** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER); + ** + ** The integer returned reveals the byte-order of the computer on which + ** SQLite is running: + ** + ** 1 big-endian, determined at run-time + ** 10 little-endian, determined at run-time + ** 432101 big-endian, determined at compile-time + ** 123410 little-endian, determined at compile-time + */ + case SQLITE_TESTCTRL_BYTEORDER: { + rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN; + break; + } + /* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N) ** ** Set the nReserve size to N for the main database on the database @@ -3322,6 +3362,16 @@ int sqlite3_test_control(int op, ...){ break; } + /* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT); + ** + ** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if + ** not. + */ + case SQLITE_TESTCTRL_ISINIT: { + if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; + break; + } + } va_end(ap); #endif /* SQLITE_OMIT_BUILTIN_TEST */ @@ -3370,7 +3420,7 @@ sqlite3_int64 sqlite3_uri_int64( ){ const char *z = sqlite3_uri_parameter(zFilename, zParam); sqlite3_int64 v; - if( z && sqlite3Atoi64(z, &v, sqlite3Strlen30(z), SQLITE_UTF8)==SQLITE_OK ){ + if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){ bDflt = v; } return bDflt; @@ -3406,5 +3456,5 @@ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){ */ int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){ Btree *pBt = sqlite3DbNameToBtree(db, zDbName); - return pBt ? sqlite3PagerIsreadonly(sqlite3BtreePager(pBt)) : -1; + return pBt ? sqlite3BtreeIsReadonly(pBt) : -1; } diff --git a/src/mem5.c b/src/mem5.c index 5d75611..67615bb 100644 --- a/src/mem5.c +++ b/src/mem5.c @@ -248,7 +248,7 @@ static void *memsys5MallocUnsafe(int nByte){ ** block. If not, then split a block of the next larger power of ** two in order to create a new free block of size iLogsize. */ - for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){} + for(iBin=iLogsize; iBin<=LOGMAX && mem5.aiFreelist[iBin]<0; iBin++){} if( iBin>LOGMAX ){ testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte); diff --git a/src/mutex.c b/src/mutex.c index b567e7c..bad5a7c 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -81,7 +81,7 @@ int sqlite3MutexEnd(void){ */ sqlite3_mutex *sqlite3_mutex_alloc(int id){ #ifndef SQLITE_OMIT_AUTOINIT - if( sqlite3_initialize() ) return 0; + if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0; #endif return sqlite3GlobalConfig.mutex.xMutexAlloc(id); } diff --git a/src/mutex_noop.c b/src/mutex_noop.c index 456e82a..1a900c2 100644 --- a/src/mutex_noop.c +++ b/src/mutex_noop.c @@ -107,7 +107,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; } ** that means that a mutex could not be allocated. */ static sqlite3_mutex *debugMutexAlloc(int id){ - static sqlite3_debug_mutex aStatic[6]; + static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_APP3 - 1]; sqlite3_debug_mutex *pNew = 0; switch( id ){ case SQLITE_MUTEX_FAST: diff --git a/src/mutex_unix.c b/src/mutex_unix.c index eca7295..c866314 100644 --- a/src/mutex_unix.c +++ b/src/mutex_unix.c @@ -96,10 +96,13 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; } **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MASTER **
  • SQLITE_MUTEX_STATIC_MEM -**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU **
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 +**
  • SQLITE_MUTEX_STATIC_APP3 ** ** ** The first two constants cause sqlite3_mutex_alloc() to create @@ -133,6 +136,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER }; sqlite3_mutex *p; diff --git a/src/mutex_w32.c b/src/mutex_w32.c index 4b88c17..218342d 100644 --- a/src/mutex_w32.c +++ b/src/mutex_w32.c @@ -9,13 +9,25 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file contains the C functions that implement mutexes for win32 +** This file contains the C functions that implement mutexes for Win32. */ #include "sqliteInt.h" +#if SQLITE_OS_WIN +/* +** Include code that is common to all os_*.c files +*/ +#include "os_common.h" + +/* +** Include the header file for the Windows VFS. +*/ +#include "os_win.h" +#endif + /* ** The code in this file is only used if we are compiling multithreaded -** on a win32 system. +** on a Win32 system. */ #ifdef SQLITE_MUTEX_W32 @@ -28,48 +40,22 @@ struct sqlite3_mutex { #ifdef SQLITE_DEBUG volatile int nRef; /* Number of enterances */ volatile DWORD owner; /* Thread holding this mutex */ - int trace; /* True to trace changes */ + volatile int trace; /* True to trace changes */ #endif }; -#define SQLITE_W32_MUTEX_INITIALIZER { 0 } -#ifdef SQLITE_DEBUG -#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 } -#else -#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 } -#endif /* -** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, -** or WinCE. Return false (zero) for Win95, Win98, or WinME. -** -** Here is an interesting observation: Win95, Win98, and WinME lack -** the LockFileEx() API. But we can still statically link against that -** API as long as we don't call it win running Win95/98/ME. A call to -** this routine is used to determine if the host is Win95/98/ME or -** WinNT/2K/XP so that we will know whether or not we can safely call -** the LockFileEx() API. -** -** mutexIsNT() is only used for the TryEnterCriticalSection() API call, -** which is only available if your application was compiled with -** _WIN32_WINNT defined to a value >= 0x0400. Currently, the only -** call to TryEnterCriticalSection() is #ifdef'ed out, so #ifdef -** this out as well. +** These are the initializer values used when declaring a "static" mutex +** on Win32. It should be noted that all mutexes require initialization +** on the Win32 platform. */ -#if 0 -#if SQLITE_OS_WINCE || SQLITE_OS_WINRT -# define mutexIsNT() (1) +#define SQLITE_W32_MUTEX_INITIALIZER { 0 } + +#ifdef SQLITE_DEBUG +#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \ + 0L, (DWORD)0, 0 } #else - static int mutexIsNT(void){ - static int osType = 0; - if( osType==0 ){ - OSVERSIONINFO sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - GetVersionEx(&sInfo); - osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; - } - return osType==2; - } -#endif /* SQLITE_OS_WINCE || SQLITE_OS_WINRT */ +#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 } #endif #ifdef SQLITE_DEBUG @@ -80,20 +66,24 @@ struct sqlite3_mutex { static int winMutexHeld(sqlite3_mutex *p){ return p->nRef!=0 && p->owner==GetCurrentThreadId(); } + static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){ return p->nRef==0 || p->owner!=tid; } + static int winMutexNotheld(sqlite3_mutex *p){ - DWORD tid = GetCurrentThreadId(); + DWORD tid = GetCurrentThreadId(); return winMutexNotheld2(p, tid); } #endif - /* ** Initialize and deinitialize the mutex subsystem. */ -static sqlite3_mutex winMutex_staticMutexes[6] = { +static sqlite3_mutex winMutex_staticMutexes[] = { + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, @@ -101,17 +91,20 @@ static sqlite3_mutex winMutex_staticMutexes[6] = { SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER }; -static int winMutex_isInit = 0; -/* As winMutexInit() and winMutexEnd() are called as part -** of the sqlite3_initialize and sqlite3_shutdown() -** processing, the "interlocked" magic is probably not -** strictly necessary. -*/ -static LONG winMutex_lock = 0; +static int winMutex_isInit = 0; +static int winMutex_isNt = -1; /* <0 means "need to query" */ + +/* As the winMutexInit() and winMutexEnd() functions are called as part +** of the sqlite3_initialize() and sqlite3_shutdown() processing, the +** "interlocked" magic used here is probably not strictly necessary. +*/ +static LONG volatile winMutex_lock = 0; + +int sqlite3_win32_is_nt(void); /* os_win.c */ void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ -static int winMutexInit(void){ +static int winMutexInit(void){ /* The first to increment to 1 does actual initialization */ if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){ int i; @@ -124,16 +117,17 @@ static int winMutexInit(void){ } winMutex_isInit = 1; }else{ - /* Someone else is in the process of initing the static mutexes */ + /* Another thread is (in the process of) initializing the static + ** mutexes */ while( !winMutex_isInit ){ sqlite3_win32_sleep(1); } } - return SQLITE_OK; + return SQLITE_OK; } -static int winMutexEnd(void){ - /* The first to decrement to 0 does actual shutdown +static int winMutexEnd(void){ + /* The first to decrement to 0 does actual shutdown ** (which should be the last to shutdown.) */ if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){ if( winMutex_isInit==1 ){ @@ -144,7 +138,7 @@ static int winMutexEnd(void){ winMutex_isInit = 0; } } - return SQLITE_OK; + return SQLITE_OK; } /* @@ -159,10 +153,13 @@ static int winMutexEnd(void){ **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MASTER **
  • SQLITE_MUTEX_STATIC_MEM -**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU **
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 +**
  • SQLITE_MUTEX_STATIC_APP3 ** ** ** The first two constants cause sqlite3_mutex_alloc() to create @@ -185,7 +182,7 @@ static int winMutexEnd(void){ ** ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() -** returns a different mutex on every call. But for the static +** returns a different mutex on every call. But for the static ** mutex types, the same mutex is returned on every call that has ** the same type number. */ @@ -196,9 +193,12 @@ static sqlite3_mutex *winMutexAlloc(int iType){ case SQLITE_MUTEX_FAST: case SQLITE_MUTEX_RECURSIVE: { p = sqlite3MallocZero( sizeof(*p) ); - if( p ){ + if( p ){ #ifdef SQLITE_DEBUG p->id = iType; +#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC + p->trace = 1; +#endif #endif #if SQLITE_OS_WINRT InitializeCriticalSectionEx(&p->mutex, 0, 0); @@ -209,12 +209,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){ break; } default: { - assert( winMutex_isInit==1 ); assert( iType-2 >= 0 ); assert( iType-2 < ArraySize(winMutex_staticMutexes) ); + assert( winMutex_isInit==1 ); p = &winMutex_staticMutexes[iType-2]; #ifdef SQLITE_DEBUG p->id = iType; +#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC + p->trace = 1; +#endif #endif break; } @@ -230,8 +233,11 @@ static sqlite3_mutex *winMutexAlloc(int iType){ */ static void winMutexFree(sqlite3_mutex *p){ assert( p ); +#ifdef SQLITE_DEBUG assert( p->nRef==0 && p->owner==0 ); assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); +#endif + assert( winMutex_isInit==1 ); DeleteCriticalSection(&p->mutex); sqlite3_free(p); } @@ -248,30 +254,39 @@ static void winMutexFree(sqlite3_mutex *p){ ** more than once, the behavior is undefined. */ static void winMutexEnter(sqlite3_mutex *p){ -#ifdef SQLITE_DEBUG - DWORD tid = GetCurrentThreadId(); - assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + DWORD tid = GetCurrentThreadId(); #endif +#ifdef SQLITE_DEBUG + assert( p ); + assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); +#else + assert( p ); +#endif + assert( winMutex_isInit==1 ); EnterCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG assert( p->nRef>0 || p->owner==0 ); - p->owner = tid; + p->owner = tid; p->nRef++; if( p->trace ){ - printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", + tid, p, p->trace, p->nRef)); } #endif } + static int winMutexTry(sqlite3_mutex *p){ -#ifndef NDEBUG - DWORD tid = GetCurrentThreadId(); +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + DWORD tid = GetCurrentThreadId(); #endif int rc = SQLITE_BUSY; + assert( p ); assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); /* ** The sqlite3_mutex_try() routine is very rarely used, and when it ** is used it is merely an optimization. So it is OK for it to always - ** fail. + ** fail. ** ** The TryEnterCriticalSection() interface is only available on WinNT. ** And some windows compilers complain if you try to use it without @@ -279,18 +294,27 @@ static int winMutexTry(sqlite3_mutex *p){ ** For that reason, we will omit this optimization for now. See ** ticket #2685. */ -#if 0 - if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){ +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 + assert( winMutex_isInit==1 ); + assert( winMutex_isNt>=-1 && winMutex_isNt<=1 ); + if( winMutex_isNt<0 ){ + winMutex_isNt = sqlite3_win32_is_nt(); + } + assert( winMutex_isNt==0 || winMutex_isNt==1 ); + if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){ +#ifdef SQLITE_DEBUG p->owner = tid; p->nRef++; +#endif rc = SQLITE_OK; } #else UNUSED_PARAMETER(p); #endif #ifdef SQLITE_DEBUG - if( rc==SQLITE_OK && p->trace ){ - printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + if( p->trace ){ + OSTRACE(("TRY-MUTEX tid=%lu, mutex=%p (%d), owner=%lu, nRef=%d, rc=%s\n", + tid, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc))); } #endif return rc; @@ -303,18 +327,23 @@ static int winMutexTry(sqlite3_mutex *p){ ** is not currently allocated. SQLite will never do either. */ static void winMutexLeave(sqlite3_mutex *p){ -#ifndef NDEBUG +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) DWORD tid = GetCurrentThreadId(); +#endif + assert( p ); +#ifdef SQLITE_DEBUG assert( p->nRef>0 ); assert( p->owner==tid ); p->nRef--; if( p->nRef==0 ) p->owner = 0; assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); #endif + assert( winMutex_isInit==1 ); LeaveCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG if( p->trace ){ - printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", + tid, p, p->trace, p->nRef)); } #endif } @@ -336,7 +365,7 @@ sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ 0 #endif }; - return &sMutex; } + #endif /* SQLITE_MUTEX_W32 */ diff --git a/src/os.h b/src/os.h index 070a2dd..3920a62 100644 --- a/src/os.h +++ b/src/os.h @@ -21,83 +21,10 @@ #define _SQLITE_OS_H_ /* -** Figure out if we are dealing with Unix, Windows, or some other -** operating system. After the following block of preprocess macros, -** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, and SQLITE_OS_OTHER -** will defined to either 1 or 0. One of the four will be 1. The other -** three will be 0. +** Attempt to automatically detect the operating system and setup the +** necessary pre-processor macros for it. */ -#if defined(SQLITE_OS_OTHER) -# if SQLITE_OS_OTHER==1 -# undef SQLITE_OS_UNIX -# define SQLITE_OS_UNIX 0 -# undef SQLITE_OS_WIN -# define SQLITE_OS_WIN 0 -# else -# undef SQLITE_OS_OTHER -# endif -#endif -#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER) -# define SQLITE_OS_OTHER 0 -# ifndef SQLITE_OS_WIN -# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) -# define SQLITE_OS_WIN 1 -# define SQLITE_OS_UNIX 0 -# else -# define SQLITE_OS_WIN 0 -# define SQLITE_OS_UNIX 1 -# endif -# else -# define SQLITE_OS_UNIX 0 -# endif -#else -# ifndef SQLITE_OS_WIN -# define SQLITE_OS_WIN 0 -# endif -#endif - -#if SQLITE_OS_WIN -# include -#endif - -/* -** Determine if we are dealing with Windows NT. -** -** We ought to be able to determine if we are compiling for win98 or winNT -** using the _WIN32_WINNT macro as follows: -** -** #if defined(_WIN32_WINNT) -** # define SQLITE_OS_WINNT 1 -** #else -** # define SQLITE_OS_WINNT 0 -** #endif -** -** However, vs2005 does not set _WIN32_WINNT by default, as it ought to, -** so the above test does not work. We'll just assume that everything is -** winNT unless the programmer explicitly says otherwise by setting -** SQLITE_OS_WINNT to 0. -*/ -#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT) -# define SQLITE_OS_WINNT 1 -#endif - -/* -** Determine if we are dealing with WindowsCE - which has a much -** reduced API. -*/ -#if defined(_WIN32_WCE) -# define SQLITE_OS_WINCE 1 -#else -# define SQLITE_OS_WINCE 0 -#endif - -/* -** Determine if we are dealing with WinRT, which provides only a subset of -** the full Win32 API. -*/ -#if !defined(SQLITE_OS_WINRT) -# define SQLITE_OS_WINRT 0 -#endif +#include "os_setup.h" /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op diff --git a/src/os_setup.h b/src/os_setup.h new file mode 100644 index 0000000..68de144 --- /dev/null +++ b/src/os_setup.h @@ -0,0 +1,57 @@ +/* +** 2013 November 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 contains pre-processor directives related to operating system +** detection and/or setup. +*/ +#ifndef _OS_SETUP_H_ +#define _OS_SETUP_H_ + +/* +** Figure out if we are dealing with Unix, Windows, or some other operating +** system. +** +** After the following block of preprocess macros, all of SQLITE_OS_UNIX, +** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of +** the three will be 1. The other two will be 0. +*/ +#if defined(SQLITE_OS_OTHER) +# if SQLITE_OS_OTHER==1 +# undef SQLITE_OS_UNIX +# define SQLITE_OS_UNIX 0 +# undef SQLITE_OS_WIN +# define SQLITE_OS_WIN 0 +# else +# undef SQLITE_OS_OTHER +# endif +#endif +#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER) +# define SQLITE_OS_OTHER 0 +# ifndef SQLITE_OS_WIN +# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \ + defined(__MINGW32__) || defined(__BORLANDC__) +# define SQLITE_OS_WIN 1 +# define SQLITE_OS_UNIX 0 +# else +# define SQLITE_OS_WIN 0 +# define SQLITE_OS_UNIX 1 +# endif +# else +# define SQLITE_OS_UNIX 0 +# endif +#else +# ifndef SQLITE_OS_WIN +# define SQLITE_OS_WIN 0 +# endif +#endif + +#endif /* _OS_SETUP_H_ */ diff --git a/src/os_unix.c b/src/os_unix.c index deb9e51..b1a0bed 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -94,11 +94,10 @@ #include #include #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 -#include +# include #endif - -#if SQLITE_ENABLE_LOCKING_STYLE +#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS # include # if OS_VXWORKS # include @@ -318,11 +317,16 @@ static int posixOpen(const char *zFile, int flags, int mode){ ** we are not running as root. */ static int posixFchown(int fd, uid_t uid, gid_t gid){ +#if OS_VXWORKS + return 0; +#else return geteuid() ? 0 : fchown(fd,uid,gid); +#endif } /* Forward reference */ static int openDirectory(const char*, int*); +static int unixGetpagesize(void); /* ** Many system calls are accessed through pointer-to-functions so that @@ -373,7 +377,7 @@ static struct unix_syscall { { "read", (sqlite3_syscall_ptr)read, 0 }, #define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) -#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE +#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) { "pread", (sqlite3_syscall_ptr)pread, 0 }, #else { "pread", (sqlite3_syscall_ptr)0, 0 }, @@ -390,7 +394,7 @@ static struct unix_syscall { { "write", (sqlite3_syscall_ptr)write, 0 }, #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) -#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE +#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, #else { "pwrite", (sqlite3_syscall_ptr)0, 0 }, @@ -444,6 +448,9 @@ static struct unix_syscall { { "mremap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent) + { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 }, +#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent) + #endif }; /* End of the overrideable system calls */ @@ -757,16 +764,6 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { case EPERM: return SQLITE_PERM; - /* EDEADLK is only possible if a call to fcntl(F_SETLKW) is made. And - ** this module never makes such a call. And the code in SQLite itself - ** asserts that SQLITE_IOERR_BLOCKED is never returned. For these reasons - ** this case is also commented out. If the system does set errno to EDEADLK, - ** the default SQLITE_IOERR_XXX code will be returned. */ -#if 0 - case EDEADLK: - return SQLITE_IOERR_BLOCKED; -#endif - #if EOPNOTSUPP!=ENOTSUP case EOPNOTSUPP: /* something went terribly awry, unless during file system support @@ -1299,9 +1296,13 @@ static int findInodeInfo( ** Return TRUE if pFile has been renamed or unlinked since it was first opened. */ static int fileHasMoved(unixFile *pFile){ +#if OS_VXWORKS + return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId; +#else struct stat buf; return pFile->pInode!=0 && - (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino); + (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino); +#endif } @@ -1914,6 +1915,13 @@ static int closeUnixFile(sqlite3_file *id){ vxworksReleaseFileId(pFile->pId); pFile->pId = 0; } +#endif +#ifdef SQLITE_UNLINK_AFTER_CLOSE + if( pFile->ctrlFlags & UNIXFILE_DELETE ){ + osUnlink(pFile->zPath); + sqlite3_free(*(char**)&pFile->zPath); + pFile->zPath = 0; + } #endif OSTRACE(("CLOSE %-3d\n", pFile->h)); OpenCounter(-1); @@ -2437,7 +2445,6 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { /* Otherwise see if some other process holds it. */ if( !reserved ){ sem_t *pSem = pFile->pInode->pSem; - struct stat statBuf; if( sem_trywait(pSem)==-1 ){ int tErrno = errno; @@ -2490,7 +2497,6 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { */ static int semLock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; - int fd; sem_t *pSem = pFile->pInode->pSem; int rc = SQLITE_OK; @@ -3953,8 +3959,25 @@ static int unixDeviceCharacteristics(sqlite3_file *id){ return rc; } -#ifndef SQLITE_OMIT_WAL +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 +/* +** Return the system page size. +** +** This function should not be called directly by other code in this file. +** Instead, it should be called via macro osGetpagesize(). +*/ +static int unixGetpagesize(void){ +#if defined(_BSD_SOURCE) + return getpagesize(); +#else + return (int)sysconf(_SC_PAGESIZE); +#endif +} + +#endif /* !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 */ + +#ifndef SQLITE_OMIT_WAL /* ** Object used to represent an shared memory buffer. @@ -4105,6 +4128,22 @@ static int unixShmSystemLock( return rc; } +/* +** Return the minimum number of 32KB shm regions that should be mapped at +** a time, assuming that each mapping must be an integer multiple of the +** current system page-size. +** +** Usually, this is 1. The exception seems to be systems that are configured +** to use 64KB pages - in this case each mapping must cover at least two +** shm regions. +*/ +static int unixShmRegionPerMap(void){ + int shmsz = 32*1024; /* SHM region size */ + int pgsz = osGetpagesize(); /* System page size */ + assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */ + if( pgszpInode->pShmNode; assert( unixMutexHeld() ); if( p && p->nRef==0 ){ + int nShmPerMap = unixShmRegionPerMap(); int i; assert( p->pInode==pFd->pInode ); sqlite3_mutex_free(p->mutex); - for(i=0; inRegion; i++){ + for(i=0; inRegion; i+=nShmPerMap){ if( p->h>=0 ){ osMunmap(p->apRegion[i], p->szRegion); }else{ @@ -4326,6 +4366,8 @@ static int unixShmMap( unixShm *p; unixShmNode *pShmNode; int rc = SQLITE_OK; + int nShmPerMap = unixShmRegionPerMap(); + int nReqRegion; /* If the shared-memory file has not yet been opened, open it now. */ if( pDbFd->pShm==0 ){ @@ -4341,9 +4383,12 @@ static int unixShmMap( assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); - if( pShmNode->nRegion<=iRegion ){ + /* Minimum number of regions required to be mapped. */ + nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; + + if( pShmNode->nRegionszRegion = szRegion; @@ -4392,17 +4437,19 @@ static int unixShmMap( /* Map the requested memory region into this processes address space. */ apNew = (char **)sqlite3_realloc( - pShmNode->apRegion, (iRegion+1)*sizeof(char *) + pShmNode->apRegion, nReqRegion*sizeof(char *) ); if( !apNew ){ rc = SQLITE_IOERR_NOMEM; goto shmpage_out; } pShmNode->apRegion = apNew; - while(pShmNode->nRegion<=iRegion){ + while( pShmNode->nRegionh>=0 ){ - pMem = osMmap(0, szRegion, + pMem = osMmap(0, nMap, pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion ); @@ -4418,8 +4465,11 @@ static int unixShmMap( } memset(pMem, 0, szRegion); } - pShmNode->apRegion[pShmNode->nRegion] = pMem; - pShmNode->nRegion++; + + for(i=0; iapRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i]; + } + pShmNode->nRegion += nShmPerMap; } } @@ -4633,19 +4683,6 @@ static void unixUnmapfile(unixFile *pFd){ } } -/* -** Return the system page size. -*/ -static int unixGetPagesize(void){ -#if HAVE_MREMAP - return 512; -#elif defined(_BSD_SOURCE) - return getpagesize(); -#else - return (int)sysconf(_SC_PAGESIZE); -#endif -} - /* ** Attempt to set the size of the memory mapping maintained by file ** descriptor pFd to nNew bytes. Any existing mapping is discarded. @@ -4682,8 +4719,12 @@ static void unixRemapfile( if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; if( pOrig ){ - const int szSyspage = unixGetPagesize(); +#if HAVE_MREMAP + i64 nReuse = pFd->mmapSize; +#else + const int szSyspage = osGetpagesize(); i64 nReuse = (pFd->mmapSize & ~(szSyspage-1)); +#endif u8 *pReq = &pOrig[nReuse]; /* Unmap any pages of the existing mapping that cannot be reused. */ @@ -5736,6 +5777,12 @@ static int unixOpen( if( isDelete ){ #if OS_VXWORKS zPath = zName; +#elif defined(SQLITE_UNLINK_AFTER_CLOSE) + zPath = sqlite3_mprintf("%s", zName); + if( zPath==0 ){ + robust_close(p, fd, __LINE__); + return SQLITE_NOMEM; + } #else osUnlink(zName); #endif @@ -5836,7 +5883,11 @@ static int unixDelete( UNUSED_PARAMETER(NotUsed); SimulateIOError(return SQLITE_IOERR_DELETE); if( osUnlink(zPath)==(-1) ){ - if( errno==ENOENT ){ + if( errno==ENOENT +#if OS_VXWORKS + || errno==0x380003 +#endif + ){ rc = SQLITE_IOERR_DELETE_NOENT; }else{ rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); @@ -7429,7 +7480,7 @@ int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==24 ); + assert( ArraySize(aSyscall)==25 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ diff --git a/src/os_win.c b/src/os_win.c index 287dad3..f479de3 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -15,16 +15,16 @@ #include "sqliteInt.h" #if SQLITE_OS_WIN /* This file is used for Windows only */ -#ifdef __CYGWIN__ -# include -# include /* amalgamator: keep */ -#endif - /* ** Include code that is common to all os_*.c files */ #include "os_common.h" +/* +** Include the header file for the Windows VFS. +*/ +#include "os_win.h" + /* ** Compiling and using WAL mode requires several APIs that are only ** available in Windows platforms based on the NT kernel. @@ -72,18 +72,14 @@ #endif /* -** Check if the GetVersionEx[AW] functions should be considered deprecated -** and avoid using them in that case. It should be noted here that if the -** value of the SQLITE_WIN32_GETVERSIONEX pre-processor macro is zero -** (whether via this block or via being manually specified), that implies -** the underlying operating system will always be based on the Windows NT -** Kernel. +** Check to see if the GetVersionEx[AW] functions are deprecated on the +** target system. GetVersionEx was first deprecated in Win8.1. */ #ifndef SQLITE_WIN32_GETVERSIONEX # if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE -# define SQLITE_WIN32_GETVERSIONEX 0 +# define SQLITE_WIN32_GETVERSIONEX 0 /* GetVersionEx() is deprecated */ # else -# define SQLITE_WIN32_GETVERSIONEX 1 +# define SQLITE_WIN32_GETVERSIONEX 1 /* GetVersionEx() is current */ # endif #endif @@ -155,7 +151,7 @@ ** [sometimes] not used by the code (e.g. via conditional compilation). */ #ifndef UNUSED_VARIABLE_VALUE -# define UNUSED_VARIABLE_VALUE(x) (void)(x) +# define UNUSED_VARIABLE_VALUE(x) (void)(x) #endif /* @@ -204,7 +200,7 @@ WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); ** Some Microsoft compilers lack this definition. */ #ifndef INVALID_FILE_ATTRIBUTES -# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif #ifndef FILE_FLAG_MASK @@ -254,7 +250,7 @@ struct winFile { int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ #if SQLITE_OS_WINCE LPWSTR zDeleteOnClose; /* Name of file to delete when closing */ - HANDLE hMutex; /* Mutex used to control access to shared lock */ + HANDLE hMutex; /* Mutex used to control access to shared lock */ HANDLE hShared; /* Shared memory segment used for locking */ winceLock local; /* Locks obtained by this instance of winFile */ winceLock *shared; /* Global shared lock memory for the file */ @@ -414,10 +410,9 @@ const sqlite3_mem_methods *sqlite3MemGetWin32(void); ** can manually set this value to 1 to emulate Win98 behavior. */ #ifdef SQLITE_TEST -int sqlite3_os_type = 0; -#elif !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ - defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_HAS_WIDE) -static int sqlite3_os_type = 0; +LONG volatile sqlite3_os_type = 0; +#else +static LONG volatile sqlite3_os_type = 0; #endif #ifndef SYSCALL @@ -1048,6 +1043,22 @@ static struct win_syscall { #define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent) +/* +** NOTE: On some sub-platforms, the InterlockedCompareExchange "function" +** is really just a macro that uses a compiler intrinsic (e.g. x64). +** So do not try to make this is into a redefinable interface. +*/ +#if defined(InterlockedCompareExchange) + { "InterlockedCompareExchange", (SYSCALL)0, 0 }, + +#define osInterlockedCompareExchange InterlockedCompareExchange +#else + { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, + +#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG volatile*, \ + LONG,LONG))aSyscall[76].pCurrent) +#endif /* defined(InterlockedCompareExchange) */ + }; /* End of the overrideable system calls */ /* @@ -1298,22 +1309,38 @@ void sqlite3_win32_sleep(DWORD milliseconds){ #elif !defined(SQLITE_WIN32_HAS_WIDE) # define osIsNT() (0) #else - static int osIsNT(void){ - if( sqlite3_os_type==0 ){ -#if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8 - OSVERSIONINFOW sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - osGetVersionExW(&sInfo); -#else - OSVERSIONINFOA sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - osGetVersionExA(&sInfo); +# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt()) +#endif + +/* +** This function determines if the machine is running a version of Windows +** based on the NT kernel. +*/ +int sqlite3_win32_is_nt(void){ +#if defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX + if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ + defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8 + OSVERSIONINFOW sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + osGetVersionExW(&sInfo); + osInterlockedCompareExchange(&sqlite3_os_type, + (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); +#elif defined(SQLITE_WIN32_HAS_ANSI) + OSVERSIONINFOA sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + osGetVersionExA(&sInfo); + osInterlockedCompareExchange(&sqlite3_os_type, + (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); #endif - sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; - } - return sqlite3_os_type==2; } + return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; +#elif SQLITE_TEST + return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; +#else + return 1; #endif +} #ifdef SQLITE_WIN32_MALLOC /* @@ -1521,7 +1548,7 @@ void sqlite3MemSetDefault(void){ #endif /* SQLITE_WIN32_MALLOC */ /* -** Convert a UTF-8 string to Microsoft Unicode (UTF-16?). +** Convert a UTF-8 string to Microsoft Unicode (UTF-16?). ** ** Space to hold the returned string is obtained from malloc. */ @@ -1574,7 +1601,7 @@ static char *winUnicodeToUtf8(LPCWSTR zWideFilename){ /* ** Convert an ANSI string to Microsoft Unicode, based on the ** current codepage settings for file apis. -** +** ** Space to hold the returned string is obtained ** from sqlite3_malloc. */ @@ -1648,7 +1675,7 @@ char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){ } /* -** Convert UTF-8 to multibyte character string. Space to hold the +** Convert UTF-8 to multibyte character string. Space to hold the ** returned string is obtained from sqlite3_malloc(). */ char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){ @@ -1788,11 +1815,11 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ ** ** This routine is invoked after an error occurs in an OS function. ** It logs a message using sqlite3_log() containing the current value of -** error code and, if possible, the human-readable equivalent from +** error code and, if possible, the human-readable equivalent from ** FormatMessage. ** ** The first argument passed to the macro should be the error code that -** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). +** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). ** The two subsequent arguments should be the name of the OS function that ** failed and the associated file-system path, if any. */ @@ -1823,7 +1850,7 @@ static int winLogErrorAtLine( /* ** The number of times that a ReadFile(), WriteFile(), and DeleteFile() -** will be retried following a locking error - probably caused by +** will be retried following a locking error - probably caused by ** antivirus software. Also the initial delay before the first retry. ** The delay increases linearly with each retry. */ @@ -1836,6 +1863,32 @@ static int winLogErrorAtLine( static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY; static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY; +/* +** The "winIoerrCanRetry1" macro is used to determine if a particular I/O +** error code obtained via GetLastError() is eligible to be retried. It +** must accept the error code DWORD as its only argument and should return +** non-zero if the error code is transient in nature and the operation +** responsible for generating the original error might succeed upon being +** retried. The argument to this macro should be a variable. +** +** Additionally, a macro named "winIoerrCanRetry2" may be defined. If it +** is defined, it will be consulted only when the macro "winIoerrCanRetry1" +** returns zero. The "winIoerrCanRetry2" macro is completely optional and +** may be used to include additional error codes in the set that should +** result in the failing I/O operation being retried by the caller. If +** defined, the "winIoerrCanRetry2" macro must exhibit external semantics +** identical to those of the "winIoerrCanRetry1" macro. +*/ +#if !defined(winIoerrCanRetry1) +#define winIoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \ + ((a)==ERROR_SHARING_VIOLATION) || \ + ((a)==ERROR_LOCK_VIOLATION) || \ + ((a)==ERROR_DEV_NOT_EXIST) || \ + ((a)==ERROR_NETNAME_DELETED) || \ + ((a)==ERROR_SEM_TIMEOUT) || \ + ((a)==ERROR_NETWORK_UNREACHABLE)) +#endif + /* ** If a ReadFile() or WriteFile() error occurs, invoke this routine ** to see if it should be retried. Return TRUE to retry. Return FALSE @@ -1849,13 +1902,18 @@ static int winRetryIoerr(int *pnRetry, DWORD *pError){ } return 0; } - if( e==ERROR_ACCESS_DENIED || - e==ERROR_LOCK_VIOLATION || - e==ERROR_SHARING_VIOLATION ){ + if( winIoerrCanRetry1(e) ){ sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); ++*pnRetry; return 1; } +#if defined(winIoerrCanRetry2) + else if( winIoerrCanRetry2(e) ){ + sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); + ++*pnRetry; + return 1; + } +#endif if( pError ){ *pError = e; } @@ -1867,7 +1925,7 @@ static int winRetryIoerr(int *pnRetry, DWORD *pError){ */ static void winLogIoerr(int nRetry){ if( nRetry ){ - sqlite3_log(SQLITE_IOERR, + sqlite3_log(SQLITE_IOERR, "delayed %dms for lock/sharing conflict", winIoerrRetryDelay*nRetry*(nRetry+1)/2 ); @@ -1961,17 +2019,17 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){ /* Acquire the mutex before continuing */ winceMutexAcquire(pFile->hMutex); - - /* Since the names of named mutexes, semaphores, file mappings etc are + + /* Since the names of named mutexes, semaphores, file mappings etc are ** case-sensitive, take advantage of that by uppercasing the mutex name ** and using that as the shared filemapping name. */ osCharUpperW(zName); pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(winceLock), - zName); + zName); - /* Set a flag that indicates we're the first to create the memory so it + /* Set a flag that indicates we're the first to create the memory so it ** must be zero-initialized */ lastErrno = osGetLastError(); if (lastErrno == ERROR_ALREADY_EXISTS){ @@ -1982,7 +2040,7 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){ /* If we succeeded in making the shared memory handle, map it. */ if( pFile->hShared ){ - pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared, + pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); /* If mapping failed, close the shared memory handle and erase it */ if( !pFile->shared ){ @@ -2008,7 +2066,7 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){ pFile->hMutex = NULL; return SQLITE_IOERR; } - + /* Initialize the shared memory if we're supposed to */ if( bInit ){ memset(pFile->shared, 0, sizeof(winceLock)); @@ -2046,13 +2104,13 @@ static void winceDestroyLock(winFile *pFile){ osCloseHandle(pFile->hShared); /* Done with the mutex */ - winceMutexRelease(pFile->hMutex); + winceMutexRelease(pFile->hMutex); osCloseHandle(pFile->hMutex); pFile->hMutex = NULL; } } -/* +/* ** An implementation of the LockFile() API of Windows for CE */ static BOOL winceLockFile( @@ -2263,8 +2321,8 @@ static BOOL winUnlockFile( #endif /* -** Move the current position of the file handle passed as the first -** argument to offset iOffset within the file. If successful, return 0. +** Move the current position of the file handle passed as the first +** argument to offset iOffset within the file. If successful, return 0. ** Otherwise, set pFile->lastErrno and return non-zero. */ static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ @@ -2279,11 +2337,11 @@ static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ upperBits = (LONG)((iOffset>>32) & 0x7fffffff); lowerBits = (LONG)(iOffset & 0xffffffff); - /* API oddity: If successful, SetFilePointer() returns a dword + /* API oddity: If successful, SetFilePointer() returns a dword ** containing the lower 32-bits of the new file-offset. Or, if it fails, - ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, - ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine - ** whether an error has actually occurred, it is also necessary to call + ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, + ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine + ** whether an error has actually occurred, it is also necessary to call ** GetLastError(). */ dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); @@ -2366,7 +2424,7 @@ static int winClose(sqlite3_file *id){ int cnt = 0; while( osDeleteFileW(pFile->zDeleteOnClose)==0 - && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff + && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff && cnt++ < WINCE_DELETION_ATTEMPTS ){ sqlite3_win32_sleep(100); /* Wait a little before trying again */ @@ -2794,7 +2852,7 @@ static int winGetReadLock(winFile *pFile){ pFile->lastErrno = osGetLastError(); /* No need to log a failure to lock */ } - OSTRACE(("READ-LOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res))); + OSTRACE(("READ-LOCK file=%p, result=%d\n", pFile->h, res)); return res; } @@ -2818,7 +2876,7 @@ static int winUnlockReadLock(winFile *pFile){ winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, "winUnlockReadLock", pFile->zPath); } - OSTRACE(("READ-UNLOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res))); + OSTRACE(("READ-UNLOCK file=%p, result=%d\n", pFile->h, res)); return res; } @@ -2893,8 +2951,16 @@ static int winLock(sqlite3_file *id, int locktype){ ** If you are using this code as a model for alternative VFSes, do not ** copy this retry logic. It is a hack intended for Windows only. */ - OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, rc=%s\n", - pFile->h, cnt, sqlite3ErrName(res))); + lastErrno = osGetLastError(); + OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n", + pFile->h, cnt, res)); + if( lastErrno==ERROR_INVALID_HANDLE ){ + pFile->lastErrno = lastErrno; + rc = SQLITE_IOERR_LOCK; + OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n", + pFile->h, cnt, sqlite3ErrName(rc))); + return rc; + } if( cnt ) sqlite3_win32_sleep(1); } gotPendingLock = res; @@ -2979,7 +3045,7 @@ static int winLock(sqlite3_file *id, int locktype){ ** non-zero, otherwise zero. */ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){ - int rc; + int res; winFile *pFile = (winFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); @@ -2987,17 +3053,17 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){ assert( id!=0 ); if( pFile->locktype>=RESERVED_LOCK ){ - rc = 1; - OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (local)\n", pFile->h, rc)); + res = 1; + OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res)); }else{ - rc = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0); - if( rc ){ + res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0); + if( res ){ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); } - rc = !rc; - OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (remote)\n", pFile->h, rc)); + res = !res; + OSTRACE(("TEST-WR-LOCK file=%p, result=%d (remote)\n", pFile->h, res)); } - *pResOut = rc; + *pResOut = res; OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", pFile->h, pResOut, *pResOut)); return SQLITE_OK; @@ -3138,6 +3204,17 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } +#ifdef SQLITE_TEST + case SQLITE_FCNTL_WIN32_SET_HANDLE: { + LPHANDLE phFile = (LPHANDLE)pArg; + HANDLE hOldFile = pFile->h; + pFile->h = *phFile; + *phFile = hOldFile; + OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n", + hOldFile, pFile->h)); + return SQLITE_OK; + } +#endif case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = 0; int rc = winGetTempname(pFile->pVfs, &zTFile); @@ -3195,7 +3272,7 @@ static int winDeviceCharacteristics(sqlite3_file *id){ ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0); } -/* +/* ** Windows will only let you create file view mappings ** on allocation size granularity boundaries. ** During sqlite3_os_init() we do a GetSystemInfo() @@ -3207,11 +3284,11 @@ static SYSTEM_INFO winSysInfo; /* ** Helper functions to obtain and relinquish the global mutex. The -** global mutex is used to protect the winLockInfo objects used by +** global mutex is used to protect the winLockInfo objects used by ** this file, all of which may be shared by multiple threads. ** -** Function winShmMutexHeld() is used to assert() that the global mutex -** is held when required. This function is only used as part of assert() +** Function winShmMutexHeld() is used to assert() that the global mutex +** is held when required. This function is only used as part of assert() ** statements. e.g. ** ** winShmEnterMutex() @@ -3241,10 +3318,10 @@ static int winShmMutexHeld(void) { ** this object or while reading or writing the following fields: ** ** nRef -** pNext +** pNext ** ** The following fields are read-only after the object is created: -** +** ** fid ** zFilename ** @@ -3340,7 +3417,7 @@ static int winShmSystemLock( if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); } - + if( rc!= 0 ){ rc = SQLITE_OK; }else{ @@ -3436,7 +3513,7 @@ static int winOpenSharedMemory(winFile *pDbFd){ } pNew->zFilename = (char*)&pNew[1]; sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); - sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); + sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); /* Look to see if there is an existing winShmNode that can be used. ** If no matching winShmNode currently exists, create a new one. @@ -3473,7 +3550,7 @@ static int winOpenSharedMemory(winFile *pDbFd){ } /* Check to see if another process is holding the dead-man switch. - ** If not, truncate the file to zero length. + ** If not, truncate the file to zero length. */ if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); @@ -3502,7 +3579,7 @@ static int winOpenSharedMemory(winFile *pDbFd){ ** the cover of the winShmEnterMutex() mutex and the pointer from the ** new (struct winShm) object to the pShmNode has been set. All that is ** left to do is to link the new object into the linked list starting - ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex + ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex ** mutex. */ sqlite3_mutex_enter(pShmNode->mutex); @@ -3522,7 +3599,7 @@ shm_open_err: } /* -** Close a connection to shared-memory. Delete the underlying +** Close a connection to shared-memory. Delete the underlying ** storage if deleteFlag is true. */ static int winShmUnmap( @@ -3611,7 +3688,7 @@ static int winShmLock( if( rc==SQLITE_OK ){ p->exclMask &= ~mask; p->sharedMask &= ~mask; - } + } }else if( flags & SQLITE_SHM_SHARED ){ u16 allShared = 0; /* Union of locks held by connections other than "p" */ @@ -3650,7 +3727,7 @@ static int winShmLock( break; } } - + /* Get the exclusive locks at the system level. Then if successful ** also mark the local connection as being locked. */ @@ -3670,7 +3747,7 @@ static int winShmLock( } /* -** Implement a memory barrier or memory fence on shared memory. +** Implement a memory barrier or memory fence on shared memory. ** ** All loads and stores begun before the barrier must complete before ** any load or store begun after the barrier. @@ -3685,22 +3762,22 @@ static void winShmBarrier( } /* -** This function is called to obtain a pointer to region iRegion of the -** shared-memory associated with the database file fd. Shared-memory regions -** are numbered starting from zero. Each shared-memory region is szRegion +** This function is called to obtain a pointer to region iRegion of the +** shared-memory associated with the database file fd. Shared-memory regions +** are numbered starting from zero. Each shared-memory region is szRegion ** bytes in size. ** ** If an error occurs, an error code is returned and *pp is set to NULL. ** ** Otherwise, if the isWrite parameter is 0 and the requested shared-memory ** region has not been allocated (by any client, including one running in a -** separate process), then *pp is set to NULL and SQLITE_OK returned. If -** isWrite is non-zero and the requested shared-memory region has not yet +** separate process), then *pp is set to NULL and SQLITE_OK returned. If +** isWrite is non-zero and the requested shared-memory region has not yet ** been allocated, it is allocated by this function. ** ** If the shared-memory region has already been allocated or is allocated by -** this call as described above, then it is mapped into this processes -** address space (if it is not already), *pp is set to point to the mapped +** this call as described above, then it is mapped into this processes +** address space (if it is not already), *pp is set to point to the mapped ** memory and SQLITE_OK returned. */ static int winShmMap( @@ -3772,17 +3849,17 @@ static int winShmMap( while( pShmNode->nRegion<=iRegion ){ HANDLE hMap = NULL; /* file-mapping handle */ void *pMap = 0; /* Mapped memory region */ - + #if SQLITE_OS_WINRT hMap = osCreateFileMappingFromApp(pShmNode->hFile.h, NULL, PAGE_READWRITE, nByte, NULL ); #elif defined(SQLITE_WIN32_HAS_WIDE) - hMap = osCreateFileMappingW(pShmNode->hFile.h, + hMap = osCreateFileMappingW(pShmNode->hFile.h, NULL, PAGE_READWRITE, 0, nByte, NULL ); #elif defined(SQLITE_WIN32_HAS_ANSI) - hMap = osCreateFileMappingA(pShmNode->hFile.h, + hMap = osCreateFileMappingA(pShmNode->hFile.h, NULL, PAGE_READWRITE, 0, nByte, NULL ); #endif @@ -3879,14 +3956,14 @@ static int winUnmapfile(winFile *pFile){ /* ** Memory map or remap the file opened by file-descriptor pFd (if the file -** is already mapped, the existing mapping is replaced by the new). Or, if -** there already exists a mapping for this file, and there are still +** is already mapped, the existing mapping is replaced by the new). Or, if +** there already exists a mapping for this file, and there are still ** outstanding xFetch() references to it, this function is a no-op. ** -** If parameter nByte is non-negative, then it is the requested size of -** the mapping to create. Otherwise, if nByte is less than zero, then the +** If parameter nByte is non-negative, then it is the requested size of +** the mapping to create. Otherwise, if nByte is less than zero, then the ** requested size is the size of the file on disk. The actual size of the -** created mapping is either the requested size or the value configured +** created mapping is either the requested size or the value configured ** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller. ** ** SQLITE_OK is returned if no error occurs (even if the mapping is not @@ -3915,7 +3992,7 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ nMap = pFd->mmapSizeMax; } nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1); - + if( nMap==0 && pFd->mmapSize>0 ){ winUnmapfile(pFd); } @@ -3987,7 +4064,7 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ ** Finally, if an error does occur, return an SQLite error code. The final ** value of *pp is undefined in this case. ** -** If this function does return a pointer, the caller must eventually +** If this function does return a pointer, the caller must eventually ** release the reference by calling winUnfetch(). */ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ @@ -4022,20 +4099,20 @@ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ } /* -** If the third argument is non-NULL, then this function releases a +** If the third argument is non-NULL, then this function releases a ** reference obtained by an earlier call to winFetch(). The second ** argument passed to this function must be the same as the corresponding -** argument that was passed to the winFetch() invocation. +** argument that was passed to the winFetch() invocation. ** -** Or, if the third argument is NULL, then this function is being called -** to inform the VFS layer that, according to POSIX, any existing mapping +** Or, if the third argument is NULL, then this function is being called +** to inform the VFS layer that, according to POSIX, any existing mapping ** may now be invalid and should be unmapped. */ static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){ #if SQLITE_MAX_MMAP_SIZE>0 winFile *pFd = (winFile*)fd; /* The underlying database file */ - /* If p==0 (unmap the entire file) then there must be no outstanding + /* If p==0 (unmap the entire file) then there must be no outstanding ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference), ** then there must be at least one outstanding. */ assert( (p==0)==(pFd->nFetchOut==0) ); @@ -4181,7 +4258,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this - ** function failing. + ** function failing. */ SimulateIOError( return SQLITE_IOERR ); @@ -4363,7 +4440,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ } /* - ** Check that the output buffer is large enough for the temporary file + ** Check that the output buffer is large enough for the temporary file ** name in the following format: ** ** "/etilqs_XXXXXXXXXXXXXXX\0\0" @@ -4466,8 +4543,8 @@ static int winOpen( #ifndef NDEBUG int isOpenJournal = (isCreate && ( - eType==SQLITE_OPEN_MASTER_JOURNAL - || eType==SQLITE_OPEN_MAIN_JOURNAL + eType==SQLITE_OPEN_MASTER_JOURNAL + || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_WAL )); #endif @@ -4475,9 +4552,9 @@ static int winOpen( OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n", zUtf8Name, id, flags, pOutFlags)); - /* Check the following statements are true: + /* Check the following statements are true: ** - ** (a) Exactly one of the READWRITE and READONLY flags must be set, and + ** (a) Exactly one of the READWRITE and READONLY flags must be set, and ** (b) if CREATE is set, then READWRITE must also be set, and ** (c) if EXCLUSIVE is set, then CREATE must also be set. ** (d) if DELETEONCLOSE is set, then CREATE must also be set. @@ -4487,7 +4564,7 @@ static int winOpen( assert(isExclusive==0 || isCreate); assert(isDelete==0 || isCreate); - /* The main DB, main journal, WAL file and master journal are never + /* The main DB, main journal, WAL file and master journal are never ** automatically deleted. Nor are they ever temporary files. */ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); @@ -4495,9 +4572,9 @@ static int winOpen( assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); /* Assert that the upper layer has set one of the "file-type" flags. */ - assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB - || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL - || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL + assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB + || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL + || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); @@ -4512,8 +4589,8 @@ static int winOpen( } #endif - /* If the second argument to this function is NULL, generate a - ** temporary file name to use + /* If the second argument to this function is NULL, generate a + ** temporary file name to use */ if( !zUtf8Name ){ assert( isDelete && !isOpenJournal ); @@ -4553,8 +4630,8 @@ static int winOpen( dwDesiredAccess = GENERIC_READ; } - /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is - ** created. SQLite doesn't use it to indicate "exclusive access" + /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is + ** created. SQLite doesn't use it to indicate "exclusive access" ** as it is usually understood. */ if( isExclusive ){ @@ -4643,7 +4720,7 @@ static int winOpen( sqlite3_free(zConverted); sqlite3_free(zTmpname); if( isReadWrite && !isExclusive ){ - return winOpen(pVfs, zName, id, + return winOpen(pVfs, zName, id, ((flags|SQLITE_OPEN_READONLY) & ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); @@ -4852,14 +4929,14 @@ static int winAccess( WIN32_FILE_ATTRIBUTE_DATA sAttrData; memset(&sAttrData, 0, sizeof(sAttrData)); while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, - GetFileExInfoStandard, + GetFileExInfoStandard, &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){} if( rc ){ /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file ** as if it does not exist. */ if( flags==SQLITE_ACCESS_EXISTS - && sAttrData.nFileSizeHigh==0 + && sAttrData.nFileSizeHigh==0 && sAttrData.nFileSizeLow==0 ){ attr = INVALID_FILE_ATTRIBUTES; }else{ @@ -4958,7 +5035,7 @@ static int winFullPathname( int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ - + #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); @@ -5271,12 +5348,12 @@ int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */ ** epoch of noon in Greenwich on November 24, 4714 B.C according to the ** proleptic Gregorian calendar. ** -** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date +** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date ** cannot be found. */ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ - /* FILETIME structure is a 64-bit value representing the number of - 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). + /* FILETIME structure is a 64-bit value representing the number of + 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). */ FILETIME ft; static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000; @@ -5284,7 +5361,7 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; #endif /* 2^32 - to avoid use of LL and warnings in gcc */ - static const sqlite3_int64 max32BitValue = + static const sqlite3_int64 max32BitValue = (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296; @@ -5300,7 +5377,7 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ #endif *piNow = winFiletimeEpoch + - ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + + ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000; #ifdef SQLITE_TEST @@ -5419,7 +5496,7 @@ int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==76 ); + assert( ArraySize(aSyscall)==77 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); @@ -5437,10 +5514,10 @@ int sqlite3_os_init(void){ sqlite3_vfs_register(&winLongPathVfs, 0); #endif - return SQLITE_OK; + return SQLITE_OK; } -int sqlite3_os_end(void){ +int sqlite3_os_end(void){ #if SQLITE_OS_WINRT if( sleepObj!=NULL ){ osCloseHandle(sleepObj); diff --git a/src/os_win.h b/src/os_win.h new file mode 100644 index 0000000..d662cd4 --- /dev/null +++ b/src/os_win.h @@ -0,0 +1,67 @@ +/* +** 2013 November 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 contains code that is specific to Windows. +*/ +#ifndef _OS_WIN_H_ +#define _OS_WIN_H_ + +/* +** Include the primary Windows SDK header file. +*/ +#include "windows.h" + +#ifdef __CYGWIN__ +# include +# include /* amalgamator: dontcache */ +#endif + +/* +** Determine if we are dealing with Windows NT. +** +** We ought to be able to determine if we are compiling for Windows 9x or +** Windows NT using the _WIN32_WINNT macro as follows: +** +** #if defined(_WIN32_WINNT) +** # define SQLITE_OS_WINNT 1 +** #else +** # define SQLITE_OS_WINNT 0 +** #endif +** +** However, Visual Studio 2005 does not set _WIN32_WINNT by default, as +** it ought to, so the above test does not work. We'll just assume that +** everything is Windows NT unless the programmer explicitly says otherwise +** by setting SQLITE_OS_WINNT to 0. +*/ +#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT) +# define SQLITE_OS_WINNT 1 +#endif + +/* +** Determine if we are dealing with Windows CE - which has a much reduced +** API. +*/ +#if defined(_WIN32_WCE) +# define SQLITE_OS_WINCE 1 +#else +# define SQLITE_OS_WINCE 0 +#endif + +/* +** Determine if we are dealing with WinRT, which provides only a subset of +** the full Win32 API. +*/ +#if !defined(SQLITE_OS_WINRT) +# define SQLITE_OS_WINRT 0 +#endif + +#endif /* _OS_WIN_H_ */ diff --git a/src/pager.c b/src/pager.c index c6485a4..a77dcec 100644 --- a/src/pager.c +++ b/src/pager.c @@ -626,7 +626,8 @@ struct Pager { u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */ u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ - u8 tempFile; /* zFilename is a temporary file */ + u8 tempFile; /* zFilename is a temporary or immutable file */ + u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ @@ -1091,7 +1092,7 @@ static int pagerUnlockDb(Pager *pPager, int eLock){ assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 ); if( isOpen(pPager->fd) ){ assert( pPager->eLock>=eLock ); - rc = sqlite3OsUnlock(pPager->fd, eLock); + rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock); if( pPager->eLock!=UNKNOWN_LOCK ){ pPager->eLock = (u8)eLock; } @@ -1115,7 +1116,7 @@ static int pagerLockDb(Pager *pPager, int eLock){ assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK ); if( pPager->eLockeLock==UNKNOWN_LOCK ){ - rc = sqlite3OsLock(pPager->fd, eLock); + rc = pPager->noLock ? SQLITE_OK : sqlite3OsLock(pPager->fd, eLock); if( rc==SQLITE_OK && (pPager->eLock!=UNKNOWN_LOCK||eLock==EXCLUSIVE_LOCK) ){ pPager->eLock = (u8)eLock; IOTRACE(("LOCK %p %d\n", pPager, eLock)) @@ -1624,12 +1625,11 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ if( !zMaster || pPager->journalMode==PAGER_JOURNALMODE_MEMORY - || pPager->journalMode==PAGER_JOURNALMODE_OFF + || !isOpen(pPager->jfd) ){ return SQLITE_OK; } pPager->setMaster = 1; - assert( isOpen(pPager->jfd) ); assert( pPager->journalHdr <= pPager->journalOff ); /* Calculate the length in bytes and the checksum of zMaster */ @@ -4675,30 +4675,38 @@ int sqlite3PagerOpen( ** + The value returned by sqlite3OsSectorSize() ** + The largest page size that can be written atomically. */ - if( rc==SQLITE_OK && !readOnly ){ - setSectorSize(pPager); - assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE); - if( szPageDfltsectorSize ){ - if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ - szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE; - }else{ - szPageDflt = (u32)pPager->sectorSize; + if( rc==SQLITE_OK ){ + int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); + if( !readOnly ){ + setSectorSize(pPager); + assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE); + if( szPageDfltsectorSize ){ + if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ + szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE; + }else{ + szPageDflt = (u32)pPager->sectorSize; + } } - } #ifdef SQLITE_ENABLE_ATOMIC_WRITE - { - int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); - int ii; - assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); - assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); - assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); - for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ - if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ - szPageDflt = ii; + { + int ii; + assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); + assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); + assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); + for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ + if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ + szPageDflt = ii; + } } } - } #endif + } + pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0); + if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0 + || sqlite3_uri_boolean(zFilename, "immutable", 0) ){ + vfsFlags |= SQLITE_OPEN_READONLY; + goto act_like_temp_file; + } } }else{ /* If a temporary file is requested, it is not opened immediately. @@ -4708,10 +4716,14 @@ int sqlite3PagerOpen( ** This branch is also run for an in-memory database. An in-memory ** database is the same as a temp-file that is never written out to ** disk and uses an in-memory rollback journal. + ** + ** This branch also runs for files marked as immutable. */ +act_like_temp_file: tempFile = 1; - pPager->eState = PAGER_READER; - pPager->eLock = EXCLUSIVE_LOCK; + pPager->eState = PAGER_READER; /* Pretend we already have a lock */ + pPager->eLock = EXCLUSIVE_LOCK; /* Pretend we are in EXCLUSIVE locking mode */ + pPager->noLock = 1; /* Do no locking */ readOnly = (vfsFlags&SQLITE_OPEN_READONLY); } @@ -4752,9 +4764,6 @@ int sqlite3PagerOpen( /* pPager->nPage = 0; */ pPager->mxPgno = SQLITE_MAX_PAGE_COUNT; /* pPager->state = PAGER_UNLOCK; */ -#if 0 - assert( pPager->state == (tempFile ? PAGER_EXCLUSIVE : PAGER_UNLOCK) ); -#endif /* pPager->errMask = 0; */ pPager->tempFile = (u8)tempFile; assert( tempFile==PAGER_LOCKINGMODE_NORMAL diff --git a/src/parse.y b/src/parse.y index ad9bedf..dbc129c 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1020,6 +1020,33 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { */ A.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[N]); sqlite3ExprDelete(pParse->db, X.pExpr); + }else if( Y->nExpr==1 ){ + /* Expressions of the form: + ** + ** expr1 IN (?1) + ** expr1 NOT IN (?2) + ** + ** with exactly one value on the RHS can be simplified to something + ** like this: + ** + ** expr1 == ?1 + ** expr1 <> ?2 + ** + ** But, the RHS of the == or <> is marked with the EP_Generic flag + ** so that it may not contribute to the computation of comparison + ** affinity or the collating sequence to use for comparison. Otherwise, + ** the semantics would be subtly different from IN or NOT IN. + */ + Expr *pRHS = Y->a[0].pExpr; + Y->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, Y); + /* pRHS cannot be NULL because a malloc error would have been detected + ** before now and control would have never reached this point */ + if( ALWAYS(pRHS) ){ + pRHS->flags &= ~EP_Collate; + pRHS->flags |= EP_Generic; + } + A.pExpr = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, X.pExpr, pRHS, 0); }else{ A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0); if( A.pExpr ){ diff --git a/src/pragma.c b/src/pragma.c index fcecad2..9ed5e13 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -480,7 +480,7 @@ static const struct sPragmaNames { ** to support legacy SQL code. The safety level used to be boolean ** and older scripts may have used numbers 0 for OFF and 1 for ON. */ -static u8 getSafetyLevel(const char *z, int omitFull, int dflt){ +static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){ /* 123456789 123456789 */ static const char zText[] = "onoffalseyestruefull"; static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16}; @@ -502,7 +502,7 @@ static u8 getSafetyLevel(const char *z, int omitFull, int dflt){ /* ** Interpret the given string as a boolean value. */ -u8 sqlite3GetBoolean(const char *z, int dflt){ +u8 sqlite3GetBoolean(const char *z, u8 dflt){ return getSafetyLevel(z,1,dflt)!=0; } @@ -1048,7 +1048,7 @@ void sqlite3Pragma( Pager *pPager = sqlite3BtreePager(pDb->pBt); i64 iLimit = -2; if( zRight ){ - sqlite3Atoi64(zRight, &iLimit, sqlite3Strlen30(zRight), SQLITE_UTF8); + sqlite3DecOrHexToI64(zRight, &iLimit); if( iLimit<-1 ) iLimit = -1; } iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit); @@ -1176,7 +1176,7 @@ void sqlite3Pragma( assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( zRight ){ int ii; - sqlite3Atoi64(zRight, &sz, sqlite3Strlen30(zRight), SQLITE_UTF8); + sqlite3DecOrHexToI64(zRight, &sz); if( sz<0 ) sz = sqlite3GlobalConfig.szMmap; if( pId2->n==0 ) db->szMmap = sz; for(ii=db->nDb-1; ii>=0; ii--){ @@ -1488,13 +1488,15 @@ void sqlite3Pragma( sqlite3VdbeAddOp2(v, OP_Null, 0, 2); sqlite3VdbeAddOp2(v, OP_Integer, (int)sqlite3LogEstToInt(pTab->szTabRow), 3); - sqlite3VdbeAddOp2(v, OP_Integer, (int)pTab->nRowEst, 4); + sqlite3VdbeAddOp2(v, OP_Integer, + (int)sqlite3LogEstToInt(pTab->nRowLogEst), 4); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); sqlite3VdbeAddOp2(v, OP_Integer, (int)sqlite3LogEstToInt(pIdx->szIdxRow), 3); - sqlite3VdbeAddOp2(v, OP_Integer, (int)pIdx->aiRowEst[0], 4); + sqlite3VdbeAddOp2(v, OP_Integer, + (int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]), 4); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4); } } @@ -1542,7 +1544,7 @@ void sqlite3Pragma( for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); - sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3); + sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } } @@ -1792,9 +1794,8 @@ void sqlite3Pragma( */ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList endCode[] = { - { OP_AddImm, 1, 0, 0}, /* 0 */ - { OP_IfNeg, 1, 0, 0}, /* 1 */ - { OP_String8, 0, 3, 0}, /* 2 */ + { OP_IfNeg, 1, 0, 0}, /* 0 */ + { OP_String8, 0, 3, 0}, /* 1 */ { OP_ResultRow, 3, 1, 0}, }; @@ -1875,7 +1876,7 @@ void sqlite3Pragma( sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), P4_DYNAMIC); - sqlite3VdbeAddOp2(v, OP_Move, 2, 4); + sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1); sqlite3VdbeJumpHere(v, addr); @@ -1906,29 +1907,77 @@ void sqlite3Pragma( pParse->nMem = MAX(pParse->nMem, 8+j); sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); + /* Verify that all NOT NULL columns really are NOT NULL */ + for(j=0; jnCol; j++){ + char *zErr; + int jmp2, jmp3; + if( j==pTab->iPKey ) continue; + if( pTab->aCol[j].notNull==0 ) continue; + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ + zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, + pTab->aCol[j].zName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); + jmp3 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); + sqlite3VdbeAddOp0(v, OP_Halt); + sqlite3VdbeJumpHere(v, jmp2); + sqlite3VdbeJumpHere(v, jmp3); + } + /* Validate index entries for the current row */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ - int jmp2, jmp3, jmp4; + int jmp2, jmp3, jmp4, jmp5; + int ckUniq = sqlite3VdbeMakeLabel(v); if( pPk==pIdx ) continue; r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, pPrior, r1); pPrior = pIdx; sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */ - jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, 0, r1, + /* Verify that an index entry exists for the current table row */ + jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, pIdx->nColumn); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC); sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); - sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, " missing from index ", - P4_STATIC); + sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, + " missing from index ", P4_STATIC); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); - sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pIdx->zName, P4_TRANSIENT); + jmp5 = sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, + pIdx->zName, P4_TRANSIENT); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); sqlite3VdbeAddOp0(v, OP_Halt); - sqlite3VdbeJumpHere(v, jmp4); sqlite3VdbeJumpHere(v, jmp2); - sqlite3VdbeResolveLabel(v, jmp3); + /* For UNIQUE indexes, verify that only one entry exists with the + ** current key. The entry is unique if (1) any column is NULL + ** or (2) the next entry has a different key */ + if( IsUniqueIndex(pIdx) ){ + int uniqOk = sqlite3VdbeMakeLabel(v); + int jmp6; + int kk; + for(kk=0; kknKeyCol; kk++){ + int iCol = pIdx->aiColumn[kk]; + assert( iCol>=0 && iColnCol ); + if( pTab->aCol[iCol].notNull ) continue; + sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); + VdbeCoverage(v); + } + jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, uniqOk); + sqlite3VdbeJumpHere(v, jmp6); + sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1, + pIdx->nKeyCol); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, + "non-unique entry in index ", P4_STATIC); + sqlite3VdbeAddOp2(v, OP_Goto, 0, jmp5); + sqlite3VdbeResolveLabel(v, uniqOk); + } + sqlite3VdbeJumpHere(v, jmp4); + sqlite3ResolvePartIdxLabel(pParse, jmp3); } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeJumpHere(v, loopTop-1); @@ -1952,9 +2001,9 @@ void sqlite3Pragma( } } addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); - sqlite3VdbeChangeP2(v, addr, -mxErr); - sqlite3VdbeJumpHere(v, addr+1); - sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC); + sqlite3VdbeChangeP3(v, addr, -mxErr); + sqlite3VdbeJumpHere(v, addr); + sqlite3VdbeChangeP4(v, addr+1, "ok", P4_STATIC); } break; #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -2217,7 +2266,7 @@ void sqlite3Pragma( */ case PragTyp_SOFT_HEAP_LIMIT: { sqlite3_int64 N; - if( zRight && sqlite3Atoi64(zRight, &N, 1000000, SQLITE_UTF8)==SQLITE_OK ){ + if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ sqlite3_soft_heap_limit64(N); } returnSingleInt(pParse, "soft_heap_limit", sqlite3_soft_heap_limit64(-1)); diff --git a/src/printf.c b/src/printf.c index 8cfa542..3791080 100644 --- a/src/printf.c +++ b/src/printf.c @@ -134,20 +134,6 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ } #endif /* SQLITE_OMIT_FLOATING_POINT */ -/* -** Append N space characters to the given string buffer. -*/ -void sqlite3AppendSpace(StrAccum *pAccum, int N){ - static const char zSpaces[] = " "; - while( N>=(int)sizeof(zSpaces)-1 ){ - sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1); - N -= sizeof(zSpaces)-1; - } - if( N>0 ){ - sqlite3StrAccumAppend(pAccum, zSpaces, N); - } -} - /* ** Set the StrAccum object to an error mode. */ @@ -237,11 +223,9 @@ void sqlite3VXPrintf( } for(; (c=(*fmt))!=0; ++fmt){ if( c!='%' ){ - int amt; bufpt = (char *)fmt; - amt = 1; - while( (c=(*++fmt))!='%' && c!=0 ) amt++; - sqlite3StrAccumAppend(pAccum, bufpt, amt); + while( (c=(*++fmt))!='%' && c!=0 ){}; + sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt)); if( c==0 ) break; } if( (c=(*++fmt))==0 ){ @@ -422,10 +406,8 @@ void sqlite3VXPrintf( *(--bufpt) = zOrd[x*2]; } { - register const char *cset; /* Use registers for speed */ - register int base; - cset = &aDigits[infop->charset]; - base = infop->base; + const char *cset = &aDigits[infop->charset]; + u8 base = infop->base; do{ /* Convert to ascii */ *(--bufpt) = cset[longvalue%base]; longvalue = longvalue/base; @@ -729,29 +711,90 @@ void sqlite3VXPrintf( ** "length" characters long. The field width is "width". Do ** the output. */ - if( !flag_leftjustify ){ - register int nspace; - nspace = width-length; - if( nspace>0 ){ - sqlite3AppendSpace(pAccum, nspace); - } - } - if( length>0 ){ - sqlite3StrAccumAppend(pAccum, bufpt, length); - } - if( flag_leftjustify ){ - register int nspace; - nspace = width-length; - if( nspace>0 ){ - sqlite3AppendSpace(pAccum, nspace); - } - } + width -= length; + if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width); + sqlite3StrAccumAppend(pAccum, bufpt, length); + if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width); + if( zExtra ) sqlite3_free(zExtra); }/* End for loop over the format string */ } /* End of function */ /* -** Append N bytes of text from z to the StrAccum object. +** Enlarge the memory allocation on a StrAccum object so that it is +** able to accept at least N more bytes of text. +** +** Return the number of bytes of text that StrAccum is able to accept +** after the attempted enlargement. The value returned might be zero. +*/ +static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ + char *zNew; + assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */ + if( p->accError ){ + testcase(p->accError==STRACCUM_TOOBIG); + testcase(p->accError==STRACCUM_NOMEM); + return 0; + } + if( !p->useMalloc ){ + N = p->nAlloc - p->nChar - 1; + setStrAccumError(p, STRACCUM_TOOBIG); + return N; + }else{ + char *zOld = (p->zText==p->zBase ? 0 : p->zText); + i64 szNew = p->nChar; + szNew += N + 1; + if( szNew > p->mxAlloc ){ + sqlite3StrAccumReset(p); + setStrAccumError(p, STRACCUM_TOOBIG); + return 0; + }else{ + p->nAlloc = (int)szNew; + } + if( p->useMalloc==1 ){ + zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); + }else{ + zNew = sqlite3_realloc(zOld, p->nAlloc); + } + if( zNew ){ + assert( p->zText!=0 || p->nChar==0 ); + if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); + p->zText = zNew; + }else{ + sqlite3StrAccumReset(p); + setStrAccumError(p, STRACCUM_NOMEM); + return 0; + } + } + return N; +} + +/* +** Append N space characters to the given string buffer. +*/ +void sqlite3AppendSpace(StrAccum *p, int N){ + if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return; + while( (N--)>0 ) p->zText[p->nChar++] = ' '; +} + +/* +** The StrAccum "p" is not large enough to accept N new bytes of z[]. +** So enlarge if first, then do the append. +** +** This is a helper routine to sqlite3StrAccumAppend() that does special-case +** work (enlarging the buffer) using tail recursion, so that the +** sqlite3StrAccumAppend() routine can use fast calling semantics. +*/ +static void enlargeAndAppend(StrAccum *p, const char *z, int N){ + N = sqlite3StrAccumEnlarge(p, N); + if( N>0 ){ + memcpy(&p->zText[p->nChar], z, N); + p->nChar += N; + } +} + +/* +** Append N bytes of text from z to the StrAccum object. Increase the +** size of the memory allocation for StrAccum if necessary. */ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ assert( z!=0 ); @@ -759,43 +802,8 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ assert( N>=0 ); assert( p->accError==0 || p->nAlloc==0 ); if( p->nChar+N >= p->nAlloc ){ - char *zNew; - if( p->accError ){ - testcase(p->accError==STRACCUM_TOOBIG); - testcase(p->accError==STRACCUM_NOMEM); - return; - } - if( !p->useMalloc ){ - N = p->nAlloc - p->nChar - 1; - setStrAccumError(p, STRACCUM_TOOBIG); - if( N<=0 ){ - return; - } - }else{ - char *zOld = (p->zText==p->zBase ? 0 : p->zText); - i64 szNew = p->nChar; - szNew += N + 1; - if( szNew > p->mxAlloc ){ - sqlite3StrAccumReset(p); - setStrAccumError(p, STRACCUM_TOOBIG); - return; - }else{ - p->nAlloc = (int)szNew; - } - if( p->useMalloc==1 ){ - zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); - }else{ - zNew = sqlite3_realloc(zOld, p->nAlloc); - } - if( zNew ){ - if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); - p->zText = zNew; - }else{ - sqlite3StrAccumReset(p); - setStrAccumError(p, STRACCUM_NOMEM); - return; - } - } + enlargeAndAppend(p,z,N); + return; } assert( p->zText ); memcpy(&p->zText[p->nChar], z, N); diff --git a/src/resolve.c b/src/resolve.c index 86169c5..935d311 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -354,7 +354,7 @@ static int lookupName( } } if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && HasRowid(pTab) ){ - /* IMP: R-24309-18625 */ + /* IMP: R-51414-32910 */ /* IMP: R-44911-55124 */ iCol = -1; } @@ -710,8 +710,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is equivalent to ** likelihood(X, 0.0625). ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is short-hand for - ** likelihood(X,0.0625). */ - pExpr->iTable = 62; /* TUNING: Default 2nd arg to unlikely() is 0.0625 */ + ** likelihood(X,0.0625). + ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand for + ** likelihood(X,0.9375). + ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent to + ** likelihood(X,0.9375). */ + /* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */ + pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938; } } } diff --git a/src/rowset.c b/src/rowset.c index 5761f98..ba2e056 100644 --- a/src/rowset.c +++ b/src/rowset.c @@ -112,8 +112,8 @@ struct RowSet { struct RowSetEntry *pFresh; /* Source of new entry objects */ struct RowSetEntry *pForest; /* List of binary trees of entries */ u16 nFresh; /* Number of objects on pFresh */ - u8 rsFlags; /* Various flags */ - u8 iBatch; /* Current insert batch */ + u16 rsFlags; /* Various flags */ + int iBatch; /* Current insert batch */ }; /* @@ -447,7 +447,7 @@ int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ ** on pRowSet->pEntry, then sort those entires into the forest at ** pRowSet->pForest so that they can be tested. */ -int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){ +int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){ struct RowSetEntry *p, *pTree; /* This routine is never called after sqlite3RowSetNext() */ diff --git a/src/select.c b/src/select.c index 850bc6a..932874d 100644 --- a/src/select.c +++ b/src/select.c @@ -14,6 +14,34 @@ */ #include "sqliteInt.h" +/* +** An instance of the following object is used to record information about +** how to process the DISTINCT keyword, to simplify passing that information +** into the selectInnerLoop() routine. +*/ +typedef struct DistinctCtx DistinctCtx; +struct DistinctCtx { + u8 isTnct; /* True if the DISTINCT keyword is present */ + u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ + int tabTnct; /* Ephemeral table used for DISTINCT processing */ + int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ +}; + +/* +** An instance of the following object is used to record information about +** the ORDER BY (or GROUP BY) clause of query is being coded. +*/ +typedef struct SortCtx SortCtx; +struct SortCtx { + ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */ + int nOBSat; /* Number of ORDER BY terms satisfied by indices */ + int iECursor; /* Cursor number for the sorter */ + int regReturn; /* Register holding block-output return address */ + int labelBkOut; /* Start label for the block-output subroutine */ + int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ + u8 sortFlags; /* Zero or more SORTFLAG_* bits */ +}; +#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure but do not deallocate @@ -87,7 +115,6 @@ Select *sqlite3SelectNew( assert( pOffset==0 || pLimit!=0 ); pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; - pNew->addrOpenEphm[2] = -1; if( db->mallocFailed ) { clearSelect(db, pNew); if( pNew!=&standin ) sqlite3DbFree(db, pNew); @@ -419,34 +446,73 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ return 0; } +/* Forward reference */ +static KeyInfo *keyInfoFromExprList( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* Form the KeyInfo object from this ExprList */ + int iStart, /* Begin with this column of pList */ + int nExtra /* Add this many extra columns to the end */ +); + /* -** Insert code into "v" that will push the record on the top of the -** stack into the sorter. +** Insert code into "v" that will push the record in register regData +** into the sorter. */ static void pushOntoSorter( Parse *pParse, /* Parser context */ - ExprList *pOrderBy, /* The ORDER BY clause */ + SortCtx *pSort, /* Information about the ORDER BY clause */ Select *pSelect, /* The whole SELECT statement */ int regData /* Register holding data to be sorted */ ){ Vdbe *v = pParse->pVdbe; - int nExpr = pOrderBy->nExpr; - int regBase = sqlite3GetTempRange(pParse, nExpr+2); - int regRecord = sqlite3GetTempReg(pParse); + int nExpr = pSort->pOrderBy->nExpr; + int regRecord = ++pParse->nMem; + int regBase = pParse->nMem+1; + int nOBSat = pSort->nOBSat; int op; + + pParse->nMem += nExpr+2; /* nExpr+2 registers allocated at regBase */ sqlite3ExprCacheClear(pParse); - sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0); - sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr); + sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0); + sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord); - if( pSelect->selFlags & SF_UseSorter ){ + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat,regRecord); + if( nOBSat>0 ){ + int regPrevKey; /* The first nOBSat columns of the previous row */ + int addrFirst; /* Address of the OP_IfNot opcode */ + int addrJmp; /* Address of the OP_Jump opcode */ + VdbeOp *pOp; /* Opcode that opens the sorter */ + int nKey; /* Number of sorting key columns, including OP_Sequence */ + KeyInfo *pKI; /* Original KeyInfo on the sorter table */ + + regPrevKey = pParse->nMem+1; + pParse->nMem += pSort->nOBSat; + nKey = nExpr - pSort->nOBSat + 1; + addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat); + pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); + if( pParse->db->mallocFailed ) return; + pOp->p2 = nKey + 1; + pKI = pOp->p4.pKeyInfo; + memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */ + sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); + pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1); + addrJmp = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); + pSort->labelBkOut = sqlite3VdbeMakeLabel(v); + pSort->regReturn = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); + sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor); + sqlite3VdbeJumpHere(v, addrFirst); + sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat); + sqlite3VdbeJumpHere(v, addrJmp); + } + if( pSort->sortFlags & SORTFLAG_UseSorter ){ op = OP_SorterInsert; }else{ op = OP_IdxInsert; } - sqlite3VdbeAddOp2(v, op, pOrderBy->iECursor, regRecord); - sqlite3ReleaseTempReg(pParse, regRecord); - sqlite3ReleaseTempRange(pParse, regBase, nExpr+2); + sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); if( pSelect->iLimit ){ int addr1, addr2; int iLimit; @@ -459,8 +525,8 @@ static void pushOntoSorter( sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1); addr2 = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, addr1); - sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor); - sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor); + sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); + sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); sqlite3VdbeJumpHere(v, addr2); } } @@ -473,10 +539,9 @@ static void codeOffset( int iOffset, /* Register holding the offset counter */ int iContinue /* Jump here to skip the current record */ ){ - if( iOffset>0 && iContinue!=0 ){ + if( iOffset>0 ){ int addr; - sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1); - addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v); + addr = sqlite3VdbeAddOp3(v, OP_IfNeg, iOffset, 0, -1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue); VdbeComment((v, "skip OFFSET records")); sqlite3VdbeJumpHere(v, addr); @@ -534,19 +599,6 @@ static int checkForMultiColumnSelectError( } #endif -/* -** An instance of the following object is used to record information about -** how to process the DISTINCT keyword, to simplify passing that information -** into the selectInnerLoop() routine. -*/ -typedef struct DistinctCtx DistinctCtx; -struct DistinctCtx { - u8 isTnct; /* True if the DISTINCT keyword is present */ - u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ - int tabTnct; /* Ephemeral table used for DISTINCT processing */ - int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ -}; - /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. @@ -561,7 +613,7 @@ static void selectInnerLoop( Select *p, /* The complete select statement being coded */ ExprList *pEList, /* List of values being extracted */ int srcTab, /* Pull data from this table */ - ExprList *pOrderBy, /* If not NULL, sort results using this key */ + SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */ DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */ SelectDest *pDest, /* How to dispose of the results */ int iContinue, /* Jump here to continue with next row */ @@ -578,7 +630,9 @@ static void selectInnerLoop( assert( v ); assert( pEList!=0 ); hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; - if( pOrderBy==0 && !hasDistinct ){ + if( pSort && pSort->pOrderBy==0 ) pSort = 0; + if( pSort==0 && !hasDistinct ){ + assert( iContinue!=0 ); codeOffset(v, p->iOffset, iContinue); } @@ -652,7 +706,7 @@ static void selectInnerLoop( sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); } - assert( sqlite3VdbeCurrentAddr(v)==iJump ); + assert( sqlite3VdbeCurrentAddr(v)==iJump || pParse->db->mallocFailed ); sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nResultCol-1); break; } @@ -668,7 +722,7 @@ static void selectInnerLoop( break; } } - if( pOrderBy==0 ){ + if( pSort==0 ){ codeOffset(v, p->iOffset, iContinue); } } @@ -699,7 +753,8 @@ static void selectInnerLoop( /* Store the result as data using a unique key. */ - case SRT_DistTable: + case SRT_Fifo: + case SRT_DistFifo: case SRT_Table: case SRT_EphemTab: { int r1 = sqlite3GetTempReg(pParse); @@ -707,8 +762,8 @@ static void selectInnerLoop( testcase( eDest==SRT_EphemTab ); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); #ifndef SQLITE_OMIT_CTE - if( eDest==SRT_DistTable ){ - /* If the destination is DistTable, then cursor (iParm+1) is open + if( eDest==SRT_DistFifo ){ + /* If the destination is DistFifo, then cursor (iParm+1) is open ** on an ephemeral index. If the current row is already present ** in the index, do not write it to the output. If not, add the ** current row to the index and proceed with writing it to the @@ -716,11 +771,11 @@ static void selectInnerLoop( int addr = sqlite3VdbeCurrentAddr(v) + 4; sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1); - assert( pOrderBy==0 ); + assert( pSort==0 ); } #endif - if( pOrderBy ){ - pushOntoSorter(pParse, pOrderBy, p, r1); + if( pSort ){ + pushOntoSorter(pParse, pSort, p, r1); }else{ int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); @@ -741,12 +796,12 @@ static void selectInnerLoop( assert( nResultCol==1 ); pDest->affSdst = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst); - if( pOrderBy ){ + if( pSort ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ - pushOntoSorter(pParse, pOrderBy, p, regResult); + pushOntoSorter(pParse, pSort, p, regResult); }else{ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1); @@ -771,8 +826,8 @@ static void selectInnerLoop( */ case SRT_Mem: { assert( nResultCol==1 ); - if( pOrderBy ){ - pushOntoSorter(pParse, pOrderBy, p, regResult); + if( pSort ){ + pushOntoSorter(pParse, pSort, p, regResult); }else{ sqlite3ExprCodeMove(pParse, regResult, iParm, 1); /* The LIMIT clause will jump out of the loop for us */ @@ -785,10 +840,10 @@ static void selectInnerLoop( case SRT_Output: { /* Return the results */ testcase( eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); - if( pOrderBy ){ + if( pSort ){ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); - pushOntoSorter(pParse, pOrderBy, p, r1); + pushOntoSorter(pParse, pSort, p, r1); sqlite3ReleaseTempReg(pParse, r1); }else if( eDest==SRT_Coroutine ){ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); @@ -865,7 +920,7 @@ static void selectInnerLoop( ** there is a sorter, in which case the sorter has already limited ** the output for us. */ - if( pOrderBy==0 && p->iLimit ){ + if( pSort==0 && p->iLimit ){ sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v); } } @@ -936,7 +991,12 @@ int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; } ** function is responsible for seeing that this structure is eventually ** freed. */ -static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){ +static KeyInfo *keyInfoFromExprList( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* Form the KeyInfo object from this ExprList */ + int iStart, /* Begin with this column of pList */ + int nExtra /* Add this many extra columns to the end */ +){ int nExpr; KeyInfo *pInfo; struct ExprList_item *pItem; @@ -944,15 +1004,15 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){ int i; nExpr = pList->nExpr; - pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra, 1); + pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1); if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); - for(i=0, pItem=pList->a; ia+iStart; ipExpr); if( !pColl ) pColl = db->pDfltColl; - pInfo->aColl[i] = pColl; - pInfo->aSortOrder[i] = pItem->sortOrder; + pInfo->aColl[i-iStart] = pColl; + pInfo->aSortOrder[i-iStart] = pItem->sortOrder; } } return pInfo; @@ -1054,24 +1114,31 @@ static void explainComposite( static void generateSortTail( Parse *pParse, /* Parsing context */ Select *p, /* The SELECT statement */ - Vdbe *v, /* Generate code into this VDBE */ + SortCtx *pSort, /* Information on the ORDER BY clause */ int nColumn, /* Number of columns of data */ SelectDest *pDest /* Write the sorted results here */ ){ + Vdbe *v = pParse->pVdbe; /* The prepared statement */ int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */ int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */ int addr; + int addrOnce = 0; int iTab; int pseudoTab = 0; - ExprList *pOrderBy = p->pOrderBy; - + ExprList *pOrderBy = pSort->pOrderBy; int eDest = pDest->eDest; int iParm = pDest->iSDParm; - int regRow; int regRowid; + int nKey; - iTab = pOrderBy->iECursor; + if( pSort->labelBkOut ){ + sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak); + sqlite3VdbeResolveLabel(v, pSort->labelBkOut); + addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); + } + iTab = pSort->iECursor; regRow = sqlite3GetTempReg(pParse); if( eDest==SRT_Output || eDest==SRT_Coroutine ){ pseudoTab = pParse->nTab++; @@ -1080,20 +1147,23 @@ static void generateSortTail( }else{ regRowid = sqlite3GetTempReg(pParse); } - if( p->selFlags & SF_UseSorter ){ + nKey = pOrderBy->nExpr - pSort->nOBSat; + if( pSort->sortFlags & SORTFLAG_UseSorter ){ int regSortOut = ++pParse->nMem; int ptab2 = pParse->nTab++; - sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, pOrderBy->nExpr+2); + sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, nKey+2); + if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut); - sqlite3VdbeAddOp3(v, OP_Column, ptab2, pOrderBy->nExpr+1, regRow); + sqlite3VdbeAddOp3(v, OP_Column, ptab2, nKey+1, regRow); sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); }else{ + if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); - sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr+1, regRow); + sqlite3VdbeAddOp3(v, OP_Column, iTab, nKey+1, regRow); } switch( eDest ){ case SRT_Table: @@ -1148,15 +1218,13 @@ static void generateSortTail( /* The bottom of the loop */ sqlite3VdbeResolveLabel(v, addrContinue); - if( p->selFlags & SF_UseSorter ){ + if( pSort->sortFlags & SORTFLAG_UseSorter ){ sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v); }else{ sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v); } + if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn); sqlite3VdbeResolveLabel(v, addrBreak); - if( eDest==SRT_Output || eDest==SRT_Coroutine ){ - sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0); - } } /* @@ -1616,7 +1684,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){ assert( db->lookaside.bEnabled==0 ); pTab->nRef = 1; pTab->zName = 0; - pTab->nRowEst = 1048576; + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); selectAddColumnTypeAndCollation(pParse, pTab, pSelect); pTab->iPKey = -1; @@ -1834,7 +1902,7 @@ static void generateWithRecursiveQuery( int regCurrent; /* Register holding Current table */ int iQueue; /* The Queue table */ int iDistinct = 0; /* To ensure unique results if UNION */ - int eDest = SRT_Table; /* How to write to Queue */ + int eDest = SRT_Fifo; /* How to write to Queue */ SelectDest destQueue; /* SelectDest targetting the Queue table */ int i; /* Loop counter */ int rc; /* Result code */ @@ -1866,13 +1934,13 @@ static void generateWithRecursiveQuery( /* Allocate cursors numbers for Queue and Distinct. The cursor number for ** the Distinct table must be exactly one greater than Queue in order - ** for the SRT_DistTable and SRT_DistQueue destinations to work. */ + ** for the SRT_DistFifo and SRT_DistQueue destinations to work. */ iQueue = pParse->nTab++; if( p->op==TK_UNION ){ - eDest = pOrderBy ? SRT_DistQueue : SRT_DistTable; + eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo; iDistinct = pParse->nTab++; }else{ - eDest = pOrderBy ? SRT_Queue : SRT_Table; + eDest = pOrderBy ? SRT_Queue : SRT_Fifo; } sqlite3SelectDestInit(&destQueue, eDest, iQueue); @@ -1938,6 +2006,7 @@ static void generateWithRecursiveQuery( sqlite3VdbeResolveLabel(v, addrBreak); end_of_recursive_query: + sqlite3ExprListDelete(pParse->db, p->pOrderBy); p->pOrderBy = pOrderBy; p->pLimit = pLimit; p->pOffset = pOffset; @@ -3754,7 +3823,7 @@ static int withExpand( pTab->nRef = 1; pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->iPKey = -1; - pTab->nRowEst = 1048576; + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral; pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); if( db->mallocFailed ) return SQLITE_NOMEM; @@ -3930,7 +3999,7 @@ static int selectExpander(Walker *pWalker, Select *p){ while( pSel->pPrior ){ pSel = pSel->pPrior; } selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol); pTab->iPKey = -1; - pTab->nRowEst = 1048576; + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral; #endif }else{ @@ -4309,7 +4378,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ "argument"); pFunc->iDistinct = -1; }else{ - KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0); + KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0); sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0, (char*)pKeyInfo, P4_KEYINFO); } @@ -4425,10 +4494,11 @@ static void explainSimpleCount( Index *pIdx /* Index used to optimize scan, or NULL */ ){ if( pParse->explain==2 ){ + int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx))); char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s", - pTab->zName, - pIdx ? " USING COVERING INDEX " : "", - pIdx ? pIdx->zName : "" + pTab->zName, + bCover ? " USING COVERING INDEX " : "", + bCover ? pIdx->zName : "" ); sqlite3VdbeAddOp4( pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC @@ -4464,12 +4534,11 @@ int sqlite3Select( ExprList *pEList; /* List of columns to extract. */ SrcList *pTabList; /* List of tables to select from */ Expr *pWhere; /* The WHERE clause. May be NULL */ - ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */ ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ Expr *pHaving; /* The HAVING clause. May be NULL */ int rc = 1; /* Value to return from this function */ - int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */ DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */ + SortCtx sSort; /* Info on how to code the ORDER BY clause */ AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ sqlite3 *db; /* The database connection */ @@ -4486,9 +4555,15 @@ int sqlite3Select( if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; memset(&sAggInfo, 0, sizeof(sAggInfo)); + assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); + assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); + assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); + assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue ); if( IgnorableOrderby(pDest) ){ assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || - pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard); + pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || + pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo || + pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo); /* If ORDER BY makes no difference in the output then neither does ** DISTINCT so it can be removed too. */ sqlite3ExprListDelete(db, p->pOrderBy); @@ -4496,7 +4571,8 @@ int sqlite3Select( p->selFlags &= ~SF_Distinct; } sqlite3SelectPrep(pParse, p, 0); - pOrderBy = p->pOrderBy; + memset(&sSort, 0, sizeof(sSort)); + sSort.pOrderBy = p->pOrderBy; pTabList = p->pSrc; pEList = p->pEList; if( pParse->nErr || db->mallocFailed ){ @@ -4574,7 +4650,7 @@ int sqlite3Select( sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow; + pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); pItem->viaCoroutine = 1; pItem->regResult = dest.iSdst; sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn); @@ -4605,7 +4681,7 @@ int sqlite3Select( sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow; + pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); VdbeComment((v, "end %s", pItem->pTab->zName)); @@ -4618,7 +4694,7 @@ int sqlite3Select( pParse->nHeight -= sqlite3SelectExprHeight(p); pTabList = p->pSrc; if( !IgnorableOrderby(pDest) ){ - pOrderBy = p->pOrderBy; + sSort.pOrderBy = p->pOrderBy; } } pEList = p->pEList; @@ -4638,18 +4714,6 @@ int sqlite3Select( } #endif - /* If there is both a GROUP BY and an ORDER BY clause and they are - ** identical, then disable the ORDER BY clause since the GROUP BY - ** will cause elements to come out in the correct order. This is - ** an optimization - the correct answer should result regardless. - ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER - ** to disable this optimization for testing purposes. - */ - if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy, -1)==0 - && OptimizationEnabled(db, SQLITE_GroupByOrder) ){ - pOrderBy = 0; - } - /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and ** if the select-list is the same as the ORDER BY list, then this query ** can be rewritten as a GROUP BY. In other words, this: @@ -4666,12 +4730,12 @@ int sqlite3Select( ** BY and DISTINCT, and an index or separate temp-table for the other. */ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct - && sqlite3ExprListCompare(pOrderBy, p->pEList, -1)==0 + && sqlite3ExprListCompare(sSort.pOrderBy, p->pEList, -1)==0 ){ p->selFlags &= ~SF_Distinct; p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); pGroupBy = p->pGroupBy; - pOrderBy = 0; + sSort.pOrderBy = 0; /* Notice that even thought SF_Distinct has been cleared from p->selFlags, ** the sDistinct.isTnct is still set. Hence, isTnct represents the ** original setting of the SF_Distinct flag, not the current setting */ @@ -4685,16 +4749,16 @@ int sqlite3Select( ** we figure out that the sorting index is not needed. The addrSortIndex ** variable is used to facilitate that change. */ - if( pOrderBy ){ + if( sSort.pOrderBy ){ KeyInfo *pKeyInfo; - pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 0); - pOrderBy->iECursor = pParse->nTab++; - p->addrOpenEphm[2] = addrSortIndex = + pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0); + sSort.iECursor = pParse->nTab++; + sSort.addrSortIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, - pOrderBy->iECursor, pOrderBy->nExpr+2, 0, + sSort.iECursor, sSort.pOrderBy->nExpr+2, 0, (char*)pKeyInfo, P4_KEYINFO); }else{ - addrSortIndex = -1; + sSort.addrSortIndex = -1; } /* If the output is destined for a temporary table, open that table. @@ -4708,9 +4772,9 @@ int sqlite3Select( iEnd = sqlite3VdbeMakeLabel(v); p->nSelectRow = LARGEST_INT64; computeLimitRegisters(pParse, p, iEnd); - if( p->iLimit==0 && addrSortIndex>=0 ){ - sqlite3VdbeGetOp(v, addrSortIndex)->opcode = OP_SorterOpen; - p->selFlags |= SF_UseSorter; + if( p->iLimit==0 && sSort.addrSortIndex>=0 ){ + sqlite3VdbeGetOp(v, sSort.addrSortIndex)->opcode = OP_SorterOpen; + sSort.sortFlags |= SORTFLAG_UseSorter; } /* Open a virtual index to use for the distinct set. @@ -4719,7 +4783,7 @@ int sqlite3Select( sDistinct.tabTnct = pParse->nTab++; sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, sDistinct.tabTnct, 0, 0, - (char*)keyInfoFromExprList(pParse, p->pEList, 0), + (char*)keyInfoFromExprList(pParse, p->pEList,0,0), P4_KEYINFO); sqlite3VdbeChangeP5(v, BTREE_UNORDERED); sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED; @@ -4732,8 +4796,8 @@ int sqlite3Select( u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0); /* Begin the database scan. */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, p->pEList, - wctrlFlags, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, + p->pEList, wctrlFlags, 0); if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); @@ -4741,19 +4805,23 @@ int sqlite3Select( if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); } - if( pOrderBy && sqlite3WhereIsOrdered(pWInfo) ) pOrderBy = 0; + if( sSort.pOrderBy ){ + sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); + if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ + sSort.pOrderBy = 0; + } + } /* If sorting index that was created by a prior OP_OpenEphemeral ** instruction ended up not being needed, then change the OP_OpenEphemeral ** into an OP_Noop. */ - if( addrSortIndex>=0 && pOrderBy==0 ){ - sqlite3VdbeChangeToNoop(v, addrSortIndex); - p->addrOpenEphm[2] = -1; + if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){ + sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); } /* Use the standard inner loop. */ - selectInnerLoop(pParse, p, pEList, -1, pOrderBy, &sDistinct, pDest, + selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest, sqlite3WhereContinueLabel(pWInfo), sqlite3WhereBreakLabel(pWInfo)); @@ -4774,6 +4842,7 @@ int sqlite3Select( int addrEnd; /* End of processing for this SELECT */ int sortPTab = 0; /* Pseudotable used to decode sorting results */ int sortOut = 0; /* Output register from the sorter */ + int orderByGrp = 0; /* True if the GROUP BY and ORDER BY are the same */ /* Remove any and all aliases between the result set and the ** GROUP BY clause. @@ -4793,6 +4862,18 @@ int sqlite3Select( p->nSelectRow = 1; } + + /* If there is both a GROUP BY and an ORDER BY clause and they are + ** identical, then it may be possible to disable the ORDER BY clause + ** on the grounds that the GROUP BY will cause elements to come out + ** in the correct order. It also may not - the GROUP BY may use a + ** database index that causes rows to be grouped together as required + ** but not actually sorted. Either way, record the fact that the + ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp + ** variable. */ + if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){ + orderByGrp = 1; + } /* Create a label to jump to when we want to abort the query */ addrEnd = sqlite3VdbeMakeLabel(v); @@ -4809,7 +4890,7 @@ int sqlite3Select( sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0; sAggInfo.pGroupBy = pGroupBy; sqlite3ExprAnalyzeAggList(&sNC, pEList); - sqlite3ExprAnalyzeAggList(&sNC, pOrderBy); + sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy); if( pHaving ){ sqlite3ExprAnalyzeAggregates(&sNC, pHaving); } @@ -4843,7 +4924,7 @@ int sqlite3Select( ** will be converted into a Noop. */ sAggInfo.sortingIdx = pParse->nTab++; - pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0); + pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0); addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, sAggInfo.sortingIdx, sAggInfo.nSortingColumn, 0, (char*)pKeyInfo, P4_KEYINFO); @@ -4872,10 +4953,11 @@ int sqlite3Select( ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, - WHERE_GROUPBY, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, + WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0 + ); if( pWInfo==0 ) goto select_end; - if( sqlite3WhereIsOrdered(pWInfo) ){ + if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){ /* The optimizer is able to deliver rows in group by order so ** we do not have to sort. The OP_OpenEphemeral table will be ** cancelled later because we still need to use the pKeyInfo @@ -4938,6 +5020,21 @@ int sqlite3Select( VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v); sAggInfo.useSortingIdx = 1; sqlite3ExprCacheClear(pParse); + + } + + /* If the index or temporary table used by the GROUP BY sort + ** will naturally deliver rows in the order required by the ORDER BY + ** clause, cancel the ephemeral table open coded earlier. + ** + ** This is an optimization - the correct answer should result regardless. + ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to + ** disable this optimization for testing purposes. */ + if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder) + && (groupBySort || sqlite3WhereIsSorted(pWInfo)) + ){ + sSort.pOrderBy = 0; + sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); } /* Evaluate the current GROUP BY terms and store in b0, b1, b2... @@ -5026,7 +5123,7 @@ int sqlite3Select( sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); finalizeAggFunctions(pParse, &sAggInfo); sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); - selectInnerLoop(pParse, p, p->pEList, -1, pOrderBy, + selectInnerLoop(pParse, p, p->pEList, -1, &sSort, &sDistinct, pDest, addrOutputRow+1, addrSetAbort); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); @@ -5158,7 +5255,7 @@ int sqlite3Select( } updateAccumulator(pParse, &sAggInfo); assert( pMinMax==0 || pMinMax->nExpr==1 ); - if( sqlite3WhereIsOrdered(pWInfo) ){ + if( sqlite3WhereIsOrdered(pWInfo)>0 ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo)); VdbeComment((v, "%s() by index", (flag==WHERE_ORDERBY_MIN?"min":"max"))); @@ -5167,7 +5264,7 @@ int sqlite3Select( finalizeAggFunctions(pParse, &sAggInfo); } - pOrderBy = 0; + sSort.pOrderBy = 0; sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL); selectInnerLoop(pParse, p, p->pEList, -1, 0, 0, pDest, addrEnd, addrEnd); @@ -5184,9 +5281,9 @@ int sqlite3Select( /* If there is an ORDER BY clause, then we need to sort the results ** and send them to the callback one by one. */ - if( pOrderBy ){ - explainTempTable(pParse, "ORDER BY"); - generateSortTail(pParse, p, v, pEList->nExpr, pDest); + if( sSort.pOrderBy ){ + explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY"); + generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest); } /* Jump here to skip this query diff --git a/src/shell.c b/src/shell.c index 2cff102..a74dcdb 100644 --- a/src/shell.c +++ b/src/shell.c @@ -64,6 +64,7 @@ #if defined(_WIN32) || defined(WIN32) # include +# include #define isatty(h) _isatty(h) #ifndef access # define access(f,m) _access((f),(m)) @@ -446,8 +447,9 @@ struct previous_mode_data { struct callback_data { sqlite3 *db; /* The database */ int echoOn; /* True to echo input commands */ - int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL statement */ + int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ int statsOn; /* True to display memory stats before each finalize */ + int outCount; /* Revert to stdout when reaching zero */ int cnt; /* Number of records displayed so far */ FILE *out; /* Write results here */ FILE *traceOut; /* Output for sqlite3_trace() */ @@ -457,6 +459,7 @@ struct callback_data { int showHeader; /* True to show column names in List or Column mode */ char *zDestTable; /* Name of destination table when MODE_Insert */ char separator[20]; /* Separator character for MODE_List */ + char newline[20]; /* Record separator in MODE_Csv */ int colWidth[100]; /* Requested width of each column when in column mode*/ int actualWidth[100]; /* Actual width of each column */ char nullvalue[20]; /* The text to print when a NULL comes back from @@ -658,7 +661,8 @@ static const char needCsvQuote[] = { /* ** Output a single term of CSV. Actually, p->separator is used for ** the separator, which may or may not be a comma. p->nullvalue is -** the null value. Strings are quoted if necessary. +** the null value. Strings are quoted if necessary. The separator +** is only issued if bSep is true. */ static void output_csv(struct callback_data *p, const char *z, int bSep){ FILE *out = p->out; @@ -697,7 +701,8 @@ static void output_csv(struct callback_data *p, const char *z, int bSep){ */ static void interrupt_handler(int NotUsed){ UNUSED_PARAMETER(NotUsed); - seenInterrupt = 1; + seenInterrupt++; + if( seenInterrupt>2 ) exit(1); if( db ) sqlite3_interrupt(db); } #endif @@ -853,17 +858,26 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int break; } case MODE_Csv: { +#if defined(WIN32) || defined(_WIN32) + fflush(p->out); + _setmode(_fileno(p->out), _O_BINARY); +#endif if( p->cnt++==0 && p->showHeader ){ for(i=0; iout,"\n"); + fprintf(p->out,"%s",p->newline); } - if( azArg==0 ) break; - for(i=0; i0 ){ + for(i=0; iout,"%s",p->newline); } - fprintf(p->out,"\n"); +#if defined(WIN32) || defined(_WIN32) + fflush(p->out); + _setmode(_fileno(p->out), _O_TEXT); +#endif break; } case MODE_Insert: { @@ -877,7 +891,8 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int }else if( aiType && aiType[i]==SQLITE_TEXT ){ if( zSep[0] ) fprintf(p->out,"%s",zSep); output_quoted_string(p->out, azArg[i]); - }else if( aiType && (aiType[i]==SQLITE_INTEGER || aiType[i]==SQLITE_FLOAT) ){ + }else if( aiType && (aiType[i]==SQLITE_INTEGER + || aiType[i]==SQLITE_FLOAT) ){ fprintf(p->out,"%s%s",zSep, azArg[i]); }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ const void *pBlob = sqlite3_column_blob(p->pStmt, i); @@ -1195,8 +1210,9 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){ int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */ int iOp; /* Index of operation in p->aiIndent[] */ - const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 }; - const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", "Rewind", 0 }; + const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", + "NextIfOpen", "PrevIfOpen", 0 }; + const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", "Rewind", 0 }; const char *azGoto[] = { "Goto", 0 }; /* Try to figure out if this is really an EXPLAIN statement. If this @@ -1568,17 +1584,19 @@ static int run_schema_dump_query( */ static char zHelp[] = ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" - ".bail ON|OFF Stop after hitting an error. Default OFF\n" + ".bail on|off Stop after hitting an error. Default OFF\n" ".clone NEWDB Clone data into NEWDB from the existing database\n" ".databases List names and files of attached databases\n" ".dump ?TABLE? ... Dump the database in an SQL text format\n" " If TABLE specified, only dump tables matching\n" " LIKE pattern TABLE.\n" - ".echo ON|OFF Turn command echo on or off\n" + ".echo on|off Turn command echo on or off\n" + ".eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN\n" ".exit Exit this program\n" - ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n" + ".explain ?on|off? Turn output mode suitable for EXPLAIN on or off.\n" " With no args, it turns EXPLAIN on.\n" - ".header(s) ON|OFF Turn display of headers on or off\n" + ".fullschema Show schema and the content of sqlite_stat tables\n" + ".headers on|off Turn display of headers on or off\n" ".help Show this message\n" ".import FILE TABLE Import data from FILE into TABLE\n" ".indices ?TABLE? Show names of all indices\n" @@ -1601,9 +1619,9 @@ static char zHelp[] = " tabs Tab-separated values\n" " tcl TCL list elements\n" ".nullvalue STRING Use STRING in place of NULL values\n" + ".once FILENAME Output for the next SQL command only to FILENAME\n" ".open ?FILENAME? Close existing database and reopen FILENAME\n" - ".output FILENAME Send output to FILENAME\n" - ".output stdout Send output to the screen\n" + ".output ?FILENAME? Send output to FILENAME or stdout\n" ".print STRING... Print literal STRING\n" ".prompt MAIN CONTINUE Replace the standard prompts\n" ".quit Exit this program\n" @@ -1613,24 +1631,85 @@ static char zHelp[] = ".schema ?TABLE? Show the CREATE statements\n" " If TABLE specified, only show tables matching\n" " LIKE pattern TABLE.\n" - ".separator STRING Change separator used by output mode and .import\n" + ".separator STRING ?NL? Change separator used by output mode and .import\n" + " NL is the end-of-line mark for CSV\n" + ".shell CMD ARGS... Run CMD ARGS... in a system shell\n" ".show Show the current values for various settings\n" - ".stats ON|OFF Turn stats on or off\n" + ".stats on|off Turn stats on or off\n" + ".system CMD ARGS... Run CMD ARGS... in a system shell\n" ".tables ?TABLE? List names of tables\n" " If TABLE specified, only list tables matching\n" " LIKE pattern TABLE.\n" ".timeout MS Try opening locked tables for MS milliseconds\n" + ".timer on|off Turn SQL timer on or off\n" ".trace FILE|off Output each SQL statement as it is run\n" ".vfsname ?AUX? Print the name of the VFS stack\n" ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n" -; - -static char zTimerHelp[] = - ".timer ON|OFF Turn the CPU timer measurement on or off\n" + " Negative values right-justify\n" ; /* Forward reference */ static int process_input(struct callback_data *p, FILE *in); +/* +** Implementation of the "readfile(X)" SQL function. The entire content +** of the file named X is read and returned as a BLOB. NULL is returned +** if the file does not exist or is unreadable. +*/ +static void readfileFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zName; + FILE *in; + long nIn; + void *pBuf; + + zName = (const char*)sqlite3_value_text(argv[0]); + if( zName==0 ) return; + in = fopen(zName, "rb"); + if( in==0 ) return; + fseek(in, 0, SEEK_END); + nIn = ftell(in); + rewind(in); + pBuf = sqlite3_malloc( nIn ); + if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ + sqlite3_result_blob(context, pBuf, nIn, sqlite3_free); + }else{ + sqlite3_free(pBuf); + } + fclose(in); +} + +/* +** Implementation of the "writefile(X,Y)" SQL function. The argument Y +** is written into file X. The number of bytes written is returned. Or +** NULL is returned if something goes wrong, such as being unable to open +** file X for writing. +*/ +static void writefileFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + FILE *out; + const char *z; + sqlite3_int64 rc; + const char *zFile; + + zFile = (const char*)sqlite3_value_text(argv[0]); + if( zFile==0 ) return; + out = fopen(zFile, "wb"); + if( out==0 ) return; + z = (const char*)sqlite3_value_blob(argv[1]); + if( z==0 ){ + rc = 0; + }else{ + rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out); + } + fclose(out); + sqlite3_result_int64(context, rc); +} /* ** Make sure the database is open. If it is not, then open it. If @@ -1654,6 +1733,10 @@ static void open_db(struct callback_data *p, int keepAlive){ #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); #endif + sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0, + readfileFunc, 0, 0); + sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0, + writefileFunc, 0, 0); } } @@ -1670,6 +1753,7 @@ static void open_db(struct callback_data *p, int keepAlive){ static void resolve_backslashes(char *z){ int i, j; char c; + while( *z && *z!='\\' ) z++; for(i=j=0; (c = z[i])!=0; i++, j++){ if( c=='\\' ){ c = z[++i]; @@ -1695,7 +1779,7 @@ static void resolve_backslashes(char *z){ } z[j] = c; } - z[j] = 0; + if( jdb, "PRAGMA writable_schema=ON;", 0, 0, 0); sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0); tryToCloneSchema(p, newDb, "type='table'", tryToCloneData); tryToCloneSchema(p, newDb, "type!='table'", 0); sqlite3_exec(newDb, "COMMIT;", 0, 0, 0); + sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); } sqlite3_close(newDb); } +/* +** Change the output file back to stdout +*/ +static void output_reset(struct callback_data *p){ + if( p->outfile[0]=='|' ){ + pclose(p->out); + }else{ + output_file_close(p->out); + } + p->outfile[0] = 0; + p->out = stdout; +} + /* ** If an input line begins with "." then invoke this routine to ** process that line. @@ -2235,8 +2334,13 @@ static int do_meta_command(char *zLine, struct callback_data *p){ sqlite3_close(pDest); }else - if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 && nArg>1 && nArg<3 ){ - bail_on_error = booleanValue(azArg[1]); + if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){ + if( nArg==2 ){ + bail_on_error = booleanValue(azArg[1]); + }else{ + fprintf(stderr, "Usage: .bail on|off\n"); + rc = 1; + } }else /* The undocumented ".breakpoint" command causes a call to the no-op @@ -2246,11 +2350,16 @@ static int do_meta_command(char *zLine, struct callback_data *p){ test_breakpoint(); }else - if( c=='c' && strncmp(azArg[0], "clone", n)==0 && nArg>1 && nArg<3 ){ - tryToClone(p, azArg[1]); + if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){ + if( nArg==2 ){ + tryToClone(p, azArg[1]); + }else{ + fprintf(stderr, "Usage: .clone FILENAME\n"); + rc = 1; + } }else - if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){ + if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ struct callback_data data; char *zErrMsg = 0; open_db(p, 0); @@ -2269,11 +2378,16 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else - if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){ + if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ open_db(p, 0); /* When playing back a "dump", the content might appear in an order ** which causes immediate foreign key constraints to be violated. ** So disable foreign-key constraint enforcement to prevent problems. */ + if( nArg!=1 && nArg!=2 ){ + fprintf(stderr, "Usage: .dump ?LIKE-PATTERN?\n"); + rc = 1; + goto meta_command_exit; + } fprintf(p->out, "PRAGMA foreign_keys=OFF;\n"); fprintf(p->out, "BEGIN TRANSACTION;\n"); p->writableSchema = 0; @@ -2318,12 +2432,22 @@ static int do_meta_command(char *zLine, struct callback_data *p){ fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n"); }else - if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){ - p->echoOn = booleanValue(azArg[1]); + if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){ + if( nArg==2 ){ + p->echoOn = booleanValue(azArg[1]); + }else{ + fprintf(stderr, "Usage: .echo on|off\n"); + rc = 1; + } }else - if( c=='e' && strncmp(azArg[0], "eqp", n)==0 && nArg>1 && nArg<3 ){ - p->autoEQP = booleanValue(azArg[1]); + if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){ + if( nArg==2 ){ + p->autoEQP = booleanValue(azArg[1]); + }else{ + fprintf(stderr, "Usage: .eqp on|off\n"); + rc = 1; + } }else if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ @@ -2331,7 +2455,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ rc = 2; }else - if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){ + if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){ int val = nArg>=2 ? booleanValue(azArg[1]) : 1; if(val == 1) { if(!p->explainPrev.valid) { @@ -2366,21 +2490,73 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else - if( c=='h' && (strncmp(azArg[0], "header", n)==0 || - strncmp(azArg[0], "headers", n)==0) && nArg>1 && nArg<3 ){ - p->showHeader = booleanValue(azArg[1]); - }else - - if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ - fprintf(stderr,"%s",zHelp); - if( HAS_TIMER ){ - fprintf(stderr,"%s",zTimerHelp); + if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){ + struct callback_data data; + char *zErrMsg = 0; + int doStats = 0; + if( nArg!=1 ){ + fprintf(stderr, "Usage: .fullschema\n"); + rc = 1; + goto meta_command_exit; + } + open_db(p, 0); + memcpy(&data, p, sizeof(data)); + data.showHeader = 0; + data.mode = MODE_Semi; + rc = sqlite3_exec(p->db, + "SELECT sql FROM" + " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" + " FROM sqlite_master UNION ALL" + " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " + "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'" + "ORDER BY rowid", + callback, &data, &zErrMsg + ); + if( rc==SQLITE_OK ){ + sqlite3_stmt *pStmt; + rc = sqlite3_prepare_v2(p->db, + "SELECT rowid FROM sqlite_master" + " WHERE name GLOB 'sqlite_stat[134]'", + -1, &pStmt, 0); + doStats = sqlite3_step(pStmt)==SQLITE_ROW; + sqlite3_finalize(pStmt); + } + if( doStats==0 ){ + fprintf(p->out, "/* No STAT tables available */\n"); + }else{ + fprintf(p->out, "ANALYZE sqlite_master;\n"); + sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'", + callback, &data, &zErrMsg); + data.mode = MODE_Insert; + data.zDestTable = "sqlite_stat1"; + shell_exec(p->db, "SELECT * FROM sqlite_stat1", + shell_callback, &data,&zErrMsg); + data.zDestTable = "sqlite_stat3"; + shell_exec(p->db, "SELECT * FROM sqlite_stat3", + shell_callback, &data,&zErrMsg); + data.zDestTable = "sqlite_stat4"; + shell_exec(p->db, "SELECT * FROM sqlite_stat4", + shell_callback, &data, &zErrMsg); + fprintf(p->out, "ANALYZE sqlite_master;\n"); } }else - if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){ - char *zTable = azArg[2]; /* Insert data into this table */ - char *zFile = azArg[1]; /* Name of file to extra content from */ + if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){ + if( nArg==2 ){ + p->showHeader = booleanValue(azArg[1]); + }else{ + fprintf(stderr, "Usage: .headers on|off\n"); + rc = 1; + } + }else + + if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ + fprintf(p->out, "%s", zHelp); + }else + + if( c=='i' && strncmp(azArg[0], "import", n)==0 ){ + char *zTable; /* Insert data into this table */ + char *zFile; /* Name of file to extra content from */ sqlite3_stmt *pStmt = NULL; /* A statement */ int nCol; /* Number of columns in the table */ int nByte; /* Number of bytes in an SQL string */ @@ -2391,6 +2567,12 @@ static int do_meta_command(char *zLine, struct callback_data *p){ CSVReader sCsv; /* Reader context */ int (*xCloser)(FILE*); /* Procedure to close th3 connection */ + if( nArg!=3 ){ + fprintf(stderr, "Usage: .import FILE TABLE\n"); + goto meta_command_exit; + } + zFile = azArg[1]; + zTable = azArg[2]; seenInterrupt = 0; memset(&sCsv, 0, sizeof(sCsv)); open_db(p, 0); @@ -2427,6 +2609,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } nByte = strlen30(zSql); rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + csv_append_char(&sCsv, 0); /* To ensure sCsv.z is allocated */ if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){ char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable); char cSep = '('; @@ -2500,7 +2683,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ "filling the rest with NULL\n", sCsv.zFile, startLine, nCol, i+1); i++; - while( idb, "SELECT name FROM sqlite_master " @@ -2557,6 +2740,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){ callback, &data, &zErrMsg ); zShellStatic = 0; + }else{ + fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n"); + rc = 1; + goto meta_command_exit; } if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); @@ -2592,9 +2779,14 @@ static int do_meta_command(char *zLine, struct callback_data *p){ #endif #ifndef SQLITE_OMIT_LOAD_EXTENSION - if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){ + if( c=='l' && strncmp(azArg[0], "load", n)==0 ){ const char *zFile, *zProc; char *zErrMsg = 0; + if( nArg<2 ){ + fprintf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n"); + rc = 1; + goto meta_command_exit; + } zFile = azArg[1]; zProc = nArg>=3 ? azArg[2] : 0; open_db(p, 0); @@ -2607,38 +2799,42 @@ static int do_meta_command(char *zLine, struct callback_data *p){ }else #endif - if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=2 ){ - const char *zFile = azArg[1]; - output_file_close(p->pLog); - p->pLog = output_file_open(zFile); + if( c=='l' && strncmp(azArg[0], "log", n)==0 ){ + if( nArg!=2 ){ + fprintf(stderr, "Usage: .log FILENAME\n"); + rc = 1; + }else{ + const char *zFile = azArg[1]; + output_file_close(p->pLog); + p->pLog = output_file_open(zFile); + } }else - if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){ - int n2 = strlen30(azArg[1]); - if( (n2==4 && strncmp(azArg[1],"line",n2)==0) - || - (n2==5 && strncmp(azArg[1],"lines",n2)==0) ){ + if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){ + const char *zMode = nArg>=2 ? azArg[1] : ""; + int n2 = (int)strlen(zMode); + int c2 = zMode[0]; + if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){ p->mode = MODE_Line; - }else if( (n2==6 && strncmp(azArg[1],"column",n2)==0) - || - (n2==7 && strncmp(azArg[1],"columns",n2)==0) ){ + }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){ p->mode = MODE_Column; - }else if( n2==4 && strncmp(azArg[1],"list",n2)==0 ){ + }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){ p->mode = MODE_List; - }else if( n2==4 && strncmp(azArg[1],"html",n2)==0 ){ + }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){ p->mode = MODE_Html; - }else if( n2==3 && strncmp(azArg[1],"tcl",n2)==0 ){ + }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){ p->mode = MODE_Tcl; sqlite3_snprintf(sizeof(p->separator), p->separator, " "); - }else if( n2==3 && strncmp(azArg[1],"csv",n2)==0 ){ + }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){ p->mode = MODE_Csv; sqlite3_snprintf(sizeof(p->separator), p->separator, ","); - }else if( n2==4 && strncmp(azArg[1],"tabs",n2)==0 ){ + sqlite3_snprintf(sizeof(p->newline), p->newline, "\r\n"); + }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){ p->mode = MODE_List; sqlite3_snprintf(sizeof(p->separator), p->separator, "\t"); - }else if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){ + }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){ p->mode = MODE_Insert; - set_table_name(p, "table"); + set_table_name(p, nArg>=3 ? azArg[2] : "table"); }else { fprintf(stderr,"Error: mode should be one of: " "column csv html insert line list tabs tcl\n"); @@ -2646,23 +2842,16 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else - if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==3 ){ - int n2 = strlen30(azArg[1]); - if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){ - p->mode = MODE_Insert; - set_table_name(p, azArg[2]); - }else { - fprintf(stderr, "Error: invalid arguments: " - " \"%s\". Enter \".help\" for help\n", azArg[2]); + if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){ + if( nArg==2 ){ + sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue, + "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]); + }else{ + fprintf(stderr, "Usage: .nullvalue STRING\n"); rc = 1; } }else - if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) { - sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue, - "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]); - }else - if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){ sqlite3 *savedDb = p->db; const char *zSavedFilename = p->zDbFilename; @@ -2683,32 +2872,45 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else - if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){ - if( p->outfile[0]=='|' ){ - pclose(p->out); - }else{ - output_file_close(p->out); + if( c=='o' + && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0) + ){ + const char *zFile = nArg>=2 ? azArg[1] : "stdout"; + if( nArg>2 ){ + fprintf(stderr, "Usage: .%s FILE\n", azArg[0]); + rc = 1; + goto meta_command_exit; } - p->outfile[0] = 0; - if( azArg[1][0]=='|' ){ - p->out = popen(&azArg[1][1], "w"); + if( n>1 && strncmp(azArg[0], "once", n)==0 ){ + if( nArg<2 ){ + fprintf(stderr, "Usage: .once FILE\n"); + rc = 1; + goto meta_command_exit; + } + p->outCount = 2; + }else{ + p->outCount = 0; + } + output_reset(p); + if( zFile[0]=='|' ){ + p->out = popen(zFile + 1, "w"); if( p->out==0 ){ - fprintf(stderr,"Error: cannot open pipe \"%s\"\n", &azArg[1][1]); + fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1); p->out = stdout; rc = 1; }else{ - sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); + sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); } }else{ - p->out = output_file_open(azArg[1]); + p->out = output_file_open(zFile); if( p->out==0 ){ - if( strcmp(azArg[1],"off")!=0 ){ - fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]); + if( strcmp(zFile,"off")!=0 ){ + fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile); } p->out = stdout; rc = 1; } else { - sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); + sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); } } }else @@ -2722,7 +2924,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ fprintf(p->out, "\n"); }else - if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){ + if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){ if( nArg >= 2) { strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1); } @@ -2731,12 +2933,18 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else - if( c=='q' && strncmp(azArg[0], "quit", n)==0 && nArg==1 ){ + if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){ rc = 2; }else - if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 && nArg==2 ){ - FILE *alt = fopen(azArg[1], "rb"); + if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){ + FILE *alt; + if( nArg!=2 ){ + fprintf(stderr, "Usage: .read FILE\n"); + rc = 1; + goto meta_command_exit; + } + alt = fopen(azArg[1], "rb"); if( alt==0 ){ fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]); rc = 1; @@ -2746,7 +2954,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else - if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 && nArg>1 && nArg<4){ + if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){ const char *zSrcFile; const char *zDb; sqlite3 *pSrc; @@ -2756,9 +2964,13 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( nArg==2 ){ zSrcFile = azArg[1]; zDb = "main"; - }else{ + }else if( nArg==3 ){ zSrcFile = azArg[2]; zDb = azArg[1]; + }else{ + fprintf(stderr, "Usage: .restore ?DB? FILE\n"); + rc = 1; + goto meta_command_exit; } rc = sqlite3_open(zSrcFile, &pSrc); if( rc!=SQLITE_OK ){ @@ -2793,14 +3005,14 @@ static int do_meta_command(char *zLine, struct callback_data *p){ sqlite3_close(pSrc); }else - if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){ + if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ struct callback_data data; char *zErrMsg = 0; open_db(p, 0); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.mode = MODE_Semi; - if( nArg>1 ){ + if( nArg==2 ){ int i; for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]); if( strcmp(azArg[1],"sqlite_master")==0 ){ @@ -2844,7 +3056,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ callback, &data, &zErrMsg); zShellStatic = 0; } - }else{ + }else if( nArg==1 ){ rc = sqlite3_exec(p->db, "SELECT sql FROM " " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" @@ -2854,6 +3066,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){ "ORDER BY rowid", callback, &data, &zErrMsg ); + }else{ + fprintf(stderr, "Usage: .schema ?LIKE-PATTERN?\n"); + rc = 1; + goto meta_command_exit; } if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); @@ -2883,20 +3099,53 @@ static int do_meta_command(char *zLine, struct callback_data *p){ for(i=1; iout, "%s", zBuf); } } }else #endif - if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){ - sqlite3_snprintf(sizeof(p->separator), p->separator, - "%.*s", (int)sizeof(p->separator)-1, azArg[1]); + if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){ + if( nArg<2 || nArg>3 ){ + fprintf(stderr, "Usage: .separator SEPARATOR ?NEWLINE?\n"); + rc = 1; + } + if( nArg>=2 ){ + sqlite3_snprintf(sizeof(p->separator), p->separator, azArg[1]); + } + if( nArg>=3 ){ + sqlite3_snprintf(sizeof(p->newline), p->newline, azArg[2]); + } }else - if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){ + if( c=='s' + && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0) + ){ + char *zCmd; + int i, x; + if( nArg<2 ){ + fprintf(stderr, "Usage: .system COMMAND\n"); + rc = 1; + goto meta_command_exit; + } + zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]); + for(i=2; iout,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off"); fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off"); fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off"); @@ -2909,6 +3158,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){ strlen30(p->outfile) ? p->outfile : "stdout"); fprintf(p->out,"%9.9s: ", "separator"); output_c_string(p->out, p->separator); + fprintf(p->out," "); + output_c_string(p->out, p->newline); fprintf(p->out, "\n"); fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off"); fprintf(p->out,"%9.9s: ","width"); @@ -2918,11 +3169,16 @@ static int do_meta_command(char *zLine, struct callback_data *p){ fprintf(p->out,"\n"); }else - if( c=='s' && strncmp(azArg[0], "stats", n)==0 && nArg>1 && nArg<3 ){ - p->statsOn = booleanValue(azArg[1]); + if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){ + if( nArg==2 ){ + p->statsOn = booleanValue(azArg[1]); + }else{ + fprintf(stderr, "Usage: .stats on|off\n"); + rc = 1; + } }else - if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){ + if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){ sqlite3_stmt *pStmt; char **azResult; int nRow, nAlloc; @@ -3024,6 +3280,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS }, { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD }, { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC }, + { "byteorder", SQLITE_TESTCTRL_BYTEORDER }, }; int testctrl = -1; int rc = 0; @@ -3064,9 +3321,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){ break; /* sqlite3_test_control(int) */ - case SQLITE_TESTCTRL_PRNG_SAVE: - case SQLITE_TESTCTRL_PRNG_RESTORE: + case SQLITE_TESTCTRL_PRNG_SAVE: + case SQLITE_TESTCTRL_PRNG_RESTORE: case SQLITE_TESTCTRL_PRNG_RESET: + case SQLITE_TESTCTRL_BYTEORDER: if( nArg==2 ){ rc = sqlite3_test_control(testctrl); fprintf(p->out, "%d (0x%08x)\n", rc, rc); @@ -3126,20 +3384,32 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else - if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){ + if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){ open_db(p, 0); - sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1])); + sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0); }else - if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 - && nArg==2 - ){ - enableTimer = booleanValue(azArg[1]); + if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){ + if( nArg==2 ){ + enableTimer = booleanValue(azArg[1]); + if( enableTimer && !HAS_TIMER ){ + fprintf(stderr, "Error: timer not available on this system.\n"); + enableTimer = 0; + } + }else{ + fprintf(stderr, "Usage: .timer on|off\n"); + rc = 1; + } }else - if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){ + if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){ open_db(p, 0); output_file_close(p->traceOut); + if( nArg!=2 ){ + fprintf(stderr, "Usage: .trace FILE|off\n"); + rc = 1; + goto meta_command_exit; + } p->traceOut = output_file_open(azArg[1]); #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) if( p->traceOut==0 ){ @@ -3170,11 +3440,11 @@ static int do_meta_command(char *zLine, struct callback_data *p){ #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){ extern int sqlite3WhereTrace; - sqlite3WhereTrace = booleanValue(azArg[1]); + sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff; }else #endif - if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){ + if( c=='w' && strncmp(azArg[0], "width", n)==0 ){ int j; assert( nArg<=ArraySize(azArg) ); for(j=1; jcolWidth); j++){ @@ -3188,6 +3458,11 @@ static int do_meta_command(char *zLine, struct callback_data *p){ rc = 1; } +meta_command_exit: + if( p->outCount ){ + p->outCount--; + if( p->outCount==0 ) output_reset(p); + } return rc; } @@ -3355,6 +3630,10 @@ static int process_input(struct callback_data *p, FILE *in){ errCnt++; } nSql = 0; + if( p->outCount ){ + output_reset(p); + p->outCount = 0; + } }else if( nSql && _all_whitespace(zSql) ){ if( p->echoOn ) printf("%s\n", zSql); nSql = 0; @@ -3497,6 +3776,7 @@ static const char zOptions[] = #ifdef SQLITE_ENABLE_MULTIPLEX " -multiplex enable the multiplexor VFS\n" #endif + " -newline SEP set newline character(s) for CSV\n" " -nullvalue TEXT set text string for NULL values. Default ''\n" " -separator SEP set output field separator. Default: '|'\n" " -stats print memory stats before each finalize\n" @@ -3526,6 +3806,7 @@ static void main_init(struct callback_data *data) { memset(data, 0, sizeof(*data)); data->mode = MODE_List; memcpy(data->separator,"|", 2); + memcpy(data->newline,"\r\n", 3); data->showHeader = 0; sqlite3_config(SQLITE_CONFIG_URI, 1); sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); @@ -3618,6 +3899,7 @@ int main(int argc, char **argv){ if( z[1]=='-' ) z++; if( strcmp(z,"-separator")==0 || strcmp(z,"-nullvalue")==0 + || strcmp(z,"-newline")==0 || strcmp(z,"-cmd")==0 ){ (void)cmdline_option_value(argc, argv, ++i); @@ -3727,6 +4009,9 @@ int main(int argc, char **argv){ }else if( strcmp(z,"-separator")==0 ){ sqlite3_snprintf(sizeof(data.separator), data.separator, "%s",cmdline_option_value(argc,argv,++i)); + }else if( strcmp(z,"-newline")==0 ){ + sqlite3_snprintf(sizeof(data.newline), data.newline, + "%s",cmdline_option_value(argc,argv,++i)); }else if( strcmp(z,"-nullvalue")==0 ){ sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue, "%s",cmdline_option_value(argc,argv,++i)); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 5d2c875..230f8d4 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -264,7 +264,7 @@ typedef sqlite_uint64 sqlite3_uint64; ** ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors ** for the [sqlite3] object. -** ^Calls to sqlite3_close() and sqlite3_close_v2() return SQLITE_OK if +** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if ** the [sqlite3] object is successfully destroyed and all associated ** resources are deallocated. ** @@ -272,7 +272,7 @@ typedef sqlite_uint64 sqlite3_uint64; ** statements or unfinished sqlite3_backup objects then sqlite3_close() ** will leave the database connection open and return [SQLITE_BUSY]. ** ^If sqlite3_close_v2() is called with unfinalized prepared statements -** and unfinished sqlite3_backups, then the database connection becomes +** and/or unfinished sqlite3_backups, then the database connection becomes ** an unusable "zombie" which will automatically be deallocated when the ** last prepared statement is finalized or the last sqlite3_backup is ** finished. The sqlite3_close_v2() interface is intended for use with @@ -285,7 +285,7 @@ typedef sqlite_uint64 sqlite3_uint64; ** with the [sqlite3] object prior to attempting to close the object. ^If ** sqlite3_close_v2() is called on a [database connection] that still has ** outstanding [prepared statements], [BLOB handles], and/or -** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation +** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation ** of resources is deferred until all [prepared statements], [BLOB handles], ** and [sqlite3_backup] objects are also destroyed. ** @@ -381,16 +381,14 @@ int sqlite3_exec( /* ** CAPI3REF: Result Codes -** KEYWORDS: SQLITE_OK {error code} {error codes} -** KEYWORDS: {result code} {result codes} +** KEYWORDS: {result code definitions} ** ** Many SQLite functions return an integer result code from the set shown ** here in order to indicate success or failure. ** ** New error codes may be added in future versions of SQLite. ** -** See also: [SQLITE_IOERR_READ | extended result codes], -** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes]. +** See also: [extended result code definitions] */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ @@ -428,26 +426,19 @@ int sqlite3_exec( /* ** CAPI3REF: Extended Result Codes -** KEYWORDS: {extended error code} {extended error codes} -** KEYWORDS: {extended result code} {extended result codes} +** KEYWORDS: {extended result code definitions} ** -** In its default configuration, SQLite API routines return one of 26 integer -** [SQLITE_OK | result codes]. However, experience has shown that many of +** In its default configuration, SQLite API routines return one of 30 integer +** [result codes]. However, experience has shown that many of ** these result codes are too coarse-grained. They do not provide as ** much information about problems as programmers might like. In an effort to ** address this, newer versions of SQLite (version 3.3.8 and later) include ** support for additional result codes that provide more detailed information -** about errors. The extended result codes are enabled or disabled +** about errors. These [extended result codes] are enabled or disabled ** on a per database connection basis using the -** [sqlite3_extended_result_codes()] API. -** -** Some of the available extended result codes are listed here. -** One may expect the number of extended result codes will increase -** over time. Software that uses extended result codes should expect -** to see new result codes in future releases of SQLite. -** -** The SQLITE_OK result code will never be extended. It will always -** be exactly zero. +** [sqlite3_extended_result_codes()] API. Or, the extended code for +** the most recent error can be obtained using +** [sqlite3_extended_errcode()]. */ #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) @@ -555,7 +546,10 @@ int sqlite3_exec( ** file that were written at the application level might have changed ** and that adjacent bytes, even bytes within the same sector are ** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN -** flag indicate that a file cannot be deleted when open. +** flag indicate that a file cannot be deleted when open. The +** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on +** read-only media and cannot be changed even by processes with +** elevated privileges. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -570,6 +564,7 @@ int sqlite3_exec( #define SQLITE_IOCAP_SEQUENTIAL 0x00000400 #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 +#define SQLITE_IOCAP_IMMUTABLE 0x00002000 /* ** CAPI3REF: File Locking Levels @@ -676,7 +671,7 @@ struct sqlite3_file { ** locking strategy (for example to use dot-file locks), to inquire ** about the status of a lock, or to break stale locks. The SQLite ** core reserves all opcodes less than 100 for its own use. -** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available. +** A [file control opcodes | list of opcodes] less than 100 is available. ** Applications that define a custom xFileControl method should use opcodes ** greater than 100 to avoid conflicts. VFS implementations should ** return [SQLITE_NOTFOUND] for file control opcodes that they do not @@ -749,6 +744,7 @@ struct sqlite3_io_methods { /* ** CAPI3REF: Standard File Control Opcodes +** KEYWORDS: {file control opcodes} {file control opcode} ** ** These integer constants are opcodes for the xFileControl method ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] @@ -938,6 +934,12 @@ struct sqlite3_io_methods { ** on whether or not the file has been renamed, moved, or deleted since it ** was first opened. ** +**
  • [[SQLITE_FCNTL_WIN32_SET_HANDLE]] +** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This +** opcode causes the xFileControl method to swap the file handle with the one +** pointed to by the pArg argument. This capability is used during testing +** and only needs to be supported when SQLITE_TEST is defined. +** ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -961,6 +963,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_HAS_MOVED 20 #define SQLITE_FCNTL_SYNC 21 #define SQLITE_FCNTL_COMMIT_PHASETWO 22 +#define SQLITE_FCNTL_WIN32_SET_HANDLE 23 /* ** CAPI3REF: Mutex Handle @@ -2021,27 +2024,33 @@ int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors ** -** ^This routine sets a callback function that might be invoked whenever -** an attempt is made to open a database table that another thread -** or process has locked. +** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X +** that might be invoked with argument P whenever +** an attempt is made to access a database table associated with +** [database connection] D when another thread +** or process has the table locked. +** The sqlite3_busy_handler() interface is used to implement +** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout]. ** -** ^If the busy callback is NULL, then [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] +** ^If the busy callback is NULL, then [SQLITE_BUSY] ** is returned immediately upon encountering the lock. ^If the busy callback ** is not NULL, then the callback might be invoked with two arguments. ** ** ^The first argument to the busy handler is a copy of the void* pointer which ** is the third argument to sqlite3_busy_handler(). ^The second argument to ** the busy handler callback is the number of times that the busy handler has -** been invoked for this locking event. ^If the +** been invoked for the same locking event. ^If the ** busy callback returns 0, then no additional attempts are made to -** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned. +** access the database and [SQLITE_BUSY] is returned +** to the application. ** ^If the callback returns non-zero, then another attempt -** is made to open the database for reading and the cycle repeats. +** is made to access the database and the cycle repeats. ** ** The presence of a busy handler does not guarantee that it will be invoked ** when there is lock contention. ^If SQLite determines that invoking the busy ** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] -** or [SQLITE_IOERR_BLOCKED] instead of invoking the busy handler. +** to the application instead of invoking the +** busy handler. ** Consider a scenario where one process is holding a read lock that ** it is trying to promote to a reserved lock and ** a second process is holding a reserved lock that it is trying @@ -2055,28 +2064,15 @@ int sqlite3_complete16(const void *sql); ** ** ^The default busy callback is NULL. ** -** ^The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED] -** when SQLite is in the middle of a large transaction where all the -** changes will not fit into the in-memory cache. SQLite will -** already hold a RESERVED lock on the database file, but it needs -** to promote this lock to EXCLUSIVE so that it can spill cache -** pages into the database file without harm to concurrent -** readers. ^If it is unable to promote the lock, then the in-memory -** cache will be left in an inconsistent state and so the error -** code is promoted from the relatively benign [SQLITE_BUSY] to -** the more severe [SQLITE_IOERR_BLOCKED]. ^This error code promotion -** forces an automatic rollback of the changes. See the -** -** CorruptionFollowingBusyError wiki page for a discussion of why -** this is important. -** ** ^(There can only be a single busy handler defined for each ** [database connection]. Setting a new busy handler clears any ** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] -** will also set or clear the busy handler. +** or evaluating [PRAGMA busy_timeout=N] will change the +** busy handler and thus clear any previously set busy handler. ** ** The busy callback should not take any actions which modify the -** database connection that invoked the busy handler. Any such actions +** database connection that invoked the busy handler. In other words, +** the busy handler is not reentrant. Any such actions ** result in undefined behavior. ** ** A busy handler must not close the database connection @@ -2092,7 +2088,7 @@ int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); ** will sleep multiple times until at least "ms" milliseconds of sleeping ** have accumulated. ^After at least "ms" milliseconds of sleeping, ** the handler returns 0 which causes [sqlite3_step()] to return -** [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED]. +** [SQLITE_BUSY]. ** ** ^Calling this routine with an argument less than or equal to zero ** turns off all busy handlers. @@ -2101,6 +2097,8 @@ int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); ** [database connection] any any given moment. If another busy handler ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ +** +** See also: [PRAGMA busy_timeout] */ int sqlite3_busy_timeout(sqlite3*, int ms); @@ -2502,8 +2500,8 @@ int sqlite3_set_authorizer( ** [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. +** Note that SQLITE_IGNORE is also used as a [conflict resolution mode] +** returned 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 */ @@ -2774,6 +2772,30 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. +** +**
  • psow: ^The psow parameter may be "true" (or "on" or "yes" or +** "1") or "false" (or "off" or "no" or "0") to indicate that the +** [powersafe overwrite] property does or does not apply to the +** storage media on which the database file resides. ^The psow query +** parameter only works for the built-in unix and Windows VFSes. +** +**
  • nolock: ^The nolock parameter is a boolean query parameter +** which if set disables file locking in rollback journal modes. This +** is useful for accessing a database on a filesystem that does not +** support locking. Caution: Database corruption might result if two +** or more processes write to the same database and any one of those +** processes uses nolock=1. +** +**
  • immutable: ^The immutable parameter is a boolean query +** parameter that indicates that the database file is stored on +** read-only media. ^When immutable is set, SQLite assumes that the +** database file cannot be changed, even by a process with higher +** privilege, and so the database is opened read-only and all locking +** and change detection is disabled. Caution: Setting the immutable +** property on a database file that does in fact change can result +** in incorrect query results and/or [SQLITE_CORRUPT] errors. +** See also: [SQLITE_IOCAP_IMMUTABLE]. +** ** ** ** ^Specifying an unknown parameter in the query component of a URI is not an @@ -2803,8 +2825,9 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** Open file "data.db" in the current directory for read-only access. ** Regardless of whether or not shared-cache mode is enabled by ** default, use a private cache. -** file:/home/fred/data.db?vfs=unix-nolock -** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". +** file:/home/fred/data.db?vfs=unix-dotfile +** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" +** that uses dot-files in place of posix advisory locking. ** file:data.db?mode=readonly ** An error. "readonly" is not a valid option for the "mode" parameter. ** @@ -4665,6 +4688,13 @@ int sqlite3_sleep(int); ** is a NULL pointer, then SQLite performs a search for an appropriate ** temporary file directory. ** +** Applications are strongly discouraged from using this global variable. +** It is required to set a temporary folder on Windows Runtime (WinRT). +** But for all other platforms, it is highly recommended that applications +** neither read nor write this variable. This global variable is a relic +** that exists for backwards compatibility of legacy applications and should +** be avoided in new projects. +** ** It is not safe to read or modify this variable in more than one ** thread at a time. It is not safe to read or modify this variable ** if a [database connection] is being used at the same time in a separate @@ -4683,6 +4713,11 @@ int sqlite3_sleep(int); ** Hence, if this variable is modified directly, either it should be ** made NULL or made to point to memory obtained from [sqlite3_malloc] ** or else the use of the [temp_store_directory pragma] should be avoided. +** Except when requested by the [temp_store_directory pragma], SQLite +** does not free the memory that sqlite3_temp_directory points to. If +** the application wants that memory to be freed, it must do +** so itself, taking care to only do so after all [database connection] +** objects have been destroyed. ** ** Note to Windows Runtime users: The temporary directory must be set ** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various @@ -5817,10 +5852,12 @@ int sqlite3_vfs_unregister(sqlite3_vfs*); **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MASTER **
  • SQLITE_MUTEX_STATIC_MEM -**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU -**
  • SQLITE_MUTEX_STATIC_LRU2 +**
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 ** )^ ** ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) @@ -6024,6 +6061,9 @@ int sqlite3_mutex_notheld(sqlite3_mutex*); #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ +#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ /* ** CAPI3REF: Retrieve the mutex for a database connection @@ -6118,7 +6158,9 @@ int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 -#define SQLITE_TESTCTRL_LAST 21 +#define SQLITE_TESTCTRL_BYTEORDER 22 +#define SQLITE_TESTCTRL_ISINIT 23 +#define SQLITE_TESTCTRL_LAST 23 /* ** CAPI3REF: SQLite Runtime Status @@ -7102,6 +7144,9 @@ void *sqlite3_wal_hook( ** ^The [wal_autocheckpoint pragma] can be used to invoke this interface ** from SQL. ** +** ^Checkpoints initiated by this mechanism are +** [sqlite3_wal_checkpoint_v2|PASSIVE]. +** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] ** pages. The use of this interface @@ -7118,6 +7163,10 @@ int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); ** empty string, then a checkpoint is run on all databases of ** connection D. ^If the database connection D is not in ** [WAL | write-ahead log mode] then this interface is a harmless no-op. +** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a +** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint. +** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL +** or RESET checkpoint. ** ** ^The [wal_checkpoint pragma] can be used to invoke this interface ** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the @@ -7140,10 +7189,12 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** Checkpoint as many frames as possible without waiting for any database ** readers or writers to finish. Sync the db file if all frames in the log ** are checkpointed. This mode is the same as calling -** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked. +** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback] +** is never invoked. ** **
    SQLITE_CHECKPOINT_FULL
    -** This mode blocks (calls the busy-handler callback) until there is no +** This mode blocks (it invokes the +** [sqlite3_busy_handler|busy-handler callback]) until there is no ** database writer and all readers are reading from the most recent database ** snapshot. It then checkpoints all frames in the log file and syncs the ** database file. This call blocks database writers while it is running, @@ -7151,7 +7202,8 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** **
    SQLITE_CHECKPOINT_RESTART
    ** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after -** checkpointing the log file it blocks (calls the busy-handler callback) +** checkpointing the log file it blocks (calls the +** [sqlite3_busy_handler|busy-handler callback]) ** until all readers are reading from the database file only. This ensures ** that the next client to write to the database file restarts the log file ** from the beginning. This call blocks database writers while it is running, @@ -7289,6 +7341,7 @@ int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Conflict resolution modes +** KEYWORDS: {conflict resolution mode} ** ** These constants are returned by [sqlite3_vtab_on_conflict()] to ** inform a [virtual table] implementation what the [ON CONFLICT] mode diff --git a/src/sqlite3.rc b/src/sqlite3.rc index aedbb63..04dd086 100644 --- a/src/sqlite3.rc +++ b/src/sqlite3.rc @@ -35,6 +35,14 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif /* defined(_WIN32) */ +/* + * Icon + */ + +#define IDI_SQLITE 101 + +IDI_SQLITE ICON "..\\art\\sqlite370.ico" + /* * Version */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 3ee39e5..ee52487 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -525,10 +525,10 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */ ** gives a possible range of values of approximately 1.0e986 to 1e-986. ** But the allowed values are "grainy". Not every value is representable. ** For example, quantities 16 and 17 are both represented by a LogEst -** of 40. However, since LogEst quantatites are suppose to be estimates, +** of 40. However, since LogEst quantaties are suppose to be estimates, ** not exact values, this imprecision is not a problem. ** -** "LogEst" is short for "Logarithimic Estimate". +** "LogEst" is short for "Logarithmic Estimate". ** ** Examples: ** 1 -> 0 20 -> 43 10000 -> 132 @@ -546,22 +546,39 @@ typedef INT16_TYPE LogEst; /* ** Macros to determine whether the machine is big or little endian, -** evaluated at runtime. +** and whether or not that determination is run-time or compile-time. +** +** For best performance, an attempt is made to guess at the byte-order +** using C-preprocessor macros. If that is unsuccessful, or if +** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined +** at run-time. */ #ifdef SQLITE_AMALGAMATION const int sqlite3one = 1; #else extern const int sqlite3one; #endif -#if defined(i386) || defined(__i386__) || defined(_M_IX86)\ - || defined(__x86_64) || defined(__x86_64__) +#if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ + defined(__arm__)) && !defined(SQLITE_RUNTIME_BYTEORDER) +# define SQLITE_BYTEORDER 1234 # define SQLITE_BIGENDIAN 0 # define SQLITE_LITTLEENDIAN 1 # define SQLITE_UTF16NATIVE SQLITE_UTF16LE -#else +#endif +#if (defined(sparc) || defined(__ppc__)) \ + && !defined(SQLITE_RUNTIME_BYTEORDER) +# define SQLITE_BYTEORDER 4321 +# define SQLITE_BIGENDIAN 1 +# define SQLITE_LITTLEENDIAN 0 +# define SQLITE_UTF16NATIVE SQLITE_UTF16BE +#endif +#if !defined(SQLITE_BYTEORDER) +# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */ # define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0) # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1) -# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) +# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) #endif /* @@ -859,7 +876,7 @@ struct Schema { Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ - u16 flags; /* Flags associated with this schema */ + u16 schemaFlags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ }; @@ -867,10 +884,10 @@ struct Schema { ** These macros can be used to test, set, or clear bits in the ** Db.pSchema->flags field. */ -#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P)) -#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0) -#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P) -#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P) +#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P)) +#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))!=0) +#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags|=(P) +#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags&=~(P) /* ** Allowed values for the DB.pSchema->flags field. @@ -1454,12 +1471,15 @@ struct Table { #ifndef SQLITE_OMIT_CHECK ExprList *pCheck; /* All CHECK constraints */ #endif - tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */ + LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ int tnum; /* Root BTree node for this table (see note above) */ i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */ i16 nCol; /* Number of columns in this table */ u16 nRef; /* Number of pointers to this Table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ +#ifdef SQLITE_ENABLE_COSTMULT + LogEst costMult; /* Cost multiplier for using this table */ +#endif u8 tabFlags; /* Mask of TF_* values */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ #ifndef SQLITE_OMIT_ALTERTABLE @@ -1627,6 +1647,7 @@ struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ u16 nField; /* Number of entries in apMem[] */ i8 default_rc; /* Comparison result if keys are equal */ + u8 isCorrupt; /* Corruption detected by xRecordCompare() */ Mem *aMem; /* Values */ int r1; /* Value to return if (lhs > rhs) */ int r2; /* Value to return if (rhs < lhs) */ @@ -1662,7 +1683,7 @@ struct UnpackedRecord { struct Index { char *zName; /* Name of this index */ i16 *aiColumn; /* Which columns are used by this index. 1st is 0 */ - tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */ + LogEst *aiRowLogEst; /* From ANALYZE: Est. rows selected by each column */ Table *pTable; /* The SQL table being indexed */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ @@ -1676,7 +1697,7 @@ struct Index { u16 nKeyCol; /* Number of columns forming the key */ u16 nColumn; /* Number of columns stored in the index */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ - unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ + unsigned idxType:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ unsigned isResized:1; /* True if resizeIndexObject() has been called */ @@ -1689,6 +1710,19 @@ struct Index { #endif }; +/* +** Allowed values for Index.idxType +*/ +#define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */ +#define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */ +#define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */ + +/* Return true if index X is a PRIMARY KEY index */ +#define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) + +/* Return true if index X is a UNIQUE index */ +#define IsUniqueIndex(X) ((X)->onError!=OE_None) + /* ** Each sample stored in the sqlite_stat3 table is represented in memory ** using a structure of this type. See documentation at the top of the @@ -1893,8 +1927,8 @@ struct Expr { #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ -#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE opeartor */ - /* unused 0x000200 */ +#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ +#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */ #define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ #define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */ @@ -1958,7 +1992,6 @@ struct Expr { */ struct ExprList { int nExpr; /* Number of expressions on the list */ - int iECursor; /* VDBE Cursor associated with this ExprList */ struct ExprList_item { /* For each expression in the list */ Expr *pExpr; /* The list of expressions */ char *zName; /* Token associated with this expression */ @@ -2108,6 +2141,8 @@ struct SrcList { #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ +#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */ +#define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */ /* Allowed return values from sqlite3WhereIsDistinct() */ @@ -2182,7 +2217,7 @@ struct Select { u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ u16 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ - int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */ + int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ u64 nSelectRow; /* Estimated number of result rows */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ @@ -2206,9 +2241,9 @@ struct Select { #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ -#define SF_UseSorter 0x0040 /* Sort using a sorter */ + /* 0x0040 NOT USED */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */ -#define SF_Materialize 0x0100 /* NOT USED */ + /* 0x0100 NOT USED */ #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */ #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */ #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */ @@ -2261,13 +2296,15 @@ struct Select { ** starting with pDest->iSdst. ** ** SRT_Table Store results in temporary table pDest->iSDParm. -** This is like SRT_EphemTab except that the table -** is assumed to already be open. +** SRT_Fifo This is like SRT_EphemTab except that the table +** is assumed to already be open. SRT_Fifo has +** the additional property of being able to ignore +** the ORDER BY clause. ** -** SRT_DistTable Store results in a temporary table pDest->iSDParm. +** SRT_DistFifo Store results in a temporary table pDest->iSDParm. ** But also use temporary table pDest->iSDParm+1 as ** a record of all prior results and ignore any duplicate -** rows. Name means: "Distinct Table". +** rows. Name means: "Distinct Fifo". ** ** SRT_Queue Store results in priority queue pDest->iSDParm (really ** an index). Append a sequence number so that all entries @@ -2281,19 +2318,20 @@ struct Select { #define SRT_Except 2 /* Remove result from a UNION index */ #define SRT_Exists 3 /* Store 1 if the result is not empty */ #define SRT_Discard 4 /* Do not save the results anywhere */ +#define SRT_Fifo 5 /* Store result as data with an automatic rowid */ +#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */ +#define SRT_Queue 7 /* Store result in an queue */ +#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */ /* The ORDER BY clause is ignored for all of the above */ -#define IgnorableOrderby(X) ((X->eDest)<=SRT_Discard) +#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue) -#define SRT_Output 5 /* Output each row of result */ -#define SRT_Mem 6 /* Store result in a memory cell */ -#define SRT_Set 7 /* Store results as keys in an index */ -#define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */ -#define SRT_Coroutine 9 /* Generate a single row of result */ -#define SRT_Table 10 /* Store result as data with an automatic rowid */ -#define SRT_DistTable 11 /* Like SRT_Table, but unique results only */ -#define SRT_Queue 12 /* Store result in an queue */ -#define SRT_DistQueue 13 /* Like SRT_Queue, but unique results only */ +#define SRT_Output 9 /* Output each row of result */ +#define SRT_Mem 10 /* Store result in a memory cell */ +#define SRT_Set 11 /* Store results as keys in an index */ +#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */ +#define SRT_Coroutine 13 /* Generate a single row of result */ +#define SRT_Table 14 /* Store result as data with an automatic rowid */ /* ** An instance of this object describes where to put of the results of @@ -2361,9 +2399,19 @@ struct TriggerPrg { ** The yDbMask datatype for the bitmask of all attached databases. */ #if SQLITE_MAX_ATTACHED>30 - typedef sqlite3_uint64 yDbMask; + typedef unsigned char yDbMask[(SQLITE_MAX_ATTACHED+9)/8]; +# define DbMaskTest(M,I) (((M)[(I)/8]&(1<<((I)&7)))!=0) +# define DbMaskZero(M) memset((M),0,sizeof(M)) +# define DbMaskSet(M,I) (M)[(I)/8]|=(1<<((I)&7)) +# define DbMaskAllZero(M) sqlite3DbMaskAllZero(M) +# define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0) #else typedef unsigned int yDbMask; +# define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0) +# define DbMaskZero(M) (M)=0 +# define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I)) +# define DbMaskAllZero(M) (M)==0 +# define DbMaskNonZero(M) (M)!=0 #endif /* @@ -2391,8 +2439,6 @@ struct Parse { u8 checkSchema; /* Causes schema cookie check after an error */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ - u8 nColCache; /* Number of entries in aColCache[] */ - u8 iColCache; /* Next entry in aColCache[] to replace */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ @@ -2690,11 +2736,10 @@ struct Sqlite3Config { int isMutexInit; /* True after mutexes are initialized */ int isMallocInit; /* True after malloc is initialized */ int isPCacheInit; /* True after malloc is initialized */ - sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ int nRefInitMutex; /* Number of users of pInitMutex */ + sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ void (*xLog)(void*,int,const char*); /* Function for logging */ void *pLogArg; /* First argument to xLog() */ - int bLocaltimeFault; /* True to fail localtime() calls */ #ifdef SQLITE_ENABLE_SQLLOG void(*xSqllog)(void*,sqlite3*,const char*, int); void *pSqllogArg; @@ -2706,6 +2751,10 @@ struct Sqlite3Config { void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */ void *pVdbeBranchArg; /* 1st argument */ #endif +#ifndef SQLITE_OMIT_BUILTIN_TEST + int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ +#endif + int bLocaltimeFault; /* True to fail localtime() calls */ }; /* @@ -3007,6 +3056,12 @@ int sqlite3ParseUri(const char*,const char*,unsigned int*, Btree *sqlite3DbNameToBtree(sqlite3*,const char*); int sqlite3CodeOnce(Parse *); +#ifdef SQLITE_OMIT_BUILTIN_TEST +# define sqlite3FaultSim(X) SQLITE_OK +#else + int sqlite3FaultSim(int); +#endif + Bitvec *sqlite3BitvecCreate(u32); int sqlite3BitvecTest(Bitvec*, u32); int sqlite3BitvecSet(Bitvec*, u32); @@ -3018,7 +3073,7 @@ int sqlite3BitvecBuiltinTest(int,int*); RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); void sqlite3RowSetClear(RowSet*); void sqlite3RowSetInsert(RowSet*, i64); -int sqlite3RowSetTest(RowSet*, u8 iBatch, i64); +int sqlite3RowSetTest(RowSet*, int iBatch, i64); int sqlite3RowSetNext(RowSet*, i64*); void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int); @@ -3029,6 +3084,9 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int); # define sqlite3ViewGetColumnNames(A,B) 0 #endif +#if SQLITE_MAX_ATTACHED>30 + int sqlite3DbMaskAllZero(yDbMask); +#endif void sqlite3DropTable(Parse*, SrcList*, int, int); void sqlite3CodeDropTable(Parse*, Table*, int, int); void sqlite3DeleteTable(sqlite3*, Table*); @@ -3074,6 +3132,7 @@ void sqlite3WhereEnd(WhereInfo*); u64 sqlite3WhereOutputRowCount(WhereInfo*); int sqlite3WhereIsDistinct(WhereInfo*); int sqlite3WhereIsOrdered(WhereInfo*); +int sqlite3WhereIsSorted(WhereInfo*); int sqlite3WhereContinueLabel(WhereInfo*); int sqlite3WhereBreakLabel(WhereInfo*); int sqlite3WhereOkOnePass(WhereInfo*, int*); @@ -3082,7 +3141,7 @@ void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCacheStore(Parse*, int, int, int); void sqlite3ExprCachePush(Parse*); -void sqlite3ExprCachePop(Parse*, int); +void sqlite3ExprCachePop(Parse*); void sqlite3ExprCacheRemove(Parse*, int, int); void sqlite3ExprCacheClear(Parse*); void sqlite3ExprCacheAffinityChange(Parse*, int, int); @@ -3134,6 +3193,7 @@ int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*); int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); +void sqlite3ResolvePartIdxLabel(Parse*,int); void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, u8,u8,int,int*); void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int); @@ -3277,6 +3337,7 @@ char sqlite3CompareAffinity(Expr *pExpr, char aff2); int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); char sqlite3ExprAffinity(Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); +int sqlite3DecOrHexToI64(const char*, i64*); void sqlite3Error(sqlite3*, int, const char*,...); void *sqlite3HexToBlob(sqlite3*, const char *z, int n); u8 sqlite3HexToInt(int h); @@ -3291,7 +3352,7 @@ int sqlite3ReadSchema(Parse *pParse); CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); -Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*); +Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*); Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); Expr *sqlite3ExprSkipCollate(Expr*); int sqlite3CheckCollSeq(Parse *, CollSeq *); @@ -3306,7 +3367,7 @@ void sqlite3FileSuffix3(const char*, char*); #else # define sqlite3FileSuffix3(X,Y) #endif -u8 sqlite3GetBoolean(const char *z,int); +u8 sqlite3GetBoolean(const char *z,u8); const void *sqlite3ValueText(sqlite3_value*, u8); int sqlite3ValueBytes(sqlite3_value*, u8); @@ -3391,7 +3452,9 @@ void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *); #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 void sqlite3AnalyzeFunctions(void); int sqlite3Stat4ProbeSetValue(Parse*,Index*,UnpackedRecord**,Expr*,u8,int,int*); +int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**); void sqlite3Stat4ProbeFree(UnpackedRecord*); +int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_value**); #endif /* @@ -3528,11 +3591,21 @@ const char *sqlite3JournalModename(int); #define sqlite3EndBenignMalloc() #endif -#define IN_INDEX_ROWID 1 -#define IN_INDEX_EPH 2 -#define IN_INDEX_INDEX_ASC 3 -#define IN_INDEX_INDEX_DESC 4 -int sqlite3FindInIndex(Parse *, Expr *, int*); +/* +** Allowed return values from sqlite3FindInIndex() +*/ +#define IN_INDEX_ROWID 1 /* Search the rowid of the table */ +#define IN_INDEX_EPH 2 /* Search an ephemeral b-tree */ +#define IN_INDEX_INDEX_ASC 3 /* Existing index ASCENDING */ +#define IN_INDEX_INDEX_DESC 4 /* Existing index DESCENDING */ +#define IN_INDEX_NOOP 5 /* No table available. Use comparisons */ +/* +** Allowed flags for the 3rd parameter to sqlite3FindInIndex(). +*/ +#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ +#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ +#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ +int sqlite3FindInIndex(Parse *, Expr *, u32, int*); #ifdef SQLITE_ENABLE_ATOMIC_WRITE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); diff --git a/src/test1.c b/src/test1.c index 3000288..56487f6 100644 --- a/src/test1.c +++ b/src/test1.c @@ -14,6 +14,10 @@ ** testing of the SQLite library. */ #include "sqliteInt.h" +#if SQLITE_OS_WIN +# include "os_win.h" +#endif + #include "vdbeInt.h" #include "tcl.h" #include @@ -113,6 +117,16 @@ int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){ return TCL_OK; } +#if SQLITE_OS_WIN +/* +** Decode a Win32 HANDLE object. +*/ +int getWin32Handle(Tcl_Interp *interp, const char *zA, LPHANDLE phFile){ + *phFile = (HANDLE)sqlite3TestTextToPtr(zA); + return TCL_OK; +} +#endif + extern const char *sqlite3ErrName(int); #define t1ErrorName sqlite3ErrName @@ -5206,6 +5220,7 @@ static int file_control_lockproxy_test( return TCL_OK; } +#if SQLITE_OS_WIN /* ** tclcmd: file_control_win32_av_retry DB NRETRY DELAY ** @@ -5239,6 +5254,42 @@ static int file_control_win32_av_retry( return TCL_OK; } +/* +** tclcmd: file_control_win32_set_handle DB HANDLE +** +** This TCL command runs the sqlite3_file_control interface with +** the SQLITE_FCNTL_WIN32_SET_HANDLE opcode. +*/ +static int file_control_win32_set_handle( + ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3 *db; + int rc; + HANDLE hFile = NULL; + char z[100]; + + if( objc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetStringFromObj(objv[0], 0), " DB HANDLE", 0); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ + return TCL_ERROR; + } + if( getWin32Handle(interp, Tcl_GetString(objv[2]), &hFile) ){ + return TCL_ERROR; + } + rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_SET_HANDLE, + (void*)&hFile); + sqlite3_snprintf(sizeof(z), z, "%d %p", rc, (void*)hFile); + Tcl_AppendResult(interp, z, (char*)0); + return TCL_OK; +} +#endif + /* ** tclcmd: file_control_persist_wal DB PERSIST-FLAG ** @@ -6230,6 +6281,7 @@ static int tclLoadStaticExtensionCmd( ){ extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); + extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); @@ -6244,6 +6296,7 @@ static int tclLoadStaticExtensionCmd( } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "closure", sqlite3_closure_init }, + { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "nextchar", sqlite3_nextchar_init }, @@ -6468,7 +6521,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "file_control_lockproxy_test", file_control_lockproxy_test, 0 }, { "file_control_chunksize_test", file_control_chunksize_test, 0 }, { "file_control_sizehint_test", file_control_sizehint_test, 0 }, +#if SQLITE_OS_WIN { "file_control_win32_av_retry", file_control_win32_av_retry, 0 }, + { "file_control_win32_set_handle", file_control_win32_set_handle, 0 }, +#endif { "file_control_persist_wal", file_control_persist_wal, 0 }, { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0}, { "file_control_vfsname", file_control_vfsname, 0 }, @@ -6525,7 +6581,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_pager_writedb_count; extern int sqlite3_pager_writej_count; #if SQLITE_OS_WIN - extern int sqlite3_os_type; + extern LONG volatile sqlite3_os_type; #endif #ifdef SQLITE_DEBUG extern int sqlite3WhereTrace; @@ -6583,7 +6639,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ #endif #if SQLITE_OS_WIN Tcl_LinkVar(interp, "sqlite_os_type", - (char*)&sqlite3_os_type, TCL_LINK_INT); + (char*)&sqlite3_os_type, TCL_LINK_LONG); #endif #ifdef SQLITE_TEST { diff --git a/src/test2.c b/src/test2.c index d130e9d..58f271f 100644 --- a/src/test2.c +++ b/src/test2.c @@ -568,7 +568,90 @@ static int testPendingByte( rc = sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, pbyte); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; -} +} + +/* +** The sqlite3FaultSim() callback: +*/ +static Tcl_Interp *faultSimInterp = 0; +static int faultSimScriptSize = 0; +static char *faultSimScript; +static int faultSimCallback(int x){ + char zInt[30]; + int i; + int isNeg; + int rc; + if( x==0 ){ + memcpy(faultSimScript+faultSimScriptSize, "0", 2); + }else{ + /* Convert x to text without using any sqlite3 routines */ + if( x<0 ){ + isNeg = 1; + x = -x; + }else{ + isNeg = 0; + } + zInt[sizeof(zInt)-1] = 0; + for(i=sizeof(zInt)-2; i>0 && x>0; i--, x /= 10){ + zInt[i] = (x%10) + '0'; + } + if( isNeg ) zInt[i--] = '-'; + memcpy(faultSimScript+faultSimScriptSize, zInt+i+1, sizeof(zInt)-i); + } + rc = Tcl_Eval(faultSimInterp, faultSimScript); + if( rc ){ + fprintf(stderr, "fault simulator script failed: [%s]", faultSimScript); + rc = SQLITE_ERROR; + }else{ + rc = atoi(Tcl_GetStringResult(faultSimInterp)); + } + Tcl_ResetResult(faultSimInterp); + return rc; +} + +/* +** sqlite3_test_control_fault_install SCRIPT +** +** Arrange to invoke SCRIPT with the integer argument to sqlite3FaultSim() +** appended, whenever sqlite3FaultSim() is called. Or, if SCRIPT is the +** empty string, cancel the sqlite3FaultSim() callback. +*/ +static int faultInstallCmd( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + const char **argv /* Text of each argument */ +){ + const char *zScript; + int nScript; + int rc; + if( argc!=1 && argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " SCRIPT\"", (void*)0); + } + zScript = argc==2 ? argv[1] : ""; + nScript = (int)strlen(zScript); + if( faultSimScript ){ + free(faultSimScript); + faultSimScript = 0; + } + if( nScript==0 ){ + rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, 0); + }else{ + faultSimScript = malloc( nScript+100 ); + if( faultSimScript==0 ){ + Tcl_AppendResult(interp, "out of memory", (void*)0); + return SQLITE_ERROR; + } + memcpy(faultSimScript, zScript, nScript); + faultSimScript[nScript] = ' '; + faultSimScriptSize = nScript+1; + faultSimInterp = interp; + rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, faultSimCallback); + } + Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); + return SQLITE_OK; +} /* ** sqlite3BitvecBuiltinTest SIZE PROGRAM @@ -638,7 +721,8 @@ int Sqlitetest2_Init(Tcl_Interp *interp){ { "fake_big_file", (Tcl_CmdProc*)fake_big_file }, #endif { "sqlite3BitvecBuiltinTest",(Tcl_CmdProc*)testBitvecBuiltinTest }, - { "sqlite3_test_control_pending_byte", (Tcl_CmdProc*)testPendingByte }, + { "sqlite3_test_control_pending_byte", (Tcl_CmdProc*)testPendingByte }, + { "sqlite3_test_control_fault_install", (Tcl_CmdProc*)faultInstallCmd }, }; int i; for(i=0; ipBt; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ MemPage *pPage = pCur->apPage[pCur->iPage]; - char *zMode = pCur->wrFlag ? "rw" : "ro"; + char *zMode = (pCur->curFlags & BTCF_WriteFlag) ? "rw" : "ro"; sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n", pCur, pCur->pgnoRoot, zMode, pPage ? pPage->pgno : 0, pCur->aiIdx[pCur->iPage], diff --git a/src/test_config.c b/src/test_config.c index 1db8198..9ce7f6f 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -20,6 +20,10 @@ #include "sqliteLimit.h" #include "sqliteInt.h" +#if SQLITE_OS_WIN +# include "os_win.h" +#endif + #include "tcl.h" #include #include @@ -326,7 +330,7 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options", "fts3", "0", TCL_GLOBAL_ONLY); #endif -#if defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_ENABLE_FTS4_UNICODE61) +#if defined(SQLITE_ENABLE_FTS3) && !defined(SQLITE_DISABLE_FTS3_UNICODE) Tcl_SetVar2(interp, "sqlite_options", "fts3_unicode", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "fts3_unicode", "0", TCL_GLOBAL_ONLY); diff --git a/src/test_multiplex.c b/src/test_multiplex.c index 45a1edf..427cc65 100644 --- a/src/test_multiplex.c +++ b/src/test_multiplex.c @@ -1176,14 +1176,20 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){ ** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while ** shutting down in order to free all remaining multiplex groups. */ -int sqlite3_multiplex_shutdown(void){ +int sqlite3_multiplex_shutdown(int eForce){ + int rc = SQLITE_OK; if( gMultiplex.isInitialized==0 ) return SQLITE_MISUSE; - if( gMultiplex.pGroups ) return SQLITE_MISUSE; + if( gMultiplex.pGroups ){ + sqlite3_log(SQLITE_MISUSE, "sqlite3_multiplex_shutdown() called " + "while database connections are still open"); + if( !eForce ) return SQLITE_MISUSE; + rc = SQLITE_MISUSE; + } gMultiplex.isInitialized = 0; sqlite3_mutex_free(gMultiplex.pMutex); sqlite3_vfs_unregister(&gMultiplex.sThisVfs); memset(&gMultiplex, 0, sizeof(gMultiplex)); - return SQLITE_OK; + return rc; } /***************************** Test Code ***********************************/ @@ -1236,13 +1242,16 @@ static int test_multiplex_shutdown( UNUSED_PARAMETER(clientData); - if( objc!=1 ){ - Tcl_WrongNumArgs(interp, 1, objv, ""); + if( objc==2 && strcmp(Tcl_GetString(objv[1]),"-force")!=0 ){ + objc = 3; + } + if( (objc!=1 && objc!=2) ){ + Tcl_WrongNumArgs(interp, 1, objv, "?-force?"); return TCL_ERROR; } /* Call sqlite3_multiplex_shutdown() */ - rc = sqlite3_multiplex_shutdown(); + rc = sqlite3_multiplex_shutdown(objc==2); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; diff --git a/src/test_multiplex.h b/src/test_multiplex.h index 9fe2f0f..d973e4a 100644 --- a/src/test_multiplex.h +++ b/src/test_multiplex.h @@ -90,7 +90,7 @@ extern int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefaul ** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while ** shutting down in order to free all remaining multiplex groups. */ -extern int sqlite3_multiplex_shutdown(void); +extern int sqlite3_multiplex_shutdown(int eForce); #ifdef __cplusplus } /* End of the 'extern "C"' block */ diff --git a/src/test_osinst.c b/src/test_osinst.c index 5314333..1701def 100644 --- a/src/test_osinst.c +++ b/src/test_osinst.c @@ -70,6 +70,12 @@ */ #include "sqlite3.h" + +#include "os_setup.h" +#if SQLITE_OS_WIN +# include "os_win.h" +#endif + #include #include @@ -221,7 +227,6 @@ static sqlite3_uint64 vfslog_time(){ return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000; } #elif SQLITE_OS_WIN -#include #include static sqlite3_uint64 vfslog_time(){ FILETIME ft; diff --git a/src/test_quota.c b/src/test_quota.c index e590996..80ebd05 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -44,49 +44,13 @@ #define sqlite3_mutex_notheld(X) ((void)(X),1) #endif /* SQLITE_THREADSAFE==0 */ - -/* -** Figure out if we are dealing with Unix, Windows, or some other -** operating system. After the following block of preprocess macros, -** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, and SQLITE_OS_OTHER -** will defined to either 1 or 0. One of the four will be 1. The other -** three will be 0. -*/ -#if defined(SQLITE_OS_OTHER) -# if SQLITE_OS_OTHER==1 -# undef SQLITE_OS_UNIX -# define SQLITE_OS_UNIX 0 -# undef SQLITE_OS_WIN -# define SQLITE_OS_WIN 0 -# else -# undef SQLITE_OS_OTHER -# endif -#endif -#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER) -# define SQLITE_OS_OTHER 0 -# ifndef SQLITE_OS_WIN -# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) \ - || defined(__MINGW32__) || defined(__BORLANDC__) -# define SQLITE_OS_WIN 1 -# define SQLITE_OS_UNIX 0 -# else -# define SQLITE_OS_WIN 0 -# define SQLITE_OS_UNIX 1 -# endif -# else -# define SQLITE_OS_UNIX 0 -# endif -#else -# ifndef SQLITE_OS_WIN -# define SQLITE_OS_WIN 0 -# endif -#endif +#include "os_setup.h" #if SQLITE_OS_UNIX # include #endif #if SQLITE_OS_WIN -# include +# include "os_win.h" # include #endif diff --git a/src/test_quota.h b/src/test_quota.h index 2d0767a..c17e15a 100644 --- a/src/test_quota.h +++ b/src/test_quota.h @@ -31,12 +31,6 @@ #include #include #include -#if SQLITE_OS_UNIX -# include -#endif -#if SQLITE_OS_WIN -# include -#endif /* Make this callable from C++ */ #ifdef __cplusplus diff --git a/src/test_rtree.c b/src/test_rtree.c index e1966c2..9d19fa0 100644 --- a/src/test_rtree.c +++ b/src/test_rtree.c @@ -35,6 +35,8 @@ struct Circle { double centerx; double centery; double radius; + double mxArea; + int eScoreType; }; /* @@ -50,11 +52,7 @@ static void circle_del(void *p){ static int circle_geom( sqlite3_rtree_geometry *p, int nCoord, -#ifdef SQLITE_RTREE_INT_ONLY - sqlite3_int64 *aCoord, -#else - double *aCoord, -#endif + sqlite3_rtree_dbl *aCoord, int *pRes ){ int i; /* Iterator variable */ @@ -62,7 +60,12 @@ static int circle_geom( double xmin, xmax; /* X dimensions of box being tested */ double ymin, ymax; /* X dimensions of box being tested */ - if( p->pUser==0 ){ + xmin = aCoord[0]; + xmax = aCoord[1]; + ymin = aCoord[2]; + ymax = aCoord[3]; + pCircle = (Circle *)p->pUser; + if( pCircle==0 ){ /* If pUser is still 0, then the parameter values have not been tested ** for correctness or stored into a Circle structure yet. Do this now. */ @@ -108,14 +111,9 @@ static int circle_geom( pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius; pCircle->aBox[1].ymin = pCircle->centery; pCircle->aBox[1].ymax = pCircle->centery; + pCircle->mxArea = (xmax - xmin)*(ymax - ymin) + 1.0; } - pCircle = (Circle *)p->pUser; - xmin = aCoord[0]; - xmax = aCoord[1]; - ymin = aCoord[2]; - ymax = aCoord[3]; - /* Check if any of the 4 corners of the bounding-box being tested lie ** inside the circular region. If they do, then the bounding-box does ** intersect the region of interest. Set the output variable to true and @@ -154,6 +152,170 @@ static int circle_geom( return SQLITE_OK; } +/* +** Implementation of "circle" r-tree geometry callback using the +** 2nd-generation interface that allows scoring. +*/ +static int circle_query_func(sqlite3_rtree_query_info *p){ + int i; /* Iterator variable */ + Circle *pCircle; /* Structure defining circular region */ + double xmin, xmax; /* X dimensions of box being tested */ + double ymin, ymax; /* X dimensions of box being tested */ + int nWithin = 0; /* Number of corners inside the circle */ + + xmin = p->aCoord[0]; + xmax = p->aCoord[1]; + ymin = p->aCoord[2]; + ymax = p->aCoord[3]; + pCircle = (Circle *)p->pUser; + if( pCircle==0 ){ + /* If pUser is still 0, then the parameter values have not been tested + ** for correctness or stored into a Circle structure yet. Do this now. */ + + /* This geometry callback is for use with a 2-dimensional r-tree table. + ** Return an error if the table does not have exactly 2 dimensions. */ + if( p->nCoord!=4 ) return SQLITE_ERROR; + + /* Test that the correct number of parameters (4) have been supplied, + ** and that the parameters are in range (that the radius of the circle + ** radius is greater than zero). */ + if( p->nParam!=4 || p->aParam[2]<0.0 ) return SQLITE_ERROR; + + /* Allocate a structure to cache parameter data in. Return SQLITE_NOMEM + ** if the allocation fails. */ + pCircle = (Circle *)(p->pUser = sqlite3_malloc(sizeof(Circle))); + if( !pCircle ) return SQLITE_NOMEM; + p->xDelUser = circle_del; + + /* Record the center and radius of the circular region. One way that + ** tested bounding boxes that intersect the circular region are detected + ** is by testing if each corner of the bounding box lies within radius + ** units of the center of the circle. */ + pCircle->centerx = p->aParam[0]; + pCircle->centery = p->aParam[1]; + pCircle->radius = p->aParam[2]; + pCircle->eScoreType = (int)p->aParam[3]; + + /* Define two bounding box regions. The first, aBox[0], extends to + ** infinity in the X dimension. It covers the same range of the Y dimension + ** as the circular region. The second, aBox[1], extends to infinity in + ** the Y dimension and is constrained to the range of the circle in the + ** X dimension. + ** + ** Then imagine each box is split in half along its short axis by a line + ** that intersects the center of the circular region. A bounding box + ** being tested can be said to intersect the circular region if it contains + ** points from each half of either of the two infinite bounding boxes. + */ + pCircle->aBox[0].xmin = pCircle->centerx; + pCircle->aBox[0].xmax = pCircle->centerx; + pCircle->aBox[0].ymin = pCircle->centery + pCircle->radius; + pCircle->aBox[0].ymax = pCircle->centery - pCircle->radius; + pCircle->aBox[1].xmin = pCircle->centerx + pCircle->radius; + pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius; + pCircle->aBox[1].ymin = pCircle->centery; + pCircle->aBox[1].ymax = pCircle->centery; + pCircle->mxArea = 200.0*200.0; + } + + /* Check if any of the 4 corners of the bounding-box being tested lie + ** inside the circular region. If they do, then the bounding-box does + ** intersect the region of interest. Set the output variable to true and + ** return SQLITE_OK in this case. */ + for(i=0; i<4; i++){ + double x = (i&0x01) ? xmax : xmin; + double y = (i&0x02) ? ymax : ymin; + double d2; + + d2 = (x-pCircle->centerx)*(x-pCircle->centerx); + d2 += (y-pCircle->centery)*(y-pCircle->centery); + if( d2<(pCircle->radius*pCircle->radius) ) nWithin++; + } + + /* Check if the bounding box covers any other part of the circular region. + ** See comments above for a description of how this test works. If it does + ** cover part of the circular region, set the output variable to true + ** and return SQLITE_OK. */ + if( nWithin==0 ){ + for(i=0; i<2; i++){ + if( xmin<=pCircle->aBox[i].xmin + && xmax>=pCircle->aBox[i].xmax + && ymin<=pCircle->aBox[i].ymin + && ymax>=pCircle->aBox[i].ymax + ){ + nWithin = 1; + break; + } + } + } + + if( pCircle->eScoreType==1 ){ + /* Depth first search */ + p->rScore = p->iLevel; + }else if( pCircle->eScoreType==2 ){ + /* Breadth first search */ + p->rScore = 100 - p->iLevel; + }else if( pCircle->eScoreType==3 ){ + /* Depth-first search, except sort the leaf nodes by area with + ** the largest area first */ + if( p->iLevel==1 ){ + p->rScore = 1.0 - (xmax-xmin)*(ymax-ymin)/pCircle->mxArea; + if( p->rScore<0.01 ) p->rScore = 0.01; + }else{ + p->rScore = 0.0; + } + }else if( pCircle->eScoreType==4 ){ + /* Depth-first search, except exclude odd rowids */ + p->rScore = p->iLevel; + if( p->iRowid&1 ) nWithin = 0; + }else{ + /* Breadth-first search, except exclude odd rowids */ + p->rScore = 100 - p->iLevel; + if( p->iRowid&1 ) nWithin = 0; + } + if( nWithin==0 ){ + p->eWithin = NOT_WITHIN; + }else if( nWithin>=4 ){ + p->eWithin = FULLY_WITHIN; + }else{ + p->eWithin = PARTLY_WITHIN; + } + return SQLITE_OK; +} +/* +** Implementation of "breadthfirstsearch" r-tree geometry callback using the +** 2nd-generation interface that allows scoring. +** +** ... WHERE id MATCH breadthfirstsearch($x0,$x1,$y0,$y1) ... +** +** It returns all entries whose bounding boxes overlap with $x0,$x1,$y0,$y1. +*/ +static int bfs_query_func(sqlite3_rtree_query_info *p){ + double x0,x1,y0,y1; /* Dimensions of box being tested */ + double bx0,bx1,by0,by1; /* Boundary of the query function */ + + if( p->nParam!=4 ) return SQLITE_ERROR; + x0 = p->aCoord[0]; + x1 = p->aCoord[1]; + y0 = p->aCoord[2]; + y1 = p->aCoord[3]; + bx0 = p->aParam[0]; + bx1 = p->aParam[1]; + by0 = p->aParam[2]; + by1 = p->aParam[3]; + p->rScore = 100 - p->iLevel; + if( p->eParentWithin==FULLY_WITHIN ){ + p->eWithin = FULLY_WITHIN; + }else if( x0>=bx0 && x1<=bx1 && y0>=by0 && y1<=by1 ){ + p->eWithin = FULLY_WITHIN; + }else if( x1>=bx0 && x0<=bx1 && y1>=by0 && y0<=by1 ){ + p->eWithin = PARTLY_WITHIN; + }else{ + p->eWithin = NOT_WITHIN; + } + return SQLITE_OK; +} + /* END of implementation of "circle" geometry callback. ************************************************************************** *************************************************************************/ @@ -194,11 +356,7 @@ static int gHere = 42; static int cube_geom( sqlite3_rtree_geometry *p, int nCoord, -#ifdef SQLITE_RTREE_INT_ONLY - sqlite3_int64 *aCoord, -#else - double *aCoord, -#endif + sqlite3_rtree_dbl *aCoord, int *piRes ){ Cube *pCube = (Cube *)p->pUser; @@ -293,6 +451,14 @@ static int register_circle_geom( } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; rc = sqlite3_rtree_geometry_callback(db, "circle", circle_geom, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_rtree_query_callback(db, "Qcircle", + circle_query_func, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_rtree_query_callback(db, "breadthfirstsearch", + bfs_query_func, 0, 0); + } Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); #endif return TCL_OK; diff --git a/src/test_syscall.c b/src/test_syscall.c index 7c0873c..0dac2e8 100644 --- a/src/test_syscall.c +++ b/src/test_syscall.c @@ -67,6 +67,11 @@ ** test_syscall list ** Return a list of all system calls. The list is constructed using ** the xNextSystemCall() VFS method. +** +** test_syscall pagesize PGSZ +** If PGSZ is a power of two greater than 256, install a wrapper around +** OS function getpagesize() that reports the system page size as PGSZ. +** Or, if PGSZ is less than zero, remove any wrapper already installed. */ #include "sqliteInt.h" @@ -89,7 +94,9 @@ static struct TestSyscallGlobal { int bPersist; /* 1 for persistent errors, 0 for transient */ int nCount; /* Fail after this many more calls */ int nFail; /* Number of failures that have occurred */ -} gSyscall = { 0, 0 }; + int pgsz; + sqlite3_syscall_ptr orig_getpagesize; +} gSyscall = { 0, 0, 0, 0, 0 }; static int ts_open(const char *, int, int); static int ts_close(int fd); @@ -650,6 +657,45 @@ static int test_syscall_defaultvfs( return TCL_OK; } +static int ts_getpagesize(void){ + return gSyscall.pgsz; +} + +static int test_syscall_pagesize( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_vfs *pVfs = sqlite3_vfs_find(0); + int pgsz; + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 2, objv, "PGSZ"); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[2], &pgsz) ){ + return TCL_ERROR; + } + + if( pgsz<0 ){ + if( gSyscall.orig_getpagesize ){ + pVfs->xSetSystemCall(pVfs, "getpagesize", gSyscall.orig_getpagesize); + } + }else{ + if( pgsz<512 || (pgsz & (pgsz-1)) ){ + Tcl_AppendResult(interp, "pgsz out of range", 0); + return TCL_ERROR; + } + gSyscall.orig_getpagesize = pVfs->xGetSystemCall(pVfs, "getpagesize"); + gSyscall.pgsz = pgsz; + pVfs->xSetSystemCall( + pVfs, "getpagesize", (sqlite3_syscall_ptr)ts_getpagesize + ); + } + + return TCL_OK; +} + static int test_syscall( void * clientData, Tcl_Interp *interp, @@ -668,6 +714,7 @@ static int test_syscall( { "exists", test_syscall_exists }, { "list", test_syscall_list }, { "defaultvfs", test_syscall_defaultvfs }, + { "pagesize", test_syscall_pagesize }, { 0, 0 } }; int iCmd; diff --git a/src/test_vfs.c b/src/test_vfs.c index 613b0fc..7ee2a93 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -127,8 +127,10 @@ struct Testvfs { #define TESTVFS_FULLPATHNAME_MASK 0x00008000 #define TESTVFS_READ_MASK 0x00010000 #define TESTVFS_UNLOCK_MASK 0x00020000 +#define TESTVFS_LOCK_MASK 0x00040000 +#define TESTVFS_CKLOCK_MASK 0x00080000 -#define TESTVFS_ALL_MASK 0x0003FFFF +#define TESTVFS_ALL_MASK 0x000FFFFF #define TESTVFS_MAX_PAGES 1024 @@ -466,8 +468,15 @@ static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ ** Lock an tvfs-file. */ static int tvfsLock(sqlite3_file *pFile, int eLock){ - TestvfsFd *p = tvfsGetFd(pFile); - return sqlite3OsLock(p->pReal, eLock); + TestvfsFd *pFd = tvfsGetFd(pFile); + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + if( p->pScript && p->mask&TESTVFS_LOCK_MASK ){ + char zLock[30]; + sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock); + tvfsExecTcl(p, "xLock", Tcl_NewStringObj(pFd->zFilename, -1), + Tcl_NewStringObj(zLock, -1), 0, 0); + } + return sqlite3OsLock(pFd->pReal, eLock); } /* @@ -476,6 +485,12 @@ static int tvfsLock(sqlite3_file *pFile, int eLock){ static int tvfsUnlock(sqlite3_file *pFile, int eLock){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + if( p->pScript && p->mask&TESTVFS_UNLOCK_MASK ){ + char zLock[30]; + sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock); + tvfsExecTcl(p, "xUnlock", Tcl_NewStringObj(pFd->zFilename, -1), + Tcl_NewStringObj(zLock, -1), 0, 0); + } if( p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){ return SQLITE_IOERR_UNLOCK; } @@ -486,8 +501,13 @@ static int tvfsUnlock(sqlite3_file *pFile, int eLock){ ** Check if another file-handle holds a RESERVED lock on an tvfs-file. */ static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){ - TestvfsFd *p = tvfsGetFd(pFile); - return sqlite3OsCheckReservedLock(p->pReal, pResOut); + TestvfsFd *pFd = tvfsGetFd(pFile); + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + if( p->pScript && p->mask&TESTVFS_CKLOCK_MASK ){ + tvfsExecTcl(p, "xCheckReservedLock", Tcl_NewStringObj(pFd->zFilename, -1), + 0, 0, 0); + } + return sqlite3OsCheckReservedLock(pFd->pReal, pResOut); } /* @@ -1111,26 +1131,32 @@ static int testvfs_obj_cmd( break; } + /* TESTVFS filter METHOD-LIST + ** + ** Activate special processing for those methods contained in the list + */ case CMD_FILTER: { static struct VfsMethod { char *zName; int mask; } vfsmethod [] = { - { "xShmOpen", TESTVFS_SHMOPEN_MASK }, - { "xShmLock", TESTVFS_SHMLOCK_MASK }, - { "xShmBarrier", TESTVFS_SHMBARRIER_MASK }, - { "xShmUnmap", TESTVFS_SHMCLOSE_MASK }, - { "xShmMap", TESTVFS_SHMMAP_MASK }, - { "xSync", TESTVFS_SYNC_MASK }, - { "xDelete", TESTVFS_DELETE_MASK }, - { "xWrite", TESTVFS_WRITE_MASK }, - { "xRead", TESTVFS_READ_MASK }, - { "xTruncate", TESTVFS_TRUNCATE_MASK }, - { "xOpen", TESTVFS_OPEN_MASK }, - { "xClose", TESTVFS_CLOSE_MASK }, - { "xAccess", TESTVFS_ACCESS_MASK }, - { "xFullPathname", TESTVFS_FULLPATHNAME_MASK }, - { "xUnlock", TESTVFS_UNLOCK_MASK }, + { "xShmOpen", TESTVFS_SHMOPEN_MASK }, + { "xShmLock", TESTVFS_SHMLOCK_MASK }, + { "xShmBarrier", TESTVFS_SHMBARRIER_MASK }, + { "xShmUnmap", TESTVFS_SHMCLOSE_MASK }, + { "xShmMap", TESTVFS_SHMMAP_MASK }, + { "xSync", TESTVFS_SYNC_MASK }, + { "xDelete", TESTVFS_DELETE_MASK }, + { "xWrite", TESTVFS_WRITE_MASK }, + { "xRead", TESTVFS_READ_MASK }, + { "xTruncate", TESTVFS_TRUNCATE_MASK }, + { "xOpen", TESTVFS_OPEN_MASK }, + { "xClose", TESTVFS_CLOSE_MASK }, + { "xAccess", TESTVFS_ACCESS_MASK }, + { "xFullPathname", TESTVFS_FULLPATHNAME_MASK }, + { "xUnlock", TESTVFS_UNLOCK_MASK }, + { "xLock", TESTVFS_LOCK_MASK }, + { "xCheckReservedLock", TESTVFS_CKLOCK_MASK }, }; Tcl_Obj **apElem = 0; int nElem = 0; @@ -1162,6 +1188,12 @@ static int testvfs_obj_cmd( break; } + /* + ** TESTVFS script ?SCRIPT? + ** + ** Query or set the script to be run when filtered VFS events + ** occur. + */ case CMD_SCRIPT: { if( objc==3 ){ int nByte; @@ -1248,6 +1280,7 @@ static int testvfs_obj_cmd( { "safe_append", SQLITE_IOCAP_SAFE_APPEND }, { "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN }, { "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE }, + { "immutable", SQLITE_IOCAP_IMMUTABLE }, { 0, 0 } }; Tcl_Obj *pRet; diff --git a/src/test_vfstrace.c b/src/test_vfstrace.c index c1792f1..d0bc29f 100644 --- a/src/test_vfstrace.c +++ b/src/test_vfstrace.c @@ -678,7 +678,7 @@ static int vfstraceAccess( vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData; sqlite3_vfs *pRoot = pInfo->pRootVfs; int rc; - vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)", + vfstrace_printf(pInfo, "%s.xAccess(\"%s\",%d)", pInfo->zVfsName, zPath, flags); rc = pRoot->xAccess(pRoot, zPath, flags, pResOut); vfstrace_print_errcode(pInfo, " -> %s", rc); diff --git a/src/tokenize.c b/src/tokenize.c index 87553e2..4017c3b 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -270,6 +270,12 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' ); testcase( z[0]=='9' ); *tokenType = TK_INTEGER; +#ifndef SQLITE_OMIT_HEX_INTEGER + if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ + for(i=3; sqlite3Isxdigit(z[i]); i++){} + return i; + } +#endif for(i=0; sqlite3Isdigit(z[i]); i++){} #ifndef SQLITE_OMIT_FLOATING_POINT if( z[i]=='.' ){ diff --git a/src/update.c b/src/update.c index 4138749..e152e90 100644 --- a/src/update.c +++ b/src/update.c @@ -187,7 +187,7 @@ void sqlite3Update( iIdxCur = iDataCur+1; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ - if( pIdx->autoIndex==2 && pPk!=0 ){ + if( IsPrimaryKeyIndex(pIdx) && pPk!=0 ){ iDataCur = pParse->nTab; pTabList->a[0].iCursor = iDataCur; } @@ -438,7 +438,8 @@ void sqlite3Update( } labelContinue = labelBreak; sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); - VdbeCoverage(v); + VdbeCoverageIf(v, pPk==0); + VdbeCoverageIf(v, pPk!=0); }else if( pPk ){ labelContinue = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); diff --git a/src/utf.c b/src/utf.c index 96b679f..9789874 100644 --- a/src/utf.c +++ b/src/utf.c @@ -148,8 +148,8 @@ static const unsigned char sqlite3Utf8Trans1[] = { ** and rendered as themselves even though they are technically ** invalid characters. ** -** * This routine accepts an infinite number of different UTF8 encodings -** for unicode values 0x80 and greater. It do not change over-length +** * This routine accepts over-length UTF8 encodings +** for unicode values 0x80 and greater. It does not change over-length ** encodings to 0xfffd as some systems recommend. */ #define READ_UTF8(zIn, zTerm, c) \ diff --git a/src/util.c b/src/util.c index d88c17b..619af7f 100644 --- a/src/util.c +++ b/src/util.c @@ -31,6 +31,24 @@ void sqlite3Coverage(int x){ } #endif +/* +** Give a callback to the test harness that can be used to simulate faults +** in places where it is difficult or expensive to do so purely by means +** of inputs. +** +** The intent of the integer argument is to let the fault simulator know +** which of multiple sqlite3FaultSim() calls has been hit. +** +** Return whatever integer value the test callback returns, or return +** SQLITE_OK if no test callback is installed. +*/ +#ifndef SQLITE_OMIT_BUILTIN_TEST +int sqlite3FaultSim(int iTest){ + int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback; + return xCallback ? xCallback(iTest) : SQLITE_OK; +} +#endif + #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Return true if the floating point value is Not a Number (NaN). @@ -457,9 +475,9 @@ static int compare2pow63(const char *zNum, int incr){ return c; } - /* -** Convert zNum to a 64-bit signed integer. +** Convert zNum to a 64-bit signed integer. zNum must be decimal. This +** routine does *not* accept hexadecimal notation. ** ** If the zNum value is representable as a 64-bit twos-complement ** integer, then write that value into *pNum and return 0. @@ -547,10 +565,44 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){ } } +/* +** Transform a UTF-8 integer literal, in either decimal or hexadecimal, +** into a 64-bit signed integer. This routine accepts hexadecimal literals, +** whereas sqlite3Atoi64() does not. +** +** Returns: +** +** 0 Successful transformation. Fits in a 64-bit signed integer. +** 1 Integer too large for a 64-bit signed integer or is malformed +** 2 Special case of 9223372036854775808 +*/ +int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ +#ifndef SQLITE_OMIT_HEX_INTEGER + if( z[0]=='0' + && (z[1]=='x' || z[1]=='X') + && sqlite3Isxdigit(z[2]) + ){ + u64 u = 0; + int i, k; + for(i=2; z[i]=='0'; i++){} + for(k=i; sqlite3Isxdigit(z[k]); k++){ + u = u*16 + sqlite3HexToInt(z[k]); + } + memcpy(pOut, &u, 8); + return (z[k]==0 && k-i<=16) ? 0 : 1; + }else +#endif /* SQLITE_OMIT_HEX_INTEGER */ + { + return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8); + } +} + /* ** If zNum represents an integer that will fit in 32-bits, then set ** *pValue to that integer and return true. Otherwise return false. ** +** This routine accepts both decimal and hexadecimal notation for integers. +** ** Any non-numeric characters that following zNum are ignored. ** This is different from sqlite3Atoi64() which requires the ** input number to be zero-terminated. @@ -565,7 +617,25 @@ int sqlite3GetInt32(const char *zNum, int *pValue){ }else if( zNum[0]=='+' ){ zNum++; } - while( zNum[0]=='0' ) zNum++; +#ifndef SQLITE_OMIT_HEX_INTEGER + else if( zNum[0]=='0' + && (zNum[1]=='x' || zNum[1]=='X') + && sqlite3Isxdigit(zNum[2]) + ){ + u32 u = 0; + zNum += 2; + while( zNum[0]=='0' ) zNum++; + for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){ + u = u*16 + sqlite3HexToInt(zNum[i]); + } + if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){ + memcpy(pValue, &u, 4); + return 1; + }else{ + return 0; + } + } +#endif for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ v = v*10 + c; } @@ -1246,8 +1316,8 @@ LogEst sqlite3LogEstAdd(LogEst a, LogEst b){ } /* -** Convert an integer into a LogEst. In other words, compute a -** good approximatation for 10*log2(x). +** Convert an integer into a LogEst. In other words, compute an +** approximation for 10*log2(x). */ LogEst sqlite3LogEst(u64 x){ static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 }; diff --git a/src/vdbe.c b/src/vdbe.c index c58b5d9..61adb9c 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -116,6 +116,12 @@ int sqlite3_found_count = 0; ** branch can go. It is usually 2. "I" is the direction the branch ** goes. 0 means falls through. 1 means branch is taken. 2 means the ** second alternative branch is taken. +** +** iSrcLine is the source code line (from the __LINE__ macro) that +** generated the VDBE instruction. This instrumentation assumes that all +** source code is in a single file (the amalgamation). Special values 1 +** and 2 for the iSrcLine parameter mean that this particular branch is +** always taken or never taken, respectively. */ #if !defined(SQLITE_VDBE_COVERAGE) # define VdbeBranchTaken(I,M) @@ -224,21 +230,21 @@ static VdbeCursor *allocateCursor( ** look like a number, leave it alone. */ static void applyNumericAffinity(Mem *pRec){ - if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){ - double rValue; - i64 iValue; - u8 enc = pRec->enc; - if( (pRec->flags&MEM_Str)==0 ) return; - if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; - if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ - pRec->u.i = iValue; - pRec->flags |= MEM_Int; - }else{ - pRec->r = rValue; - pRec->flags |= MEM_Real; - } + double rValue; + i64 iValue; + u8 enc = pRec->enc; + if( (pRec->flags&MEM_Str)==0 ) return; + if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; + if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ + pRec->u.i = iValue; + pRec->flags |= MEM_Int; + }else{ + pRec->r = rValue; + pRec->flags |= MEM_Real; } } +#define ApplyNumericAffinity(X) \ + if(((X)->flags&(MEM_Real|MEM_Int))==0){applyNumericAffinity(X);} /* ** Processing is determine by the affinity parameter: @@ -275,7 +281,7 @@ static void applyAffinity( }else if( affinity!=SQLITE_AFF_NONE ){ assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL || affinity==SQLITE_AFF_NUMERIC ); - applyNumericAffinity(pRec); + ApplyNumericAffinity(pRec); if( pRec->flags & MEM_Real ){ sqlite3VdbeIntegerAffinity(pRec); } @@ -310,6 +316,29 @@ void sqlite3ValueApplyAffinity( applyAffinity((Mem *)pVal, affinity, enc); } +/* +** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or +** none. +** +** Unlike applyNumericAffinity(), this routine does not modify pMem->flags. +** But it does set pMem->r and pMem->u.i appropriately. +*/ +static u16 numericType(Mem *pMem){ + if( pMem->flags & (MEM_Int|MEM_Real) ){ + return pMem->flags & (MEM_Int|MEM_Real); + } + if( pMem->flags & (MEM_Str|MEM_Blob) ){ + if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){ + return 0; + } + if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){ + return MEM_Int; + } + return MEM_Real; + } + return 0; +} + #ifdef SQLITE_DEBUG /* ** Write a nice string representation of the contents of cell pMem @@ -744,12 +773,14 @@ case OP_Return: { /* in1 */ /* Opcode: InitCoroutine P1 P2 P3 * * ** -** Set up register P1 so that it will OP_Yield to the co-routine +** Set up register P1 so that it will Yield to the coroutine ** located at address P3. ** -** If P2!=0 then the co-routine implementation immediately follows -** this opcode. So jump over the co-routine implementation to +** If P2!=0 then the coroutine implementation immediately follows +** this opcode. So jump over the coroutine implementation to ** address P2. +** +** See also: EndCoroutine */ case OP_InitCoroutine: { /* jump */ assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); @@ -765,9 +796,11 @@ case OP_InitCoroutine: { /* jump */ /* Opcode: EndCoroutine P1 * * * * ** -** The instruction at the address in register P1 is an OP_Yield. -** Jump to the P2 parameter of that OP_Yield. +** The instruction at the address in register P1 is a Yield. +** Jump to the P2 parameter of that Yield. ** After the jump, register P1 becomes undefined. +** +** See also: InitCoroutine */ case OP_EndCoroutine: { /* in1 */ VdbeOp *pCaller; @@ -784,11 +817,16 @@ case OP_EndCoroutine: { /* in1 */ /* Opcode: Yield P1 P2 * * * ** -** Swap the program counter with the value in register P1. +** Swap the program counter with the value in register P1. This +** has the effect of yielding to a coroutine. ** -** If the co-routine ends with OP_Yield or OP_Return then continue -** to the next instruction. But if the co-routine ends with -** OP_EndCoroutine, jump immediately to P2. +** If the coroutine that is launched by this instruction ends with +** Yield or Return then continue to the next instruction. But if +** the coroutine launched by this instruction ends with +** EndCoroutine, then jump to P2 rather than continuing with the +** next instruction. +** +** See also: InitCoroutine */ case OP_Yield: { /* in1, jump */ int pcDest; @@ -951,7 +989,7 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */ ** Synopsis: r[P2]='P4' ** ** P4 points to a nul terminated UTF-8 string. This opcode is transformed -** into an OP_String before it is executed for the first time. During +** into a String before it is executed for the first time. During ** this transformation, the length of string P4 is computed and stored ** as the P1 parameter. */ @@ -1080,10 +1118,11 @@ case OP_Variable: { /* out2-prerelease */ /* Opcode: Move P1 P2 P3 * * ** Synopsis: r[P2@P3]=r[P1@P3] ** -** Move the values in register P1..P1+P3 over into -** registers P2..P2+P3. Registers P1..P1+P3 are +** Move the P3 values in register P1..P1+P3-1 over into +** registers P2..P2+P3-1. Registers P1..P1+P3-1 are ** left holding a NULL. It is an error for register ranges -** P1..P1+P3 and P2..P2+P3 to overlap. +** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error +** for P3 to be less than 1. */ case OP_Move: { char *zMalloc; /* Holding variable for allocated memory */ @@ -1094,7 +1133,7 @@ case OP_Move: { n = pOp->p3; p1 = pOp->p1; p2 = pOp->p2; - assert( n>=0 && p1>0 && p2>0 ); + assert( n>0 && p1>0 && p2>0 ); assert( p1+n<=p2 || p2+n<=p1 ); pIn1 = &aMem[p1]; @@ -1118,7 +1157,7 @@ case OP_Move: { REGISTER_TRACE(p2++, pOut); pIn1++; pOut++; - }while( n-- ); + }while( --n ); break; } @@ -1350,20 +1389,22 @@ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ char bIntint; /* Started out as two integer operands */ - int flags; /* Combined MEM_* flags from both inputs */ + u16 flags; /* Combined MEM_* flags from both inputs */ + u16 type1; /* Numeric type of left operand */ + u16 type2; /* Numeric type of right operand */ i64 iA; /* Integer value of left operand */ i64 iB; /* Integer value of right operand */ double rA; /* Real value of left operand */ double rB; /* Real value of right operand */ pIn1 = &aMem[pOp->p1]; - applyNumericAffinity(pIn1); + type1 = numericType(pIn1); pIn2 = &aMem[pOp->p2]; - applyNumericAffinity(pIn2); + type2 = numericType(pIn2); pOut = &aMem[pOp->p3]; flags = pIn1->flags | pIn2->flags; if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null; - if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){ + if( (type1 & type2 & MEM_Int)!=0 ){ iA = pIn1->u.i; iB = pIn2->u.i; bIntint = 1; @@ -1419,7 +1460,7 @@ fp_math: } pOut->r = rB; MemSetTypeFlag(pOut, MEM_Real); - if( (flags & MEM_Real)==0 && !bIntint ){ + if( ((type1|type2)&MEM_Real)==0 && !bIntint ){ sqlite3VdbeIntegerAffinity(pOut); } #endif @@ -1995,6 +2036,7 @@ case OP_Permutation: { } /* Opcode: Compare P1 P2 P3 P4 P5 +** Synopsis: r[P1@P3] <-> r[P2@P3] ** ** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this ** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of @@ -2169,10 +2211,14 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ /* Opcode: Once P1 P2 * * * ** -** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise, -** set the flag and fall through to the next instruction. In other words, -** this opcode causes all following opcodes up through P2 (but not including -** P2) to run just once and to be skipped on subsequent times through the loop. +** Check the "once" flag number P1. If it is set, jump to instruction P2. +** Otherwise, set the flag and fall through to the next instruction. +** In other words, this opcode causes all following opcodes up through P2 +** (but not including P2) to run just once and to be skipped on subsequent +** times through the loop. +** +** All "once" flags are initially cleared whenever a prepared statement +** first begins to run. */ case OP_Once: { /* jump */ assert( pOp->p1nOnceFlag ); @@ -2189,13 +2235,13 @@ case OP_Once: { /* jump */ ** ** Jump to P2 if the value in register P1 is true. The value ** is considered true if it is numeric and non-zero. If the value -** in P1 is NULL then take the jump if P3 is non-zero. +** in P1 is NULL then take the jump if and only if P3 is non-zero. */ /* Opcode: IfNot P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is False. The value ** is considered false if it has a numeric value of zero. If the value -** in P1 is NULL then take the jump if P3 is zero. +** in P1 is NULL then take the jump if and only if P3 is non-zero. */ case OP_If: /* jump, in1 */ case OP_IfNot: { /* jump, in1 */ @@ -3007,7 +3053,7 @@ case OP_Transaction: { assert( p->bIsReader ); assert( p->readOnly==0 || pOp->p2==0 ); assert( pOp->p1>=0 && pOp->p1nDb ); - assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p1) ); if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){ rc = SQLITE_READONLY; goto abort_due_to_error; @@ -3102,7 +3148,7 @@ case OP_ReadCookie: { /* out2-prerelease */ assert( pOp->p3=0 && iDbnDb ); assert( db->aDb[iDb].pBt!=0 ); - assert( (p->btreeMask & (((yDbMask)1)<btreeMask, iDb) ); sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta); pOut->u.i = iMeta; @@ -3123,7 +3169,7 @@ case OP_SetCookie: { /* in3 */ Db *pDb; assert( pOp->p2p1>=0 && pOp->p1nDb ); - assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); @@ -3178,7 +3224,21 @@ case OP_SetCookie: { /* in3 */ ** sequence of the index being opened. Otherwise, if P4 is an integer ** value, it is set to the number of columns in the table. ** -** See also OpenWrite. +** See also: OpenWrite, ReopenIdx +*/ +/* Opcode: ReopenIdx P1 P2 P3 P4 P5 +** Synopsis: root=P2 iDb=P3 +** +** The ReopenIdx opcode works exactly like ReadOpen except that it first +** checks to see if the cursor on P1 is already open with a root page +** number of P2 and if it is this opcode becomes a no-op. In other words, +** if the cursor is already open, do not reopen it. +** +** The ReopenIdx opcode may only be used with P5==0 and with P4 being +** a P4_KEYINFO object. Furthermore, the P3 value must be the same as +** every other ReopenIdx or OpenRead for the same cursor number. +** +** See the OpenRead opcode documentation for additional information. */ /* Opcode: OpenWrite P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 @@ -3200,6 +3260,19 @@ case OP_SetCookie: { /* in3 */ ** ** See also OpenRead. */ +case OP_ReopenIdx: { + VdbeCursor *pCur; + + assert( pOp->p5==0 ); + assert( pOp->p4type==P4_KEYINFO ); + pCur = p->apCsr[pOp->p1]; + if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){ + assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */ + break; + } + /* If the cursor is not currently open or is open on a different + ** index, then fall through into OP_OpenRead to force a reopen */ +} case OP_OpenRead: case OP_OpenWrite: { int nField; @@ -3214,7 +3287,8 @@ case OP_OpenWrite: { assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 ); assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 ); assert( p->bIsReader ); - assert( pOp->opcode==OP_OpenRead || p->readOnly==0 ); + assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx + || p->readOnly==0 ); if( p->expired ){ rc = SQLITE_ABORT; @@ -3226,7 +3300,7 @@ case OP_OpenWrite: { p2 = pOp->p2; iDb = pOp->p3; assert( iDb>=0 && iDbnDb ); - assert( (p->btreeMask & (((yDbMask)1)<btreeMask, iDb) ); pDb = &db->aDb[iDb]; pX = pDb->pBt; assert( pX!=0 ); @@ -3271,6 +3345,7 @@ case OP_OpenWrite: { if( pCur==0 ) goto no_mem; pCur->nullRow = 1; pCur->isOrdered = 1; + pCur->pgnoRoot = p2; rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor); pCur->pKeyInfo = pKeyInfo; assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); @@ -3330,6 +3405,7 @@ case OP_OpenEphemeral: { pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; + pCx->isEphemeral = 1; rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); if( rc==SQLITE_OK ){ @@ -3424,7 +3500,7 @@ case OP_Close: { break; } -/* Opcode: SeekGe P1 P2 P3 P4 * +/* Opcode: SeekGE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), @@ -3436,9 +3512,13 @@ case OP_Close: { ** is greater than or equal to the key value. If there are no records ** greater than or equal to the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, Distinct, SeekLt, SeekGt, SeekLe +** This opcode leaves the cursor configured to move in forward order, +** from the beginning toward the end. In other words, the cursor is +** configured to use Next, not Prev. +** +** See also: Found, NotFound, SeekLt, SeekGt, SeekLe */ -/* Opcode: SeekGt P1 P2 P3 P4 * +/* Opcode: SeekGT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), @@ -3450,9 +3530,13 @@ case OP_Close: { ** is greater than the key value. If there are no records greater than ** the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, Distinct, SeekLt, SeekGe, SeekLe +** This opcode leaves the cursor configured to move in forward order, +** from the beginning toward the end. In other words, the cursor is +** configured to use Next, not Prev. +** +** See also: Found, NotFound, SeekLt, SeekGe, SeekLe */ -/* Opcode: SeekLt P1 P2 P3 P4 * +/* Opcode: SeekLT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), @@ -3464,9 +3548,13 @@ case OP_Close: { ** is less than the key value. If there are no records less than ** the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLe +** This opcode leaves the cursor configured to move in reverse order, +** from the end toward the beginning. In other words, the cursor is +** configured to use Prev, not Next. +** +** See also: Found, NotFound, SeekGt, SeekGe, SeekLe */ -/* Opcode: SeekLe P1 P2 P3 P4 * +/* Opcode: SeekLE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), @@ -3478,7 +3566,11 @@ case OP_Close: { ** is less than or equal to the key value. If there are no records ** less than or equal to the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLt +** This opcode leaves the cursor configured to move in reverse order, +** from the end toward the beginning. In other words, the cursor is +** configured to use Prev, not Next. +** +** See also: Found, NotFound, SeekGt, SeekGe, SeekLt */ case OP_SeekLT: /* jump, in3 */ case OP_SeekLE: /* jump, in3 */ @@ -3503,12 +3595,15 @@ case OP_SeekGT: { /* jump, in3 */ assert( pC->pCursor!=0 ); oc = pOp->opcode; pC->nullRow = 0; +#ifdef SQLITE_DEBUG + pC->seekOp = pOp->opcode; +#endif if( pC->isTable ){ /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so covert it. */ pIn3 = &aMem[pOp->p3]; - applyNumericAffinity(pIn3); + ApplyNumericAffinity(pIn3); iKey = sqlite3VdbeIntValue(pIn3); pC->rowidIsValid = 0; @@ -3658,6 +3753,10 @@ case OP_Seek: { /* in2 */ ** is a prefix of any entry in P1 then a jump is made to P2 and ** P1 is left pointing at the matching entry. ** +** This operation leaves the cursor in a state where it can be +** advanced in the forward direction. The Next instruction will work, +** but not the Prev instruction. +** ** See also: NotFound, NoConflict, NotExists. SeekGe */ /* Opcode: NotFound P1 P2 P3 P4 * @@ -3673,6 +3772,10 @@ case OP_Seek: { /* in2 */ ** falls through to the next instruction and P1 is left pointing at the ** matching entry. ** +** This operation leaves the cursor in a state where it cannot be +** advanced in either direction. In other words, the Next and Prev +** opcodes do not work after this operation. +** ** See also: Found, NotExists, NoConflict */ /* Opcode: NoConflict P1 P2 P3 P4 * @@ -3692,6 +3795,10 @@ case OP_Seek: { /* in2 */ ** This opcode is similar to OP_NotFound with the exceptions that the ** branch is always taken if any part of the search key input is NULL. ** +** This operation leaves the cursor in a state where it cannot be +** advanced in either direction. In other words, the Next and Prev +** opcodes do not work after this operation. +** ** See also: NotFound, Found, NotExists */ case OP_NoConflict: /* jump, in3 */ @@ -3714,6 +3821,9 @@ case OP_Found: { /* jump, in3 */ assert( pOp->p4type==P4_INT32 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); +#ifdef SQLITE_DEBUG + pC->seekOp = pOp->opcode; +#endif pIn3 = &aMem[pOp->p3]; assert( pC->pCursor!=0 ); assert( pC->isTable==0 ); @@ -3785,6 +3895,10 @@ case OP_Found: { /* jump, in3 */ ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** +** This opcode leaves the cursor in a state where it cannot be advanced +** in either direction. In other words, the Next and Prev opcodes will +** not work following this opcode. +** ** See also: Found, NotFound, NoConflict */ case OP_NotExists: { /* jump, in3 */ @@ -3798,6 +3912,9 @@ case OP_NotExists: { /* jump, in3 */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); +#ifdef SQLITE_DEBUG + pC->seekOp = 0; +#endif assert( pC->isTable ); assert( pC->pseudoTableReg==0 ); pCrsr = pC->pCursor; @@ -3820,7 +3937,7 @@ case OP_NotExists: { /* jump, in3 */ } /* Opcode: Sequence P1 P2 * * * -** Synopsis: r[P2]=rowid +** Synopsis: r[P2]=cursor[P1].ctr++ ** ** Find the next available sequence number for cursor P1. ** Write the sequence number into register P2. @@ -4100,7 +4217,7 @@ case OP_InsertInt: { ** The cursor will be left pointing at either the next or the previous ** record in the table. If it is left pointing at the next record, then ** the next Next instruction will be a no-op. Hence it is OK to delete -** a record from within an Next loop. +** a record from within a Next loop. ** ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is ** incremented (otherwise not). @@ -4160,12 +4277,12 @@ case OP_ResetCount: { } /* Opcode: SorterCompare P1 P2 P3 P4 -** Synopsis: if key(P1)!=rtrim(r[P3],P4) goto P2 +** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2 ** ** P1 is a sorter cursor. This instruction compares a prefix of the -** the record blob in register P3 against a prefix of the entry that -** the sorter cursor currently points to. The final P4 fields of both -** the P3 and sorter record are ignored. +** record blob in register P3 against a prefix of the entry that +** the sorter cursor currently points to. Only the first P4 fields +** of r[P3] and the sorter record are compared. ** ** If either P3 or the sorter contains a NULL in one of their significant ** fields (not counting the P4 fields at the end which are ignored) then @@ -4177,14 +4294,14 @@ case OP_ResetCount: { case OP_SorterCompare: { VdbeCursor *pC; int res; - int nIgnore; + int nKeyCol; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); assert( pOp->p4type==P4_INT32 ); pIn3 = &aMem[pOp->p3]; - nIgnore = pOp->p4.i; - rc = sqlite3VdbeSorterCompare(pC, pIn3, nIgnore, &res); + nKeyCol = pOp->p4.i; + rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res); VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2-1; @@ -4204,6 +4321,7 @@ case OP_SorterData: { pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); rc = sqlite3VdbeSorterRowkey(pC, pOut); + assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); break; } @@ -4363,11 +4481,15 @@ case OP_NullRow: { /* Opcode: Last P1 P2 * * * ** -** The next use of the Rowid or Column or Next instruction for P1 +** The next use of the Rowid or Column or Prev instruction for P1 ** will refer to the last entry in the database table or index. ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. +** +** This opcode leaves the cursor configured to move in reverse order, +** from the end toward the beginning. In other words, the cursor is +** configured to use Prev, not Next. */ case OP_Last: { /* jump */ VdbeCursor *pC; @@ -4385,6 +4507,9 @@ case OP_Last: { /* jump */ pC->deferredMoveto = 0; pC->rowidIsValid = 0; pC->cacheStatus = CACHE_STALE; +#ifdef SQLITE_DEBUG + pC->seekOp = OP_Last; +#endif if( pOp->p2>0 ){ VdbeBranchTaken(res!=0,2); if( res ) pc = pOp->p2 - 1; @@ -4421,6 +4546,10 @@ case OP_Sort: { /* jump */ ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. +** +** This opcode leaves the cursor configured to move in forward order, +** from the beginning toward the end. In other words, the cursor is +** configured to use Next, not Prev. */ case OP_Rewind: { /* jump */ VdbeCursor *pC; @@ -4432,6 +4561,9 @@ case OP_Rewind: { /* jump */ assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) ); res = 1; +#ifdef SQLITE_DEBUG + pC->seekOp = OP_Rewind; +#endif if( isSorter(pC) ){ rc = sqlite3VdbeSorterRewind(db, pC, &res); }else{ @@ -4458,6 +4590,10 @@ case OP_Rewind: { /* jump */ ** to the following instruction. But if the cursor advance was successful, ** jump immediately to P2. ** +** The Next opcode is only valid following an SeekGT, SeekGE, or +** OP_Rewind opcode used to position the cursor. Next is not allowed +** to follow SeekLT, SeekLE, or OP_Last. +** ** The P1 cursor must be for a real table, not a pseudo-table. P1 must have ** been opened prior to this opcode or the program will segfault. ** @@ -4476,7 +4612,7 @@ case OP_Rewind: { /* jump */ */ /* Opcode: NextIfOpen P1 P2 P3 P4 P5 ** -** This opcode works just like OP_Next except that if cursor P1 is not +** This opcode works just like Next except that if cursor P1 is not ** open it behaves a no-op. */ /* Opcode: Prev P1 P2 P3 P4 P5 @@ -4486,6 +4622,11 @@ case OP_Rewind: { /* jump */ ** to the following instruction. But if the cursor backup was successful, ** jump immediately to P2. ** +** +** The Prev opcode is only valid following an SeekLT, SeekLE, or +** OP_Last opcode used to position the cursor. Prev is not allowed +** to follow SeekGT, SeekGE, or OP_Rewind. +** ** The P1 cursor must be for a real table, not a pseudo-table. If P1 is ** not open then the behavior is undefined. ** @@ -4502,7 +4643,7 @@ case OP_Rewind: { /* jump */ */ /* Opcode: PrevIfOpen P1 P2 P3 P4 P5 ** -** This opcode works just like OP_Prev except that if cursor P1 is not +** This opcode works just like Prev except that if cursor P1 is not ** open it behaves a no-op. */ case OP_SorterNext: { /* jump */ @@ -4511,6 +4652,7 @@ case OP_SorterNext: { /* jump */ pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); + res = 0; rc = sqlite3VdbeSorterNext(db, pC, &res); goto next_tail; case OP_PrevIfOpen: /* jump */ @@ -4532,6 +4674,16 @@ case OP_Next: /* jump */ assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext ); assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious); + + /* The Next opcode is only used after SeekGT, SeekGE, and Rewind. + ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */ + assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen + || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE + || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found); + assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen + || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE + || pC->seekOp==OP_Last ); + rc = pOp->p4.xAdvance(pC->pCursor, &res); next_tail: pC->cacheStatus = CACHE_STALE; @@ -4814,7 +4966,7 @@ case OP_Destroy: { /* out2-prerelease */ }else{ iDb = pOp->p3; assert( iCnt==1 ); - assert( (p->btreeMask & (((yDbMask)1)<btreeMask, iDb) ); iMoved = 0; /* Not needed. Only to silence a warning. */ rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved); pOut->flags = MEM_Int; @@ -4854,7 +5006,7 @@ case OP_Clear: { nChange = 0; assert( p->readOnly==0 ); - assert( (p->btreeMask & (((yDbMask)1)<p2))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p2) ); rc = sqlite3BtreeClearTable( db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0) ); @@ -4869,6 +5021,29 @@ case OP_Clear: { break; } +/* Opcode: ResetSorter P1 * * * * +** +** Delete all contents from the ephemeral table or sorter +** that is open on cursor P1. +** +** This opcode only works for cursors used for sorting and +** opened with OP_OpenEphemeral or OP_SorterOpen. +*/ +case OP_ResetSorter: { + VdbeCursor *pC; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + if( pC->pSorter ){ + sqlite3VdbeSorterReset(db, pC->pSorter); + }else{ + assert( pC->isEphemeral ); + rc = sqlite3BtreeClearTableOfCursor(pC->pCursor); + } + break; +} + /* Opcode: CreateTable P1 P2 * * * ** Synopsis: r[P2]=root iDb=P1 ** @@ -4901,7 +5076,7 @@ case OP_CreateTable: { /* out2-prerelease */ pgno = 0; assert( pOp->p1>=0 && pOp->p1nDb ); - assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); @@ -4989,7 +5164,8 @@ case OP_LoadAnalysis: { ** ** Remove the internal (in-memory) data structures that describe ** the table named P4 in database P1. This is called after a table -** is dropped in order to keep the internal representation of the +** is dropped from disk (using the Destroy opcode) in order to keep +** the internal representation of the ** schema consistent with what is on disk. */ case OP_DropTable: { @@ -5001,7 +5177,8 @@ case OP_DropTable: { ** ** Remove the internal (in-memory) data structures that describe ** the index named P4 in database P1. This is called after an index -** is dropped in order to keep the internal representation of the +** is dropped from disk (using the Destroy opcode) +** in order to keep the internal representation of the ** schema consistent with what is on disk. */ case OP_DropIndex: { @@ -5013,7 +5190,8 @@ case OP_DropIndex: { ** ** Remove the internal (in-memory) data structures that describe ** the trigger named P4 in database P1. This is called after a trigger -** is dropped in order to keep the internal representation of the +** is dropped from disk (using the Destroy opcode) in order to keep +** the internal representation of the ** schema consistent with what is on disk. */ case OP_DropTrigger: { @@ -5066,7 +5244,7 @@ case OP_IntegrityCk: { } aRoot[j] = 0; assert( pOp->p5nDb ); - assert( (p->btreeMask & (((yDbMask)1)<p5))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p5) ); z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot, (int)pnErr->u.i, &nErr); sqlite3DbFree(db, aRoot); @@ -5175,9 +5353,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */ assert( pOp->p4type==P4_INT32 ); assert( iSet==-1 || iSet>=0 ); if( iSet ){ - exists = sqlite3RowSetTest(pIn1->u.pRowSet, - (u8)(iSet>=0 ? iSet & 0xf : 0xff), - pIn3->u.i); + exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i); VdbeBranchTaken(exists!=0,2); if( exists ){ pc = pOp->p2 - 1; @@ -5430,17 +5606,16 @@ case OP_IfPos: { /* jump, in1 */ break; } -/* Opcode: IfNeg P1 P2 * * * -** Synopsis: if r[P1]<0 goto P2 +/* Opcode: IfNeg P1 P2 P3 * * +** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2 ** -** If the value of register P1 is less than zero, jump to P2. -** -** It is illegal to use this instruction on a register that does -** not contain an integer. An assertion fault will result if you try. +** Register P1 must contain an integer. Add literal P3 to the value in +** register P1 then if the value of register P1 is less than zero, jump to P2. */ case OP_IfNeg: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); + pIn1->u.i += pOp->p3; VdbeBranchTaken(pIn1->u.i<0, 2); if( pIn1->u.i<0 ){ pc = pOp->p2 - 1; @@ -5453,9 +5628,6 @@ case OP_IfNeg: { /* jump, in1 */ ** ** The register P1 must contain an integer. Add literal P3 to the ** value in register P1. If the result is exactly 0, jump to P2. -** -** It is illegal to use this instruction on a register that does -** not contain an integer. An assertion fault will result if you try. */ case OP_IfZero: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; @@ -5728,7 +5900,7 @@ case OP_IncrVacuum: { /* jump */ Btree *pBt; assert( pOp->p1>=0 && pOp->p1nDb ); - assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pBt = db->aDb[pOp->p1].pBt; rc = sqlite3BtreeIncrVacuum(pBt); @@ -5743,12 +5915,13 @@ case OP_IncrVacuum: { /* jump */ /* Opcode: Expire P1 * * * * ** -** Cause precompiled statements to become expired. An expired statement -** fails with an error code of SQLITE_SCHEMA if it is ever executed -** (via sqlite3_step()). +** Cause precompiled statements to expire. When an expired statement +** is executed using sqlite3_step() it will either automatically +** reprepare itself (if it was originally created using sqlite3_prepare_v2()) +** or it will fail with SQLITE_SCHEMA. ** ** If P1 is 0, then all SQL statements become expired. If P1 is non-zero, -** then only the currently executing statement is affected. +** then only the currently executing statement is expired. */ case OP_Expire: { if( !pOp->p1 ){ @@ -5780,7 +5953,7 @@ case OP_TableLock: { if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){ int p1 = pOp->p1; assert( p1>=0 && p1nDb ); - assert( (p->btreeMask & (((yDbMask)1)<btreeMask, p1) ); assert( isWriteLock==0 || isWriteLock==1 ); rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); if( (rc&0xFF)==SQLITE_LOCKED ){ @@ -5877,7 +6050,7 @@ case OP_VOpen: { #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VFilter P1 P2 P3 P4 * -** Synopsis: iPlan=r[P3] zPlan='P4' +** Synopsis: iplan=r[P3] zplan='P4' ** ** P1 is a cursor opened using VOpen. P2 is an address to jump to if ** the filtered result set is empty. @@ -6230,7 +6403,7 @@ case OP_Init: { /* jump */ if( zTrace ){ int i; for(i=0; inDb; i++){ - if( MASKBIT(i) & p->btreeMask)==0 ) continue; + if( DbMaskTest(p->btreeMask, i)==0 ) continue; sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace); } } @@ -6273,8 +6446,8 @@ default: { /* This is really OP_Noop and OP_Explain */ #ifdef VDBE_PROFILE { - u64 elapsed = sqlite3Hwtime() - start; - pOp->cycles += elapsed; + u64 endTime = sqlite3Hwtime(); + if( endTime>start ) pOp->cycles += endTime - start; pOp->cnt++; } #endif diff --git a/src/vdbe.h b/src/vdbe.h index 8e300b8..ef91010 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -209,12 +209,13 @@ void sqlite3VdbeSetVarmask(Vdbe*, int); #ifndef SQLITE_OMIT_TRACE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif +int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); -int sqlite3VdbeRecordCompare(int,const void*,const UnpackedRecord*,int); +int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int); UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); -typedef int (*RecordCompare)(int,const void*,const UnpackedRecord*,int); +typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int); RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); #ifndef SQLITE_OMIT_TRIGGER diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 0394782..141573e 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -68,13 +68,18 @@ struct VdbeCursor { int pseudoTableReg; /* Register holding pseudotable content. */ i16 nField; /* Number of fields in the header */ u16 nHdrParsed; /* Number of header fields parsed so far */ +#ifdef SQLITE_DEBUG + u8 seekOp; /* Most recent seek operation on this cursor */ +#endif i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ u8 rowidIsValid; /* True if lastRowid is valid */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ + Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ Bool isTable:1; /* True if a table requiring integer keys */ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */ + Pgno pgnoRoot; /* Root page of the open btree cursor */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ @@ -391,9 +396,8 @@ u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); void sqlite3VdbeDeleteAuxData(Vdbe*, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); -int sqlite3VdbeIdxKeyCompare(VdbeCursor*,const UnpackedRecord*,int*); +int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*); int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *); -int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); int sqlite3VdbeExec(Vdbe*); int sqlite3VdbeList(Vdbe*); int sqlite3VdbeHalt(Vdbe*); @@ -437,6 +441,7 @@ int sqlite3VdbeFrameRestore(VdbeFrame *); int sqlite3VdbeTransferError(Vdbe *p); int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); +void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 5d7a0b0..5e5bb81 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1323,7 +1323,7 @@ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){ */ int sqlite3_stmt_busy(sqlite3_stmt *pStmt){ Vdbe *v = (Vdbe*)pStmt; - return v!=0 && v->pc>0 && v->magic==VDBE_MAGIC_RUN; + return v!=0 && v->pc>=0 && v->magic==VDBE_MAGIC_RUN; } /* diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 96fd401..fb3f7c3 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -84,18 +84,35 @@ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ } /* -** Resize the Vdbe.aOp array so that it is at least one op larger than -** it was. +** Resize the Vdbe.aOp array so that it is at least nOp elements larger +** than its current size. nOp is guaranteed to be less than or equal +** to 1024/sizeof(Op). ** ** If an out-of-memory error occurs while resizing the array, return -** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain +** SQLITE_NOMEM. In this case Vdbe.aOp and Parse.nOpAlloc remain ** unchanged (this is so that any opcodes already allocated can be ** correctly deallocated along with the rest of the Vdbe). */ -static int growOpArray(Vdbe *v){ +static int growOpArray(Vdbe *v, int nOp){ VdbeOp *pNew; Parse *p = v->pParse; + + /* The SQLITE_TEST_REALLOC_STRESS compile-time option is designed to force + ** more frequent reallocs and hence provide more opportunities for + ** simulated OOM faults. SQLITE_TEST_REALLOC_STRESS is generally used + ** during testing only. With SQLITE_TEST_REALLOC_STRESS grow the op array + ** by the minimum* amount required until the size reaches 512. Normal + ** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current + ** size of the op array or add 1KB of space, whichever is smaller. */ +#ifdef SQLITE_TEST_REALLOC_STRESS + int nNew = (p->nOpAlloc>=512 ? p->nOpAlloc*2 : p->nOpAlloc+nOp); +#else int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op))); + UNUSED_PARAMETER(nOp); +#endif + + assert( nOp<=(1024/sizeof(Op)) ); + assert( nNew>=(p->nOpAlloc+nOp) ); pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); if( pNew ){ p->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op); @@ -139,7 +156,7 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ assert( p->magic==VDBE_MAGIC_INIT ); assert( op>0 && op<0xff ); if( p->pParse->nOpAlloc<=i ){ - if( growOpArray(p) ){ + if( growOpArray(p, 1) ){ return 1; } } @@ -276,7 +293,7 @@ void sqlite3VdbeResolveLabel(Vdbe *v, int x){ int j = -1-x; assert( v->magic==VDBE_MAGIC_INIT ); assert( jnLabel ); - if( j>=0 && p->aLabel ){ + if( ALWAYS(j>=0) && p->aLabel ){ p->aLabel[j] = v->nOp; } p->iFixedOp = v->nOp - 1; @@ -499,7 +516,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ pParse->aLabel = 0; pParse->nLabel = 0; *pMaxFuncArgs = nMaxArgs; - assert( p->bIsReader!=0 || p->btreeMask==0 ); + assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); } /* @@ -526,7 +543,7 @@ VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){ assert( aOp && !p->db->mallocFailed ); /* Check that sqlite3VdbeUsesBtree() was not called on this VM */ - assert( p->btreeMask==0 ); + assert( DbMaskAllZero(p->btreeMask) ); resolveP2Values(p, pnMaxArg); *pnOp = p->nOp; @@ -541,7 +558,7 @@ VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){ int addr; assert( p->magic==VDBE_MAGIC_INIT ); - if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p) ){ + if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){ return 0; } addr = p->nOp; @@ -726,7 +743,7 @@ void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){ ** Change the opcode at addr into OP_Noop */ void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ - if( p->aOp ){ + if( addrnOp ){ VdbeOp *pOp = &p->aOp[addr]; sqlite3 *db = p->db; freeP4(db, pOp->p4type, pOp->p4.p); @@ -783,7 +800,9 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ addr = p->nOp - 1; } pOp = &p->aOp[addr]; - assert( pOp->p4type==P4_NOTUSED || pOp->p4type==P4_INT32 ); + assert( pOp->p4type==P4_NOTUSED + || pOp->p4type==P4_INT32 + || pOp->p4type==P4_KEYINFO ); freeP4(db, pOp->p4type, pOp->p4.p); pOp->p4.p = 0; if( n==P4_INT32 ){ @@ -1109,9 +1128,9 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ void sqlite3VdbeUsesBtree(Vdbe *p, int i){ assert( i>=0 && idb->nDb && i<(int)sizeof(yDbMask)*8 ); assert( i<(int)sizeof(p->btreeMask)*8 ); - p->btreeMask |= ((yDbMask)1)<btreeMask, i); if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){ - p->lockMask |= ((yDbMask)1)<lockMask, i); } } @@ -1139,16 +1158,15 @@ void sqlite3VdbeUsesBtree(Vdbe *p, int i){ */ void sqlite3VdbeEnter(Vdbe *p){ int i; - yDbMask mask; sqlite3 *db; Db *aDb; int nDb; - if( p->lockMask==0 ) return; /* The common case */ + if( DbMaskAllZero(p->lockMask) ) return; /* The common case */ db = p->db; aDb = db->aDb; nDb = db->nDb; - for(i=0, mask=1; ilockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){ + for(i=0; ilockMask,i) && ALWAYS(aDb[i].pBt!=0) ){ sqlite3BtreeEnter(aDb[i].pBt); } } @@ -1161,16 +1179,15 @@ void sqlite3VdbeEnter(Vdbe *p){ */ void sqlite3VdbeLeave(Vdbe *p){ int i; - yDbMask mask; sqlite3 *db; Db *aDb; int nDb; - if( p->lockMask==0 ) return; /* The common case */ + if( DbMaskAllZero(p->lockMask) ) return; /* The common case */ db = p->db; aDb = db->aDb; nDb = db->nDb; - for(i=0, mask=1; ilockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){ + for(i=0; ilockMask,i) && ALWAYS(aDb[i].pBt!=0) ){ sqlite3BtreeLeave(aDb[i].pBt); } } @@ -2141,7 +2158,7 @@ static void checkActiveVdbeCnt(sqlite3 *db){ int nRead = 0; p = db->pVdbe; while( p ){ - if( p->magic==VDBE_MAGIC_RUN && p->pc>=0 ){ + if( sqlite3_stmt_busy((sqlite3_stmt*)p) ){ cnt++; if( p->readOnly==0 ) nWrite++; if( p->bIsReader ) nRead++; @@ -2301,7 +2318,6 @@ int sqlite3VdbeHalt(Vdbe *p){ /* Check for one of the special errors */ mrc = p->rc & 0xff; - assert( p->rc!=SQLITE_IOERR_BLOCKED ); /* This error no longer exists */ isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL; if( isSpecialError ){ @@ -2733,7 +2749,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){ if( rc ) return rc; if( hasMoved ){ p->cacheStatus = CACHE_STALE; - p->nullRow = 1; + if( hasMoved==2 ) p->nullRow = 1; } } return SQLITE_OK; @@ -2786,7 +2802,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){ */ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){ int flags = pMem->flags; - int n; + u32 n; if( flags&MEM_Null ){ return 0; @@ -2816,11 +2832,11 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){ return 7; } assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) ); - n = pMem->n; + assert( pMem->n>=0 ); + n = (u32)pMem->n; if( flags & MEM_Zero ){ n += pMem->u.nZero; } - assert( n>=0 ); return ((n*2) + 12 + ((flags&MEM_Str)!=0)); } @@ -3403,10 +3419,13 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ ** Key1 and Key2 do not have to contain the same number of fields. If all ** fields that appear in both keys are equal, then pPKey2->default_rc is ** returned. +** +** If database corruption is discovered, set pPKey2->isCorrupt to non-zero +** and return 0. */ int sqlite3VdbeRecordCompare( int nKey1, const void *pKey1, /* Left key */ - const UnpackedRecord *pPKey2, /* Right key */ + UnpackedRecord *pPKey2, /* Right key */ int bSkip /* If true, skip the first field */ ){ u32 d1; /* Offset into aKey[] of next data element */ @@ -3432,7 +3451,10 @@ int sqlite3VdbeRecordCompare( }else{ idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; - if( d1>(unsigned)nKey1 ) return 1; /* Corruption */ + if( d1>(unsigned)nKey1 ){ + pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ + } i = 0; } @@ -3509,7 +3531,8 @@ int sqlite3VdbeRecordCompare( testcase( (d1+mem1.n)==(unsigned)nKey1 ); testcase( (d1+mem1.n+1)==(unsigned)nKey1 ); if( (d1+mem1.n) > (unsigned)nKey1 ){ - rc = 1; /* Corruption */ + pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ }else if( pKeyInfo->aColl[i] ){ mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; @@ -3535,7 +3558,8 @@ int sqlite3VdbeRecordCompare( testcase( (d1+nStr)==(unsigned)nKey1 ); testcase( (d1+nStr+1)==(unsigned)nKey1 ); if( (d1+nStr) > (unsigned)nKey1 ){ - rc = 1; /* Corruption */ + pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ }else{ int nCmp = MIN(nStr, pRhs->n); rc = memcmp(&aKey1[d1], pRhs->z, nCmp); @@ -3579,6 +3603,7 @@ int sqlite3VdbeRecordCompare( ** value. */ assert( CORRUPT_DB || pPKey2->default_rc==vdbeRecordCompareDebug(nKey1, pKey1, pPKey2) + || pKeyInfo->db->mallocFailed ); return pPKey2->default_rc; } @@ -3588,10 +3613,13 @@ int sqlite3VdbeRecordCompare( ** that (a) the first field of pPKey2 is an integer, and (b) the ** size-of-header varint at the start of (pKey1/nKey1) fits in a single ** byte (i.e. is less than 128). +** +** To avoid concerns about buffer overreads, this routine is only used +** on schemas where the maximum valid header size is 63 bytes or less. */ static int vdbeRecordCompareInt( int nKey1, const void *pKey1, /* Left key */ - const UnpackedRecord *pPKey2, /* Right key */ + UnpackedRecord *pPKey2, /* Right key */ int bSkip /* Ignored */ ){ const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F]; @@ -3604,6 +3632,7 @@ static int vdbeRecordCompareInt( UNUSED_PARAMETER(bSkip); assert( bSkip==0 ); + assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB ); switch( serial_type ){ case 1: { /* 1-byte signed integer */ lhs = ONE_BYTE_INT(aKey); @@ -3688,7 +3717,7 @@ static int vdbeRecordCompareInt( */ static int vdbeRecordCompareString( int nKey1, const void *pKey1, /* Left key */ - const UnpackedRecord *pPKey2, /* Right key */ + UnpackedRecord *pPKey2, /* Right key */ int bSkip ){ const u8 *aKey1 = (const u8*)pKey1; @@ -3709,7 +3738,10 @@ static int vdbeRecordCompareString( int szHdr = aKey1[0]; nStr = (serial_type-12) / 2; - if( (szHdr + nStr) > nKey1 ) return 0; /* Corruption */ + if( (szHdr + nStr) > nKey1 ){ + pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ + } nCmp = MIN( pPKey2->aMem[0].n, nStr ); res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp); @@ -3737,6 +3769,7 @@ static int vdbeRecordCompareString( || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) || CORRUPT_DB + || pPKey2->pKeyInfo->db->mallocFailed ); return res; } @@ -3874,7 +3907,7 @@ idx_rowid_corruption: */ int sqlite3VdbeIdxKeyCompare( VdbeCursor *pC, /* The cursor to compare against */ - const UnpackedRecord *pUnpacked, /* Unpacked version of key */ + UnpackedRecord *pUnpacked, /* Unpacked version of key */ int *res /* Write the comparison result here */ ){ i64 nCellKey = 0; diff --git a/src/vdbeblob.c b/src/vdbeblob.c index cf7495e..083f3f4 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -77,9 +77,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){ p->iOffset = pC->aType[p->iCol + pC->nField]; p->nByte = sqlite3VdbeSerialTypeLen(type); p->pCsr = pC->pCursor; - sqlite3BtreeEnterCursor(p->pCsr); - sqlite3BtreeCacheOverflow(p->pCsr); - sqlite3BtreeLeaveCursor(p->pCsr); + sqlite3BtreeIncrblobCursor(p->pCsr); } } diff --git a/src/vdbemem.c b/src/vdbemem.c index 2c4aa4a..cf44aa7 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -1152,6 +1152,68 @@ void sqlite3AnalyzeFunctions(void){ } } +/* +** Attempt to extract a value from pExpr and use it to construct *ppVal. +** +** If pAlloc is not NULL, then an UnpackedRecord object is created for +** pAlloc if one does not exist and the new value is added to the +** UnpackedRecord object. +** +** A value is extracted in the following cases: +** +** * (pExpr==0). In this case the value is assumed to be an SQL NULL, +** +** * The expression is a bound variable, and this is a reprepare, or +** +** * The expression is a literal value. +** +** On success, *ppVal is made to point to the extracted value. The caller +** is responsible for ensuring that the value is eventually freed. +*/ +static int stat4ValueFromExpr( + Parse *pParse, /* Parse context */ + Expr *pExpr, /* The expression to extract a value from */ + u8 affinity, /* Affinity to use */ + struct ValueNewStat4Ctx *pAlloc,/* How to allocate space. Or NULL */ + sqlite3_value **ppVal /* OUT: New value object (or NULL) */ +){ + int rc = SQLITE_OK; + sqlite3_value *pVal = 0; + sqlite3 *db = pParse->db; + + /* Skip over any TK_COLLATE nodes */ + pExpr = sqlite3ExprSkipCollate(pExpr); + + if( !pExpr ){ + pVal = valueNew(db, pAlloc); + if( pVal ){ + sqlite3VdbeMemSetNull((Mem*)pVal); + } + }else if( pExpr->op==TK_VARIABLE + || NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE) + ){ + Vdbe *v; + int iBindVar = pExpr->iColumn; + sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar); + if( (v = pParse->pReprepare)!=0 ){ + pVal = valueNew(db, pAlloc); + if( pVal ){ + rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]); + if( rc==SQLITE_OK ){ + sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); + } + pVal->db = pParse->db; + } + } + }else{ + rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, pAlloc); + } + + assert( pVal==0 || pVal->db==db ); + *ppVal = pVal; + return rc; +} + /* ** This function is used to allocate and populate UnpackedRecord ** structures intended to be compared against sample index keys stored @@ -1191,50 +1253,88 @@ int sqlite3Stat4ProbeSetValue( int iVal, /* Array element to populate */ int *pbOk /* OUT: True if value was extracted */ ){ - int rc = SQLITE_OK; + int rc; sqlite3_value *pVal = 0; - sqlite3 *db = pParse->db; - - struct ValueNewStat4Ctx alloc; + alloc.pParse = pParse; alloc.pIdx = pIdx; alloc.ppRec = ppRec; alloc.iVal = iVal; - /* Skip over any TK_COLLATE nodes */ - pExpr = sqlite3ExprSkipCollate(pExpr); - - if( !pExpr ){ - pVal = valueNew(db, &alloc); - if( pVal ){ - sqlite3VdbeMemSetNull((Mem*)pVal); - } - }else if( pExpr->op==TK_VARIABLE - || NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE) - ){ - Vdbe *v; - int iBindVar = pExpr->iColumn; - sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar); - if( (v = pParse->pReprepare)!=0 ){ - pVal = valueNew(db, &alloc); - if( pVal ){ - rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]); - if( rc==SQLITE_OK ){ - sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); - } - pVal->db = pParse->db; - } - } - }else{ - rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, &alloc); - } + rc = stat4ValueFromExpr(pParse, pExpr, affinity, &alloc, &pVal); + assert( pVal==0 || pVal->db==pParse->db ); *pbOk = (pVal!=0); - - assert( pVal==0 || pVal->db==db ); return rc; } +/* +** Attempt to extract a value from expression pExpr using the methods +** as described for sqlite3Stat4ProbeSetValue() above. +** +** If successful, set *ppVal to point to a new value object and return +** SQLITE_OK. If no value can be extracted, but no other error occurs +** (e.g. OOM), return SQLITE_OK and set *ppVal to NULL. Or, if an error +** does occur, return an SQLite error code. The final value of *ppVal +** is undefined in this case. +*/ +int sqlite3Stat4ValueFromExpr( + Parse *pParse, /* Parse context */ + Expr *pExpr, /* The expression to extract a value from */ + u8 affinity, /* Affinity to use */ + sqlite3_value **ppVal /* OUT: New value object (or NULL) */ +){ + return stat4ValueFromExpr(pParse, pExpr, affinity, 0, ppVal); +} + +/* +** Extract the iCol-th column from the nRec-byte record in pRec. Write +** the column value into *ppVal. If *ppVal is initially NULL then a new +** sqlite3_value object is allocated. +** +** If *ppVal is initially NULL then the caller is responsible for +** ensuring that the value written into *ppVal is eventually freed. +*/ +int sqlite3Stat4Column( + sqlite3 *db, /* Database handle */ + const void *pRec, /* Pointer to buffer containing record */ + int nRec, /* Size of buffer pRec in bytes */ + int iCol, /* Column to extract */ + sqlite3_value **ppVal /* OUT: Extracted value */ +){ + u32 t; /* a column type code */ + int nHdr; /* Size of the header in the record */ + int iHdr; /* Next unread header byte */ + int iField; /* Next unread data byte */ + int szField; /* Size of the current data field */ + int i; /* Column index */ + u8 *a = (u8*)pRec; /* Typecast byte array */ + Mem *pMem = *ppVal; /* Write result into this Mem object */ + + assert( iCol>0 ); + iHdr = getVarint32(a, nHdr); + if( nHdr>nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT; + iField = nHdr; + for(i=0; i<=iCol; i++){ + iHdr += getVarint32(&a[iHdr], t); + testcase( iHdr==nHdr ); + testcase( iHdr==nHdr+1 ); + if( iHdr>nHdr ) return SQLITE_CORRUPT_BKPT; + szField = sqlite3VdbeSerialTypeLen(t); + iField += szField; + } + testcase( iField==nRec ); + testcase( iField==nRec+1 ); + if( iField>nRec ) return SQLITE_CORRUPT_BKPT; + if( pMem==0 ){ + pMem = *ppVal = sqlite3ValueNew(db); + if( pMem==0 ) return SQLITE_NOMEM; + } + sqlite3VdbeSerialGet(&a[iField-szField], t, pMem); + pMem->enc = ENC(db); + return SQLITE_OK; +} + /* ** Unless it is NULL, the argument must be an UnpackedRecord object returned ** by an earlier call to sqlite3Stat4ProbeSetValue(). This call deletes diff --git a/src/vdbesort.c b/src/vdbesort.c index b9ed97e..6a5855f 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -350,7 +350,6 @@ static int vdbeSorterIterInit( rc = sqlite3OsRead( pSorter->pTemp1, &pIter->aBuffer[iBuf], nRead, iStart ); - assert( rc!=SQLITE_IOERR_SHORT_READ ); } if( rc==SQLITE_OK ){ @@ -386,7 +385,7 @@ static int vdbeSorterIterInit( */ static void vdbeSorterCompare( const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */ - int nIgnore, /* Ignore the last nIgnore fields */ + int nKeyCol, /* Num of columns. 0 means "all" */ const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2, /* Right side of comparison */ int *pRes /* OUT: Result of comparison */ @@ -400,10 +399,9 @@ static void vdbeSorterCompare( sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2); } - if( nIgnore ){ - r2->nField = pKeyInfo->nField - nIgnore; - assert( r2->nField>0 ); - for(i=0; inField; i++){ + if( nKeyCol ){ + r2->nField = nKeyCol; + for(i=0; iaMem[i].flags & MEM_Null ){ *pRes = -1; return; @@ -504,23 +502,40 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ } } +/* +** Reset a sorting cursor back to its original empty state. +*/ +void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){ + if( pSorter->aIter ){ + int i; + for(i=0; inTree; i++){ + vdbeSorterIterZero(db, &pSorter->aIter[i]); + } + sqlite3DbFree(db, pSorter->aIter); + pSorter->aIter = 0; + } + if( pSorter->pTemp1 ){ + sqlite3OsCloseFree(pSorter->pTemp1); + pSorter->pTemp1 = 0; + } + vdbeSorterRecordFree(db, pSorter->pRecord); + pSorter->pRecord = 0; + pSorter->iWriteOff = 0; + pSorter->iReadOff = 0; + pSorter->nInMemory = 0; + pSorter->nTree = 0; + pSorter->nPMA = 0; + pSorter->aTree = 0; +} + + /* ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. */ void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ VdbeSorter *pSorter = pCsr->pSorter; if( pSorter ){ - if( pSorter->aIter ){ - int i; - for(i=0; inTree; i++){ - vdbeSorterIterZero(db, &pSorter->aIter[i]); - } - sqlite3DbFree(db, pSorter->aIter); - } - if( pSorter->pTemp1 ){ - sqlite3OsCloseFree(pSorter->pTemp1); - } - vdbeSorterRecordFree(db, pSorter->pRecord); + sqlite3VdbeSorterReset(db, pSorter); sqlite3DbFree(db, pSorter->pUnpacked); sqlite3DbFree(db, pSorter); pCsr->pSorter = 0; @@ -956,14 +971,55 @@ int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){ if( pSorter->aTree ){ int iPrev = pSorter->aTree[1];/* Index of iterator to advance */ - int i; /* Index of aTree[] to recalculate */ - rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]); - for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){ - rc = vdbeSorterDoCompare(pCsr, i); - } + if( rc==SQLITE_OK ){ + int i; /* Index of aTree[] to recalculate */ + VdbeSorterIter *pIter1; /* First iterator to compare */ + VdbeSorterIter *pIter2; /* Second iterator to compare */ + u8 *pKey2; /* To pIter2->aKey, or 0 if record cached */ - *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); + /* Find the first two iterators to compare. The one that was just + ** advanced (iPrev) and the one next to it in the array. */ + pIter1 = &pSorter->aIter[(iPrev & 0xFFFE)]; + pIter2 = &pSorter->aIter[(iPrev | 0x0001)]; + pKey2 = pIter2->aKey; + + for(i=(pSorter->nTree+iPrev)/2; i>0; i=i/2){ + /* Compare pIter1 and pIter2. Store the result in variable iRes. */ + int iRes; + if( pIter1->pFile==0 ){ + iRes = +1; + }else if( pIter2->pFile==0 ){ + iRes = -1; + }else{ + vdbeSorterCompare(pCsr, 0, + pIter1->aKey, pIter1->nKey, pKey2, pIter2->nKey, &iRes + ); + } + + /* If pIter1 contained the smaller value, set aTree[i] to its index. + ** Then set pIter2 to the next iterator to compare to pIter1. In this + ** case there is no cache of pIter2 in pSorter->pUnpacked, so set + ** pKey2 to point to the record belonging to pIter2. + ** + ** Alternatively, if pIter2 contains the smaller of the two values, + ** set aTree[i] to its index and update pIter1. If vdbeSorterCompare() + ** was actually called above, then pSorter->pUnpacked now contains + ** a value equivalent to pIter2. So set pKey2 to NULL to prevent + ** vdbeSorterCompare() from decoding pIter2 again. */ + if( iRes<=0 ){ + pSorter->aTree[i] = (int)(pIter1 - pSorter->aIter); + pIter2 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ]; + pKey2 = pIter2->aKey; + }else{ + if( pIter1->pFile ) pKey2 = 0; + pSorter->aTree[i] = (int)(pIter2 - pSorter->aIter); + pIter1 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ]; + } + + } + *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); + } }else{ SorterRecord *pFree = pSorter->pRecord; pSorter->pRecord = pFree->pNext; @@ -1027,13 +1083,13 @@ int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal, /* Value to compare to current sorter key */ - int nIgnore, /* Ignore this many fields at the end */ + int nKeyCol, /* Only compare this many fields */ int *pRes /* OUT: Result of comparison */ ){ VdbeSorter *pSorter = pCsr->pSorter; void *pKey; int nKey; /* Sorter key to compare pVal with */ pKey = vdbeSorterRowkey(pSorter, &nKey); - vdbeSorterCompare(pCsr, nIgnore, pVal->z, pVal->n, pKey, nKey, pRes); + vdbeSorterCompare(pCsr, nKeyCol, pVal->z, pVal->n, pKey, nKey, pRes); return SQLITE_OK; } diff --git a/src/wal.c b/src/wal.c index ad76065..70395f8 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2096,8 +2096,8 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this ** is more of a scheduler yield than an actual delay. But on the 10th ** an subsequent retries, the delays start becoming longer and longer, - ** so that on the 100th (and last) RETRY we delay for 21 milliseconds. - ** The total delay time before giving up is less than 1 second. + ** so that on the 100th (and last) RETRY we delay for 323 milliseconds. + ** The total delay time before giving up is less than 10 seconds. */ if( cnt>5 ){ int nDelay = 1; /* Pause time in microseconds */ @@ -2105,7 +2105,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ VVA_ONLY( pWal->lockError = 1; ) return SQLITE_PROTOCOL; } - if( cnt>=10 ) nDelay = (cnt-9)*238; /* Max delay 21ms. Total delay 996ms */ + if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; sqlite3OsSleep(pWal->pVfs, nDelay); } diff --git a/src/where.c b/src/where.c index d8389a4..9c30136 100644 --- a/src/where.c +++ b/src/where.c @@ -39,7 +39,7 @@ int sqlite3WhereIsDistinct(WhereInfo *pWInfo){ ** Return FALSE if the output needs to be sorted. */ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ - return pWInfo->bOBSat!=0; + return pWInfo->nOBSat; } /* @@ -47,6 +47,7 @@ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ ** immediately with the next row of a WHERE clause. */ int sqlite3WhereContinueLabel(WhereInfo *pWInfo){ + assert( pWInfo->iContinue!=0 ); return pWInfo->iContinue; } @@ -226,7 +227,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){ if( p && ExprHasProperty(p, EP_Unlikely) ){ pTerm->truthProb = sqlite3LogEst(p->iTable) - 99; }else{ - pTerm->truthProb = -1; + pTerm->truthProb = 1; } pTerm->pExpr = sqlite3ExprSkipCollate(p); pTerm->wtFlags = wtFlags; @@ -543,7 +544,7 @@ static WhereTerm *whereScanInit( if( pIdx && iColumn>=0 ){ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ - if( NEVER(j>=pIdx->nKeyCol) ) return 0; + if( NEVER(j>pIdx->nColumn) ) return 0; } pScan->zCollName = pIdx->azColl[j]; }else{ @@ -1469,7 +1470,7 @@ static int isDistinctRedundant( ** contain a "col=X" term are subject to a NOT NULL constraint. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->onError==OE_None ) continue; + if( !IsUniqueIndex(pIdx) ) continue; for(i=0; inKeyCol; i++){ i16 iCol = pIdx->aiColumn[i]; if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){ @@ -1493,8 +1494,7 @@ static int isDistinctRedundant( ** Estimate the logarithm of the input value to base 2. */ static LogEst estLog(LogEst N){ - LogEst x = sqlite3LogEst(N); - return x>33 ? x - 33 : 0; + return N<=10 ? 0 : sqlite3LogEst(N) - 33; } /* @@ -1955,10 +1955,11 @@ static void whereKeyStats( iLower = 0; iUpper = aSample[0].anLt[iCol]; }else{ - iUpper = i>=pIdx->nSample ? pIdx->aiRowEst[0] : aSample[i].anLt[iCol]; + i64 nRow0 = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]); + iUpper = i>=pIdx->nSample ? nRow0 : aSample[i].anLt[iCol]; iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol]; } - aStat[1] = (pIdx->nKeyCol>iCol ? pIdx->aAvgEq[iCol] : 1); + aStat[1] = pIdx->aAvgEq[iCol]; if( iLower>=iUpper ){ iGap = 0; }else{ @@ -1974,6 +1975,138 @@ static void whereKeyStats( } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +/* +** If it is not NULL, pTerm is a term that provides an upper or lower +** bound on a range scan. Without considering pTerm, it is estimated +** that the scan will visit nNew rows. This function returns the number +** estimated to be visited after taking pTerm into account. +** +** If the user explicitly specified a likelihood() value for this term, +** then the return value is the likelihood multiplied by the number of +** input rows. Otherwise, this function assumes that an "IS NOT NULL" term +** has a likelihood of 0.50, and any other term a likelihood of 0.25. +*/ +static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){ + LogEst nRet = nNew; + if( pTerm ){ + if( pTerm->truthProb<=0 ){ + nRet += pTerm->truthProb; + }else if( (pTerm->wtFlags & TERM_VNULL)==0 ){ + nRet -= 20; assert( 20==sqlite3LogEst(4) ); + } + } + return nRet; +} + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +/* +** This function is called to estimate the number of rows visited by a +** range-scan on a skip-scan index. For example: +** +** CREATE INDEX i1 ON t1(a, b, c); +** SELECT * FROM t1 WHERE a=? AND c BETWEEN ? AND ?; +** +** Value pLoop->nOut is currently set to the estimated number of rows +** visited for scanning (a=? AND b=?). This function reduces that estimate +** by some factor to account for the (c BETWEEN ? AND ?) expression based +** on the stat4 data for the index. this scan will be peformed multiple +** times (once for each (a,b) combination that matches a=?) is dealt with +** by the caller. +** +** It does this by scanning through all stat4 samples, comparing values +** extracted from pLower and pUpper with the corresponding column in each +** sample. If L and U are the number of samples found to be less than or +** equal to the values extracted from pLower and pUpper respectively, and +** N is the total number of samples, the pLoop->nOut value is adjusted +** as follows: +** +** nOut = nOut * ( min(U - L, 1) / N ) +** +** If pLower is NULL, or a value cannot be extracted from the term, L is +** set to zero. If pUpper is NULL, or a value cannot be extracted from it, +** U is set to N. +** +** Normally, this function sets *pbDone to 1 before returning. However, +** if no value can be extracted from either pLower or pUpper (and so the +** estimate of the number of rows delivered remains unchanged), *pbDone +** is left as is. +** +** If an error occurs, an SQLite error code is returned. Otherwise, +** SQLITE_OK. +*/ +static int whereRangeSkipScanEst( + Parse *pParse, /* Parsing & code generating context */ + WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */ + WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ + WhereLoop *pLoop, /* Update the .nOut value of this loop */ + int *pbDone /* Set to true if at least one expr. value extracted */ +){ + Index *p = pLoop->u.btree.pIndex; + int nEq = pLoop->u.btree.nEq; + sqlite3 *db = pParse->db; + int nLower = -1; + int nUpper = p->nSample+1; + int rc = SQLITE_OK; + int iCol = p->aiColumn[nEq]; + u8 aff = iCol>=0 ? p->pTable->aCol[iCol].affinity : SQLITE_AFF_INTEGER; + CollSeq *pColl; + + sqlite3_value *p1 = 0; /* Value extracted from pLower */ + sqlite3_value *p2 = 0; /* Value extracted from pUpper */ + sqlite3_value *pVal = 0; /* Value extracted from record */ + + pColl = sqlite3LocateCollSeq(pParse, p->azColl[nEq]); + if( pLower ){ + rc = sqlite3Stat4ValueFromExpr(pParse, pLower->pExpr->pRight, aff, &p1); + nLower = 0; + } + if( pUpper && rc==SQLITE_OK ){ + rc = sqlite3Stat4ValueFromExpr(pParse, pUpper->pExpr->pRight, aff, &p2); + nUpper = p2 ? 0 : p->nSample; + } + + if( p1 || p2 ){ + int i; + int nDiff; + for(i=0; rc==SQLITE_OK && inSample; i++){ + rc = sqlite3Stat4Column(db, p->aSample[i].p, p->aSample[i].n, nEq, &pVal); + if( rc==SQLITE_OK && p1 ){ + int res = sqlite3MemCompare(p1, pVal, pColl); + if( res>=0 ) nLower++; + } + if( rc==SQLITE_OK && p2 ){ + int res = sqlite3MemCompare(p2, pVal, pColl); + if( res>=0 ) nUpper++; + } + } + nDiff = (nUpper - nLower); + if( nDiff<=0 ) nDiff = 1; + + /* If there is both an upper and lower bound specified, and the + ** comparisons indicate that they are close together, use the fallback + ** method (assume that the scan visits 1/64 of the rows) for estimating + ** the number of rows visited. Otherwise, estimate the number of rows + ** using the method described in the header comment for this function. */ + if( nDiff!=1 || pUpper==0 || pLower==0 ){ + int nAdjust = (sqlite3LogEst(p->nSample) - sqlite3LogEst(nDiff)); + pLoop->nOut -= nAdjust; + *pbDone = 1; + WHERETRACE(0x10, ("range skip-scan regions: %u..%u adjust=%d est=%d\n", + nLower, nUpper, nAdjust*-1, pLoop->nOut)); + } + + }else{ + assert( *pbDone==0 ); + } + + sqlite3ValueFree(p1); + sqlite3ValueFree(p2); + sqlite3ValueFree(pVal); + + return rc; +} +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ + /* ** This function is used to estimate the number of rows that will be visited ** by scanning an index for a range of values. The range may have an upper @@ -2010,9 +2143,9 @@ static void whereKeyStats( ** to account for the range contraints pLower and pUpper. ** ** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be -** used, each range inequality reduces the search space by a factor of 4. -** Hence a pair of constraints (x>? AND x? AND xu.btree.nEq; if( p->nSample>0 - && nEq==pBuilder->nRecValid && nEqnSampleCol && OptimizationEnabled(pParse->db, SQLITE_Stat3) ){ - UnpackedRecord *pRec = pBuilder->pRec; - tRowcnt a[2]; - u8 aff; + if( nEq==pBuilder->nRecValid ){ + UnpackedRecord *pRec = pBuilder->pRec; + tRowcnt a[2]; + u8 aff; - /* Variable iLower will be set to the estimate of the number of rows in - ** the index that are less than the lower bound of the range query. The - ** lower bound being the concatenation of $P and $L, where $P is the - ** key-prefix formed by the nEq values matched against the nEq left-most - ** columns of the index, and $L is the value in pLower. - ** - ** Or, if pLower is NULL or $L cannot be extracted from it (because it - ** is not a simple variable or literal value), the lower bound of the - ** range is $P. Due to a quirk in the way whereKeyStats() works, even - ** if $L is available, whereKeyStats() is called for both ($P) and - ** ($P:$L) and the larger of the two returned values used. - ** - ** Similarly, iUpper is to be set to the estimate of the number of rows - ** less than the upper bound of the range query. Where the upper bound - ** is either ($P) or ($P:$U). Again, even if $U is available, both values - ** of iUpper are requested of whereKeyStats() and the smaller used. - */ - tRowcnt iLower; - tRowcnt iUpper; + /* Variable iLower will be set to the estimate of the number of rows in + ** the index that are less than the lower bound of the range query. The + ** lower bound being the concatenation of $P and $L, where $P is the + ** key-prefix formed by the nEq values matched against the nEq left-most + ** columns of the index, and $L is the value in pLower. + ** + ** Or, if pLower is NULL or $L cannot be extracted from it (because it + ** is not a simple variable or literal value), the lower bound of the + ** range is $P. Due to a quirk in the way whereKeyStats() works, even + ** if $L is available, whereKeyStats() is called for both ($P) and + ** ($P:$L) and the larger of the two returned values used. + ** + ** Similarly, iUpper is to be set to the estimate of the number of rows + ** less than the upper bound of the range query. Where the upper bound + ** is either ($P) or ($P:$U). Again, even if $U is available, both values + ** of iUpper are requested of whereKeyStats() and the smaller used. + */ + tRowcnt iLower; + tRowcnt iUpper; - if( nEq==p->nKeyCol ){ - aff = SQLITE_AFF_INTEGER; - }else{ - aff = p->pTable->aCol[p->aiColumn[nEq]].affinity; - } - /* Determine iLower and iUpper using ($P) only. */ - if( nEq==0 ){ - iLower = 0; - iUpper = p->aiRowEst[0]; - }else{ - /* Note: this call could be optimized away - since the same values must - ** have been requested when testing key $P in whereEqualScanEst(). */ - whereKeyStats(pParse, p, pRec, 0, a); - iLower = a[0]; - iUpper = a[0] + a[1]; - } - - /* If possible, improve on the iLower estimate using ($P:$L). */ - if( pLower ){ - int bOk; /* True if value is extracted from pExpr */ - Expr *pExpr = pLower->pExpr->pRight; - assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 ); - rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); - if( rc==SQLITE_OK && bOk ){ - tRowcnt iNew; - whereKeyStats(pParse, p, pRec, 0, a); - iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0); - if( iNew>iLower ) iLower = iNew; - nOut--; - } - } - - /* If possible, improve on the iUpper estimate using ($P:$U). */ - if( pUpper ){ - int bOk; /* True if value is extracted from pExpr */ - Expr *pExpr = pUpper->pExpr->pRight; - assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); - rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); - if( rc==SQLITE_OK && bOk ){ - tRowcnt iNew; - whereKeyStats(pParse, p, pRec, 1, a); - iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0); - if( iNewpRec = pRec; - if( rc==SQLITE_OK ){ - if( iUpper>iLower ){ - nNew = sqlite3LogEst(iUpper - iLower); + if( nEq==p->nKeyCol ){ + aff = SQLITE_AFF_INTEGER; }else{ - nNew = 10; assert( 10==sqlite3LogEst(2) ); + aff = p->pTable->aCol[p->aiColumn[nEq]].affinity; } - if( nNewaiRowLogEst[0]); + }else{ + /* Note: this call could be optimized away - since the same values must + ** have been requested when testing key $P in whereEqualScanEst(). */ + whereKeyStats(pParse, p, pRec, 0, a); + iLower = a[0]; + iUpper = a[0] + a[1]; } - pLoop->nOut = (LogEst)nOut; - WHERETRACE(0x10, ("range scan regions: %u..%u est=%d\n", - (u32)iLower, (u32)iUpper, nOut)); - return SQLITE_OK; + + /* If possible, improve on the iLower estimate using ($P:$L). */ + if( pLower ){ + int bOk; /* True if value is extracted from pExpr */ + Expr *pExpr = pLower->pExpr->pRight; + assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 ); + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); + if( rc==SQLITE_OK && bOk ){ + tRowcnt iNew; + whereKeyStats(pParse, p, pRec, 0, a); + iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0); + if( iNew>iLower ) iLower = iNew; + nOut--; + } + } + + /* If possible, improve on the iUpper estimate using ($P:$U). */ + if( pUpper ){ + int bOk; /* True if value is extracted from pExpr */ + Expr *pExpr = pUpper->pExpr->pRight; + assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); + if( rc==SQLITE_OK && bOk ){ + tRowcnt iNew; + whereKeyStats(pParse, p, pRec, 1, a); + iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0); + if( iNewpRec = pRec; + if( rc==SQLITE_OK ){ + if( iUpper>iLower ){ + nNew = sqlite3LogEst(iUpper - iLower); + }else{ + nNew = 10; assert( 10==sqlite3LogEst(2) ); + } + if( nNewnOut = (LogEst)nOut; + WHERETRACE(0x10, ("range scan regions: %u..%u est=%d\n", + (u32)iLower, (u32)iUpper, nOut)); + return SQLITE_OK; + } + }else{ + int bDone = 0; + rc = whereRangeSkipScanEst(pParse, pLower, pUpper, pLoop, &bDone); + if( bDone ) return rc; } } #else @@ -2126,17 +2264,18 @@ static int whereRangeScanEst( UNUSED_PARAMETER(pBuilder); #endif assert( pLower || pUpper ); - /* TUNING: Each inequality constraint reduces the search space 4-fold. - ** A BETWEEN operator, therefore, reduces the search space 16-fold */ - nNew = nOut; - if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){ - nNew -= 20; assert( 20==sqlite3LogEst(4) ); - nOut--; - } - if( pUpper ){ - nNew -= 20; assert( 20==sqlite3LogEst(4) ); - nOut--; - } + assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 ); + nNew = whereRangeAdjust(pLower, nOut); + nNew = whereRangeAdjust(pUpper, nNew); + + /* TUNING: If there is both an upper and lower limit, assume the range is + ** reduced by an additional 75%. This means that, by default, an open-ended + ** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the + ** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to + ** match 1/64 of the index. */ + if( pLower && pUpper ) nNew -= 20; + + nOut -= (pLower!=0) + (pUpper!=0); if( nNew<10 ) nNew = 10; if( nNewnOut = (LogEst)nOut; @@ -2176,7 +2315,7 @@ static int whereEqualScanEst( int bOk; assert( nEq>=1 ); - assert( nEq<=(p->nKeyCol+1) ); + assert( nEq<=p->nColumn ); assert( p->aSample!=0 ); assert( p->nSample>0 ); assert( pBuilder->nRecValidp->nKeyCol ){ + if( nEq>=p->nColumn ){ *pnRow = 1; return SQLITE_OK; } @@ -2233,6 +2372,7 @@ static int whereInScanEst( tRowcnt *pnRow /* Write the revised row estimate here */ ){ Index *p = pBuilder->pNew->u.btree.pIndex; + i64 nRow0 = sqlite3LogEstToInt(p->aiRowLogEst[0]); int nRecValid = pBuilder->nRecValid; int rc = SQLITE_OK; /* Subfunction return code */ tRowcnt nEst; /* Number of rows for a single term */ @@ -2241,14 +2381,14 @@ static int whereInScanEst( assert( p->aSample!=0 ); for(i=0; rc==SQLITE_OK && inExpr; i++){ - nEst = p->aiRowEst[0]; + nEst = nRow0; rc = whereEqualScanEst(pParse, pBuilder, pList->a[i].pExpr, &nEst); nRowEst += nEst; pBuilder->nRecValid = nRecValid; } if( rc==SQLITE_OK ){ - if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0]; + if( nRowEst > nRow0 ) nRowEst = nRow0; *pnRow = nRowEst; WHERETRACE(0x10,("IN row estimate: est=%g\n", nRowEst)); } @@ -2382,7 +2522,7 @@ static int codeEqualityTerm( } assert( pX->op==TK_IN ); iReg = iTarget; - eType = sqlite3FindInIndex(pParse, pX, 0); + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0); if( eType==IN_INDEX_INDEX_DESC ){ testcase( bRev ); bRev = !bRev; @@ -2619,7 +2759,7 @@ static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){ txt.db = db; sqlite3StrAccumAppend(&txt, " (", 2); for(i=0; inKeyCol ) ? "rowid" : aCol[aiColumn[i]].zName; + char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName; if( i>=nSkip ){ explainAppendTerm(&txt, i, z, "="); }else{ @@ -2632,11 +2772,11 @@ static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){ j = i; if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ - char *z = (j==pIndex->nKeyCol ) ? "rowid" : aCol[aiColumn[j]].zName; + char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; explainAppendTerm(&txt, i++, z, ">"); } if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ - char *z = (j==pIndex->nKeyCol ) ? "rowid" : aCol[aiColumn[j]].zName; + char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; explainAppendTerm(&txt, i, z, "<"); } sqlite3StrAccumAppend(&txt, ")", 1); @@ -2691,13 +2831,20 @@ static void explainOneScan( if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 && ALWAYS(pLoop->u.btree.pIndex!=0) ){ + const char *zFmt; + Index *pIdx = pLoop->u.btree.pIndex; char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); - zMsg = sqlite3MAppendf(db, zMsg, - ((flags & WHERE_AUTO_INDEX) ? - "%s USING AUTOMATIC %sINDEX%.0s%s" : - "%s USING %sINDEX %s%s"), - zMsg, ((flags & WHERE_IDX_ONLY) ? "COVERING " : ""), - pLoop->u.btree.pIndex->zName, zWhere); + assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); + if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ + zFmt = zWhere ? "%s USING PRIMARY KEY%.0s%s" : "%s%.0s%s"; + }else if( flags & WHERE_AUTO_INDEX ){ + zFmt = "%s USING AUTOMATIC COVERING INDEX%.0s%s"; + }else if( flags & WHERE_IDX_ONLY ){ + zFmt = "%s USING COVERING INDEX %s%s"; + }else{ + zFmt = "%s USING INDEX %s%s"; + } + zMsg = sqlite3MAppendf(db, zMsg, zFmt, zMsg, pIdx->zName, zWhere); sqlite3DbFree(db, zWhere); }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg); @@ -2840,7 +2987,7 @@ static Bitmask codeOneLoopStart( pLevel->p1 = iCur; pLevel->p2 = sqlite3VdbeCurrentAddr(v); sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -3036,8 +3183,11 @@ static Bitmask codeOneLoopStart( ** the first one after the nEq equality constraints in the index, ** this requires some special handling. */ + assert( pWInfo->pOrderBy==0 + || pWInfo->pOrderBy->nExpr==1 + || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 ); if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0 - && (pWInfo->bOBSat!=0) + && pWInfo->nOBSat>0 && (pIdx->nKeyCol>nEq) ){ assert( pLoop->u.btree.nSkip==0 ); @@ -3186,7 +3336,7 @@ static Bitmask codeOneLoopStart( sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */ - }else{ + }else if( iCur!=iIdxCur ){ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; jnKeyCol; j++){ @@ -3208,8 +3358,7 @@ static Bitmask codeOneLoopStart( pLevel->op = OP_Next; } pLevel->p1 = iIdxCur; - assert( (WHERE_UNQ_WANTED>>16)==1 ); - pLevel->p3 = (pLoop->wsFlags>>16)&1; + pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0; if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; }else{ @@ -3257,6 +3406,10 @@ static Bitmask codeOneLoopStart( ** ** B: ** + ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then + ** use an ephermeral index instead of a RowSet to record the primary + ** keys of the rows we have already seen. + ** */ WhereClause *pOrWc; /* The OR-clause broken out into subterms */ SrcList *pOrTab; /* Shortened table list or OR-clause generation */ @@ -3270,7 +3423,9 @@ static Bitmask codeOneLoopStart( int iRetInit; /* Address of regReturn init */ int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ + u16 wctrlFlags; /* Flags for sub-WHERE clause */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ + Table *pTab = pTabItem->pTab; pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); @@ -3303,7 +3458,8 @@ static Bitmask codeOneLoopStart( } /* Initialize the rowset register to contain NULL. An SQL NULL is - ** equivalent to an empty rowset. + ** equivalent to an empty rowset. Or, create an ephermeral index + ** capable of holding primary keys in the case of a WITHOUT ROWID. ** ** Also initialize regReturn to contain the address of the instruction ** immediately following the OP_Return at the bottom of the loop. This @@ -3314,9 +3470,16 @@ static Bitmask codeOneLoopStart( ** called on an uninitialized cursor. */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ - regRowset = ++pParse->nMem; + if( HasRowid(pTab) ){ + regRowset = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + regRowset = pParse->nTab++; + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, regRowset, pPk->nKeyCol); + sqlite3VdbeSetP4KeyInfo(pParse, pPk); + } regRowid = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); } iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); @@ -3352,36 +3515,88 @@ static Bitmask codeOneLoopStart( } } + /* Run a separate WHERE clause for each term of the OR clause. After + ** eliminating duplicates from other WHERE clauses, the action for each + ** sub-WHERE clause is to to invoke the main loop body as a subroutine. + */ + wctrlFlags = WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY | + WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY; for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ - WhereInfo *pSubWInfo; /* Info for single OR-term scan */ - Expr *pOrExpr = pOrTerm->pExpr; + WhereInfo *pSubWInfo; /* Info for single OR-term scan */ + Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ + int j1 = 0; /* Address of jump operation */ if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){ pAndExpr->pLeft = pOrExpr; pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, - WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY | - WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur); + wctrlFlags, iCovCur); assert( pSubWInfo || pParse->nErr || db->mallocFailed ); if( pSubWInfo ){ WhereLoop *pSubLoop; explainOneScan( pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 ); + /* This is the sub-WHERE clause body. First skip over + ** duplicate rows from prior sub-WHERE clauses, and record the + ** rowid (or PRIMARY KEY) for the current row so that the same + ** row will be skipped in subsequent sub-WHERE clauses. + */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ - int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); int r; - r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur, - regRowid, 0); - sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, - sqlite3VdbeCurrentAddr(v)+2, r, iSet); - VdbeCoverage(v); + int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); + if( HasRowid(pTab) ){ + r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0); + j1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, r,iSet); + VdbeCoverage(v); + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + int nPk = pPk->nKeyCol; + int iPk; + + /* Read the PK into an array of temp registers. */ + r = sqlite3GetTempRange(pParse, nPk); + for(iPk=0; iPkaiColumn[iPk]; + sqlite3ExprCodeGetColumn(pParse, pTab, iCol, iCur, r+iPk, 0); + } + + /* Check if the temp table already contains this key. If so, + ** the row has already been included in the result set and + ** can be ignored (by jumping past the Gosub below). Otherwise, + ** insert the key into the temp table and proceed with processing + ** the row. + ** + ** Use some of the same optimizations as OP_RowSetTest: If iSet + ** is zero, assume that the key cannot already be present in + ** the temp table. And if iSet is -1, assume that there is no + ** need to insert the key into the temp table, as it will never + ** be tested for. */ + if( iSet ){ + j1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk); + VdbeCoverage(v); + } + if( iSet>=0 ){ + sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid); + sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0); + if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + } + + /* Release the array of temp registers */ + sqlite3ReleaseTempRange(pParse, r, nPk); + } } + + /* Invoke the main loop body as a subroutine */ sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody); + /* Jump here (skipping the main loop body subroutine) if the + ** current sub-WHERE row is a duplicate from prior sub-WHEREs. */ + if( j1 ) sqlite3VdbeJumpHere(v, j1); + /* The pSubWInfo->untestedTerms flag means that this OR term ** contained one or more AND term from a notReady table. The ** terms from the notReady table could not be tested and will @@ -3405,9 +3620,11 @@ static Bitmask codeOneLoopStart( assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 && (ii==0 || pSubLoop->u.btree.pIndex==pCov) + && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex)) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); pCov = pSubLoop->u.btree.pIndex; + wctrlFlags |= WHERE_REOPEN_IDX; }else{ pCov = 0; } @@ -3586,7 +3803,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ sqlite3DebugPrintf(" %-19s", z); sqlite3_free(z); } - sqlite3DebugPrintf(" f %04x N %d", p->wsFlags, p->nLTerm); + sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); #ifdef SQLITE_ENABLE_TREE_EXPLAIN /* If the 0x100 bit of wheretracing is set, then show all of the constraint @@ -3708,6 +3925,161 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ } } +/* +** Return TRUE if both of the following are true: +** +** (1) X has the same or lower cost that Y +** (2) X is a proper subset of Y +** +** By "proper subset" we mean that X uses fewer WHERE clause terms +** than Y and that every WHERE clause term used by X is also used +** by Y. +** +** If X is a proper subset of Y then Y is a better choice and ought +** to have a lower cost. This routine returns TRUE when that cost +** relationship is inverted and needs to be adjusted. +*/ +static int whereLoopCheaperProperSubset( + const WhereLoop *pX, /* First WhereLoop to compare */ + const WhereLoop *pY /* Compare against this WhereLoop */ +){ + int i, j; + if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */ + if( pX->rRun >= pY->rRun ){ + if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */ + if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */ + } + for(i=pX->nLTerm-1; i>=0; i--){ + for(j=pY->nLTerm-1; j>=0; j--){ + if( pY->aLTerm[j]==pX->aLTerm[i] ) break; + } + if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ + } + return 1; /* All conditions meet */ +} + +/* +** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so +** that: +** +** (1) pTemplate costs less than any other WhereLoops that are a proper +** subset of pTemplate +** +** (2) pTemplate costs more than any other WhereLoops for which pTemplate +** is a proper subset. +** +** To say "WhereLoop X is a proper subset of Y" means that X uses fewer +** WHERE clause terms than Y and that every WHERE clause term used by X is +** also used by Y. +** +** This adjustment is omitted for SKIPSCAN loops. In a SKIPSCAN loop, the +** WhereLoop.nLTerm field is not an accurate measure of the number of WHERE +** clause terms covered, since some of the first nLTerm entries in aLTerm[] +** will be NULL (because they are skipped). That makes it more difficult +** to compare the loops. We could add extra code to do the comparison, and +** perhaps we will someday. But SKIPSCAN is sufficiently uncommon, and this +** adjustment is sufficient minor, that it is very difficult to construct +** a test case where the extra code would improve the query plan. Better +** to avoid the added complexity and just omit cost adjustments to SKIPSCAN +** loops. +*/ +static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ + if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return; + if( (pTemplate->wsFlags & WHERE_SKIPSCAN)!=0 ) return; + for(; p; p=p->pNextLoop){ + if( p->iTab!=pTemplate->iTab ) continue; + if( (p->wsFlags & WHERE_INDEXED)==0 ) continue; + if( (p->wsFlags & WHERE_SKIPSCAN)!=0 ) continue; + if( whereLoopCheaperProperSubset(p, pTemplate) ){ + /* Adjust pTemplate cost downward so that it is cheaper than its + ** subset p */ + pTemplate->rRun = p->rRun; + pTemplate->nOut = p->nOut - 1; + }else if( whereLoopCheaperProperSubset(pTemplate, p) ){ + /* Adjust pTemplate cost upward so that it is costlier than p since + ** pTemplate is a proper subset of p */ + pTemplate->rRun = p->rRun; + pTemplate->nOut = p->nOut + 1; + } + } +} + +/* +** Search the list of WhereLoops in *ppPrev looking for one that can be +** supplanted by pTemplate. +** +** Return NULL if the WhereLoop list contains an entry that can supplant +** pTemplate, in other words if pTemplate does not belong on the list. +** +** If pX is a WhereLoop that pTemplate can supplant, then return the +** link that points to pX. +** +** If pTemplate cannot supplant any existing element of the list but needs +** to be added to the list, then return a pointer to the tail of the list. +*/ +static WhereLoop **whereLoopFindLesser( + WhereLoop **ppPrev, + const WhereLoop *pTemplate +){ + WhereLoop *p; + for(p=(*ppPrev); p; ppPrev=&p->pNextLoop, p=*ppPrev){ + if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){ + /* If either the iTab or iSortIdx values for two WhereLoop are different + ** then those WhereLoops need to be considered separately. Neither is + ** a candidate to replace the other. */ + continue; + } + /* In the current implementation, the rSetup value is either zero + ** or the cost of building an automatic index (NlogN) and the NlogN + ** is the same for compatible WhereLoops. */ + assert( p->rSetup==0 || pTemplate->rSetup==0 + || p->rSetup==pTemplate->rSetup ); + + /* whereLoopAddBtree() always generates and inserts the automatic index + ** case first. Hence compatible candidate WhereLoops never have a larger + ** rSetup. Call this SETUP-INVARIANT */ + assert( p->rSetup>=pTemplate->rSetup ); + + /* Any loop using an appliation-defined index (or PRIMARY KEY or + ** UNIQUE constraint) with one or more == constraints is better + ** than an automatic index. */ + if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 + && (pTemplate->wsFlags & WHERE_INDEXED)!=0 + && (pTemplate->wsFlags & WHERE_COLUMN_EQ)!=0 + && (p->prereq & pTemplate->prereq)==pTemplate->prereq + ){ + break; + } + + /* If existing WhereLoop p is better than pTemplate, pTemplate can be + ** discarded. WhereLoop p is better if: + ** (1) p has no more dependencies than pTemplate, and + ** (2) p has an equal or lower cost than pTemplate + */ + if( (p->prereq & pTemplate->prereq)==p->prereq /* (1) */ + && p->rSetup<=pTemplate->rSetup /* (2a) */ + && p->rRun<=pTemplate->rRun /* (2b) */ + && p->nOut<=pTemplate->nOut /* (2c) */ + ){ + return 0; /* Discard pTemplate */ + } + + /* If pTemplate is always better than p, then cause p to be overwritten + ** with pTemplate. pTemplate is better than p if: + ** (1) pTemplate has no more dependences than p, and + ** (2) pTemplate has an equal or lower cost than p. + */ + if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */ + && p->rRun>=pTemplate->rRun /* (2a) */ + && p->nOut>=pTemplate->nOut /* (2b) */ + ){ + assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */ + break; /* Cause p to be overwritten by pTemplate */ + } + } + return ppPrev; +} + /* ** Insert or replace a WhereLoop entry using the template supplied. ** @@ -3717,25 +4089,23 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** fewer dependencies than the template. Otherwise a new WhereLoop is ** added based on the template. ** -** If pBuilder->pOrSet is not NULL then we only care about only the +** If pBuilder->pOrSet is not NULL then we care about only the ** prerequisites and rRun and nOut costs of the N best loops. That ** information is gathered in the pBuilder->pOrSet object. This special ** processing mode is used only for OR clause processing. ** ** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we ** still might overwrite similar loops with the new template if the -** template is better. Loops may be overwritten if the following +** new template is better. Loops may be overwritten if the following ** conditions are met: ** ** (1) They have the same iTab. ** (2) They have the same iSortIdx. ** (3) The template has same or fewer dependencies than the current loop ** (4) The template has the same or lower cost than the current loop -** (5) The template uses more terms of the same index but has no additional -** dependencies */ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ - WhereLoop **ppPrev, *p, *pNext = 0; + WhereLoop **ppPrev, *p; WhereInfo *pWInfo = pBuilder->pWInfo; sqlite3 *db = pWInfo->pParse->db; @@ -3758,64 +4128,23 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ return SQLITE_OK; } - /* Search for an existing WhereLoop to overwrite, or which takes - ** priority over pTemplate. + /* Look for an existing WhereLoop to replace with pTemplate */ - for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){ - if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){ - /* If either the iTab or iSortIdx values for two WhereLoop are different - ** then those WhereLoops need to be considered separately. Neither is - ** a candidate to replace the other. */ - continue; - } - /* In the current implementation, the rSetup value is either zero - ** or the cost of building an automatic index (NlogN) and the NlogN - ** is the same for compatible WhereLoops. */ - assert( p->rSetup==0 || pTemplate->rSetup==0 - || p->rSetup==pTemplate->rSetup ); + whereLoopAdjustCost(pWInfo->pLoops, pTemplate); + ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate); - /* whereLoopAddBtree() always generates and inserts the automatic index - ** case first. Hence compatible candidate WhereLoops never have a larger - ** rSetup. Call this SETUP-INVARIANT */ - assert( p->rSetup>=pTemplate->rSetup ); - - if( (p->prereq & pTemplate->prereq)==p->prereq - && p->rSetup<=pTemplate->rSetup - && p->rRun<=pTemplate->rRun - && p->nOut<=pTemplate->nOut - ){ - /* This branch taken when p is equal or better than pTemplate in - ** all of (1) dependencies (2) setup-cost, (3) run-cost, and - ** (4) number of output rows. */ - assert( p->rSetup==pTemplate->rSetup ); - if( p->prereq==pTemplate->prereq - && p->nLTermnLTerm - && (p->wsFlags & pTemplate->wsFlags & WHERE_INDEXED)!=0 - && (p->u.btree.pIndex==pTemplate->u.btree.pIndex - || pTemplate->rRun+p->nLTerm<=p->rRun+pTemplate->nLTerm) - ){ - /* Overwrite an existing WhereLoop with an similar one that uses - ** more terms of the index */ - pNext = p->pNextLoop; - break; - }else{ - /* pTemplate is not helpful. - ** Return without changing or adding anything */ - goto whereLoopInsert_noop; - } - } - if( (p->prereq & pTemplate->prereq)==pTemplate->prereq - && p->rRun>=pTemplate->rRun - && p->nOut>=pTemplate->nOut - ){ - /* Overwrite an existing WhereLoop with a better one: one that is - ** better at one of (1) dependencies, (2) setup-cost, (3) run-cost - ** or (4) number of output rows, and is no worse in any of those - ** categories. */ - assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */ - pNext = p->pNextLoop; - break; + if( ppPrev==0 ){ + /* There already exists a WhereLoop on the list that is better + ** than pTemplate, so just ignore pTemplate */ +#if WHERETRACE_ENABLED /* 0x8 */ + if( sqlite3WhereTrace & 0x8 ){ + sqlite3DebugPrintf("ins-noop: "); + whereLoopPrint(pTemplate, pBuilder->pWC); } +#endif + return SQLITE_OK; + }else{ + p = *ppPrev; } /* If we reach this point it means that either p[] should be overwritten @@ -3833,13 +4162,33 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ } #endif if( p==0 ){ - p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); + /* Allocate a new WhereLoop to add to the end of the list */ + *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); if( p==0 ) return SQLITE_NOMEM; whereLoopInit(p); + p->pNextLoop = 0; + }else{ + /* We will be overwriting WhereLoop p[]. But before we do, first + ** go through the rest of the list and delete any other entries besides + ** p[] that are also supplated by pTemplate */ + WhereLoop **ppTail = &p->pNextLoop; + WhereLoop *pToDel; + while( *ppTail ){ + ppTail = whereLoopFindLesser(ppTail, pTemplate); + if( ppTail==0 ) break; + pToDel = *ppTail; + if( pToDel==0 ) break; + *ppTail = pToDel->pNextLoop; +#if WHERETRACE_ENABLED /* 0x8 */ + if( sqlite3WhereTrace & 0x8 ){ + sqlite3DebugPrintf("ins-del: "); + whereLoopPrint(pToDel, pBuilder->pWC); + } +#endif + whereLoopDelete(db, pToDel); + } } whereLoopXfer(db, p, pTemplate); - p->pNextLoop = pNext; - *ppPrev = p; if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ Index *pIndex = p->u.btree.pIndex; if( pIndex && pIndex->tnum==0 ){ @@ -3847,16 +4196,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ } } return SQLITE_OK; - - /* Jump here if the insert is a no-op */ -whereLoopInsert_noop: -#if WHERETRACE_ENABLED /* 0x8 */ - if( sqlite3WhereTrace & 0x8 ){ - sqlite3DebugPrintf("ins-noop: "); - whereLoopPrint(pTemplate, pBuilder->pWC); - } -#endif - return SQLITE_OK; } /* @@ -3886,13 +4225,30 @@ static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){ if( pX==pTerm ) break; if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; } - if( j<0 ) pLoop->nOut += pTerm->truthProb; + if( j<0 ){ + pLoop->nOut += (pTerm->truthProb<=0 ? pTerm->truthProb : -1); + } } } /* -** We have so far matched pBuilder->pNew->u.btree.nEq terms of the index pIndex. -** Try to match one more. +** Adjust the cost C by the costMult facter T. This only occurs if +** compiled with -DSQLITE_ENABLE_COSTMULT +*/ +#ifdef SQLITE_ENABLE_COSTMULT +# define ApplyCostMultiplier(C,T) C += T +#else +# define ApplyCostMultiplier(C,T) +#endif + +/* +** We have so far matched pBuilder->pNew->u.btree.nEq terms of the +** index pIndex. Try to match one more. +** +** When this function is called, pBuilder->pNew->nOut contains the +** number of rows expected to be visited by filtering using the nEq +** terms only. If it is modified, this value is restored before this +** function returns. ** ** If pProbe->tnum==0, that means pIndex is a fake index used for the ** INTEGER PRIMARY KEY. @@ -3918,7 +4274,6 @@ static int whereLoopAddBtreeIndex( LogEst saved_nOut; /* Original value of pNew->nOut */ int iCol; /* Index of the column in the table */ int rc = SQLITE_OK; /* Return code */ - LogEst nRowEst; /* Estimated index selectivity */ LogEst rLogSize; /* Logarithm of table size */ WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ @@ -3936,15 +4291,9 @@ static int whereLoopAddBtreeIndex( } if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); - assert( pNew->u.btree.nEq<=pProbe->nKeyCol ); - if( pNew->u.btree.nEq < pProbe->nKeyCol ){ - iCol = pProbe->aiColumn[pNew->u.btree.nEq]; - nRowEst = sqlite3LogEst(pProbe->aiRowEst[pNew->u.btree.nEq+1]); - if( nRowEst==0 && pProbe->onError==OE_None ) nRowEst = 1; - }else{ - iCol = -1; - nRowEst = 0; - } + assert( pNew->u.btree.nEqnColumn ); + iCol = pProbe->aiColumn[pNew->u.btree.nEq]; + pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, opMask, pProbe); saved_nEq = pNew->u.btree.nEq; @@ -3954,18 +4303,23 @@ static int whereLoopAddBtreeIndex( saved_prereq = pNew->prereq; saved_nOut = pNew->nOut; pNew->rSetup = 0; - rLogSize = estLog(sqlite3LogEst(pProbe->aiRowEst[0])); + rLogSize = estLog(pProbe->aiRowLogEst[0]); /* Consider using a skip-scan if there are no WHERE clause constraints ** available for the left-most terms of the index, and if the average - ** number of repeats in the left-most terms is at least 18. The magic - ** number 18 was found by experimentation to be the payoff point where - ** skip-scan become faster than a full-scan. - */ + ** number of repeats in the left-most terms is at least 18. + ** + ** The magic number 18 is selected on the basis that scanning 17 rows + ** is almost always quicker than an index seek (even though if the index + ** contains fewer than 2^17 rows we assume otherwise in other parts of + ** the code). And, even if it is not, it should not be too much slower. + ** On the other hand, the extra seeks could end up being significantly + ** more expensive. */ + assert( 42==sqlite3LogEst(18) ); if( pTerm==0 && saved_nEq==saved_nSkip && saved_nEq+1nKeyCol - && pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */ + && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK ){ LogEst nIter; @@ -3973,34 +4327,40 @@ static int whereLoopAddBtreeIndex( pNew->u.btree.nSkip++; pNew->aLTerm[pNew->nLTerm++] = 0; pNew->wsFlags |= WHERE_SKIPSCAN; - nIter = sqlite3LogEst(pProbe->aiRowEst[0]/pProbe->aiRowEst[saved_nEq+1]); - pNew->rRun = rLogSize + nIter; - pNew->nOut += nIter; - whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter); + nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1]; + pNew->nOut -= nIter; + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul); pNew->nOut = saved_nOut; } for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ + u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */ + LogEst rCostIdx; + LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */ int nIn = 0; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nRecValid = pBuilder->nRecValid; #endif - if( (pTerm->eOperator==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) + if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) && (iCol<0 || pSrc->pTab->aCol[iCol].notNull) ){ continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */ } if( pTerm->prereqRight & pNew->maskSelf ) continue; - assert( pNew->nOut==saved_nOut ); - pNew->wsFlags = saved_wsFlags; pNew->u.btree.nEq = saved_nEq; pNew->nLTerm = saved_nLTerm; if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ pNew->aLTerm[pNew->nLTerm++] = pTerm; pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf; - pNew->rRun = rLogSize; /* Baseline cost is log2(N). Adjustments below */ - if( pTerm->eOperator & WO_IN ){ + + assert( nInMul==0 + || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0 + || (pNew->wsFlags & WHERE_COLUMN_IN)!=0 + || (pNew->wsFlags & WHERE_SKIPSCAN)!=0 + ); + + if( eOp & WO_IN ){ Expr *pExpr = pTerm->pExpr; pNew->wsFlags |= WHERE_COLUMN_IN; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ @@ -4010,85 +4370,120 @@ static int whereLoopAddBtreeIndex( /* "x IN (value, value, ...)" */ nIn = sqlite3LogEst(pExpr->x.pList->nExpr); } - pNew->rRun += nIn; - pNew->u.btree.nEq++; - pNew->nOut = nRowEst + nInMul + nIn; - }else if( pTerm->eOperator & (WO_EQ) ){ - assert( - (pNew->wsFlags & (WHERE_COLUMN_NULL|WHERE_COLUMN_IN|WHERE_SKIPSCAN))!=0 - || nInMul==0 - ); + assert( nIn>0 ); /* RHS always has 2 or more terms... The parser + ** changes "x IN (?)" into "x=?". */ + + }else if( eOp & (WO_EQ) ){ pNew->wsFlags |= WHERE_COLUMN_EQ; - if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1)){ - assert( (pNew->wsFlags & WHERE_COLUMN_IN)==0 || iCol<0 ); - if( iCol>=0 && pProbe->onError==OE_None ){ + if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){ + if( iCol>=0 && !IsUniqueIndex(pProbe) ){ pNew->wsFlags |= WHERE_UNQ_WANTED; }else{ pNew->wsFlags |= WHERE_ONEROW; } } - pNew->u.btree.nEq++; - pNew->nOut = nRowEst + nInMul; - }else if( pTerm->eOperator & (WO_ISNULL) ){ + }else if( eOp & WO_ISNULL ){ pNew->wsFlags |= WHERE_COLUMN_NULL; - pNew->u.btree.nEq++; - /* TUNING: IS NULL selects 2 rows */ - nIn = 10; assert( 10==sqlite3LogEst(2) ); - pNew->nOut = nRowEst + nInMul + nIn; - }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ - testcase( pTerm->eOperator & WO_GT ); - testcase( pTerm->eOperator & WO_GE ); + }else if( eOp & (WO_GT|WO_GE) ){ + testcase( eOp & WO_GT ); + testcase( eOp & WO_GE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pBtm = pTerm; pTop = 0; }else{ - assert( pTerm->eOperator & (WO_LT|WO_LE) ); - testcase( pTerm->eOperator & WO_LT ); - testcase( pTerm->eOperator & WO_LE ); + assert( eOp & (WO_LT|WO_LE) ); + testcase( eOp & WO_LT ); + testcase( eOp & WO_LE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; pTop = pTerm; pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? pNew->aLTerm[pNew->nLTerm-2] : 0; } + + /* At this point pNew->nOut is set to the number of rows expected to + ** be visited by the index scan before considering term pTerm, or the + ** values of nIn and nInMul. In other words, assuming that all + ** "x IN(...)" terms are replaced with "x = ?". This block updates + ** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */ + assert( pNew->nOut==saved_nOut ); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ - /* Adjust nOut and rRun for STAT3 range values */ - assert( pNew->nOut==saved_nOut ); + /* Adjust nOut using stat3/stat4 data. Or, if there is no stat3/stat4 + ** data, using some other estimate. */ whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew); - } + }else{ + int nEq = ++pNew->u.btree.nEq; + assert( eOp & (WO_ISNULL|WO_EQ|WO_IN) ); + + assert( pNew->nOut==saved_nOut ); + if( pTerm->truthProb<=0 && iCol>=0 ){ + assert( (eOp & WO_IN) || nIn==0 ); + testcase( eOp & WO_IN ); + pNew->nOut += pTerm->truthProb; + pNew->nOut -= nIn; + }else{ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - if( nInMul==0 - && pProbe->nSample - && pNew->u.btree.nEq<=pProbe->nSampleCol - && OptimizationEnabled(db, SQLITE_Stat3) - ){ - Expr *pExpr = pTerm->pExpr; - tRowcnt nOut = 0; - if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){ - testcase( pTerm->eOperator & WO_EQ ); - testcase( pTerm->eOperator & WO_ISNULL ); - rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); - }else if( (pTerm->eOperator & WO_IN) - && !ExprHasProperty(pExpr, EP_xIsSelect) ){ - rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut); - } - assert( nOut==0 || rc==SQLITE_OK ); - if( nOut ){ - pNew->nOut = sqlite3LogEst(nOut); - if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut; - } - } + tRowcnt nOut = 0; + if( nInMul==0 + && pProbe->nSample + && pNew->u.btree.nEq<=pProbe->nSampleCol + && OptimizationEnabled(db, SQLITE_Stat3) + && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) + ){ + Expr *pExpr = pTerm->pExpr; + if( (eOp & (WO_EQ|WO_ISNULL))!=0 ){ + testcase( eOp & WO_EQ ); + testcase( eOp & WO_ISNULL ); + rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); + }else{ + rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut); + } + if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; + if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */ + if( nOut ){ + pNew->nOut = sqlite3LogEst(nOut); + if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut; + pNew->nOut -= nIn; + } + } + if( nOut==0 ) #endif - if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ - /* Each row involves a step of the index, then a binary search of - ** the main table */ - pNew->rRun = sqlite3LogEstAdd(pNew->rRun,rLogSize>27 ? rLogSize-17 : 10); + { + pNew->nOut += (pProbe->aiRowLogEst[nEq] - pProbe->aiRowLogEst[nEq-1]); + if( eOp & WO_ISNULL ){ + /* TUNING: If there is no likelihood() value, assume that a + ** "col IS NULL" expression matches twice as many rows + ** as (col=?). */ + pNew->nOut += 10; + } + } + } } - /* Step cost for each output row */ - pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut); + + /* Set rCostIdx to the cost of visiting selected rows in index. Add + ** it to pNew->rRun, which is currently set to the cost of the index + ** seek only. Then, if this is a non-covering index, add the cost of + ** visiting the rows in the main table. */ + rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; + pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx); + if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ + pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16); + } + ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult); + + nOutUnadjusted = pNew->nOut; + pNew->rRun += nInMul + nIn; + pNew->nOut += nInMul + nIn; whereLoopOutputAdjust(pBuilder->pWC, pNew); rc = whereLoopInsert(pBuilder, pNew); + + if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ + pNew->nOut = saved_nOut; + }else{ + pNew->nOut = nOutUnadjusted; + } + if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 - && pNew->u.btree.nEq<(pProbe->nKeyCol + (pProbe->zName!=0)) + && pNew->u.btree.nEqnColumn ){ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); } @@ -4170,6 +4565,37 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){ ** Add all WhereLoop objects for a single table of the join where the table ** is idenfied by pBuilder->pNew->iTab. That table is guaranteed to be ** a b-tree table, not a virtual table. +** +** The costs (WhereLoop.rRun) of the b-tree loops added by this function +** are calculated as follows: +** +** For a full scan, assuming the table (or index) contains nRow rows: +** +** cost = nRow * 3.0 // full-table scan +** cost = nRow * K // scan of covering index +** cost = nRow * (K+3.0) // scan of non-covering index +** +** where K is a value between 1.1 and 3.0 set based on the relative +** estimated average size of the index and table records. +** +** For an index scan, where nVisit is the number of index rows visited +** by the scan, and nSeek is the number of seek operations required on +** the index b-tree: +** +** cost = nSeek * (log(nRow) + K * nVisit) // covering index +** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index +** +** Normally, nSeek is 1. nSeek values greater than 1 come about if the +** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when +** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans. +** +** The estimated values (nRow, nVisit, nSeek) often contain a large amount +** of uncertainty. For this reason, scoring is designed to pick plans that +** "do the least harm" if the estimates are inaccurate. For example, a +** log(nRow) factor is omitted from a non-covering index scan in order to +** bias the scoring in favor of using an index, since the worst-case +** performance of using an index is far better than the worst-case performance +** of a full table scan. */ static int whereLoopAddBtree( WhereLoopBuilder *pBuilder, /* WHERE clause information */ @@ -4178,7 +4604,7 @@ static int whereLoopAddBtree( WhereInfo *pWInfo; /* WHERE analysis context */ Index *pProbe; /* An index we are evaluating */ Index sPk; /* A fake index object for the primary key */ - tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ + LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */ i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */ SrcList *pTabList; /* The FROM clause */ struct SrcList_item *pSrc; /* The FROM clause btree term to add */ @@ -4212,12 +4638,14 @@ static int whereLoopAddBtree( Index *pFirst; /* First of real indices on the table */ memset(&sPk, 0, sizeof(Index)); sPk.nKeyCol = 1; + sPk.nColumn = 1; sPk.aiColumn = &aiColumnPk; - sPk.aiRowEst = aiRowEstPk; + sPk.aiRowLogEst = aiRowEstPk; sPk.onError = OE_Replace; sPk.pTable = pTab; - aiRowEstPk[0] = pTab->nRowEst; - aiRowEstPk[1] = 1; + sPk.szIdxRow = pTab->szTabRow; + aiRowEstPk[0] = pTab->nRowLogEst; + aiRowEstPk[1] = 0; pFirst = pSrc->pTab->pIndex; if( pSrc->notIndexed==0 ){ /* The real indices of the table are only considered if the @@ -4226,7 +4654,7 @@ static int whereLoopAddBtree( } pProbe = &sPk; } - rSize = sqlite3LogEst(pTab->nRowEst); + rSize = pTab->nRowLogEst; rLogSize = estLog(rSize); #ifndef SQLITE_OMIT_AUTOMATIC_INDEX @@ -4255,6 +4683,7 @@ static int whereLoopAddBtree( ** approximately 7*N*log2(N) where N is the number of rows in ** the table being indexed. */ pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) ); + ApplyCostMultiplier(pNew->rSetup, pTab->costMult); /* TUNING: Each index lookup yields 20 rows in the table. This ** is more than the usual guess of 10 rows, since we have no way ** of knowning how selective the index will ultimately be. It would @@ -4276,6 +4705,7 @@ static int whereLoopAddBtree( && !whereUsablePartialIndex(pNew->iTab, pWC, pProbe->pPartIdxWhere) ){ continue; /* Partial index inappropriate for this query */ } + rSize = pProbe->aiRowLogEst[0]; pNew->u.btree.nEq = 0; pNew->u.btree.nSkip = 0; pNew->nLTerm = 0; @@ -4293,10 +4723,9 @@ static int whereLoopAddBtree( /* Full table scan */ pNew->iSortIdx = b ? iSortIdx : 0; - /* TUNING: Cost of full table scan is 3*(N + log2(N)). - ** + The extra 3 factor is to encourage the use of indexed lookups - ** over full scans. FIXME */ - pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 16; + /* TUNING: Cost of full table scan is (N*3.0). */ + pNew->rRun = rSize + 16; + ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; @@ -4323,19 +4752,16 @@ static int whereLoopAddBtree( ) ){ pNew->iSortIdx = b ? iSortIdx : 0; - if( m==0 ){ - /* TUNING: Cost of a covering index scan is K*(N + log2(N)). - ** + The extra factor K of between 1.1 and 3.0 that depends - ** on the relative sizes of the table and the index. K - ** is smaller for smaller indices, thus favoring them. - */ - pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 1 + - (15*pProbe->szIdxRow)/pTab->szTabRow; - }else{ - /* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N) - ** which we will simplify to just N*log2(N) */ - pNew->rRun = rSize + rLogSize; + + /* The cost of visiting the index rows is N*K, where K is + ** between 1.1 and 3.0, depending on the relative sizes of the + ** index and table rows. If this is a non-covering index scan, + ** also add the cost of visiting table rows (N*3.0). */ + pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow; + if( m!=0 ){ + pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16); } + ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; @@ -4506,8 +4932,8 @@ static int whereLoopAddVirtual( pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; pIdxInfo->needToFreeIdxStr = 0; pNew->u.vtab.idxStr = pIdxInfo->idxStr; - pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0) - && pIdxInfo->orderByConsumed); + pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? + pIdxInfo->nOrderBy : 0); pNew->rSetup = 0; pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); @@ -4539,7 +4965,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ int iCur; WhereClause tempWC; WhereLoopBuilder sSubBuild; - WhereOrSet sSum, sCur, sPrev; + WhereOrSet sSum, sCur; struct SrcList_item *pItem; pWC = pBuilder->pWC; @@ -4548,7 +4974,6 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ pNew = pBuilder->pNew; memset(&sSum, 0, sizeof(sSum)); pItem = pWInfo->pTabList->a + pNew->iTab; - if( !HasRowid(pItem->pTab) ) return SQLITE_OK; iCur = pItem->iCursor; for(pTerm=pWC->a; pTermiSortIdx = 0; memset(&pNew->u, 0, sizeof(pNew->u)); for(i=0; rc==SQLITE_OK && irRun = sSum.a[i].rRun + 18; + /* TUNING: Currently sSum.a[i].rRun is set to the sum of the costs + ** of all sub-scans required by the OR-scan. However, due to rounding + ** errors, it may be that the cost of the OR-scan is equal to its + ** most expensive sub-scan. Add the smallest possible penalty + ** (equivalent to multiplying the cost by 1.07) to ensure that + ** this does not happen. Otherwise, for WHERE clauses such as the + ** following where there is an index on "y": + ** + ** WHERE likelihood(x=?, 0.99) OR y=? + ** + ** the planner may elect to "OR" together a full-table scan and an + ** index lookup. And other similarly odd results. */ + pNew->rRun = sSum.a[i].rRun + 1; pNew->nOut = sSum.a[i].nOut; pNew->prereq = sSum.a[i].prereq; rc = whereLoopInsert(pBuilder, pNew); @@ -4668,21 +5105,21 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ /* ** Examine a WherePath (with the addition of the extra WhereLoop of the 5th ** parameters) to see if it outputs rows in the requested ORDER BY -** (or GROUP BY) without requiring a separate sort operation. Return: +** (or GROUP BY) without requiring a separate sort operation. Return N: ** -** 0: ORDER BY is not satisfied. Sorting required -** 1: ORDER BY is satisfied. Omit sorting -** -1: Unknown at this time +** N>0: N terms of the ORDER BY clause are satisfied +** N==0: No terms of the ORDER BY clause are satisfied +** N<0: Unknown yet how many terms of ORDER BY might be satisfied. ** ** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as ** strict. With GROUP BY and DISTINCT the only requirement is that ** equivalent rows appear immediately adjacent to one another. GROUP BY -** and DISTINT do not require rows to appear in any particular order as long +** and DISTINCT do not require rows to appear in any particular order as long ** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT ** the pOrderBy terms can be matched in any order. With ORDER BY, the ** pOrderBy terms must be matched in strict left-to-right order. */ -static int wherePathSatisfiesOrderBy( +static i8 wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ WherePath *pPath, /* The WherePath to check */ @@ -4738,14 +5175,6 @@ static int wherePathSatisfiesOrderBy( */ assert( pOrderBy!=0 ); - - /* Sortability of virtual tables is determined by the xBestIndex method - ** of the virtual table itself */ - if( pLast->wsFlags & WHERE_VIRTUALTABLE ){ - testcase( nLoop>0 ); /* True when outer loops are one-row and match - ** no ORDER BY terms */ - return pLast->u.vtab.isOrdered; - } if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0; nOrderBy = pOrderBy->nExpr; @@ -4758,7 +5187,10 @@ static int wherePathSatisfiesOrderBy( for(iLoop=0; isOrderDistinct && obSat0 ) ready |= pLoop->maskSelf; pLoop = iLoopaLoop[iLoop] : pLast; - assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); + if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ + if( pLoop->u.vtab.isOrdered ) obSat = obDone; + break; + } iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; /* Mark off any ORDER BY term X that is a column in the table of @@ -4799,7 +5231,7 @@ static int wherePathSatisfiesOrderBy( nColumn = pIndex->nColumn; assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); assert( pIndex->aiColumn[nColumn-1]==(-1) || !HasRowid(pIndex->pTable)); - isOrderDistinct = pIndex->onError!=OE_None; + isOrderDistinct = IsUniqueIndex(pIndex); } /* Loop through all columns of the index and deal with the ones @@ -4846,7 +5278,7 @@ static int wherePathSatisfiesOrderBy( } /* Find the ORDER BY term that corresponds to the j-th column - ** of the index and and mark that ORDER BY term off + ** of the index and mark that ORDER BY term off */ bOnce = 1; isMatch = 0; @@ -4867,23 +5299,23 @@ static int wherePathSatisfiesOrderBy( isMatch = 1; break; } + if( isMatch && (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ + /* Make sure the sort order is compatible in an ORDER BY clause. + ** Sort order is irrelevant for a GROUP BY clause. */ + if( revSet ){ + if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0; + }else{ + rev = revIdx ^ pOrderBy->a[i].sortOrder; + if( rev ) *pRevMask |= MASKBIT(iLoop); + revSet = 1; + } + } if( isMatch ){ if( iColumn<0 ){ testcase( distinctColumns==0 ); distinctColumns = 1; } obSat |= MASKBIT(i); - if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ - /* Make sure the sort order is compatible in an ORDER BY clause. - ** Sort order is irrelevant for a GROUP BY clause. */ - if( revSet ){ - if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) return 0; - }else{ - rev = revIdx ^ pOrderBy->a[i].sortOrder; - if( rev ) *pRevMask |= MASKBIT(iLoop); - revSet = 1; - } - } }else{ /* No match found */ if( j==0 || j0; i--){ + Bitmask m = MASKBIT(i) - 1; + if( (obSat&m)==m ) return i; + } + return 0; + } return -1; } + +/* +** If the WHERE_GROUPBY flag is set in the mask passed to sqlite3WhereBegin(), +** the planner assumes that the specified pOrderBy list is actually a GROUP +** BY clause - and so any order that groups rows as required satisfies the +** request. +** +** Normally, in this case it is not possible for the caller to determine +** whether or not the rows are really being delivered in sorted order, or +** just in some other order that provides the required grouping. However, +** if the WHERE_SORTBYGROUP flag is also passed to sqlite3WhereBegin(), then +** this function may be called on the returned WhereInfo object. It returns +** true if the rows really will be sorted in the specified order, or false +** otherwise. +** +** For example, assuming: +** +** CREATE INDEX i1 ON t1(x, Y); +** +** then +** +** SELECT * FROM t1 GROUP BY x,y ORDER BY x,y; -- IsSorted()==1 +** SELECT * FROM t1 GROUP BY y,x ORDER BY y,x; -- IsSorted()==0 +*/ +int sqlite3WhereIsSorted(WhereInfo *pWInfo){ + assert( pWInfo->wctrlFlags & WHERE_GROUPBY ); + assert( pWInfo->wctrlFlags & WHERE_SORTBYGROUP ); + return pWInfo->sorted; +} + #ifdef WHERETRACE_ENABLED /* For debugging use only: */ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ @@ -4932,6 +5400,44 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ } #endif +/* +** Return the cost of sorting nRow rows, assuming that the keys have +** nOrderby columns and that the first nSorted columns are already in +** order. +*/ +static LogEst whereSortingCost( + WhereInfo *pWInfo, + LogEst nRow, + int nOrderBy, + int nSorted +){ + /* TUNING: Estimated cost of a full external sort, where N is + ** the number of rows to sort is: + ** + ** cost = (3.0 * N * log(N)). + ** + ** Or, if the order-by clause has X terms but only the last Y + ** terms are out of order, then block-sorting will reduce the + ** sorting cost to: + ** + ** cost = (3.0 * N * log(N)) * (Y/X) + ** + ** The (Y/X) term is implemented using stack variable rScale + ** below. */ + LogEst rScale, rSortCost; + assert( nOrderBy>0 && 66==sqlite3LogEst(100) ); + rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66; + rSortCost = nRow + estLog(nRow) + rScale + 16; + + /* TUNING: The cost of implementing DISTINCT using a B-TREE is + ** similar but with a larger constant of proportionality. + ** Multiply by an additional factor of 3.0. */ + if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ + rSortCost += 16; + } + + return rSortCost; +} /* ** Given the list of WhereLoop objects at pWInfo->pLoops, this routine @@ -4953,11 +5459,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ int mxI = 0; /* Index of next entry to replace */ - LogEst rCost; /* Cost of a path */ - LogEst nOut; /* Number of outputs */ + int nOrderBy; /* Number of ORDER BY clause terms */ LogEst mxCost = 0; /* Maximum cost of a set of paths */ - LogEst mxOut = 0; /* Maximum nOut value on the set of paths */ - LogEst rSortCost; /* Cost to do a sort */ + LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ WherePath *aTo; /* The nTo best paths at the current level */ @@ -4965,7 +5469,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ WherePath *pTo; /* An element of aTo[] that we are working on */ WhereLoop *pWLoop; /* One of the WhereLoop objects */ WhereLoop **pX; /* Used to divy up the pSpace memory */ + LogEst *aSortCost = 0; /* Sorting and partial sorting costs */ char *pSpace; /* Temporary memory used by this routine */ + int nSpace; /* Bytes of space allocated at pSpace */ pParse = pWInfo->pParse; db = pParse->db; @@ -4973,13 +5479,25 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ /* TUNING: For simple queries, only the best path is tracked. ** For 2-way joins, the 5 best paths are followed. ** For joins of 3 or more tables, track the 10 best paths */ - mxChoice = (nLoop==1) ? 1 : (nLoop==2 ? 5 : 10); + mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10); assert( nLoop<=pWInfo->pTabList->nSrc ); - WHERETRACE(0x002, ("---- begin solver\n")); + WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst)); - /* Allocate and initialize space for aTo and aFrom */ - ii = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; - pSpace = sqlite3DbMallocRaw(db, ii); + /* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this + ** case the purpose of this call is to estimate the number of rows returned + ** by the overall query. Once this estimate has been obtained, the caller + ** will invoke this function a second time, passing the estimate as the + ** nRowEst parameter. */ + if( pWInfo->pOrderBy==0 || nRowEst==0 ){ + nOrderBy = 0; + }else{ + nOrderBy = pWInfo->pOrderBy->nExpr; + } + + /* Allocate and initialize space for aTo, aFrom and aSortCost[] */ + nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; + nSpace += sizeof(LogEst) * nOrderBy; + pSpace = sqlite3DbMallocRaw(db, nSpace); if( pSpace==0 ) return SQLITE_NOMEM; aTo = (WherePath*)pSpace; aFrom = aTo+mxChoice; @@ -4988,6 +5506,18 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ for(ii=mxChoice*2, pFrom=aTo; ii>0; ii--, pFrom++, pX += nLoop){ pFrom->aLoop = pX; } + if( nOrderBy ){ + /* If there is an ORDER BY clause and it is not being ignored, set up + ** space for the aSortCost[] array. Each element of the aSortCost array + ** is either zero - meaning it has not yet been initialized - or the + ** cost of sorting nRowEst rows of data where the first X terms of + ** the ORDER BY clause are already in order, where X is the array + ** index. */ + aSortCost = (LogEst*)pX; + memset(aSortCost, 0, sizeof(LogEst) * nOrderBy); + } + assert( aSortCost==0 || &pSpace[nSpace]==(char*)&aSortCost[nOrderBy] ); + assert( aSortCost!=0 || &pSpace[nSpace]==(char*)pX ); /* Seed the search with a single WherePath containing zero WhereLoops. ** @@ -4996,19 +5526,15 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ ** rows, then do not use the automatic index. */ aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) ); nFrom = 1; - - /* Precompute the cost of sorting the final result set, if the caller - ** to sqlite3WhereBegin() was concerned about sorting */ - rSortCost = 0; - if( pWInfo->pOrderBy==0 || nRowEst==0 ){ - aFrom[0].isOrderedValid = 1; - }else{ - /* TUNING: Estimated cost of sorting is 48*N*log2(N) where N is the - ** number of output rows. The 48 is the expected size of a row to sort. - ** FIXME: compute a better estimate of the 48 multiplier based on the - ** result set expressions. */ - rSortCost = nRowEst + estLog(nRowEst); - WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost)); + assert( aFrom[0].isOrdered==0 ); + if( nOrderBy ){ + /* If nLoop is zero, then there are no FROM terms in the query. Since + ** in this case the query may return a maximum of one row, the results + ** are already in the requested order. Set isOrdered to nOrderBy to + ** indicate this. Or, if nLoop is greater than zero, set isOrdered to + ** -1, indicating that the result set may or may not be ordered, + ** depending on the loops added to the current plan. */ + aFrom[0].isOrdered = nLoop>0 ? -1 : nOrderBy; } /* Compute successively longer WherePaths using the previous generation @@ -5018,60 +5544,82 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ nTo = 0; for(ii=0, pFrom=aFrom; iipLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ - Bitmask maskNew; - Bitmask revMask = 0; - u8 isOrderedValid = pFrom->isOrderedValid; - u8 isOrdered = pFrom->isOrdered; + LogEst nOut; /* Rows visited by (pFrom+pWLoop) */ + LogEst rCost; /* Cost of path (pFrom+pWLoop) */ + LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */ + i8 isOrdered = pFrom->isOrdered; /* isOrdered for (pFrom+pWLoop) */ + Bitmask maskNew; /* Mask of src visited by (..) */ + Bitmask revMask = 0; /* Mask of rev-order loops for (..) */ + if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; /* At this point, pWLoop is a candidate to be the next loop. ** Compute its cost */ - rCost = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); - rCost = sqlite3LogEstAdd(rCost, pFrom->rCost); + rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); + rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted); nOut = pFrom->nRow + pWLoop->nOut; maskNew = pFrom->maskLoop | pWLoop->maskSelf; - if( !isOrderedValid ){ - switch( wherePathSatisfiesOrderBy(pWInfo, + if( isOrdered<0 ){ + isOrdered = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags, - iLoop, pWLoop, &revMask) ){ - case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */ - isOrdered = 1; - isOrderedValid = 1; - break; - case 0: /* No. pFrom+pWLoop will require a separate sort */ - isOrdered = 0; - isOrderedValid = 1; - rCost = sqlite3LogEstAdd(rCost, rSortCost); - break; - default: /* Cannot tell yet. Try again on the next iteration */ - break; - } + iLoop, pWLoop, &revMask); }else{ revMask = pFrom->revLoop; } - /* Check to see if pWLoop should be added to the mxChoice best so far */ + if( isOrdered>=0 && isOrderedisOrdered^isOrdered)&0x80)==0" is equivalent + ** to (pTo->isOrdered==(-1))==(isOrdered==(-1))" for the range + ** of legal values for isOrdered, -1..64. + */ for(jj=0, pTo=aTo; jjmaskLoop==maskNew - && pTo->isOrderedValid==isOrderedValid - && ((pTo->rCost<=rCost && pTo->nRow<=nOut) || - (pTo->rCost>=rCost && pTo->nRow>=nOut)) + && ((pTo->isOrdered^isOrdered)&0x80)==0 ){ testcase( jj==nTo-1 ); break; } } if( jj>=nTo ){ - if( nTo>=mxChoice && rCost>=mxCost ){ + /* None of the existing best-so-far paths match the candidate. */ + if( nTo>=mxChoice + && (rCost>mxCost || (rCost==mxCost && rUnsorted>=mxUnsorted)) + ){ + /* The current candidate is no better than any of the mxChoice + ** paths currently in the best-so-far buffer. So discard + ** this candidate as not viable. */ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, - isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); + isOrdered>=0 ? isOrdered+'0' : '?'); } #endif continue; } - /* Add a new Path to the aTo[] set */ + /* If we reach this points it means that the new candidate path + ** needs to be added to the set of best-so-far paths. */ if( nTo=0 ? isOrdered+'0' : '?'); } #endif }else{ - if( pTo->rCost<=rCost && pTo->nRow<=nOut ){ + /* Control reaches here if best-so-far path pTo=aTo[jj] covers the + ** same set of loops and has the sam isOrdered setting as the + ** candidate path. Check to see if the candidate should replace + ** pTo or if the candidate should be skipped */ + if( pTo->rCostrCost==rCost && pTo->nRow<=nOut) ){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Skip %s cost=%-3d,%3d order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, - isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); + isOrdered>=0 ? isOrdered+'0' : '?'); sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); + pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif + /* Discard the candidate path from further consideration */ testcase( pTo->rCost==rCost ); continue; } testcase( pTo->rCost==rCost+1 ); - /* A new and better score for a previously created equivalent path */ + /* Control reaches here if the candidate path is better than the + ** pTo path. Replace pTo with the candidate. */ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Update %s cost=%-3d,%3d order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, - isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); + isOrdered>=0 ? isOrdered+'0' : '?'); sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); + pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif } @@ -5122,18 +5676,20 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pTo->revLoop = revMask; pTo->nRow = nOut; pTo->rCost = rCost; - pTo->isOrderedValid = isOrderedValid; + pTo->rUnsorted = rUnsorted; pTo->isOrdered = isOrdered; memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop); pTo->aLoop[iLoop] = pWLoop; if( nTo>=mxChoice ){ mxI = 0; mxCost = aTo[0].rCost; - mxOut = aTo[0].nRow; + mxUnsorted = aTo[0].nRow; for(jj=1, pTo=&aTo[1]; jjrCost>mxCost || (pTo->rCost==mxCost && pTo->nRow>mxOut) ){ + if( pTo->rCost>mxCost + || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted) + ){ mxCost = pTo->rCost; - mxOut = pTo->nRow; + mxUnsorted = pTo->rUnsorted; mxI = jj; } } @@ -5147,8 +5703,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ for(ii=0, pTo=aTo; iirCost, pTo->nRow, - pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); - if( pTo->isOrderedValid && pTo->isOrdered ){ + pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?'); + if( pTo->isOrdered>0 ){ sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop); }else{ sqlite3DebugPrintf("\n"); @@ -5191,16 +5747,33 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ Bitmask notUsed; int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom, WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); - if( rc==1 ) pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; - } - if( pFrom->isOrdered ){ - if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ + if( rc==pWInfo->pResultSet->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; - }else{ - pWInfo->bOBSat = 1; - pWInfo->revMask = pFrom->revLoop; } } + if( pWInfo->pOrderBy ){ + if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ + if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ + pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; + } + }else{ + pWInfo->nOBSat = pFrom->isOrdered; + if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0; + pWInfo->revMask = pFrom->revLoop; + } + if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) + && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr + ){ + Bitmask notUsed = 0; + int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, + pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used + ); + assert( pWInfo->sorted==0 ); + pWInfo->sorted = (nOrder==pWInfo->pOrderBy->nExpr); + } + } + + pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ @@ -5254,7 +5827,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pLoop->aLTermSpace==pLoop->aLTerm ); assert( ArraySize(pLoop->aLTermSpace)==4 ); - if( pIdx->onError==OE_None + if( !IsUniqueIndex(pIdx) || pIdx->pPartIdxWhere!=0 || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) ) continue; @@ -5282,7 +5855,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur); pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; - if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1; + if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } @@ -5386,7 +5959,7 @@ WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ - ExprList *pOrderBy, /* An ORDER BY clause, or NULL */ + ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ ExprList *pResultSet, /* Result set of the query */ u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */ @@ -5408,6 +5981,10 @@ WhereInfo *sqlite3WhereBegin( /* Variable initialization */ db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); + + /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */ + testcase( pOrderBy && pOrderBy->nExpr==BMS-1 ); + if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0; sWLB.pOrderBy = pOrderBy; /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via @@ -5452,7 +6029,7 @@ WhereInfo *sqlite3WhereBegin( pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; pWInfo->pResultSet = pResultSet; - pWInfo->iBreak = sqlite3VdbeMakeLabel(v); + pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v); pWInfo->wctrlFlags = wctrlFlags; pWInfo->savedNQueryLoop = pParse->nQueryLoop; pMaskSet = &pWInfo->sMaskSet; @@ -5486,7 +6063,7 @@ WhereInfo *sqlite3WhereBegin( /* Special case: No FROM clause */ if( nTabList==0 ){ - if( pOrderBy ) pWInfo->bOBSat = 1; + if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr; if( wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } @@ -5597,8 +6174,8 @@ WhereInfo *sqlite3WhereBegin( if( sqlite3WhereTrace ){ int ii; sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); - if( pWInfo->bOBSat ){ - sqlite3DebugPrintf(" ORDERBY=0x%llx", pWInfo->revMask); + if( pWInfo->nOBSat>0 ){ + sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask); } switch( pWInfo->eDistinct ){ case WHERE_DISTINCT_UNIQUE: { @@ -5721,7 +6298,14 @@ WhereInfo *sqlite3WhereBegin( int op = OP_OpenRead; /* iIdxCur is always set if to a positive value if ONEPASS is possible */ assert( iIdxCur!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); - if( pWInfo->okOnePass ){ + if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx) + && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 + ){ + /* This is one term of an OR-optimization using the PRIMARY KEY of a + ** WITHOUT ROWID table. No need for a separate index */ + iIndexCur = pLevel->iTabCur; + op = 0; + }else if( pWInfo->okOnePass ){ Index *pJ = pTabItem->pTab->pIndex; iIndexCur = iIdxCur; assert( wctrlFlags & WHERE_ONEPASS_DESIRED ); @@ -5733,15 +6317,18 @@ WhereInfo *sqlite3WhereBegin( pWInfo->aiCurOnePass[1] = iIndexCur; }else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){ iIndexCur = iIdxCur; + if( wctrlFlags & WHERE_REOPEN_IDX ) op = OP_ReopenIdx; }else{ iIndexCur = pParse->nTab++; } pLevel->iIdxCur = iIndexCur; assert( pIx->pSchema==pTab->pSchema ); assert( iIndexCur>=0 ); - sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); - sqlite3VdbeSetP4KeyInfo(pParse, pIx); - VdbeComment((v, "%s", pIx->zName)); + if( op ){ + sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIx); + VdbeComment((v, "%s", pIx->zName)); + } } if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); notReady &= ~getMask(&pWInfo->sMaskSet, pTabItem->iCursor); diff --git a/src/whereInt.h b/src/whereInt.h index 23f929c..81f4a03 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -121,7 +121,7 @@ struct WhereLoop { struct { /* Information for virtual tables */ int idxNum; /* Index number */ u8 needFree; /* True if sqlite3_free(idxStr) is needed */ - u8 isOrdered; /* True if satisfies ORDER BY */ + i8 isOrdered; /* True if satisfies ORDER BY */ u16 omitMask; /* Terms that may be omitted */ char *idxStr; /* Index identifier string */ } vtab; @@ -183,8 +183,8 @@ struct WherePath { Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */ LogEst nRow; /* Estimated number of rows generated by this path */ LogEst rCost; /* Total cost of this path */ - u8 isOrdered; /* True if this path satisfies ORDER BY */ - u8 isOrderedValid; /* True if the isOrdered field is valid */ + LogEst rUnsorted; /* Total cost of this path ignoring sorting costs */ + i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */ WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */ }; @@ -398,7 +398,8 @@ struct WhereInfo { Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ LogEst nRowOut; /* Estimated number of output rows */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ - u8 bOBSat; /* ORDER BY satisfied by indices */ + i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ + u8 sorted; /* True if really sorted (not just grouped) */ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ diff --git a/test/alter.test b/test/alter.test index 557162f..ddf1698 100644 --- a/test/alter.test +++ b/test/alter.test @@ -875,4 +875,42 @@ do_execsql_test alter-16.2 { SELECT * FROM t16a_rn ORDER BY a; } {abc 1.25 99 xyzzy cba 5.5 98 fizzle} +#------------------------------------------------------------------------- +# Verify that NULL values into the internal-use-only sqlite_rename_*() +# functions do not cause problems. +# +do_execsql_test alter-17.1 { + SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)','abc'); +} {{CREATE TABLE "abc"(a,b,c)}} +do_execsql_test alter-17.2 { + SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)',NULL); +} {{CREATE TABLE "(NULL)"(a,b,c)}} +do_execsql_test alter-17.3 { + SELECT sqlite_rename_table(NULL,'abc'); +} {{}} +do_execsql_test alter-17.4 { + SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN','abc'); +} {{CREATE TRIGGER r1 ON "abc" WHEN}} +do_execsql_test alter-17.5 { + SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN',NULL); +} {{CREATE TRIGGER r1 ON "(NULL)" WHEN}} +do_execsql_test alter-17.6 { + SELECT sqlite_rename_trigger(NULL,'abc'); +} {{}} +do_execsql_test alter-17.7 { + SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")', + 'xyzzy','lmnop'); +} {{CREATE TABLE t1(a REFERENCES "lmnop")}} +do_execsql_test alter-17.8 { + SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")', + 'xyzzy',NULL); +} {{CREATE TABLE t1(a REFERENCES "(NULL)")}} +do_execsql_test alter-17.9 { + SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")', + NULL, 'lmnop'); +} {{}} +do_execsql_test alter-17.10 { + SELECT sqlite_rename_parent(NULL,'abc','xyz'); +} {{}} + finish_test diff --git a/test/analyze3.test b/test/analyze3.test index fb26303..e7416d5 100644 --- a/test/analyze3.test +++ b/test/analyze3.test @@ -103,12 +103,21 @@ do_test analyze3-1.1.1 { } } {1} +do_execsql_test analyze3-1.1.x { + SELECT count(*) FROM t1 WHERE x>200 AND x<300; + SELECT count(*) FROM t1 WHERE x>0 AND x<1100; +} {99 1000} + +# The first of the following two SELECT statements visits 99 rows. So +# it is better to use the index. But the second visits every row in +# the table (1000 in total) so it is better to do a full-table scan. +# do_eqp_test analyze3-1.1.2 { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x0 AND x<1100 -} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x200 AND x<300 } @@ -125,17 +134,17 @@ do_test analyze3-1.1.6 { } {199 0 14850} do_test analyze3-1.1.7 { sf_execsql { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 } -} {2000 0 499500} +} {999 999 499500} do_test analyze3-1.1.8 { set l [string range "0" 0 end] set u [string range "1100" 0 end] sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } -} {2000 0 499500} +} {999 999 499500} do_test analyze3-1.1.9 { set l [expr int(0)] set u [expr int(1100)] sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } -} {2000 0 499500} +} {999 999 499500} # The following tests are similar to the block above. The difference is @@ -152,12 +161,17 @@ do_test analyze3-1.2.1 { ANALYZE; } } {} +do_execsql_test analyze3-2.1.x { + SELECT count(*) FROM t2 WHERE x>1 AND x<2; + SELECT count(*) FROM t2 WHERE x>0 AND x<99; +} {200 990} do_eqp_test analyze3-1.2.2 { SELECT sum(y) FROM t2 WHERE x>1 AND x<2 } {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x0 AND x<99 -} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x12 AND x<20 } } {161 0 4760} @@ -173,17 +187,17 @@ do_test analyze3-1.2.6 { } {161 0 integer integer 4760} do_test analyze3-1.2.7 { sf_execsql { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 } -} {1981 0 490555} +} {999 999 490555} do_test analyze3-1.2.8 { set l [string range "0" 0 end] set u [string range "99" 0 end] sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} -} {1981 0 text text 490555} +} {999 999 text text 490555} do_test analyze3-1.2.9 { set l [expr int(0)] set u [expr int(99)] sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} -} {1981 0 integer integer 490555} +} {999 999 integer integer 490555} # Same tests a third time. This time, column x has INTEGER affinity and # is not the leftmost column of the table. This triggered a bug causing @@ -199,12 +213,16 @@ do_test analyze3-1.3.1 { ANALYZE; } } {} +do_execsql_test analyze3-1.3.x { + SELECT count(*) FROM t3 WHERE x>200 AND x<300; + SELECT count(*) FROM t3 WHERE x>0 AND x<1100 +} {99 1000} do_eqp_test analyze3-1.3.2 { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x0 AND x<1100 -} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x200 AND x<300 } @@ -221,17 +239,17 @@ do_test analyze3-1.3.6 { } {199 0 14850} do_test analyze3-1.3.7 { sf_execsql { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 } -} {2000 0 499500} +} {999 999 499500} do_test analyze3-1.3.8 { set l [string range "0" 0 end] set u [string range "1100" 0 end] sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } -} {2000 0 499500} +} {999 999 499500} do_test analyze3-1.3.9 { set l [expr int(0)] set u [expr int(1100)] sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } -} {2000 0 499500} +} {999 999 499500} #------------------------------------------------------------------------- # Test that the values of bound SQL variables may be used for the LIKE diff --git a/test/analyze6.test b/test/analyze6.test index f77f053..31ace8e 100644 --- a/test/analyze6.test +++ b/test/analyze6.test @@ -91,7 +91,7 @@ do_test analyze6-2.3 { } {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)}} do_test analyze6-2.4 { execsql { - INSERT INTO t201 VALUES(1,2,3); + INSERT INTO t201 VALUES(1,2,3),(2,3,4),(3,4,5); ANALYZE t201; } eqp {SELECT * FROM t201 WHERE z=5} diff --git a/test/analyze9.test b/test/analyze9.test index 820bcdb..0d72658 100644 --- a/test/analyze9.test +++ b/test/analyze9.test @@ -566,7 +566,7 @@ foreach {tn schema} { drop_all_tables do_test 13.1 { execsql { - CREATE TABLE t1(a, b, c); + CREATE TABLE t1(a, b, c, d); CREATE INDEX i1 ON t1(a); CREATE INDEX i2 ON t1(b, c); } @@ -577,16 +577,16 @@ do_test 13.1 { execsql ANALYZE } {} do_eqp_test 13.2.1 { - SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<20 + SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<12 } {/SEARCH TABLE t1 USING INDEX i1/} do_eqp_test 13.2.2 { - SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<20 + SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<12 } {/SEARCH TABLE t1 USING INDEX i1/} do_eqp_test 13.3.1 { - SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<20 + SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<12 } {/SEARCH TABLE t1 USING INDEX i2/} do_eqp_test 13.3.2 { - SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<20 + SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<12 } {/SEARCH TABLE t1 USING INDEX i2/} #------------------------------------------------------------------------- @@ -953,4 +953,139 @@ for {set i 0} {$i<16} {incr i} { } {1} } +#------------------------------------------------------------------------- +# +reset_db + +do_execsql_test 21.0 { + CREATE TABLE t2(a, b); + CREATE INDEX i2 ON t2(a); +} + +do_test 21.1 { + for {set i 1} {$i < 100} {incr i} { + execsql { + INSERT INTO t2 VALUES(CASE WHEN $i < 80 THEN 'one' ELSE 'two' END, $i) + } + } + execsql ANALYZE +} {} + +# Condition (a='one') matches 80% of the table. (rowid<10) reduces this to +# 10%, but (rowid<50) only reduces it to 50%. So in the first case below +# the index is used. In the second, it is not. +# +do_eqp_test 21.2 { + SELECT * FROM t2 WHERE a='one' AND rowid < 10 +} {/*USING INDEX i2 (a=? AND rowid45 AND x<96) THEN 'B' ELSE 'A' END, /* Column "a" */ + x, /* Column "b" */ + CASE WHEN (x<51) THEN 'one' ELSE 'two' END, /* Column "c" */ + x /* Column "d" */ + FROM r; + + CREATE INDEX i3 ON t3(c); + CREATE INDEX i4 ON t3(d); + ANALYZE; +} + +# Expression (c='one' AND a='B') matches 5 table rows. But (c='one' AND a=A') +# matches 45. Expression (d. AND a<...*/} +do_execsql_test 1.2 { + SELECT c FROM t1 ORDER BY a; +} {3 111 6 12 9 12} +do_execsql_test 1.3 { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {/.*SCAN TABLE t1 USING INDEX t1a.*/} +do_execsql_test 1.3x { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {~/.*B-TREE FOR ORDER BY.*/} + +# Now mark the t1a index as "unordered". Range queries and ORDER BY no +# longer use the index, but equality queries do. +# +do_execsql_test 2.0 { + UPDATE sqlite_stat1 SET stat='12345 2 unordered' WHERE idx='t1a'; + ANALYZE sqlite_master; + SELECT *, '#' FROM t1 WHERE a BETWEEN 3 AND 8 ORDER BY c; +} {4 5 6 # 7 8 9 # 4 8 12 #} +do_execsql_test 2.1 { + EXPLAIN QUERY PLAN + SELECT *, '#' FROM t1 WHERE a BETWEEN 3 AND 8 ORDER BY c; +} {~/.*USING INDEX.*/} +do_execsql_test 2.2 { + SELECT c FROM t1 ORDER BY a; +} {3 111 6 12 9 12} +do_execsql_test 2.3 { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {~/.*USING INDEX.*/} +do_execsql_test 2.3x { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {/.*B-TREE FOR ORDER BY.*/} + +# Ignore extraneous text parameters in the sqlite_stat1.stat field. +# +do_execsql_test 3.0 { + UPDATE sqlite_stat1 SET stat='12345 2 whatever=5 unordered xyzzy=11' + WHERE idx='t1a'; + ANALYZE sqlite_master; + SELECT *, '#' FROM t1 WHERE a BETWEEN 3 AND 8 ORDER BY c; +} {4 5 6 # 7 8 9 # 4 8 12 #} +do_execsql_test 3.1 { + EXPLAIN QUERY PLAN + SELECT *, '#' FROM t1 WHERE a BETWEEN 3 AND 8 ORDER BY c; +} {~/.*USING INDEX.*/} +do_execsql_test 3.2 { + SELECT c FROM t1 ORDER BY a; +} {3 111 6 12 9 12} +do_execsql_test 3.3 { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {~/.*USING INDEX.*/} +do_execsql_test 3.3x { + EXPLAIN QUERY PLAN + SELECT c FROM t1 ORDER BY a; +} {/.*B-TREE FOR ORDER BY.*/} + +# The sz=NNN parameter determines which index to scan +# +do_execsql_test 4.0 { + DROP INDEX t1a; + CREATE INDEX t1ab ON t1(a,b); + CREATE INDEX t1ca ON t1(c,a); + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1(tbl,idx,stat) + VALUES('t1','t1ab','12345 3 2 sz=10'),('t1','t1ca','12345 3 2 sz=20'); + ANALYZE sqlite_master; + SELECT count(a) FROM t1; +} {6} +do_execsql_test 4.1 { + EXPLAIN QUERY PLAN + SELECT count(a) FROM t1; +} {/.*INDEX t1ab.*/} +do_execsql_test 4.2 { + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1(tbl,idx,stat) + VALUES('t1','t1ab','12345 3 2 sz=20'),('t1','t1ca','12345 3 2 sz=10'); + ANALYZE sqlite_master; + SELECT count(a) FROM t1; +} {6} +do_execsql_test 4.3 { + EXPLAIN QUERY PLAN + SELECT count(a) FROM t1; +} {/.*INDEX t1ca.*/} + + +# The sz=NNN parameter works even if there is other extraneous text +# in the sqlite_stat1.stat column. +# +do_execsql_test 5.0 { + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1(tbl,idx,stat) + VALUES('t1','t1ab','12345 3 2 x=5 sz=10 y=10'), + ('t1','t1ca','12345 3 2 whatever sz=20 junk'); + ANALYZE sqlite_master; + SELECT count(a) FROM t1; +} {6} +do_execsql_test 5.1 { + EXPLAIN QUERY PLAN + SELECT count(a) FROM t1; +} {/.*INDEX t1ab.*/} +do_execsql_test 5.2 { + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1(tbl,idx,stat) + VALUES('t1','t1ca','12345 3 2 x=5 sz=10 y=10'), + ('t1','t1ab','12345 3 2 whatever sz=20 junk'); + ANALYZE sqlite_master; + SELECT count(a) FROM t1; +} {6} +do_execsql_test 5.3 { + EXPLAIN QUERY PLAN + SELECT count(a) FROM t1; +} {/.*INDEX t1ca.*/} + + + + +finish_test diff --git a/test/autoindex1.test b/test/autoindex1.test index 0e5032b..6cb0ab1 100644 --- a/test/autoindex1.test +++ b/test/autoindex1.test @@ -97,6 +97,8 @@ do_test autoindex1-210 { PRAGMA automatic_index=ON; ANALYZE; UPDATE sqlite_stat1 SET stat='10000' WHERE tbl='t1'; + -- Table t2 actually contains 8 rows. + UPDATE sqlite_stat1 SET stat='16' WHERE tbl='t2'; ANALYZE sqlite_master; SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1; } diff --git a/test/autoindex2.test b/test/autoindex2.test new file mode 100644 index 0000000..f4da416 --- /dev/null +++ b/test/autoindex2.test @@ -0,0 +1,271 @@ +# 2014-06-17 +# +# 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 automatic index creation logic. +# +# This file contains a single real-world test case that was giving +# suboptimal performance because of over-use of automatic indexes. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + + +do_execsql_test autoindex2-100 { + CREATE TABLE t1( + t1_id largeint, + did char(9), + ptime largeint, + exbyte char(4), + pe_id int, + field_id int, + mass float, + param10 float, + param11 float, + exmass float, + deviation float, + trange float, + vstatus int, + commit_status int, + formula char(329), + tier int DEFAULT 2, + ssid int DEFAULT 0, + last_operation largeint DEFAULT 0, + admin_uuid int DEFAULT 0, + previous_value float, + job_id largeint, + last_t1 largeint DEFAULT 0, + data_t1 int, + previous_date largeint DEFAULT 0, + flg8 int DEFAULT 1, + failed_fields char(100) + ); + CREATE INDEX t1x0 on t1 (t1_id); + CREATE INDEX t1x1 on t1 (ptime, vstatus); + CREATE INDEX t1x2 on t1 (did, ssid, ptime, vstatus, exbyte, t1_id); + CREATE INDEX t1x3 on t1 (job_id); + + CREATE TABLE t2( + did char(9), + client_did char(30), + description char(49), + uid int, + tzid int, + privilege int, + param2 int, + type char(30), + subtype char(32), + dparam1 char(7) DEFAULT '', + param5 char(3) DEFAULT '', + notional float DEFAULT 0.000000, + create_time largeint, + sample_time largeint DEFAULT 0, + param6 largeint, + frequency int, + expiration largeint, + uw_status int, + next_sample largeint, + last_sample largeint, + reserve1 char(29) DEFAULT '', + reserve2 char(29) DEFAULT '', + reserve3 char(29) DEFAULT '', + bxcdr char(19) DEFAULT 'XY', + ssid int DEFAULT 1, + last_t1_id largeint, + reserve4 char(29) DEFAULT '', + reserve5 char(29) DEFAULT '', + param12 int DEFAULT 0, + long_did char(100) DEFAULT '', + gr_code int DEFAULT 0, + drx char(100) DEFAULT '', + parent_id char(9) DEFAULT '', + param13 int DEFAULT 0, + position float DEFAULT 1.000000, + client_did3 char(100) DEFAULT '', + client_did4 char(100) DEFAULT '', + dlib_id char(9) DEFAULT '' + ); + CREATE INDEX t2x0 on t2 (did); + CREATE INDEX t2x1 on t2 (client_did); + CREATE INDEX t2x2 on t2 (long_did); + CREATE INDEX t2x3 on t2 (uid); + CREATE INDEX t2x4 on t2 (param2); + CREATE INDEX t2x5 on t2 (type); + CREATE INDEX t2x6 on t2 (subtype); + CREATE INDEX t2x7 on t2 (last_sample); + CREATE INDEX t2x8 on t2 (param6); + CREATE INDEX t2x9 on t2 (frequency); + CREATE INDEX t2x10 on t2 (privilege); + CREATE INDEX t2x11 on t2 (sample_time); + CREATE INDEX t2x12 on t2 (notional); + CREATE INDEX t2x13 on t2 (tzid); + CREATE INDEX t2x14 on t2 (gr_code); + CREATE INDEX t2x15 on t2 (parent_id); + + CREATE TABLE t3( + uid int, + param3 int, + uuid int, + acc_id int, + cust_num int, + numerix_id int, + pfy char(29), + param4 char(29), + param15 int DEFAULT 0, + flg7 int DEFAULT 0, + param21 int DEFAULT 0, + bxcdr char(2) DEFAULT 'PC', + c31 int DEFAULT 0, + c33 int DEFAULT 0, + c35 int DEFAULT 0, + c37 int, + mgr_uuid int, + back_up_uuid int, + priv_mars int DEFAULT 0, + is_qc int DEFAULT 0, + c41 int DEFAULT 0, + deleted int DEFAULT 0, + c47 int DEFAULT 1 + ); + CREATE INDEX t3x0 on t3 (uid); + CREATE INDEX t3x1 on t3 (param3); + CREATE INDEX t3x2 on t3 (uuid); + CREATE INDEX t3x3 on t3 (acc_id); + CREATE INDEX t3x4 on t3 (param4); + CREATE INDEX t3x5 on t3 (pfy); + CREATE INDEX t3x6 on t3 (is_qc); + SELECT count(*) FROM sqlite_master; +} {30} +do_execsql_test autoindex2-110 { + ANALYZE sqlite_master; + INSERT INTO sqlite_stat1 VALUES('t1','t1x3','10747267 260'); + INSERT INTO sqlite_stat1 VALUES('t1','t1x2','10747267 121 113 2 2 2 1'); + INSERT INTO sqlite_stat1 VALUES('t1','t1x1','10747267 50 40'); + INSERT INTO sqlite_stat1 VALUES('t1','t1x0','10747267 1'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x15','39667 253'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x14','39667 19834'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x13','39667 13223'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x12','39667 7'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x11','39667 17'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x10','39667 19834'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x9','39667 7934'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x8','39667 11'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x7','39667 5'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x6','39667 242'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x5','39667 1984'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x4','39667 4408'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x3','39667 81'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x2','39667 551'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x1','39667 2'); + INSERT INTO sqlite_stat1 VALUES('t2','t2x0','39667 1'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x6','569 285'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x5','569 2'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x4','569 2'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x3','569 5'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x2','569 3'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x1','569 6'); + INSERT INTO sqlite_stat1 VALUES('t3','t3x0','569 1'); + ANALYZE sqlite_master; +} {} +do_execsql_test autoindex2-120 { + EXPLAIN QUERY PLAN + SELECT + t1_id, + t1.did, + param2, + param3, + t1.ptime, + t1.trange, + t1.exmass, + t1.mass, + t1.vstatus, + type, + subtype, + t1.deviation, + t1.formula, + dparam1, + reserve1, + reserve2, + param4, + t1.last_operation, + t1.admin_uuid, + t1.previous_value, + t1.job_id, + client_did, + t1.last_t1, + t1.data_t1, + t1.previous_date, + param5, + param6, + mgr_uuid + FROM + t1, + t2, + t3 + WHERE + t1.ptime > 1393520400 + AND param3<>9001 + AND t3.flg7 = 1 + AND t1.did = t2.did + AND t2.uid = t3.uid + ORDER BY t1.ptime desc LIMIT 500; +} {0 0 0 {SEARCH TABLE t1 USING INDEX t1x1 (ptime>?)} 0 1 1 {SEARCH TABLE t2 USING INDEX t2x0 (did=?)} 0 2 2 {SEARCH TABLE t3 USING INDEX t3x0 (uid=?)}} +# +# ^^^--- Before being fixed, the above was using an automatic covering +# on t3 and reordering the tables so that t3 was in the outer loop and +# implementing the ORDER BY clause using a B-Tree. + +do_execsql_test autoindex2-120 { + EXPLAIN QUERY PLAN + SELECT + t1_id, + t1.did, + param2, + param3, + t1.ptime, + t1.trange, + t1.exmass, + t1.mass, + t1.vstatus, + type, + subtype, + t1.deviation, + t1.formula, + dparam1, + reserve1, + reserve2, + param4, + t1.last_operation, + t1.admin_uuid, + t1.previous_value, + t1.job_id, + client_did, + t1.last_t1, + t1.data_t1, + t1.previous_date, + param5, + param6, + mgr_uuid + FROM + t3, + t2, + t1 + WHERE + t1.ptime > 1393520400 + AND param3<>9001 + AND t3.flg7 = 1 + AND t1.did = t2.did + AND t2.uid = t3.uid + ORDER BY t1.ptime desc LIMIT 500; +} {0 0 2 {SEARCH TABLE t1 USING INDEX t1x1 (ptime>?)} 0 1 1 {SEARCH TABLE t2 USING INDEX t2x0 (did=?)} 0 2 0 {SEARCH TABLE t3 USING INDEX t3x0 (uid=?)}} + +finish_test diff --git a/test/autoindex3.test b/test/autoindex3.test new file mode 100644 index 0000000..33053bb --- /dev/null +++ b/test/autoindex3.test @@ -0,0 +1,58 @@ +# 2014-06-17 +# +# 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 automatic index creation logic, +# and specifically that an automatic index will not be created that +# shadows a declared index. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# The t1b and t2d indexes are not very selective. It used to be that +# the autoindex mechanism would create automatic indexes on t1(b) or +# t2(d), make assumptions that they were reasonably selective, and use +# them instead of t1b or t2d. But that would be cheating, because the +# automatic index cannot be any more selective than the real index. +# +# This test verifies that the cheat is no longer allowed. +# +do_execsql_test autoindex3-100 { + CREATE TABLE t1(a,b,x); + CREATE TABLE t2(c,d,y); + CREATE INDEX t1b ON t1(b); + CREATE INDEX t2d ON t2(d); + ANALYZE sqlite_master; + INSERT INTO sqlite_stat1 VALUES('t1','t1b','10000 500'); + INSERT INTO sqlite_stat1 VALUES('t2','t2d','10000 500'); + ANALYZE sqlite_master; + EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE d=b; +} {~/AUTO/} + +# Automatic indexes can still be used if existing indexes do not +# participate in == constraints. +# +do_execsql_test autoindex3-110 { + EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE d>b AND x=y; +} {/AUTO/} +do_execsql_test autoindex3-120 { + EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE d=3071200 + && [code2 { set ::sqlite_libversion }] >=3071200 + } { + do_test backcompat-3.9 { + sql1 { INSERT INTO t2(t2) VALUES('merge=100,4'); } + sql2 { INSERT INTO t2(t2) VALUES('merge=100,4'); } + sql1 { INSERT INTO t2(t2) VALUES('merge=100,4'); } + sql2 { INSERT INTO t2(t2) VALUES('merge=2500,4'); } + sql2 { + SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level; + } + } {0 {0 1} 1 0} + + do_test backcompat-3.10 { + sql1 { INSERT INTO t2(t2) VALUES('integrity-check') } + sql2 { INSERT INTO t2(t2) VALUES('integrity-check') } + } {} + } } } } diff --git a/test/capi3d.test b/test/capi3d.test index ed3765b..fb8abe8 100644 --- a/test/capi3d.test +++ b/test/capi3d.test @@ -144,4 +144,41 @@ do_test capi3d-3.99 { sqlite3_stmt_busy 0 } {0} +#-------------------------------------------------------------------------- +# Test the sqlite3_stmt_busy() function with ROLLBACK statements. +# +reset_db + +do_execsql_test capi3d-4.1 { + CREATE TABLE t4(x,y); + BEGIN; +} + +do_test capi3d-4.2.1 { + breakpoint + set ::s1 [sqlite3_prepare_v2 db "ROLLBACK" -1 notused] + sqlite3_step $::s1 +} {SQLITE_DONE} + +do_test capi3d-4.2.2 { + sqlite3_stmt_busy $::s1 +} {1} + +do_catchsql_test capi3d-4.2.3 { + VACUUM +} {1 {cannot VACUUM - SQL statements in progress}} + +do_test capi3d-4.2.4 { + sqlite3_reset $::s1 +} {SQLITE_OK} + +do_catchsql_test capi3d-4.2.5 { + VACUUM +} {0 {}} + +do_test capi3d-4.2.6 { + sqlite3_finalize $::s1 +} {SQLITE_OK} + + finish_test diff --git a/test/corruptG.test b/test/corruptG.test index 1ec5d6f..af920ed 100644 --- a/test/corruptG.test +++ b/test/corruptG.test @@ -47,12 +47,12 @@ do_test 1.2 { catchsql { SELECT c FROM t1 WHERE a>'abc'; } -} {0 {}} +} {1 {database disk image is malformed}} do_test 1.3 { catchsql { PRAGMA integrity_check } -} {0 ok} +} {1 {database disk image is malformed}} do_test 1.4 { catchsql { SELECT c FROM t1 ORDER BY a; @@ -71,11 +71,6 @@ do_test 2.1 { catchsql { SELECT rowid FROM t1 WHERE a='abc' and b='xyz123456789XYZ'; } - # The following test result is brittle. The point above is to try to - # force a buffer overread by a corrupt database file. If we get an - # incorrect answer from a corrupt database file, that is OK. If the - # result below changes, that just means that "undefined behavior" has - # changed. -} {/0 .*/} +} {1 {database disk image is malformed}} finish_test diff --git a/test/corruptI.test b/test/corruptI.test index 087a0f3..41200c5 100644 --- a/test/corruptI.test +++ b/test/corruptI.test @@ -51,7 +51,7 @@ do_test 1.3 { hexio_write test.db $off FFFF7f02 sqlite3 db test.db catchsql { SELECT * FROM t1 WHERE a = 10 } -} {0 {}} +} {1 {database disk image is malformed}} do_test 2.0 { execsql { @@ -75,5 +75,31 @@ do_test 2.2 { catchsql { SELECT * FROM r WHERE x >= 10 } } {1 {database disk image is malformed}} +reset_db + +do_execsql_test 3.1 { + PRAGMA page_size = 512; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + WITH s(a, b) AS ( + SELECT 2, 'abcdefghij' + UNION ALL + SELECT a+2, b FROM s WHERe a < 40 + ) + INSERT INTO t1 SELECT * FROM s; +} {} + +do_test 3.2 { + hexio_write test.db [expr 512+3] 0054 + db close + sqlite3 db test.db + execsql { INSERT INTO t1 VALUES(5, 'klmnopqrst') } + execsql { INSERT INTO t1 VALUES(7, 'klmnopqrst') } +} {} + +db close +sqlite3 db test.db +do_catchsql_test 3.2 { + INSERT INTO t1 VALUES(9, 'klmnopqrst'); +} {1 {database disk image is malformed}} finish_test diff --git a/test/cost.test b/test/cost.test new file mode 100644 index 0000000..92fff9c --- /dev/null +++ b/test/cost.test @@ -0,0 +1,292 @@ +# 2014-04-26 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix cost + + +do_execsql_test 1.1 { + CREATE TABLE t3(id INTEGER PRIMARY KEY, b NOT NULL); + CREATE TABLE t4(c, d, e); + CREATE UNIQUE INDEX i3 ON t3(b); + CREATE UNIQUE INDEX i4 ON t4(c, d); +} +do_eqp_test 1.2 { + SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d; +} { + 0 0 0 {SCAN TABLE t3 USING COVERING INDEX i3} + 0 1 1 {SEARCH TABLE t4 USING INDEX i4 (c=?)} +} + + +do_execsql_test 2.1 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a); +} + +# It is better to use an index for ORDER BY than sort externally, even +# if the index is a non-covering index. +do_eqp_test 2.2 { + SELECT * FROM t1 ORDER BY a; +} { + 0 0 0 {SCAN TABLE t1 USING INDEX i1} +} + +do_execsql_test 3.1 { + CREATE TABLE t5(a INTEGER PRIMARY KEY,b,c,d,e,f,g); + CREATE INDEX t5b ON t5(b); + CREATE INDEX t5c ON t5(c); + CREATE INDEX t5d ON t5(d); + CREATE INDEX t5e ON t5(e); + CREATE INDEX t5f ON t5(f); + CREATE INDEX t5g ON t5(g); +} + +do_eqp_test 3.2 { + SELECT a FROM t5 + WHERE b IS NULL OR c IS NULL OR d IS NULL + ORDER BY a; +} { + 0 0 0 {SEARCH TABLE t5 USING INDEX t5b (b=?)} + 0 0 0 {SEARCH TABLE t5 USING INDEX t5c (c=?)} + 0 0 0 {SEARCH TABLE t5 USING INDEX t5d (d=?)} + 0 0 0 {USE TEMP B-TREE FOR ORDER BY} +} + +#------------------------------------------------------------------------- +# If there is no likelihood() or stat3 data, SQLite assumes that a closed +# range scan (e.g. one constrained by "col BETWEEN ? AND ?" constraint) +# visits 1/64 of the rows in a table. +# +# Note: 1/63 =~ 0.016 +# Note: 1/65 =~ 0.015 +# +reset_db +do_execsql_test 4.1 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a); + CREATE INDEX i2 ON t1(b); +} +do_eqp_test 4.2 { + SELECT * FROM t1 WHERE likelihood(a=?, 0.014) AND b BETWEEN ? AND ?; +} { + 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} +} +do_eqp_test 4.3 { + SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?; +} { + 0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b>? AND b? AND x? AND b=950 AND b<=1010) OR (b IS NULL AND c NOT NULL) + ORDER BY a +} { + 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b16; + DROP TABLE IF EXISTS x1; + CREATE VIRTUAL TABLE x1 USING fts4; +} + +db func second second +proc second {L} {lindex $L 1} + +for {set tn 0} {$tn < 40} {incr tn} { + do_test 2.2.$tn { + for {set i 0} {$i < 100} {incr i} { + tt 0 ; tt 1 ; tt 2 ; tt 3 + } + execsql { SELECT max(level) FROM x1_segdir } + } {1} +} + + +finish_test + diff --git a/test/fts4merge4.test b/test/fts4merge4.test index 8e2119d..038e460 100644 --- a/test/fts4merge4.test +++ b/test/fts4merge4.test @@ -53,6 +53,50 @@ do_execsql_test 2.2 { SELECT count(*) FROM t1_segdir; } 35 do_execsql_test 2.3 { INSERT INTO t1(t1) VALUES('optimize') } {} do_execsql_test 2.4 { SELECT count(*) FROM t1_segdir; } 1 +#------------------------------------------------------------------------- +# Now test that the automerge=? option appears to work. +# +do_execsql_test 2.1 { CREATE VIRTUAL TABLE t2 USING fts4; } + +set doc "" +foreach c1 "a b c d e f g h i j" { + foreach c2 "a b c d e f g h i j" { + foreach c3 "a b c d e f g h i j" { + lappend doc "$c1$c2$c3" + } + } +} +set doc [string repeat $doc 10] + +foreach {tn am expected} { + 1 {automerge=2} {1 1 2 1 4 1 6 1} + 2 {automerge=4} {1 2 2 1 3 1} + 3 {automerge=8} {0 4 1 3 2 1} + 4 {automerge=1} {0 4 1 3 2 1} +} { + foreach {tn2 openclose} {1 {} 2 { db close ; sqlite3 db test.db }} { + do_test 2.2.$tn.$tn2 { + execsql { DELETE FROM t2 } + execsql { INSERT INTO t2(t2) VALUES($am) }; + + eval $openclose + + for {set i 0} {$i < 100} {incr i} { + execsql { + BEGIN; + INSERT INTO t2 VALUES($doc); + INSERT INTO t2 VALUES($doc); + INSERT INTO t2 VALUES($doc); + INSERT INTO t2 VALUES($doc); + INSERT INTO t2 VALUES($doc); + COMMIT; + } + } + + execsql { SELECT level, count(*) FROM t2_segdir GROUP BY level } + } [list {*}$expected] + } +} sqlite3_enable_shared_cache $::enable_shared_cache finish_test diff --git a/test/fts4noti.test b/test/fts4noti.test index e926228..c90999b 100644 --- a/test/fts4noti.test +++ b/test/fts4noti.test @@ -165,6 +165,68 @@ do_execsql_test 5.4 { SELECT docid FROM t2 WHERE t2 MATCH 'c' } {3} do_execsql_test 5.x { DROP TABLE t2 } +#------------------------------------------------------------------------- +# Check that if an indexed column name is a prefix of a notindexed column +# name, the column is still correctly tokenized. This was a problem at one +# point. +do_execsql_test 6.1.1 { + CREATE VIRTUAL TABLE t1 USING fts4( + poiCategory, poiCategoryId, notindexed=poiCategoryId + ); + INSERT INTO t1(poiCategory, poiCategoryId) values ("Restaurant", 6021); +} + +do_execsql_test 6.1.2 { + SELECT * FROM t1 WHERE t1 MATCH 'restaurant'; +} { Restaurant 6021 } +do_execsql_test 6.1.3 { + SELECT * FROM t1 WHERE t1 MATCH 're*'; +} { Restaurant 6021 } +do_execsql_test 6.1.4 { + SELECT * FROM t1 WHERE t1 MATCH '6021'; +} {} +do_execsql_test 6.1.5 { + SELECT * FROM t1 WHERE t1 MATCH '60*'; +} {} + +do_execsql_test 6.2.1 { + DROP TABLE t1; + CREATE VIRTUAL TABLE t1 USING fts4( + poiCategory, poiCategoryId, notindexed=poiCategory + ); + INSERT INTO t1(poiCategory, poiCategoryId) values ("Restaurant", 6021); +} + +do_execsql_test 6.2.2 { + SELECT * FROM t1 WHERE t1 MATCH 'restaurant'; +} {} +do_execsql_test 6.2.3 { + SELECT * FROM t1 WHERE t1 MATCH 're*'; +} {} +do_execsql_test 6.2.4 { + SELECT * FROM t1 WHERE t1 MATCH '6021'; +} { Restaurant 6021 } +do_execsql_test 6.2.5 { + SELECT * FROM t1 WHERE t1 MATCH '60*'; +} { Restaurant 6021 } + +do_execsql_test 6.3.1 { + DROP TABLE t1; + CREATE VIRTUAL TABLE t1 USING fts4(abc, ab, a, notindexed=abc); + CREATE VIRTUAL TABLE t2 USING fts4(a, ab, abc, notindexed=abc); + + INSERT INTO t1 VALUES('no', 'yes', 'yep'); + INSERT INTO t2 VALUES('yep', 'yes', 'no'); + + SELECT count(*) FROM t1 WHERE t1 MATCH 'no'; + SELECT count(*) FROM t1 WHERE t1 MATCH 'yes'; + SELECT count(*) FROM t1 WHERE t1 MATCH 'yep'; + + SELECT count(*) FROM t2 WHERE t2 MATCH 'no'; + SELECT count(*) FROM t2 WHERE t2 MATCH 'yes'; + SELECT count(*) FROM t2 WHERE t2 MATCH 'yep'; +} {0 1 1 0 1 1} + finish_test diff --git a/test/func.test b/test/func.test index 0fafd18..98ae8dd 100644 --- a/test/func.test +++ b/test/func.test @@ -1194,6 +1194,18 @@ do_test func-24.12 { WHEN 'program' THEN null ELSE t1 END) FROM tbl1 } } {,is,free,software} +# Tests to verify ticket http://www.sqlite.org/src/tktview/55746f9e65f8587c0 +do_test func-24.13 { + execsql { + SELECT typeof(group_concat(x)) FROM (SELECT '' AS x); + } +} {text} +do_test func-24.14 { + execsql { + SELECT typeof(group_concat(x,'')) + FROM (SELECT '' AS x UNION ALL SELECT ''); + } +} {text} # Use the test_isolation function to make sure that type conversions @@ -1301,11 +1313,13 @@ do_test func-29.3 { db eval {SELECT typeof(+x) FROM t29 ORDER BY id} } {integer null real blob text} if {[permutation] != "mmap"} { - do_test func-29.4 { - set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1] - if {$x>100} {set x many} - set x - } {many} + ifcapable !direct_read { + do_test func-29.4 { + set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1] + if {$x>100} {set x many} + set x + } {many} + } } do_test func-29.5 { db close diff --git a/test/func3.test b/test/func3.test index 2a2b7be..3b1613b 100644 --- a/test/func3.test +++ b/test/func3.test @@ -149,8 +149,42 @@ do_execsql_test func3-5.35 { # the code generator optimizes away so that it consumes no CPU cycles at # run-time (that is, during calls to sqlite3_step()). # -do_test func3-5.40 { +do_test func3-5.39 { db eval {EXPLAIN SELECT unlikely(min(1.0+'2.0',4*11))} } [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}] + +# EVIDENCE-OF: R-23735-03107 The likely(X) function returns the argument +# X unchanged. +# +do_execsql_test func3-5.50 { + SELECT likely(9223372036854775807); +} {9223372036854775807} +do_execsql_test func3-5.51 { + SELECT likely(-9223372036854775808); +} {-9223372036854775808} +do_execsql_test func3-5.52 { + SELECT likely(14.125); +} {14.125} +do_execsql_test func3-5.53 { + SELECT likely(NULL); +} {{}} +do_execsql_test func3-5.54 { + SELECT likely('test-string'); +} {test-string} +do_execsql_test func3-5.55 { + SELECT quote(likely(x'010203000405')); +} {X'010203000405'} + +# EVIDENCE-OF: R-43464-09689 The likely(X) function is a no-op that the +# code generator optimizes away so that it consumes no CPU cycles at +# run-time (that is, during calls to sqlite3_step()). +# +do_test func3-5.59 { + db eval {EXPLAIN SELECT likely(min(1.0+'2.0',4*11))} +} [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}] + + + + finish_test diff --git a/test/fuzz.test b/test/fuzz.test index e1b22ae..0deed3b 100644 --- a/test/fuzz.test +++ b/test/fuzz.test @@ -285,7 +285,7 @@ do_test fuzz-1.18 { ) )) } -} {0 -4294967298} +} {0 {{}}} # At one point the following INSERT statement caused an assert() to fail. # diff --git a/test/hexlit.test b/test/hexlit.test new file mode 100644 index 0000000..10909e6 --- /dev/null +++ b/test/hexlit.test @@ -0,0 +1,114 @@ +# 2014-07-23 +# +# 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 tests for hexadecimal literals + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +proc hexlit1 {tnum val ans} { + do_execsql_test hexlit-$tnum "SELECT $val" $ans +} + +hexlit1 100 0x0 0 +hexlit1 101 0x0000000000000000000000000000000000000000000001 1 +hexlit1 102 0x2 2 +hexlit1 103 0x4 4 +hexlit1 104 0x8 8 +hexlit1 105 0x00000000000000000000000000000000000000000000010 16 +hexlit1 103 0x20 32 +hexlit1 106 0x40 64 +hexlit1 107 0x80 128 +hexlit1 108 0x100 256 +hexlit1 109 0x200 512 +hexlit1 110 0X400 1024 +hexlit1 111 0x800 2048 +hexlit1 112 0x1000 4096 +hexlit1 113 0x2000 8192 +hexlit1 114 0x4000 16384 +hexlit1 115 0x8000 32768 +hexlit1 116 0x10000 65536 +hexlit1 117 0x20000 131072 +hexlit1 118 0x40000 262144 +hexlit1 119 0x80000 524288 +hexlit1 120 0x100000 1048576 +hexlit1 121 0x200000 2097152 +hexlit1 122 0x400000 4194304 +hexlit1 123 0x800000 8388608 +hexlit1 124 0x1000000 16777216 +hexlit1 125 0x2000000 33554432 +hexlit1 126 0x4000000 67108864 +hexlit1 127 0x8000000 134217728 +hexlit1 128 0x10000000 268435456 +hexlit1 129 0x20000000 536870912 +hexlit1 130 0x40000000 1073741824 +hexlit1 131 0x80000000 2147483648 +hexlit1 132 0x100000000 4294967296 +hexlit1 133 0x200000000 8589934592 +hexlit1 134 0x400000000 17179869184 +hexlit1 135 0x800000000 34359738368 +hexlit1 136 0x1000000000 68719476736 +hexlit1 137 0x2000000000 137438953472 +hexlit1 138 0x4000000000 274877906944 +hexlit1 139 0x8000000000 549755813888 +hexlit1 140 0x10000000000 1099511627776 +hexlit1 141 0x20000000000 2199023255552 +hexlit1 142 0x40000000000 4398046511104 +hexlit1 143 0x80000000000 8796093022208 +hexlit1 144 0x100000000000 17592186044416 +hexlit1 145 0x200000000000 35184372088832 +hexlit1 146 0x400000000000 70368744177664 +hexlit1 147 0x800000000000 140737488355328 +hexlit1 148 0x1000000000000 281474976710656 +hexlit1 149 0x2000000000000 562949953421312 +hexlit1 150 0x4000000000000 1125899906842624 +hexlit1 151 0x8000000000000 2251799813685248 +hexlit1 152 0x10000000000000 4503599627370496 +hexlit1 153 0x20000000000000 9007199254740992 +hexlit1 154 0x40000000000000 18014398509481984 +hexlit1 155 0x80000000000000 36028797018963968 +hexlit1 156 0x100000000000000 72057594037927936 +hexlit1 157 0x200000000000000 144115188075855872 +hexlit1 158 0x400000000000000 288230376151711744 +hexlit1 159 0x800000000000000 576460752303423488 +hexlit1 160 0X1000000000000000 1152921504606846976 +hexlit1 161 0x2000000000000000 2305843009213693952 +hexlit1 162 0X4000000000000000 4611686018427387904 +hexlit1 163 0x8000000000000000 -9223372036854775808 +hexlit1 164 0XFFFFFFFFFFFFFFFF -1 + +for {set n 1} {$n < 0x10} {incr n} { + hexlit1 200.$n.1 0X[format %03X $n] $n + hexlit1 200.$n.2 0x[format %03X $n] $n + hexlit1 200.$n.3 0X[format %03x $n] $n + hexlit1 200.$n.4 0x[format %03x $n] $n +} + +# String literals that look like hex do not get cast or coerced. +# +do_execsql_test hexlit-300 { + CREATE TABLE t1(x INT, y REAL); + INSERT INTO t1 VALUES('1234','4567'),('0x1234','0x4567'); + SELECT typeof(x), x, typeof(y), y, '#' FROM t1 ORDER BY rowid; +} {integer 1234 real 4567.0 # text 0x1234 text 0x4567 #} +do_execsql_test hexlit-301 { + SELECT CAST('0x1234' AS INTEGER); +} {0} + +# Oversized hex literals are rejected +# +do_catchsql_test hexlist-400 { + SELECT 0x10000000000000000; +} {1 {hex literal too big: 0x10000000000000000}} + + +finish_test diff --git a/test/in4.test b/test/in4.test index 470f4f0..a89961f 100644 --- a/test/in4.test +++ b/test/in4.test @@ -159,4 +159,181 @@ do_test in4-3.12 { execsql { SELECT * FROM t3 WHERE x IN (1, 2) AND y IN ()} } {} +# Tests for "... IN (?)" and "... NOT IN (?)". In other words, tests +# for when the RHS of IN is a single expression. This should work the +# same as the == and <> operators. +# +do_execsql_test in4-3.21 { + SELECT * FROM t3 WHERE x=10 AND y IN (10); +} {10 10 10} +do_execsql_test in4-3.22 { + SELECT * FROM t3 WHERE x IN (10) AND y=10; +} {10 10 10} +do_execsql_test in4-3.23 { + SELECT * FROM t3 WHERE x IN (10) AND y IN (10); +} {10 10 10} +do_execsql_test in4-3.24 { + SELECT * FROM t3 WHERE x=1 AND y NOT IN (10); +} {1 1 1} +do_execsql_test in4-3.25 { + SELECT * FROM t3 WHERE x NOT IN (10) AND y=1; +} {1 1 1} +do_execsql_test in4-3.26 { + SELECT * FROM t3 WHERE x NOT IN (10) AND y NOT IN (10); +} {1 1 1} + +# The query planner recognizes that "x IN (?)" only generates a +# single match and can use this information to optimize-out ORDER BY +# clauses. +# +do_execsql_test in4-3.31 { + DROP INDEX t3i1; + CREATE UNIQUE INDEX t3xy ON t3(x,y); + + SELECT *, '|' FROM t3 A, t3 B + WHERE A.x=10 AND A.y IN (10) + AND B.x=1 AND B.y IN (1); +} {10 10 10 1 1 1 |} +do_execsql_test in4-3.32 { + EXPLAIN QUERY PLAN + SELECT *, '|' FROM t3 A, t3 B + WHERE A.x=10 AND A.y IN (10) + AND B.x=1 AND B.y IN (1); +} {~/B-TREE/} ;# No separate sorting pass +do_execsql_test in4-3.33 { + SELECT *, '|' FROM t3 A, t3 B + WHERE A.x IN (10) AND A.y=10 + AND B.x IN (1) AND B.y=1; +} {10 10 10 1 1 1 |} +do_execsql_test in4-3.34 { + EXPLAIN QUERY PLAN + SELECT *, '|' FROM t3 A, t3 B + WHERE A.x IN (10) AND A.y=10 + AND B.x IN (1) AND B.y=1; +} {~/B-TREE/} ;# No separate sorting pass + +# An expression of the form "x IN (?,?)" creates an ephemeral table to +# hold the list of values on the RHS. But "x IN (?)" does not create +# an ephemeral table. +# +do_execsql_test in4-3.41 { + SELECT * FROM t3 WHERE x IN (10,11); +} {10 10 10} +do_execsql_test in4-3.42 { + EXPLAIN + SELECT * FROM t3 WHERE x IN (10,11); +} {/OpenEphemeral/} +do_execsql_test in4-3.43 { + SELECT * FROM t3 WHERE x IN (10); +} {10 10 10} +do_execsql_test in4-3.44 { + EXPLAIN + SELECT * FROM t3 WHERE x IN (10); +} {~/OpenEphemeral/} +do_execsql_test in4-3.45 { + SELECT * FROM t3 WHERE x NOT IN (10,11,99999); +} {1 1 1} +do_execsql_test in4-3.46 { + EXPLAIN + SELECT * FROM t3 WHERE x NOT IN (10,11,99999); +} {/OpenEphemeral/} +do_execsql_test in4-3.47 { + SELECT * FROM t3 WHERE x NOT IN (10); +} {1 1 1} +do_execsql_test in4-3.48 { + EXPLAIN + SELECT * FROM t3 WHERE x NOT IN (10); +} {~/OpenEphemeral/} + +# Make sure that when "x IN (?)" is converted into "x==?" that collating +# sequence and affinity computations do not get messed up. +# +do_execsql_test in4-4.1 { + CREATE TABLE t4a(a TEXT, b TEXT COLLATE nocase, c); + INSERT INTO t4a VALUES('ABC','abc',1); + INSERT INTO t4a VALUES('def','xyz',2); + INSERT INTO t4a VALUES('ghi','ghi',3); + SELECT c FROM t4a WHERE a=b ORDER BY c; +} {3} +do_execsql_test in4-4.2 { + SELECT c FROM t4a WHERE b=a ORDER BY c; +} {1 3} +do_execsql_test in4-4.3 { + SELECT c FROM t4a WHERE (a||'')=b ORDER BY c; +} {1 3} +do_execsql_test in4-4.4 { + SELECT c FROM t4a WHERE (a||'')=(b||'') ORDER BY c; +} {3} +do_execsql_test in4-4.5 { + SELECT c FROM t4a WHERE a IN (b) ORDER BY c; +} {3} +do_execsql_test in4-4.6 { + SELECT c FROM t4a WHERE (a||'') IN (b) ORDER BY c; +} {3} + + +do_execsql_test in4-4.11 { + CREATE TABLE t4b(a TEXT, b NUMERIC, c); + INSERT INTO t4b VALUES('1.0',1,4); + SELECT c FROM t4b WHERE a=b; +} {4} +do_execsql_test in4-4.12 { + SELECT c FROM t4b WHERE b=a; +} {4} +do_execsql_test in4-4.13 { + SELECT c FROM t4b WHERE +a=b; +} {4} +do_execsql_test in4-4.14 { + SELECT c FROM t4b WHERE a=+b; +} {} +do_execsql_test in4-4.15 { + SELECT c FROM t4b WHERE +b=a; +} {} +do_execsql_test in4-4.16 { + SELECT c FROM t4b WHERE b=+a; +} {4} +do_execsql_test in4-4.17 { + SELECT c FROM t4b WHERE a IN (b); +} {} +do_execsql_test in4-4.18 { + SELECT c FROM t4b WHERE b IN (a); +} {4} +do_execsql_test in4-4.19 { + SELECT c FROM t4b WHERE +b IN (a); +} {} + +do_execsql_test in4-5.1 { + CREATE TABLE t5(c INTEGER PRIMARY KEY, d TEXT COLLATE nocase); + INSERT INTO t5 VALUES(17, 'fuzz'); + SELECT 1 FROM t5 WHERE 'fuzz' IN (d); -- match + SELECT 2 FROM t5 WHERE 'FUZZ' IN (d); -- no match + SELECT 3 FROM t5 WHERE d IN ('fuzz'); -- match + SELECT 4 FROM t5 WHERE d IN ('FUZZ'); -- match +} {1 3 4} + +# An expression of the form "x IN (y)" can be used as "x=y" by the +# query planner when computing transitive constraints or to run the +# query using an index on y. +# +do_execsql_test in4-6.1 { + CREATE TABLE t6a(a INTEGER PRIMARY KEY, b); + INSERT INTO t6a VALUES(1,2),(3,4),(5,6); + CREATE TABLE t6b(c INTEGER PRIMARY KEY, d); + INSERT INTO t6b VALUES(4,44),(5,55),(6,66); + + SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c); +} {3 4 4 44} +do_execsql_test in4-6.1-eqp { + EXPLAIN QUERY PLAN + SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c); +} {~/SCAN/} +do_execsql_test in4-6.2 { + SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b); +} {3 4 4 44} +do_execsql_test in4-6.2-eqp { + EXPLAIN QUERY PLAN + SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b); +} {~/SCAN/} + + finish_test diff --git a/test/incrblob_err.test b/test/incrblob_err.test index 35d37fe..a08bea3 100644 --- a/test/incrblob_err.test +++ b/test/incrblob_err.test @@ -14,6 +14,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set ::testprefix incrblob_err ifcapable {!incrblob || !memdebug || !tclvar} { finish_test diff --git a/test/index6.test b/test/index6.test index 48706be..68bdd06 100644 --- a/test/index6.test +++ b/test/index6.test @@ -145,11 +145,11 @@ do_test index6-2.1 { execsql { CREATE TABLE t2(a,b); INSERT INTO t2(a,b) SELECT value, value FROM nums WHERE value<1000; - UPDATE t2 SET a=NULL WHERE b%5==0; + UPDATE t2 SET a=NULL WHERE b%2==0; CREATE INDEX t2a1 ON t2(a) WHERE a IS NOT NULL; SELECT count(*) FROM t2 WHERE a IS NOT NULL; } -} {800} +} {500} do_test index6-2.2 { execsql { EXPLAIN QUERY PLAN @@ -157,6 +157,7 @@ do_test index6-2.2 { } } {/.* TABLE t2 USING INDEX t2a1 .*/} ifcapable stat4||stat3 { + execsql ANALYZE do_test index6-2.3stat4 { execsql { EXPLAIN QUERY PLAN @@ -248,4 +249,23 @@ do_execsql_test index6-5.0 { SELECT stat+0 FROM sqlite_stat1 WHERE idx='t3b'; } {6 6} +# Test case for ticket [2ea3e9fe6379fc3f6ce7e090ce483c1a3a80d6c9] from +# 2014-04-13: Partial index causes assertion fault on UPDATE OR REPLACE. +# +do_execsql_test index6-6.0 { + CREATE TABLE t6(a,b); + CREATE UNIQUE INDEX t6ab ON t1(a,b); + CREATE INDEX t6b ON t6(b) WHERE b=1; + INSERT INTO t6(a,b) VALUES(123,456); + SELECT * FROM t6; +} {123 456} +do_execsql_test index6-6.1 { + UPDATE OR REPLACE t6 SET b=789; + SELECT * FROM t6; +} {123 789} +do_execsql_test index6-6.2 { + PRAGMA integrity_check; +} {ok} + + finish_test diff --git a/test/insert.test b/test/insert.test index 776bce1..cb675b9 100644 --- a/test/insert.test +++ b/test/insert.test @@ -413,6 +413,29 @@ do_execsql_test insert-11.1 { } {123456789 '123456789' '123456789'} +# More columns of input than there are columns in the table. +# Ticket http://www.sqlite.org/src/info/e9654505cfda9361 +# +do_execsql_test insert-12.1 { + CREATE TABLE t12a(a,b,c,d,e,f,g); + INSERT INTO t12a VALUES(101,102,103,104,105,106,107); + CREATE TABLE t12b(x); + INSERT INTO t12b(x,rowid,x,x,x,x,x) SELECT * FROM t12a; + SELECT rowid, x FROM t12b; +} {102 101} +do_execsql_test insert-12.2 { + CREATE TABLE tab1( value INTEGER); + INSERT INTO tab1 (value, _rowid_) values( 11, 1); + INSERT INTO tab1 (value, _rowid_) SELECT 22,999; + SELECT * FROM tab1; +} {11 22} +do_execsql_test insert-12.3 { + CREATE TABLE t12c(a, b DEFAULT 'xyzzy', c); + INSERT INTO t12c(a, rowid, c) SELECT 'one', 999, 'two'; + SELECT * FROM t12c; +} {one xyzzy two} + + integrity_check insert-99.0 finish_test diff --git a/test/join.test b/test/join.test index 28d9ddf..4c83fa6 100644 --- a/test/join.test +++ b/test/join.test @@ -36,6 +36,17 @@ do_test join-1.2 { } } {1 2 3 2 3 4 3 4 5} +# A FROM clause of the form: ",
    ON " is not +# allowed by the SQLite syntax diagram, nor by any other SQL database +# engine that we are aware of. Nevertheless, historic versions of +# SQLite have allowed it. We need to continue to support it moving +# forward to prevent breakage of legacy applications. Though, we will +# not advertise it as being supported. +# +do_execsql_test join-1.2.1 { + SELECT t1.rowid, t2.rowid, '|' FROM t1, t2 ON t1.a=t2.b; +} {1 1 | 2 2 | 3 3 |} + do_test join-1.3 { execsql2 { SELECT * FROM t1 NATURAL JOIN t2; diff --git a/test/limit.test b/test/limit.test index c5b75c2..5d6ef33 100644 --- a/test/limit.test +++ b/test/limit.test @@ -616,4 +616,24 @@ do_test limit-13.81 { db eval {SELECT z FROM v13c LIMIT 1 OFFSET 8} } {} +do_execsql_test limit-14.1 { + SELECT 123 LIMIT 1 OFFSET 0 +} {123} +do_execsql_test limit-14.2 { + SELECT 123 LIMIT 1 OFFSET 1 +} {} +do_execsql_test limit-14.3 { + SELECT 123 LIMIT 0 OFFSET 0 +} {} +do_execsql_test limit-14.4 { + SELECT 123 LIMIT 0 OFFSET 1 +} {} +do_execsql_test limit-14.6 { + SELECT 123 LIMIT -1 OFFSET 0 +} {123} +do_execsql_test limit-14.7 { + SELECT 123 LIMIT -1 OFFSET 1 +} {} + + finish_test diff --git a/test/malloc.test b/test/malloc.test index 5d03aa8..4276b58 100644 --- a/test/malloc.test +++ b/test/malloc.test @@ -20,6 +20,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set ::testprefix malloc # Only run these tests if memory debugging is turned on. diff --git a/test/mallocK.test b/test/mallocK.test index 971bd56..dcf00da 100644 --- a/test/mallocK.test +++ b/test/mallocK.test @@ -16,6 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl +set testprefix mallocK set sql {SELECT * FROM t1, t2 WHERE (a=1 OR a=2)} for {set x 1} {$x<5} {incr x} { @@ -68,5 +69,70 @@ ifcapable vtab { } } +#------------------------------------------------------------------------- +# Test that OOM errors are correctly handled by the code that uses stat4 +# data to estimate the number of rows visited by a skip-scan range query. +# +add_alignment_test_collations db +do_execsql_test 6.0 { + CREATE TABLE t3(a TEXT, b TEXT COLLATE utf16_aligned, c); + INSERT INTO t3 VALUES('one', '.....', 0); + INSERT INTO t3 VALUES('one', '....x', 1); + INSERT INTO t3 VALUES('one', '...x.', 2); + INSERT INTO t3 VALUES('one', '...xx', 3); + INSERT INTO t3 VALUES('one', '..x..', 4); + INSERT INTO t3 VALUES('one', '..x.x', 5); + INSERT INTO t3 VALUES('one', '..xx.', 6); + INSERT INTO t3 VALUES('one', '..xxx', 7); + INSERT INTO t3 VALUES('one', '.x...', 8); + INSERT INTO t3 VALUES('one', '.x..x', 9); + INSERT INTO t3 VALUES('one', '.x.x.', 10); + INSERT INTO t3 VALUES('one', '.x.xx', 11); + INSERT INTO t3 VALUES('one', '.xx..', 12); + INSERT INTO t3 VALUES('one', '.xx.x', 13); + INSERT INTO t3 VALUES('one', '.xxx.', 14); + INSERT INTO t3 VALUES('one', '.xxxx', 15); + + INSERT INTO t3 VALUES('two', 'x....', 16); + INSERT INTO t3 VALUES('two', 'x...x', 17); + INSERT INTO t3 VALUES('two', 'x..x.', 18); + INSERT INTO t3 VALUES('two', 'x..xx', 19); + INSERT INTO t3 VALUES('two', 'x.x..', 20); + INSERT INTO t3 VALUES('two', 'x.x.x', 21); + INSERT INTO t3 VALUES('two', 'x.xx.', 22); + INSERT INTO t3 VALUES('two', 'x.xxx', 23); + INSERT INTO t3 VALUES('two', 'xx...', 24); + INSERT INTO t3 VALUES('two', 'xx..x', 25); + INSERT INTO t3 VALUES('two', 'xx.x.', 26); + INSERT INTO t3 VALUES('two', 'xx.xx', 27); + INSERT INTO t3 VALUES('two', 'xxx..', 28); + INSERT INTO t3 VALUES('two', 'xxx.x', 29); + INSERT INTO t3 VALUES('two', 'xxxx.', 30); + INSERT INTO t3 VALUES('two', 'xxxxx', 31); + + INSERT INTO t3 SELECT * FROM t3; + + CREATE INDEX i3 ON t3(a, b); + ANALYZE; + + SELECT 'x' > '.'; +} {1} + +ifcapable stat4 { + do_eqp_test 6.1 { + SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx'; + } { + 0 0 0 {SEARCH TABLE t3 USING INDEX i3 (ANY(a) AND b>? AND bdata.txt +# wish show_speedtest1_rtree.tcl +# +# The filename "data.txt" is hard coded into this script and so that name +# must be used on lines 3 and 4 above. Elsewhere, different filenames can +# be used. The --size N parameter can be adjusted as desired. +# +package require Tk +set f [open data.txt rb] +set data [read $f] +close $f +canvas .c +frame .b +button .b.b1 -text X-Y -command refill-xy +button .b.b2 -text X-Z -command refill-xz +button .b.b3 -text Y-Z -command refill-yz +pack .b.b1 .b.b2 .b.b3 -side left +pack .c -side top -fill both -expand 1 +pack .b -side top +proc resize_canvas_to_fit {} { + foreach {x0 y0 x1 y1} [.c bbox all] break + set w [expr {$x1-$x0}] + set h [expr {$y1-$y0}] + .c config -width $w -height $h +} +proc refill-xy {} { + .c delete all + foreach {id x0 x1 y0 y1 z0 z1} $::data { + .c create rectangle $x0 $y0 $x1 $y1 + } + .c scale all 0 0 0.05 0.05 + resize_canvas_to_fit +} +proc refill-xz {} { + .c delete all + foreach {id x0 x1 y0 y1 z0 z1} $::data { + .c create rectangle $x0 $z0 $x1 $z1 + } + .c scale all 0 0 0.05 0.05 + resize_canvas_to_fit +} +proc refill-yz {} { + .c delete all + foreach {id x0 x1 y0 y1 z0 z1} $::data { + .c create rectangle $y0 $z0 $y1 $z1 + } + .c scale all 0 0 0.05 0.05 + resize_canvas_to_fit +} +refill-xy diff --git a/test/skipscan1.test b/test/skipscan1.test index 81cbc1d..8150b01 100644 --- a/test/skipscan1.test +++ b/test/skipscan1.test @@ -181,7 +181,7 @@ do_execsql_test skipscan1-3.2 { do_execsql_test skipscan1-3.2eqp { EXPLAIN QUERY PLAN SELECT a,b,c,d,'|' FROM t3 WHERE b=345 ORDER BY a; -} {/* INDEX sqlite_autoindex_t3_1 (ANY(a) AND b=?)*/} +} {/* PRIMARY KEY (ANY(a) AND b=?)*/} do_execsql_test skipscan1-3.2sort { EXPLAIN QUERY PLAN SELECT a,b,c,d,'|' FROM t3 WHERE b=345 ORDER BY a; diff --git a/test/skipscan2.test b/test/skipscan2.test index e39b16e..a42ff2d 100644 --- a/test/skipscan2.test +++ b/test/skipscan2.test @@ -74,6 +74,7 @@ do_execsql_test skipscan2-1.4 { -- of a skip-scan. So make a manual adjustment to the stat1 table -- to make it seem like there are many more. UPDATE sqlite_stat1 SET stat='10000 5000 20' WHERE idx='people_idx1'; + UPDATE sqlite_stat1 SET stat='10000 1' WHERE idx='sqlite_autoindex_people_1'; ANALYZE sqlite_master; } db cache flush @@ -185,6 +186,20 @@ do_execsql_test skipscan2-2.5eqp { SELECT name FROM peoplew WHERE height>=180 ORDER BY +name; } {/*INDEX peoplew_idx1 */} +# A skip-scan on a PK index of a WITHOUT ROWID table. +# +do_execsql_test skipscan2-3.1 { + CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b)) WITHOUT ROWID; +} +do_test skipscan2-3.2 { + for {set i 0} {$i < 1000} {incr i} { + execsql { INSERT INTO t3 VALUES($i%2, $i, 'xyz') } + } + execsql { ANALYZE } +} {} +do_eqp_test skipscan2-3.3eqp { + SELECT * FROM t3 WHERE b=42; +} {0 0 0 {SEARCH TABLE t3 USING PRIMARY KEY (ANY(a) AND b=?)}} finish_test diff --git a/test/skipscan5.test b/test/skipscan5.test new file mode 100644 index 0000000..5d6d392 --- /dev/null +++ b/test/skipscan5.test @@ -0,0 +1,186 @@ +# 2013-11-13 +# +# 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 tests of the "skip-scan" query strategy. In +# particular it tests that stat4 data can be used by a range query +# that uses the skip-scan approach. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix skipscan5 + +ifcapable !stat4 { + finish_test + return +} + +do_execsql_test 1.1 { + CREATE TABLE t1(a INT, b INT, c INT); + CREATE INDEX i1 ON t1(a, b); +} {} + +expr srand(4) +do_test 1.2 { + for {set i 0} {$i < 100} {incr i} { + set a [expr int(rand()*4.0) + 1] + set b [expr int(rand()*20.0) + 1] + execsql { INSERT INTO t1 VALUES($a, $b, NULL) } + } + execsql ANALYZE +} {} + +foreach {tn q res} { + 1 "b = 5" {/*ANY(a) AND b=?*/} + 2 "b > 12 AND b < 16" {/*ANY(a) AND b>? AND b 2 AND b < 16" {/*SCAN TABLE t1*/} + 4 "b > 18 AND b < 25" {/*ANY(a) AND b>? AND b 15" {/*ANY(a) AND b>?*/} + 6 "b > 5" {/*SCAN TABLE t1*/} + 7 "b < 15" {/*SCAN TABLE t1*/} + 8 "b < 5" {/*ANY(a) AND b b" {/*ANY(a) AND b '12' AND b < '16'" {/*ANY(a) AND b>? AND b '2' AND b < '16'" {/*SCAN TABLE t1*/} + 13 "b > '18' AND b < '25'" {/*ANY(a) AND b>? AND b '15'" {/*ANY(a) AND b>?*/} + 15 "b > '5'" {/*SCAN TABLE t1*/} + 16 "b < '15'" {/*SCAN TABLE t1*/} + 17 "b < '5'" {/*ANY(a) AND b b" {/*ANY(a) AND b? AND c 'q' } {/*ANY(a) AND ANY(b) AND c>?*/} + 4 { c > 'e' } {/*SCAN TABLE t2*/} + 5 { c < 'q' } {/*SCAN TABLE t2*/} + 4 { c < 'e' } {/*ANY(a) AND ANY(b) AND c? AND b X'5555'" {/*ANY(a) AND b>?*/} + 5 "b > 'zzz'" {/*ANY(a) AND b>?*/} + 6 "b < 'zzz'" {/*SCAN TABLE t3*/} +} { + set sql "EXPLAIN QUERY PLAN SELECT * FROM t3 WHERE $q" + do_execsql_test 3.3.$tn $sql $res +} + +finish_test + + + + diff --git a/test/speedtest1.c b/test/speedtest1.c index 05160e0..383f580 100644 --- a/test/speedtest1.c +++ b/test/speedtest1.c @@ -29,6 +29,7 @@ static const char zHelp[] = " --trace Turn on SQL tracing\n" " --utf16be Set text encoding to UTF-16BE\n" " --utf16le Set text encoding to UTF-16LE\n" + " --verify Run additional verification steps.\n" " --without-rowid Use WITHOUT ROWID where appropriate\n" ; @@ -51,6 +52,7 @@ static struct Global { int bReprepare; /* True to reprepare the SQL on each rerun */ int bSqlOnly; /* True to print the SQL once only */ int bExplain; /* Print SQL with EXPLAIN prefix */ + int bVerify; /* Try to verify that results are correct */ int szTest; /* Scale factor for test iterations */ const char *zWR; /* Might be WITHOUT ROWID */ const char *zNN; /* Might be NOT NULL */ @@ -474,7 +476,7 @@ void testset_main(void){ speedtest1_end_test(); - n = g.szTest/2; + n = 25; speedtest1_begin_test(130, "%d SELECTS, numeric BETWEEN, unindexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( @@ -492,7 +494,7 @@ void testset_main(void){ speedtest1_end_test(); - n = g.szTest/5; + n = 10; speedtest1_begin_test(140, "%d SELECTS, LIKE, unindexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( @@ -512,6 +514,45 @@ void testset_main(void){ speedtest1_end_test(); + n = 10; + speedtest1_begin_test(142, "%d SELECTS w/ORDER BY, unindexed", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "SELECT a, b, c FROM t1 WHERE c LIKE ?1\n" + " ORDER BY a; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%maxb; + zNum[0] = '%'; + len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2); + zNum[len] = '%'; + zNum[len+1] = 0; + sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + n = 10; //g.szTest/5; + speedtest1_begin_test(145, "%d SELECTS w/ORDER BY and LIMIT, unindexed", n); + speedtest1_exec("BEGIN"); + speedtest1_prepare( + "SELECT a, b, c FROM t1 WHERE c LIKE ?1\n" + " ORDER BY a LIMIT 10; -- %d times", n + ); + for(i=1; i<=n; i++){ + x1 = speedtest1_random()%maxb; + zNum[0] = '%'; + len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2); + zNum[len] = '%'; + zNum[len+1] = 0; + sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + speedtest1_begin_test(150, "CREATE INDEX five times"); speedtest1_exec("BEGIN;"); speedtest1_exec("CREATE UNIQUE INDEX t1b ON t1(b);"); @@ -892,6 +933,183 @@ void testset_cte(void){ } +/* Generate two numbers between 1 and mx. The first number is less than +** the second. Usually the numbers are near each other but can sometimes +** be far apart. +*/ +static void twoCoords( + int p1, int p2, /* Parameters adjusting sizes */ + unsigned mx, /* Range of 1..mx */ + unsigned *pX0, unsigned *pX1 /* OUT: write results here */ +){ + unsigned d, x0, x1, span; + + span = mx/100 + 1; + if( speedtest1_random()%3==0 ) span *= p1; + if( speedtest1_random()%p2==0 ) span = mx/2; + d = speedtest1_random()%span + 1; + x0 = speedtest1_random()%(mx-d) + 1; + x1 = x0 + d; + *pX0 = x0; + *pX1 = x1; +} + +/* The following routine is an R-Tree geometry callback. It returns +** true if the object overlaps a slice on the Y coordinate between the +** two values given as arguments. In other words +** +** SELECT count(*) FROM rt1 WHERE id MATCH xslice(10,20); +** +** Is the same as saying: +** +** SELECT count(*) FROM rt1 WHERE y1>=10 AND y0<=20; +*/ +static int xsliceGeometryCallback( + sqlite3_rtree_geometry *p, + int nCoord, + double *aCoord, + int *pRes +){ + *pRes = aCoord[3]>=p->aParam[0] && aCoord[2]<=p->aParam[1]; + return SQLITE_OK; +} + +/* +** A testset for the R-Tree virtual table +*/ +void testset_rtree(int p1, int p2){ + unsigned i, n; + unsigned mxCoord; + unsigned x0, x1, y0, y1, z0, z1; + unsigned iStep; + int *aCheck = sqlite3_malloc( sizeof(int)*g.szTest*100 ); + + mxCoord = 15000; + n = g.szTest*100; + speedtest1_begin_test(100, "%d INSERTs into an r-tree", n); + speedtest1_exec("BEGIN"); + speedtest1_exec("CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1,z0,z1)"); + speedtest1_prepare("INSERT INTO rt1(id,x0,x1,y0,y1,z0,z1)" + "VALUES(?1,?2,?3,?4,?5,?6,?7)"); + for(i=1; i<=n; i++){ + twoCoords(p1, p2, mxCoord, &x0, &x1); + twoCoords(p1, p2, mxCoord, &y0, &y1); + twoCoords(p1, p2, mxCoord, &z0, &z1); + sqlite3_bind_int(g.pStmt, 1, i); + sqlite3_bind_int(g.pStmt, 2, x0); + sqlite3_bind_int(g.pStmt, 3, x1); + sqlite3_bind_int(g.pStmt, 4, y0); + sqlite3_bind_int(g.pStmt, 5, y1); + sqlite3_bind_int(g.pStmt, 6, z0); + sqlite3_bind_int(g.pStmt, 7, z1); + speedtest1_run(); + } + speedtest1_exec("COMMIT"); + speedtest1_end_test(); + + speedtest1_begin_test(101, "Copy from rtree to a regular table"); + speedtest1_exec("CREATE TABLE t1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)"); + speedtest1_exec("INSERT INTO t1 SELECT * FROM rt1"); + speedtest1_end_test(); + + n = g.szTest*20; + speedtest1_begin_test(110, "%d one-dimensional intersect slice queries", n); + speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x0>=?1 AND x1<=?2"); + iStep = mxCoord/n; + for(i=0; i=?1 AND x1<=?2"); + iStep = mxCoord/n; + for(i=0; i=?1 AND y0<=?2"); + iStep = mxCoord/n; + for(i=0; i=?1 AND y0<=?2"); + iStep = mxCoord/n; + for(i=0; i=?1 AND x0<=?2" + " AND y1>=?1 AND y0<=?2 AND z1>=?1 AND z0<=?2"); + iStep = mxCoord/n; + for(i=0; i? AND O_ORDERDATE?" + 2 "SELECT * FROM t1 WHERE a > 100" {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} {0 0 0 {SCAN TABLE t1}} 3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid" diff --git a/test/vtab_shared.test b/test/vtab_shared.test index 13237a8..3473992 100644 --- a/test/vtab_shared.test +++ b/test/vtab_shared.test @@ -15,6 +15,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix vtab_shared ifcapable !vtab||!shared_cache { finish_test @@ -228,5 +229,51 @@ do_test vtab_shared_1.15.3 { db close db2 close + +#--------------------------------------------------------------- +# Test calling sqlite3_close() with vtabs on the disconnect list. +# +ifcapable rtree { + reset_db + do_test 2.1.1 { + sqlite3 db test.db + sqlite3 db2 test.db + + # Create a virtual table using [db]. + execsql { + CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2); + INSERT INTO rt VALUES(1, 2 ,3); + SELECT * FROM rt; + } + + # Drop the virtual table using [db2]. The sqlite3_vtab object belonging + # to [db] is moved to the sqlite3.pDisconnect list. + execsql { DROP TABLE rt } db2 + + # Immediately close [db]. At one point this would fail due to the + # unfinalized statements held by the un-xDisconnect()ed sqlite3_vtab. + db close + } {} + db2 close +} + +ifcapable fts3 { + # Same test as above, except using fts3 instead of rtree. + reset_db + do_test 2.2.1 { + sqlite3 db test.db + sqlite3 db2 test.db + execsql { + CREATE VIRTUAL TABLE ft USING fts3; + INSERT INTO ft VALUES('hello world'); + SELECT * FROM ft; + } + execsql { DROP TABLE ft } db2 + db close + } {} + db2 close +} + sqlite3_enable_shared_cache 0 finish_test + diff --git a/test/wal.test b/test/wal.test index 3a69de5..675be73 100644 --- a/test/wal.test +++ b/test/wal.test @@ -1574,4 +1574,17 @@ sqlite3_shutdown test_sqlite3_log sqlite3_initialize +# Make sure PRAGMA journal_mode=WAL works with ATTACHED databases in +# all journal modes. +# +foreach mode {OFF MEMORY PERSIST DELETE TRUNCATE WAL} { + delete_file test.db test2.db + sqlite3 db test.db + do_test wal-25.$mode { + db eval "PRAGMA journal_mode=$mode" + db eval {ATTACH 'test2.db' AS t2; PRAGMA journal_mode=WAL;} + } {wal} + db close +} + finish_test diff --git a/test/wal2.test b/test/wal2.test index b331d5e..9d45444 100644 --- a/test/wal2.test +++ b/test/wal2.test @@ -811,7 +811,13 @@ do_test wal2-7.1.1 { do_test wal2-7.1.2 { forcecopy test.db test2.db forcecopy test.db-wal test2.db-wal - hexio_write test2.db-wal 48 FF + # The first 32 bytes of the WAL file contain the WAL header. Offset 48 + # is the first byte of the checksum for the first frame in the WAL. + # The following three lines replaces the contents of that byte with + # a different value. + set newval FF + if {$newval == [hexio_read test2.db-wal 48 1]} { set newval 00 } + hexio_write test2.db-wal 48 $newval } {1} do_test wal2-7.1.3 { sqlite3 db2 test2.db diff --git a/test/wal64k.test b/test/wal64k.test new file mode 100644 index 0000000..e962da1 --- /dev/null +++ b/test/wal64k.test @@ -0,0 +1,51 @@ +# 2010 April 13 +# +# 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 file is testing the operation of the library in +# "PRAGMA journal_mode=WAL" mode. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix wal64k + +ifcapable !wal {finish_test ; return } + +if {$tcl_platform(platform) != "unix"} { + finish_test + return +} + +db close +test_syscall pagesize 65536 +sqlite3 db test.db + +do_execsql_test 1.0 { + PRAGMA journal_mode = WAL; + CREATE TABLE t1(x); + CREATE INDEX i1 ON t1(x); +} {wal} +do_test 1.1 { file size test.db-shm } {65536} + +do_test 1.2 { + execsql BEGIN + while {[file size test.db-shm]==65536} { + execsql { INSERT INTO t1 VALUES( randstr(900,1100) ) } + } + execsql COMMIT + file size test.db-shm +} {131072} + +integrity_check 1.3 + +db close +test_syscall pagesize -1 +finish_test diff --git a/test/where2.test b/test/where2.test index d9b2b23..367eb0d 100644 --- a/test/where2.test +++ b/test/where2.test @@ -751,5 +751,13 @@ do_execsql_test where2-12.1 { } {/.*SEARCH TABLE t12 AS b .*SEARCH TABLE t12 AS b .*/} } +# Verify that all necessary OP_OpenRead opcodes occur in the OR optimization. +# +do_execsql_test where2-13.1 { + CREATE TABLE t13(a,b); + CREATE INDEX t13a ON t13(a); + INSERT INTO t13 VALUES(4,5); + SELECT * FROM t13 WHERE (1=2 AND a=3) OR a=4; +} {4 5} finish_test diff --git a/test/where3.test b/test/where3.test index 8fa9fa7..c2804b5 100644 --- a/test/where3.test +++ b/test/where3.test @@ -231,6 +231,7 @@ do_execsql_test where3-3.0 { CREATE TABLE t301(a INTEGER PRIMARY KEY,b,c); CREATE INDEX t301c ON t301(c); INSERT INTO t301 VALUES(1,2,3); + INSERT INTO t301 VALUES(2,2,3); CREATE TABLE t302(x, y); INSERT INTO t302 VALUES(4,5); ANALYZE; @@ -251,7 +252,7 @@ do_execsql_test where3-3.2 { } {} do_execsql_test where3-3.3 { SELECT * FROM t301 WHERE c=3 AND a IS NOT NULL; -} {1 2 3} +} {1 2 3 2 2 3} if 0 { # Query planner no longer does this # Verify that when there are multiple tables in a join which must be diff --git a/test/where9.test b/test/where9.test index 1c32ff8..d073074 100644 --- a/test/where9.test +++ b/test/where9.test @@ -781,7 +781,12 @@ do_test where9-6.8.2 { OR (b NOT NULL AND c NOT NULL AND d IS NULL) } } {1 {no query solution}} + +set solution_possible 0 ifcapable stat4||stat3 { + if {[permutation] != "no_optimization"} { set solution_possible 1 } +} +if $solution_possible { # When STAT3 is enabled, the "b NOT NULL" terms get translated # into b>NULL, which can be satified by the index t1b. It is a very # expensive way to do the query, but it works, and so a solution is possible. diff --git a/test/whereD.test b/test/whereD.test index eb0f864..db99304 100644 --- a/test/whereD.test +++ b/test/whereD.test @@ -217,6 +217,59 @@ do_execsql_test 4.7 { ORDER BY a; } {3 4 3 4} +# Verify fix of a bug reported on the mailing list by Peter Reid +# +do_execsql_test 5.1 { + DROP TABLE IF EXISTS t; + CREATE TABLE t(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17); + CREATE INDEX tc0 ON t(c0); + CREATE INDEX tc1 ON t(c1); + CREATE INDEX tc2 ON t(c2); + CREATE INDEX tc3 ON t(c3); + CREATE INDEX tc4 ON t(c4); + CREATE INDEX tc5 ON t(c5); + CREATE INDEX tc6 ON t(c6); + CREATE INDEX tc7 ON t(c7); + CREATE INDEX tc8 ON t(c8); + CREATE INDEX tc9 ON t(c9); + CREATE INDEX tc10 ON t(c10); + CREATE INDEX tc11 ON t(c11); + CREATE INDEX tc12 ON t(c12); + CREATE INDEX tc13 ON t(c13); + CREATE INDEX tc14 ON t(c14); + CREATE INDEX tc15 ON t(c15); + CREATE INDEX tc16 ON t(c16); + CREATE INDEX tc17 ON t(c17); + + INSERT INTO t(c0, c16) VALUES (1,1); + + SELECT * FROM t WHERE + c0=1 or c1=1 or c2=1 or c3=1 or + c4=1 or c5=1 or c6=1 or c7=1 or + c8=1 or c9=1 or c10=1 or c11=1 or + c12=1 or c13=1 or c14=1 or c15=1 or + c16=1 or c17=1; +} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1 {}} +do_execsql_test 5.2 { + DELETE FROM t; + INSERT INTO t(c0,c17) VALUES(1,1); + SELECT * FROM t WHERE + c0=1 or c1=1 or c2=1 or c3=1 or + c4=1 or c5=1 or c6=1 or c7=1 or + c8=1 or c9=1 or c10=1 or c11=1 or + c12=1 or c13=1 or c14=1 or c15=1 or + c16=1 or c17=1; +} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1} +do_execsql_test 5.3 { + DELETE FROM t; + INSERT INTO t(c0,c15) VALUES(1,1); + SELECT * FROM t WHERE + c0=1 or c1=1 or c2=1 or c3=1 or + c4=1 or c5=1 or c6=1 or c7=1 or + c8=1 or c9=1 or c10=1 or c11=1 or + c12=1 or c13=1 or c14=1 or c15=1 or + c16=1 or c17=1; +} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1 {} {}} finish_test diff --git a/test/whereG.test b/test/whereG.test index 1b6a861..c2c54db 100644 --- a/test/whereG.test +++ b/test/whereG.test @@ -9,11 +9,12 @@ # #*********************************************************************** # -# Test cases for query planning decisions and the unlikely() and +# Test cases for query planning decisions and the likely(), unlikely(), and # likelihood() functions. set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix whereG do_execsql_test whereG-1.0 { CREATE TABLE composer( @@ -95,7 +96,7 @@ do_eqp_test whereG-1.5 { WHERE cname LIKE '%bach%' AND composer.cid=track.cid AND album.aid=track.aid; -} {/.*track.*composer.*album.*/} +} {/.*track.*(composer.*album|album.*composer).*/} do_execsql_test whereG-1.6 { SELECT DISTINCT aname FROM album, composer, track @@ -110,7 +111,7 @@ do_eqp_test whereG-1.7 { WHERE cname LIKE '%bach%' AND unlikely(composer.cid=track.cid) AND unlikely(album.aid=track.aid); -} {/.*track.*composer.*album.*/} +} {/.*track.*(composer.*album|album.*composer).*/} do_execsql_test whereG-1.8 { SELECT DISTINCT aname FROM album, composer, track @@ -166,5 +167,67 @@ do_eqp_test whereG-3.4 { SELECT * FROM a, b WHERE a2=5 AND a1=b1; } {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} +# Ticket [1e64dd782a126f48d78c43a664844a41d0e6334e]: +# Incorrect result in a nested GROUP BY/DISTINCT due to the use of an OP_SCopy +# where an OP_Copy was needed. +# +do_execsql_test whereG-4.0 { + CREATE TABLE t4(x); + INSERT INTO t4 VALUES('right'),('wrong'); + SELECT DISTINCT x + FROM (SELECT x FROM t4 GROUP BY x) + WHERE x='right' + ORDER BY x; +} {right} + +#------------------------------------------------------------------------- +# Test that likelihood() specifications on indexed terms are taken into +# account by various forms of loops. +# +# 5.1.*: open ended range scans +# 5.2.*: skip-scans +# +reset_db + +do_execsql_test 5.1 { + CREATE TABLE t1(a, b, c); + CREATE INDEX i1 ON t1(a, b); +} +do_eqp_test 5.1.2 { + SELECT * FROM t1 WHERE a>? +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} +do_eqp_test 5.1.3 { + SELECT * FROM t1 WHERE likelihood(a>?, 0.9) +} {0 0 0 {SCAN TABLE t1}} +do_eqp_test 5.1.4 { + SELECT * FROM t1 WHERE likely(a>?) +} {0 0 0 {SCAN TABLE t1}} + +do_test 5.2 { + for {set i 0} {$i < 100} {incr i} { + execsql { INSERT INTO t1 VALUES('abc', $i, $i); } + } + execsql { INSERT INTO t1 SELECT 'def', b, c FROM t1; } + execsql { ANALYZE } +} {} +do_eqp_test 5.2.2 { + SELECT * FROM t1 WHERE likelihood(b>?, 0.01) +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (ANY(a) AND b>?)}} +do_eqp_test 5.2.3 { + SELECT * FROM t1 WHERE likelihood(b>?, 0.9) +} {0 0 0 {SCAN TABLE t1}} +do_eqp_test 5.2.4 { + SELECT * FROM t1 WHERE likely(b>?) +} {0 0 0 {SCAN TABLE t1}} + +do_eqp_test 5.3.1 { + SELECT * FROM t1 WHERE a=? +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} +do_eqp_test 5.3.2 { + SELECT * FROM t1 WHERE likelihood(a=?, 0.9) +} {0 0 0 {SCAN TABLE t1}} +do_eqp_test 5.3.3 { + SELECT * FROM t1 WHERE likely(a=?) +} {0 0 0 {SCAN TABLE t1}} finish_test diff --git a/test/whereH.test b/test/whereH.test new file mode 100644 index 0000000..c252fe1 --- /dev/null +++ b/test/whereH.test @@ -0,0 +1,139 @@ +# 2014-03-31 +# +# 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. +# +#*********************************************************************** +# +# Test cases for query planning decisions where one candidate index +# covers a proper superset of the WHERE clause terms of another +# candidate index. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test whereH-1.1 { + CREATE TABLE t1(a,b,c,d); + CREATE INDEX t1abc ON t1(a,b,c); + CREATE INDEX t1bc ON t1(b,c); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c; +} {/INDEX t1abc /} +do_execsql_test whereH-1.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-2.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d); + CREATE INDEX t1bc ON t1(b,c); + CREATE INDEX t1abc ON t1(a,b,c); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c; +} {/INDEX t1abc /} +do_execsql_test whereH-2.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-3.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1cd ON t1(c,d); + CREATE INDEX t1bcd ON t1(b,c,d); + CREATE INDEX t1abcd ON t1(a,b,c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-3.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-4.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1cd ON t1(c,d); + CREATE INDEX t1abcd ON t1(a,b,c,d); + CREATE INDEX t1bcd ON t1(b,c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-4.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-5.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1bcd ON t1(b,c,d); + CREATE INDEX t1cd ON t1(c,d); + CREATE INDEX t1abcd ON t1(a,b,c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-5.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-6.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1bcd ON t1(b,c,d); + CREATE INDEX t1abcd ON t1(a,b,c,d); + CREATE INDEX t1cd ON t1(c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-6.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-7.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1abcd ON t1(a,b,c,d); + CREATE INDEX t1bcd ON t1(b,c,d); + CREATE INDEX t1cd ON t1(c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-7.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + +do_execsql_test whereH-8.1 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c,d,e); + CREATE INDEX t1abcd ON t1(a,b,c,d); + CREATE INDEX t1cd ON t1(c,d); + CREATE INDEX t1bcd ON t1(b,c,d); + + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {/INDEX t1abcd /} +do_execsql_test whereH-8.2 { + EXPLAIN QUERY PLAN + SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d; +} {~/TEMP B-TREE FOR ORDER BY/} + + + +finish_test diff --git a/test/whereI.test b/test/whereI.test new file mode 100644 index 0000000..452e7f8 --- /dev/null +++ b/test/whereI.test @@ -0,0 +1,92 @@ +# 2014-03-31 +# +# 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. +# +#*********************************************************************** +# The focus of this file is testing the OR optimization on WITHOUT ROWID +# tables. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix whereI + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b, c, PRIMARY KEY(a)) WITHOUT ROWID; + INSERT INTO t1 VALUES(1, 'a', 'z'); + INSERT INTO t1 VALUES(2, 'b', 'y'); + INSERT INTO t1 VALUES(3, 'c', 'x'); + INSERT INTO t1 VALUES(4, 'd', 'w'); + CREATE INDEX i1 ON t1(b); + CREATE INDEX i2 ON t1(c); +} + +do_eqp_test 1.1 { + SELECT a FROM t1 WHERE b='b' OR c='x' +} { + 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b=?)} + 0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)} +} + +do_execsql_test 1.2 { + SELECT a FROM t1 WHERE b='b' OR c='x' +} {2 3} + +do_execsql_test 1.3 { + SELECT a FROM t1 WHERE b='a' OR c='z' +} {1} + +#---------------------------------------------------------------------- +# Try that again, this time with non integer PRIMARY KEY values. +# +do_execsql_test 2.0 { + CREATE TABLE t2(a, b, c, PRIMARY KEY(a)) WITHOUT ROWID; + INSERT INTO t2 VALUES('i', 'a', 'z'); + INSERT INTO t2 VALUES('ii', 'b', 'y'); + INSERT INTO t2 VALUES('iii', 'c', 'x'); + INSERT INTO t2 VALUES('iv', 'd', 'w'); + CREATE INDEX i3 ON t2(b); + CREATE INDEX i4 ON t2(c); +} + +do_eqp_test 2.1 { + SELECT a FROM t2 WHERE b='b' OR c='x' +} { + 0 0 0 {SEARCH TABLE t2 USING INDEX i3 (b=?)} + 0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)} +} + +do_execsql_test 2.2 { + SELECT a FROM t2 WHERE b='b' OR c='x' +} {ii iii} + +do_execsql_test 2.3 { + SELECT a FROM t2 WHERE b='a' OR c='z' +} {i} + +#---------------------------------------------------------------------- +# On a table with a multi-column PK. +# +do_execsql_test 3.0 { + CREATE TABLE t3(a, b, c, d, PRIMARY KEY(c, b)) WITHOUT ROWID; + + INSERT INTO t3 VALUES('f', 1, 1, 'o'); + INSERT INTO t3 VALUES('o', 2, 1, 't'); + INSERT INTO t3 VALUES('t', 1, 2, 't'); + INSERT INTO t3 VALUES('t', 2, 2, 'f'); + + CREATE INDEX t3i1 ON t3(d); + CREATE INDEX t3i2 ON t3(a); + + SELECT c||'.'||b FROM t3 WHERE a='t' OR d='t' +} { + 2.1 2.2 1.2 +} + +finish_test + diff --git a/test/whereJ.test b/test/whereJ.test new file mode 100644 index 0000000..5209f16 --- /dev/null +++ b/test/whereJ.test @@ -0,0 +1,375 @@ +# 2014-06-06 +# +# 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 a complex +# query planning case. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix whereJ + +ifcapable !stat4 { + finish_test + return +} + +do_execsql_test whereJ-1.0 { + CREATE TABLE tx1 ( + est, + cid, + sid, + fid, + aid, + edate, + rstat, + ftype, + cx, + fyear, + fp, + acode, + a1, + curx, + tdate, + gstat, + trgtpx, + effdate, + adate, + ytime, + mstat + ); + CREATE INDEX ix0 on tx1(a1,curx,aid,cid,sid,ftype,fp,fyear DESC,edate DESC,fid); + CREATE INDEX ix1 on tx1(a1,curx,aid,ftype,fp,fyear DESC,fid,edate DESC,cid,sid); + CREATE INDEX ix2 on tx1(a1,curx,cid,sid,ftype,fp,fyear DESC,edate DESC,aid,fid); + CREATE INDEX ix3 on tx1(a1,curx,fid,ftype,fp,fyear DESC,cid,sid,aid,edate DESC); + CREATE INDEX ix4 on tx1(a1,curx,ftype,cid,sid,aid,edate DESC,fid,fp,fyear DESC); + CREATE INDEX ix5 on tx1(a1,curx,ftype,aid,fid,cid,sid,edate DESC,fp,fyear DESC); + CREATE INDEX ix6 on tx1(ftype,fp,fyear DESC,cid,sid,edate DESC,a1,fid,aid,curx,est,rstat,cx,acode,tdate,gstat,trgtpx,effdate,adate,ytime,mstat); + CREATE INDEX ix7 on tx1(cid,a1,curx,sid,ftype,est,fid,aid,edate,rstat,cx,fyear,fp,acode,tdate,gstat,trgtpx,effdate,adate,ytime,mstat); + CREATE INDEX ix8 on tx1(cid,sid,edate DESC,aid,est); + CREATE INDEX ix9 on tx1(aid,edate DESC,a1,curx); +} {} +do_execsql_test whereJ-1.1 { + ANALYZE sqlite_master; + DELETE FROM sqlite_stat1; + DELETE FROM sqlite_stat4; + INSERT INTO sqlite_stat1 VALUES('tx1','ix9','11680827 289 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix8','11680827 286 250 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix7','11680827 286 194 98 88 83 18 7 6 2 2 2 2 2 2 2 2 2 2 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix6','11680827 5840414 5840414 5840414 240 212 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix5','11680827 5840414 2920207 1668690 114 90 8 8 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix4','11680827 5840414 2920207 1668690 92 83 9 2 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix3','11680827 5840414 2920207 2048 1835 1835 1835 12 11 8 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix2','11680827 5840414 2920207 98 88 83 83 83 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix1','11680827 5840414 2920207 117 114 114 114 90 2 2 2'); + INSERT INTO sqlite_stat1 VALUES('tx1','ix0','11680827 5840414 2920207 117 9 9 9 9 9 2 2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','6736 21 21 21 1','29210 29404 29404 29404 29424','44 12184 13020 13079 29424',X'06030409080416C1150133512800B01FCA'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','6658 24 21 21 1','452220 453273 453276 453276 453296','622 226258 235279 236774 453296',X'06030409080416F34501332ADC00AA1BD3'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','820 2 2 2 1','1297771 1297869 1297869 1297869 1297869','1964 681724 711020 715822 1297869',X'06030409080317875501332C6C55AF4D'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','26985 2216 2216 2216 1','1797607 1797782 1797782 1797782 1799997','3162 970307 1008879 1016089 1799997',X'0603040809041A08040132401A0099A334'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','10434 19 17 17 1','2118117 2120403 2120405 2120405 2120421','3815 1136110 1181459 1190207 2120421',X'0603040908041AD36901332CD000861A2F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','437 1 1 1 1','2595414 2595739 2595739 2595739 2595739','5005 1409452 1464066 1475163 2595739',X'0603040808031CE7FD01317FD46BFBCC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','12619 38 38 38 1','2595957 2600212 2600212 2600212 2600249','5007 1410347 1464961 1476068 2600249',X'0603040808041CE87E01328F61008CE96A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','7534 23 18 18 1','3329985 3334890 3334895 3334895 3334912','6901 1834013 1902216 1917268 3334912',X'060304090804244E1901328F59008CAA39'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','5693 1 1 1 1','3891665 3893609 3893609 3893609 3893609','8357 2164400 2245393 2263185 3893609',X'0603040808043063B70132B66800A28A43'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','44405 2588 2223 1527 1','4220255 4221633 4221998 4222694 4224220','9221 2354858 2441973 2461511 4224220',X'0603040909043377630133517A00B0DE4F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','6883 32 28 28 1','4423918 4429926 4429930 4429930 4429957','9690 2452276 2543443 2563995 4429957',X'06030409080434F46801328F5C008CC3DA'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','6974 27 26 26 1','5048404 5051129 5051130 5051130 5051155','11703 2817010 2920184 2944013 5051155',X'0603040908043C1C5C0132DEA5009F7473'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','476 2 2 2 1','5191322 5191479 5191479 5191479 5191479','12242 2901130 3006663 3031222 5191479',X'0603040908033DC6080132DEA478849A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','627 4 4 4 1','6488823 6489349 6489349 6489349 6489349','16423 3644815 3778857 3809866 6489349',X'0603040808035AA00E0131F4AE342150'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','145 2 2 1 1','7787091 7787218 7787218 7787219 7787219','20223 4343720 4510110 4547961 7787219',X'0603040809037254890132189C703706'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','20 1 1 1 1','9085074 9085089 9085089 9085089 9085089','25315 5033102 5230788 5275692 9085089',X'06040408080300EAE6CA01326657620652'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','229621 6135 5934 5934 1','9507353 9572696 9572696 9572696 9576801','27189 5255584 5463962 5511784 9576801',X'06040408080300F2FA440132DF1A7D1A60'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','6376 24 22 22 1','10381524 10382938 10382940 10382940 10382959','30519 5581705 5804515 5856651 10382959',X'06040409080400F9DBF3013305AC00A688A4'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','7761 45 9 9 1','10569039 10572476 10572512 10572512 10572520','31455 5661599 5888691 5941811 10572520',X'06040409080400FB31560132DDD800A05DF5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','8382 37 37 37 1','10866664 10867565 10867565 10867565 10867601','33475 5809193 6042611 6097741 10867601',X'06040409080400FFA4A701332A0E00A93957'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','76136 4099 3018 3018 1','11283107 11308143 11309224 11309224 11312241','37001 6022861 6264510 6322923 11312241',X'060404090804010B0A5C0133517200B0E8E0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','23472 2188 2188 2181 1','11365285 11380281 11380281 11380288 11382468','37055 6026680 6268909 6327509 11382468',X'060404080904010B3C6701332B2E00AA4374'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','59591 4087 4073 4 1','11415316 11448759 11448773 11452842 11452845','37350 6040743 6283483 6342389 11452845',X'060404090904010BFA810133512800B010AE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix9','43891 3029 3021 4 1','11598477 11622881 11622889 11625906 11625909','39110 6107644 6353109 6413914 11625909',X'0604040909040113B9960133512800B01235'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7340 4977 19 1 1 1','206533 206533 208739 208757 208757 208757','125 164 111403 207397 207399 208757',X'070308040407030187840132B54B0101A0D1401C0000000000004C87E5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','8877 8788 45 1 1 1','1221375 1221375 1224509 1224553 1224553 1224553','931 1117 679933 1216705 1216722 1224553',X'07030804040703018D3F0133023D010B9B67401C0000000000007A99EF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7204 7204 39 1 1 1','1240162 1240162 1242572 1242610 1242610 1242610','942 1131 688420 1234655 1234672 1242610',X'07030804040703018D4F0132DB820105D324401C0000000000007EC569'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','9608 9608 44 1 1 1','1264939 1264939 1266529 1266572 1266572 1266572','952 1145 699518 1258423 1258440 1266572',X'07030804040704018D61013305B9010D3CEB406E8000000000000081E17A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','6636 6636 1 1 1 1','1294580 1294580 1297869 1297869 1297869 1297869','964 1159 713121 1289522 1289540 1297869',X'07030804030704018D7801328F693482A2403400000000000000A26728'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7822 6629 26 1 1 1','2375708 2375708 2381333 2381358 2381358 2381358','3423 3833 1371902 2366527 2366559 2381358',X'0703080403070301B1F501317F16403B7B403F00000000000060D67A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','1403 1303 5 1 1 1','2594767 2594767 2595737 2595739 2595739 2595739','3914 4427 1512042 2580073 2580114 2595739',X'0703080403070301B6480131CC18558082407120000000000029CC12'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7901 6067 26 1 1 1','3424107 3424107 3425939 3425964 3425964 3425964','5872 6630 2032411 3406550 3406594 3425964',X'0703080404070401C3F90132B7A100FDCC04403E00000000000000A014CE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7483 6161 22 1 1 1','3549446 3549446 3555223 3555244 3555244 3555244','5932 6752 2099309 3535259 3535304 3555244',X'0703080403070301C4490131573F4104F8403400000000000067FD1E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','12076 8263 37 1 1 1','3558079 3558079 3560036 3560072 3560072 3560072','5935 6758 2101989 3540078 3540123 3560072',X'0703080404070301C44E0132DD0901076DA9404200000000000076F994'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','1123 1113 1 1 1 1','3892913 3892913 3893609 3893609 3893609 3893609','6594 7611 2305483 3871711 3871770 3893609',X'0703080403070301CA280131CA1C215083401C00000000000071F6B2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','9344 7315 41 1 1 1','4213510 4213510 4219434 4219474 4219474 4219474','7200 8390 2503024 4196141 4196204 4219474',X'0703080404070301CE8C01317DE800FE4E8B4034000000000000458317'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','8062 3291 1 1 1 1','5037060 5037060 5040350 5040350 5040350 5040350','10201 11915 3045602 5012912 5012997 5040350',X'070308040307030213B20130B83A16DF86403600000000000028F8CD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','9125 2926 1 1 1 1','5046490 5052665 5055590 5055590 5055590 5055590','10203 11926 3055524 5028097 5028182 5055590',X'070302040307030213B5232A013107F01745AF40330000000000002B57DE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','591 591 1 1 1 1','5190991 5190991 5191479 5191479 5191479 5191479','10649 12426 3145181 5163206 5163296 5191479',X'070308040307030244AD0131315217C1CD401C00000000000003BC32'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7381 4689 1 1 1 1','6112248 6112248 6116936 6116936 6116936 6116936','13780 16308 3748958 6083681 6083797 6116936',X'0703080403070402A9D1013108B531A21C401C0000000000000092F5C6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7569 7381 28 1 1 1','6280084 6280084 6281842 6281869 6281869 6281869','14559 17217 3856803 6247722 6247841 6281869',X'0703080404070302C14C0132DBF101044CC7401C00000000000074FB16'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','8289 7047 28 1 1 1','6290764 6290764 6296854 6296881 6296881 6296881','14569 17229 3863206 6262658 6262777 6296881',X'0703080403070302C16401317CC348B670401C0000000000006824BB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','2209 2209 1 1 1 1','6489075 6489075 6489349 6489349 6489349 6489349','15377 18147 3986912 6454194 6454318 6489349',X'0703080403070402EA5901332A656C6F5E401C00000000000000AE7C03'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7381 6799 1 1 1 1','7314420 7314420 7321218 7321218 7321218 7321218','18403 21722 4532963 7281695 7281847 7321218',X'07030804030703049EE501310667176DC940438000000000005ED2B5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','7163 7001 31 1 1 1','7652849 7652849 7658600 7658630 7658630 7658630','19462 22956 4750159 7617449 7617608 7658630',X'070308040407030503EB01317DEF010ADD3F402800000000000061C3EF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','1433 1433 2 1 1 1','7785842 7785842 7787219 7787219 7787219 7787219','20001 23575 4834605 7745315 7745477 7787219',X'07030804030703055010013156D81B11AC404380000000000004A313'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','2247 2247 1 1 1 1','9083272 9083272 9085089 9085089 9085089 9085089','24940 29143 5668423 9036693 9036887 9085089',X'070308040307031A620A01323EEB5CE39C406FE000000000006F8177'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix8','107 107 5 1 1 1','10382912 10382912 10382957 10382959 10382959 10382959','31251 36297 6541362 10329764 10330008 10382959',X'0704080403070400955501013350516AA9D0406060000000000000884648'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7340 4770 4527 3331 3331 970 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','206533 206533 206533 206533 206533 206596 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565 207565','125 202 402 512 560 6209 20696 25885 206260 206260 206260 206260 206260 206260 206260 206260 206260 206260 206260 206260 206260 207565',X'1703080808080704030408030808010308070808080803018784401C000000000000024FD353493F8801317E4700FFFF0F00FFFFC0F869E0000000002642C5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','8877 4669 71 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','1221375 1225583 1230181 1230249 1230249 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251 1230251','931 1504 2992 3495 3751 39629 120561 147424 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1222711 1230251',X'1703090902080704030408090808010108070404040804018D3F03E8405680000000000000822B981EB823013351F00F0C4086E00000000000013351F0013351F053870D7500B22A8C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7204 4801 193 193 4 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','1240162 1240162 1244770 1244770 1244959 1244961 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962 1244962','942 1520 3024 3531 3791 40098 122274 149540 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1237296 1244962',X'1703080908010703030408030808010308070408040803018D4F07406FE000000000000602CF16DE05013303C300FFFF0300FFFFC0F869E000000000013303C3008000004BD756'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','9608 6098 5910 5910 5910 2149 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','1264939 1264939 1264939 1264939 1264939 1265217 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365 1267365','952 1536 3055 3576 3841 40616 124132 151876 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1259547 1267365',X'1703080808080704030408090808010101070404040803018D61401C0000000000000131374D1726AB0132DD780F0C0540390000000000000132DD780132DD784E2789C6190CA9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','6636 4411 4237 4237 4237 33 8 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1','1294580 1294580 1294580 1294580 1294580 1297842 1297862 1297862 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869','964 1557 3097 3622 3888 41246 126538 154868 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1289863 1297869',X'1703080808080703030408090808010308070808080803018D7840420000000000007332F1227B5901321AF80800FFFF40260000000000006D0CEB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7822 4817 260 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','2375708 2375708 2380265 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524 2380524','3423 5117 10120 11184 11775 86237 242937 294878 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2366404 2380524',X'170308090308070304040803080801030807040408080401B1F501831C405C40000000000077646800EAD44C0132697000FFFF0300FFFFC0F869E0000000000132696F0132696F0094935E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','1403 1022 82 74 74 55 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','2594767 2594767 2595707 2595707 2595707 2595708 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739','3914 5817 11518 12879 13613 98100 278304 342850 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2580971 2595739',X'170308090808070303040803080801030807080808080301B648405C400000000000038EAC243F770131A6F700FFFF0E00FFFFC0F869E0000000005C8664'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7901 5298 291 55 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','3424107 3424107 3429114 3429350 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404 3429404','5872 8944 17727 19769 20846 145206 401995 498360 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3411279 3429404',X'170308090201070404040803080801030807040808080401C3F9232807405C40000000000000FF559400F2FA440133294600FFFF0300FFFFC0F869E000000000013329460083157B'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7483 5407 230 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','3549446 3549446 3554623 3554845 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852 3554852','5932 9041 17921 20139 21264 149060 417718 520064 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3536268 3554852',X'170308090201070404040803080801030807040808080401C449232807405C40000000000000FF559400F2FA440133294600FFFF0300FFFFC0F869E000000000013329460083162A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','12076 8365 7981 5546 5546 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','3558079 3558079 3558079 3558079 3558079 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624 3563624','5935 9046 17930 20154 21279 149235 418443 521109 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3544970 3563624',X'170308080808070303040803080801030107040408080301C44E4074300000000000029EB13BB98E01328EFE00FFFF0E00FFFF0AC0F869E00000000001328F0001328F0071D802'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','1123 916 875 875 875 93 22 22 1 1 1 1 1 1 1 1 1 1 1 1 1 1','3892913 3892913 3892913 3892913 3892913 3893531 3893602 3893602 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609','6594 10057 19942 22653 23964 165533 468498 587524 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3873325 3893609',X'170308080808070403040802080801030107040404080301CA28403F00000000000000832DC71933330132DB8800FC0F00FFFF054050C000000000000132DB870132DB8A4D5E35A2107205'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','9344 6359 6022 9 9 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','4213510 4213510 4213510 4219523 4219523 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531 4219531','7200 11025 21872 25036 26543 181203 517345 652858 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4198057 4219531',X'170308080308070303040803080801030807080808080301CE8C0186A0403F00000000000002C2142F19870131554100FFFF0F00FFFFC0F869E0000000000687F7'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','8062 4993 241 53 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','5037060 5037060 5041812 5042000 5042051 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052 5042052','10201 15484 30736 35196 37326 231854 654010 829510 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5017193 5042052',X'17030809020107030404080308080103080704080808030213B2245407406FE0000000000002C0AA00F6ABA101332A7E00FFFF0300FFFFC0F869E00000000001332A7E5287C0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','9125 5761 264 5 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','5046490 5046490 5051987 5052246 5052246 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250 5052250','10203 15488 30744 35230 37365 232178 654964 830718 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5027358 5052250',X'17030809030807030304080308080103080708080808030213B501831F406FE00000000000029E627136F901328DD500FFFF0300FFFFC0F869E000000000290DD6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','591 591 566 566 566 27 18 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1','5190991 5190991 5190991 5190991 5190991 5191461 5191464 5191474 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479','10649 16115 31973 36593 38793 239550 673441 853755 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5165855 5191479',X'17030808080807030404080108080101080708080808040244AD4045800000000000029E6200EAE8740132690D0A0F0C402E00000000000000941EAF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7381 3728 83 16 16 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','6112248 6115901 6119546 6119613 6119613 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628 6119628','13780 20707 41067 47538 50438 296473 834203 1056686 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6089878 6119628',X'170309090208070304040809080801010807040404080402A9D12328407360000000000002172300EABCFF0133517F0F0C404AA6665E02EA960133517F01335239538BC5C1008B5EC9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7569 5785 274 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','6280084 6280084 6285595 6285867 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868 6285868','14559 21811 43240 50020 53057 307264 862871 1092992 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6255378 6285868',X'170308090301070404040803080801030807040808080302C14C01832707405C40000000000000FF559400F2FA440133294600FFFF0300FFFFC0F869E000000000013329461E5109'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','8289 5734 266 33 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','6290764 6290764 6296232 6296465 6296495 6296495 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497 6296497','14569 21827 43272 50056 53096 307563 864043 1094585 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6265950 6296497',X'170308090201070404040803080801030807040808080402C164232807405C40000000000000FF559400F2FA440133294600FFFF0300FFFFC0F869E0000000000133294600A90415'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','2209 1450 1369 1369 1369 597 13 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1','6489075 6489075 6489075 6489075 6489075 6489139 6489344 6489344 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349','15377 22998 45584 52641 55837 319564 895653 1134252 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6458046 6489349',X'170308080808070303040802080801030807040404080302EA59401C0000000000000D4B201AD8B30132DF0400FC0600FFFF40180000000000000132DF040132DF054EBA338714FBBA'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7381 5446 171 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','7314420 7314420 7319695 7319855 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865 7319865','18403 27319 54152 62541 66337 369851 1032180 1306261 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7284923 7319865',X'1703080902010703030408030808010308070408080804049EE503E907405C400000000000029EC32E97BE0133061F00FFFF0300FFFFC0F869E0000000000133061F00A9ECEF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','7163 4782 209 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','7652849 7652849 7657422 7657626 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630 7657630','19462 28830 57147 65962 69945 388539 1084446 1372423 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7621247 7657630',X'17030809020107040404080308080103080704080808040503EB03EA07405C40000000000000FF559400F2FA440133294600FFFF0300FFFFC0F869E0000000000133294600831554'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','1433 582 571 571 571 15 15 15 1 1 1 1 1 1 1 1 1 1 1 1 1 1','7785842 7786693 7786693 7786693 7786693 7787208 7787208 7787208 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219','20001 29582 58632 67649 71736 396840 1107204 1400830 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7750264 7787219',X'1703090808080703040408090808010108070404040804055010406E80000000000001C7A600FC429201332D890F0C402C00000000000001332D890133505352D7248A008775D8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','2247 682 657 657 657 117 45 45 1 1 1 1 1 1 1 1 1 1 1 1 1 1','9083272 9084837 9084837 9084837 9084837 9085088 9085088 9085088 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089','24940 36384 72113 82665 87632 474987 1318830 1664527 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9042708 9085089',X'17030908080807030304080208080103010704040408031A620A403E00000000000001C3D332CF850132DE9D00FC0200FFFF054050E000000000000132DE9D0132DE9D4E8C092E790553'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix7','107 77 69 69 69 11 5 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1','10382912 10382942 10382942 10382942 10382942 10382952 10382956 10382956 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959','31251 45639 90416 102896 109225 567280 1544395 1943661 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10337289 10382959',X'170409080808070303040809080801010807040404080300955501403E000000000000029E686E250B01332D220F0C402E00000000000001332D220133504E52CFCF4F21CD7F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7337 4975 19 19 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 206462 206462 210789 210789 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807 210807','0 0 0 125 164 112407 128579 207456 209489 209490 209490 209490 209490 209490 209490 209490 209490 209490 209490 209490 209490 210807',X'170808080308040804030807080301030807080808080301878401317F26024FD3531E2DAF404200000000000000FFFF0200FFFFC0F869E0000000002642C4'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 8874 8785 45 25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 1221012 1221012 1224145 1224165 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189 1224189','0 0 0 931 1117 679896 773861 1207582 1216653 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1216673 1224189',X'1708080803080409040408070809010308070404040803018D3F0133023D01940C420106B14D40420000000000000F00FFFF4070E000000000000133023D0133023D4F2053654AE525'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7200 7200 39 15 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 1239793 1239793 1242199 1242223 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237 1242237','0 0 0 942 1131 688381 783660 1225441 1234602 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1234622 1242237',X'1708080803080409040308070809010301070404040804018D4F0132DB820113FAB92F19C5401C0000000000000F00FFFF0F403A0000000000000132DB820132DB824D542A4F009B5C72'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 9606 9606 44 25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 1264560 1264560 1266149 1266168 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192 1266192','0 0 0 952 1145 699479 796008 1249062 1258369 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1258391 1266192',X'1708080803080409040308070809010101070404040803018D61013305B9017CDF4916F8B140280000000000000F0C0A403600000000000001330557013305B9507EA8DD212E79'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 6635 6635 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 1294199 1294199 1297868 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869 1297869','0 0 0 964 1159 713241 812408 1280435 1289849 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1289871 1297869',X'1708080803080409030308070803010308070808080803018D78013267DC0EF747387106403F00000000000000FFFF0F00FFFFC0F869E00000000006B968'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7815 6624 26 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 2374939 2374939 2380559 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584 2380584','0 0 0 3423 3833 1371803 1539928 2350493 2366415 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2366460 2380584',X'170808080308040903030807080301030807080808080301B1F501317F160DDEA51C46AB405280000000000000FFFF0F00FFFFC0F869E0000000006ADDA9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 3595 3459 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 2595336 2595336 2595734 2595737 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739 2595739','0 0 0 3918 4433 1512586 1693312 2557025 2580917 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2580967 2595739',X'170808080308040903030807080101010107040404080301B64F01332ACC029E833D19084028000000000000320F0C054074A0000000000001332A0901332ACC518A316F1F30D6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7894 6061 26 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 3422592 3422592 3424418 3424434 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443 3424443','0 0 0 5872 6630 2032185 2267240 3366727 3406294 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3406363 3424443',X'170808080308040904030807080101030807040404080401C3F90132B7A100D6FD7F6CE97F4070500000000000100F00FFFF40560000000000000132B7310132DB2D4D3F72D9009AE8EE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7479 6158 22 22 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 3547845 3547845 3553619 3553619 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640 3553640','0 0 0 5932 6752 2099067 2343370 3491679 3534981 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3535053 3553640',X'170808080308040804030807080301030807080808080301C4490131573F008E7AC03077E0403E00000000000000FFFF0F00FFFFC0F869E00000000065B45A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 12068 8257 37 17 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 3556474 3556474 3558426 3558446 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462 3558462','0 0 0 5935 6758 2101744 2346448 3496404 3539797 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3539869 3558462',X'170808080308040904030807080201010107040404080301C44E0132DD09016891C11788EB404200000000000000FC0F0C0F400199999999999A0132DD090132DD094DE5DCE3763299'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 1510 1497 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 3892149 3892149 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609 3893609','0 0 0 6596 7614 2306358 2572095 3823194 3873232 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3873319 3893609',X'170808080308040803030807080301030807080808080301CA2E01312E3A038EE6257265400000000000000000FFFF0600FFFFC0F869E00000000032518F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 9341 7313 41 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 4211282 4211282 4217204 4217243 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244 4217244','0 0 0 7200 8390 2502650 2792131 4139620 4195704 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4195798 4217244',X'170808080308040903030807080301030807080808080301CE8C01317DE8029E9D3B6D23403E00000000000000FFFF0F00FFFFC0F869E00000000008EF7D'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 8055 3290 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 5033936 5033936 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225 5037225','0 0 0 10201 11915 3045026 3383481 4941323 5012256 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5012369 5037225',X'17080808030804090303080708030803080708080808030213B20130B83A018A7516DF86403600000000000000FFFF00FFFFC0F869E00000000028F8CD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 9117 2923 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 5043358 5049528 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450 5052450','0 0 0 10203 11926 3054947 3394812 4956408 5027439 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5027552 5052450',X'17080808030204080303080708030103080708080808030213B5232A013107F00217231745AF403300000000000000FFFF0200FFFFC0F869E0000000002B57DE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 333 333 4 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 5191271 5191271 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479 5191479','0 0 0 10672 12452 3147059 3494842 5093162 5165710 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5165827 5191479',X'17080808030804080303080708030103080708080808030244F00131CB4201C1C917188E403F00000000000000FFFF0800FFFFC0F869E00000000001C5CB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7374 4684 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 6107894 6107894 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577 6112577','0 0 0 13780 16308 3748117 4153600 5995776 6082692 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6082834 6112577',X'170808080308040803030807080301030807080808080402A9D1013108B5029E6831A21C401C00000000000000FFFF0200FFFFC0F869E0000000000092F5C6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7562 7376 28 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 6275521 6275521 6277274 6277291 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301 6277301','0 0 0 14559 17217 3855913 4271255 6156622 6246677 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6246823 6277301',X'170808080308040904030807080201030107040404080302C14C0132DBF100832DC739FF53403F00000000000000FC0F00FFFF05402C0000000000000132DBF10132DBF34D89B7AA1114CB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 8282 7043 28 28 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 6286191 6286191 6292277 6292277 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304 6292304','0 0 0 14569 17229 3862314 4278722 6171137 6261611 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6261757 6292304',X'170808080308040804030807080301030807080808080302C16401317CC301B5AA4A1AB270405680000000000000FFFF0F00FFFFC0F869E00000000048FD4C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 3101 3101 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 6486495 6486495 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349 6489349','0 0 0 15379 18149 3988504 4417216 6363796 6457879 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6458036 6489349',X'170808080308040803030807080301030807080808080302EA6601317F7301C3EB17C4CE401C00000000000000FFFF0F00FFFFC0F869E000000000398198'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 7379 6798 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 7308682 7308682 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479 7315479','0 0 0 18403 21722 4531809 5008068 7172304 7280343 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7280536 7315479',X'1708080803080408040308070803010308070808080803049EE501310667008390D0176DC9404380000000000000FFFF0500FFFFC0F869E0000000005ED2B5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 211 211 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 7787150 7787150 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219','0 0 0 20027 23602 4837427 5341824 7634169 7750020 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7750224 7787219',X'17080808030804080303080708090103080704040808030550B30132B73501A79C17C3D840340000000000000F00FFFF40140000000000000132B6D00132B7400D1DB9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 26 26 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 9085083 9085083 9085088 9085088 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089 9085089','0 0 0 24964 29171 5671673 6246216 8904392 9042441 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9042684 9085089',X'17080808030804080303080708030103080708080808031AA25C0131CA197A6D831B1D84401C00000000000000FFFF0F00FFFFC0F869E00000000071E307'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','11668540 11668540 11668540 1261 1261 9 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','0 0 0 10381872 10381872 10382956 10382956 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959 10382959','0 0 0 31297 36344 6545140 7198586 10180602 10336983 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10337266 10382959',X'17080808040804080303080708010101080708080808030095A4C401321BB603010141073C401C000000000000080F0C40308000000000007E55BE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix6','12287 12287 12287 17 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1','11668540 11668540 11668540 11672111 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127 11672127','1 1 1 43128 49243 7431284 8170740 11452355 11624787 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11625093 11672127',X'1701080803020408040409070803010308070408040804070267C127130133041E00AB540900E64074405C40000000000000FFFF0300FFFFC0F869E0000000000133041E0080000000A3EE16'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 24157 24157 29 29 1 1 1 1','0 0 0 1236590 1236590 1251799 1251799 1251827 1251827 1251827 1251827','0 0 0 3120 4771 71527 72755 1238782 1238782 1238782 1251827',X'0C08080803040308040808031A080400FF5594029BB30131CD372B1368'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 1209 1209 129 129 1 1 1 1','0 0 0 1296873 1296873 1297744 1297744 1297869 1297869 1297869 1297869','0 0 0 3203 4902 74577 75831 1284645 1284645 1284645 1297869',X'0C08080803030308040808041A215F04C9D901B0A30131066F0087162A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 12129 9261 428 428 1 1 1 1','0 0 0 1790076 1790076 1790076 1790076 1790503 1790503 1790503 1790503','0 0 0 4938 7561 108783 110860 1774402 1774402 1774402 1790503',X'0C08080803030308040808031CE87E029E6B018700013219C1373BA8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 273 273 5 5 1 1 1 1','0 0 0 2595625 2595625 2595738 2595738 2595739 2595739 2595739 2595739','0 0 0 7863 12132 166423 169877 2575172 2575172 2575172 2595739',X'0C08080803030308040808042F020502DA0E02C73A0133049700A711F8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 7735 7735 29 29 1 1 1 1','0 0 0 2924165 2924165 2929754 2929754 2929782 2929782 2929782 2929782','0 0 0 9123 14045 191316 195293 2907742 2907742 2907742 2929782',X'0C080808030403080408080333776300FF559475928D013329435A824F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 360 229 27 27 1 1 1 1','0 0 0 3893374 3893505 3893605 3893605 3893609 3893609 3893609 3893609','0 0 0 13912 21124 273265 278784 3866425 3866425 3866425 3893609',X'0C08080803030308040808044717710E070B01E88F0131A5B80098D0A5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 683 671 32 32 1 1 1 1','0 0 0 5191447 5191459 5191477 5191477 5191479 5191479 5191479 5191479','0 0 0 20361 30776 381171 389104 5158962 5158962 5158962 5191479',X'0C08080803030308040808037370D10F00290188450132B537354C5E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 213354 213354 113 113 1 1 1 1','0 0 0 6102233 6102233 6155183 6155183 6155295 6155295 6155295 6155295','0 0 0 26812 39489 472780 483115 6119281 6119281 6119281 6155295',X'0C080808040403080408080300F2FA4400FF5594019B6D01324067714AE8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 3675 3675 241 241 1 1 1 1','0 0 0 6486701 6486701 6489287 6489287 6489349 6489349 6489349 6489349','0 0 0 28380 41383 502486 513750 6452691 6452691 6452691 6489349',X'0C080808040304080408080300F6ABAC6C967D009F84B60132DBDD155A2A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 24063 24063 38 38 1 1 1 1','0 0 0 7080911 7080911 7102380 7102380 7102417 7102417 7102417 7102417','0 0 0 35724 49844 582928 595393 7065320 7065320 7065320 7102417',X'0C0808080404040804080803010B0A5C00FF559400CCD3EE0133294559DDCD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 7173953 7173950 20284 20284 38 38 1 1 1 1','0 0 0 7107237 7107237 7126606 7126606 7126643 7126643 7126643 7126643','0 0 0 35764 49885 586473 599030 7089546 7089546 7089546 7126643',X'0C0808080404040804080803010B3C6700FF55940114CE73013329432225CC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 630326 618063 11855 11855 3 1 1 1 1 1','0 7173953 7173953 7665258 7665258 7672559 7672561 7672561 7672561 7672561 7672561','0 1 2 64320 91213 1077048 1100563 7630436 7630436 7630436 7672561',X'0C080908040403020408080400F2FA4400FF559405DD0A23280132DD75009F3468'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 630326 618063 4 4 1 1 1 1 1 1','0 7173953 7173953 7787218 7787218 7787219 7787219 7787219 7787219 7787219 7787219','0 1 2 74034 102405 1189484 1215034 7745001 7745001 7745001 7787219',X'0C0809080403040804080803010DDABE0368B700FEBFF60133068F22D1E5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','7804279 630326 12263 1433 1433 1 1 1 1 1 1','0 7173953 7792016 7797877 7797877 7799309 7799309 7799309 7799309 7799309 7799309','0 1 3 76213 104626 1201397 1227113 7757087 7757087 7757087 7799309',X'0C08090104040408040808030700F2FA4400FF559401C3969E013329461E5052'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 8657 8657 605 605 1 1 1 1','7804279 7804279 7804279 8360485 8360485 8364643 8364643 8365247 8365247 8365247 8365247','1 2 4 77865 106290 1217527 1243460 8321843 8321843 8321843 8365247',X'0C09080803030308040808031AD369021FFC0DC36E01328E2F3D9128'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 33421 33421 57 26 1 1 1 1','7804279 7804279 7804279 8873934 8873934 8891008 8891039 8891064 8891064 8891064 8891064','1 2 4 78914 107340 1231432 1257622 8846644 8846644 8846644 8891064',X'0C090808030403020408080433776300FF55940CE166232801332A1800836DFB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 2182 2182 94 94 1 1 1 1','7804279 7804279 7804279 9083187 9083187 9085006 9085006 9085089 9085089 9085089 9085089','1 2 4 79307 107733 1237174 1263453 9040316 9040316 9040316 9085089',X'0C09080803030308040808033AC92C021FFC04AF670132B5FC38DBD0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 6023 6023 50 50 1 1 1 1','7804279 7804279 7804279 9393480 9393480 9395815 9395815 9395864 9395864 9395864 9395864','1 2 4 79973 108402 1245294 1271679 9350536 9350536 9350536 9395864',X'0C09080803030308040808034CDD9A7E1C2301C30D0132908703CC11'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 79 79 6 6 1 1 1 1','7804279 7804279 7804279 10382946 10382946 10382956 10382956 10382959 10382959 10382959 10382959','1 2 4 82501 110947 1276304 1303221 10336296 10336296 10336296 10382959',X'0C090808040303080408080400E9A10A0CC31602A47201332C6C00ABCD60'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 8251 8251 280 280 1 1 1 1','7804279 7804279 7804279 11067468 11067468 11072690 11072690 11072969 11072969 11072969 11072969','1 2 4 85529 113989 1307763 1335183 11025935 11025935 11025935 11072969',X'0C090808040404080408080300FFA4A7008A66AD0089DBDD0132B5FF6AE2B8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 44772 44772 58 58 1 1 1 1','7804279 7804279 7804279 11268036 11268036 11269261 11269261 11269318 11269318 11269318 11269318','1 2 4 87132 115597 1321101 1348736 11222284 11222284 11222284 11269318',X'0C0908080404030804080804010B0A5C00FF5594018ACD0133294300B0E291'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 53775 53775 37 19 1 1 1 1','7804279 7804279 7804279 11330929 11330929 11355027 11355045 11355063 11355063 11355063 11355063','1 2 4 87335 115800 1327560 1355328 11308029 11308029 11308029 11355063',X'0C0908080404030204080803010BFA8100FF5594026C24232801332B2E1F8BB5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 3718791 3718791 39430 39430 39 39 1 1 1 1','7804279 7804279 7804279 11458789 11458789 11476757 11476757 11476795 11476795 11476795 11476795','1 2 4 88502 116970 1340484 1368500 11429761 11429761 11429761 11476795',X'0C09080804040308040808030113B99600FF559402F6AF01332B2E1F8A54'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix5','3876548 157757 157736 5317 5317 1 1 1 1 1 1','7804279 11523070 11523070 11652823 11652823 11658139 11658139 11658139 11658139 11658139 11658139','1 3 5 100045 128561 1480184 1510648 11611105 11611105 11611105 11658139',X'0C0909080404040204080803010BFA8100FF559402594CCB2328013351E85B0F5D'); +} {} +do_execsql_test whereJ-1.3 { + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 4748 4629 308 1 1 1 1 1','0 0 0 634880 634880 639119 639426 639426 639426 639426 639426','0 0 0 779 907 26900 633919 633920 633920 633920 639426',X'0C0808080308040403080803018C4A00F450A80132671F029EAC271DA5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 4608 4608 246 1 1 1 1 1','0 0 0 752580 752580 755578 755823 755823 755823 755823 755823','0 0 0 936 1089 31876 749384 749385 749385 749385 755823',X'0C0808080308030403080804018D4F347FD20131547D018A7500936FE2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 4776 4776 240 1 1 1 1 1','0 0 0 762070 762070 764545 764784 764784 764784 764784 764784','0 0 0 940 1097 32187 758274 758275 758275 758275 764784',X'0C0808080308030403080804018D562E0EAB0131A68F029E9300994D36'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5910 5910 257 1 1 1 1 1','0 0 0 771353 771353 772646 772902 772902 772902 772902 772902','0 0 0 946 1103 32460 766333 766334 766334 766334 772902',X'0C0808080308030404080803018D611726F40130E13C00822B980302A0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 1834 1834 46 1 1 1 1 1','0 0 0 1296866 1296866 1297832 1297869 1297869 1297869 1297869 1297869','0 0 0 2621 2842 56932 1287063 1287064 1287064 1287064 1297869',X'0C080808030803040308080301A6E33010BC01317F2005516E3932DB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5007 3959 317 1 1 1 1 1','0 0 0 2152400 2152400 2153781 2154097 2154097 2154097 2154097 2154097','0 0 0 5683 6304 111431 2139450 2139457 2139457 2139457 2154097',X'0C080808030803040308080301C3F91E114001315549029F74635F36'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 4768 4609 397 1 1 1 1 1','0 0 0 2200466 2200466 2200700 2201096 2201096 2201096 2201096 2201096','0 0 0 5714 6370 114266 2186220 2186227 2186227 2186227 2201096',X'0C080808030803040308080401C42217887E01312D72036D5B009AF3F8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5177 4669 264 1 1 1 1 1','0 0 0 2234078 2234078 2235865 2236128 2236128 2236128 2236128 2236128','0 0 0 5743 6422 116499 2221108 2221115 2221115 2221115 2236128',X'0C080808030803040308080401C4491EF49D013155450D4B200091BFB3'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 7981 5546 272 1 1 1 1 1','0 0 0 2239923 2239923 2242583 2242854 2242854 2242854 2242854 2242854','0 0 0 5746 6428 116800 2227775 2227782 2227782 2227782 2242854',X'0C080808030803040308080301C44E2EFF35013109E67764687E36D6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 351 336 15 1 1 1 1 1','0 0 0 2595725 2595725 2595725 2595739 2595739 2595739 2595739 2595739','0 0 0 6747 7717 144364 2578697 2578708 2578708 2578708 2595739',X'0C080808030803040308080401CCC91782C20131CC1902D7C0008E7A4F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 6022 4942 304 1 1 1 1 1','0 0 0 2648510 2648510 2648849 2649152 2649152 2649152 2649152 2649152','0 0 0 6934 7959 149030 2631886 2631900 2631900 2631900 2649152',X'0C080808030803040308080301CE8C17887E01312D6E036D5B424939'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 4752 1965 5 1 1 1 1 1','0 0 0 3161780 3161780 3163740 3163744 3163744 3163744 3163744 3163744','0 0 0 9707 11219 194477 3143873 3143896 3143896 3143896 3163744',X'0C08080803080404030808030213B20116290C01332B9D0270102494C2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5497 1880 3 1 1 1 1 1','0 0 0 3167643 3167643 3169520 3169522 3169522 3169522 3169522 3169522','0 0 0 9709 11226 194760 3149632 3149655 3149655 3149655 3169522',X'0C08080803080404040808030213B5010B0A5C0133294500FF55941DCA72'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 2185 2126 134 1 1 1 1 1','0 0 0 3891669 3891669 3893607 3893609 3893609 3893609 3893609 3893609','0 0 0 13596 15952 257364 3869701 3869733 3869733 3869733 3893609',X'0C080808030804040308080302BD5F01010F13013350517B8BF356D913'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5511 5355 345 1 1 1 1 1','0 0 0 3931849 3931849 3931954 3932298 3932298 3932298 3932298 3932298','0 0 0 13793 16188 260160 3908172 3908206 3908206 3908206 3932298',X'0C080808030803040308080402C14C17887E01312D75036D5B009AF4B1'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5468 5115 310 1 1 1 1 1','0 0 0 3939090 3939090 3939894 3940203 3940203 3940203 3940203 3940203','0 0 0 13803 16200 260571 3916034 3916068 3916068 3916068 3940203',X'0C080808030803040308080302C164191E7F0131A4FC0606F30CE25A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 5275 4792 252 1 1 1 1 1','0 0 0 4590216 4590216 4591340 4591591 4591591 4591591 4591591 4591591','0 0 0 17456 20455 315887 4563939 4563981 4563981 4563981 4591591',X'0C0808080308030403080804049EE51EB67B01317C5204C9D900AE08CD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 339 339 20 1 1 1 1 1','0 0 0 5191257 5191257 5191475 5191479 5191479 5191479 5191479 5191479','0 0 0 20754 24230 366257 5160652 5160701 5160701 5160701 5191479',X'0C08080803080404030808030CEE9300E50D8D013242BE018A755F6BC3'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 7173953 7173950 13 13 1 1 1 1 1 1','0 0 0 6489337 6489337 6489349 6489349 6489349 6489349 6489349 6489349','0 0 0 29449 33987 481632 6453309 6453378 6453378 6453378 6489349',X'0C08080804080304030808030091B3AB600E9801323F54029F7403EF0C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 630326 618063 10 9 1 1 1 1 1 1','0 7173953 7173953 7787217 7787217 7787219 7787219 7787219 7787219 7787219 7787219','0 1 2 74978 85458 1107555 7744920 7744997 7744997 7744997 7787219',X'0C0809080408030403080804014F459B48960801332ADC01C7A600AA1BA3'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','7804279 630326 12263 17 1 1 1 1 1 1 1','0 7173953 7792016 7795570 7795586 7795586 7795586 7795586 7795586 7795586 7795586','0 1 3 78329 89057 1115864 7753287 7753364 7753364 7753364 7795586',X'0C0809010302040404080804070267C1271300E640740133041E00AB540900A3EE16'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','3876548 3718791 3718791 397 397 46 1 1 1 1 1','7804279 7804279 7804279 9084892 9084892 9085088 9085089 9085089 9085089 9085089 9085089','1 2 4 87584 99143 1159195 9040539 9040616 9040616 9040616 9085089',X'0C090808030804040308080301CBAF00E5C288013351810C390F26671E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','3876548 3718791 3718791 141 141 20 1 1 1 1 1','7804279 7804279 7804279 10382921 10382921 10382951 10382959 10382959 10382959 10382959 10382959','1 2 4 95054 107437 1210217 10336699 10336776 10336776 10336776 10382959',X'0C09080803080304030808030DB5C14114E301332A7E018A751F17C1'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix4','3876548 157757 157736 83 16 1 1 1 1 1 1','7804279 11523070 11523070 11587733 11587800 11587815 11587815 11587815 11587815 11587815 11587815','1 3 5 112412 126326 1332792 11540704 11540781 11540781 11540781 11587815',X'0C090908030204040308080402A9D12328010B92880133517F029E9D008B5B23'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 213279 213279 213279 213279 376 212 101 1 1','0 0 12394 12394 12394 12394 18421 18421 18421 18424 18424','0 0 3 3 3 3 810 1027 1949 18324 18424',X'0C0808030808080308030403018A75018788178574013265FC611E2A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 86515 86515 86515 86515 377 377 377 1 1','0 0 271240 271240 271240 271240 274521 274521 274521 274780 274780','0 0 8 8 8 8 9766 10762 19602 273178 274780',X'0C080803080808030803040401A79C01886F174AEF0132678B00A4AEFF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 193482 193482 193482 193482 444 444 444 1 1','0 0 542802 542802 542802 542802 575453 575453 575453 575505 575505','0 0 27 27 27 27 24310 25597 43165 571774 575505',X'0C080803080808030803040401C3EB018CCE55312F013305B700AF487C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 126108 126108 126108 126108 200 200 28 1 1','0 0 747801 747801 747801 747801 762121 762121 762293 762320 762320','0 0 33 33 33 33 30770 32410 56629 757315 762320',X'0C080803080808030803040301C7A6018A9D6AB1100131F17D04364A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 149712 149712 149712 149712 216 216 5 1 1','0 0 1107747 1107747 1107747 1107747 1147090 1147090 1147301 1147305 1147305','0 0 98 98 98 98 51603 53785 94043 1139967 1147305',X'0C080803080808030803040302172301B84D2E828501317B95651924'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 87289 87289 87289 87289 27 27 12 1 1','0 0 1257751 1257751 1257751 1257751 1297850 1297850 1297865 1297869 1297869','0 0 100 100 100 100 57625 60123 107069 1289807 1297869',X'0C0808030808080308040403021FFC02554D00E643C7013242692A9BBC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 192597 192597 192597 192597 291 291 3 1 1','0 0 1464077 1464077 1464077 1464077 1512946 1512946 1513234 1513236 1513236','0 0 134 134 134 134 67476 70262 123260 1502886 1513236',X'0C0808030808080308040404029E6201B94000F8341701330419008B74DA'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 196917 196917 196917 196917 326 326 12 1 1','0 0 1677739 1677739 1677739 1677739 1797333 1797333 1797647 1797658 1797658','0 0 136 136 136 136 76717 80026 143308 1785522 1797658',X'0C0808030808080308040404029E6802B7DC0108ACBA0132DD7B0087795F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 140297 140297 140297 140297 206 188 90 1 1','0 0 1951850 1951850 1951850 1951850 2020506 2020524 2020622 2020711 2020711','0 0 146 146 146 146 85439 89181 160816 2006993 2020711',X'0C0808030808080302040403029E8102171603E800FA82B20132B5AD384ECD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 132041 132041 132041 132041 173 173 20 1 1','0 0 2415706 2415706 2415706 2415706 2428962 2428962 2429115 2429134 2429134','0 0 163 163 163 163 100984 105182 186071 2412732 2429134',X'0C0808030808080308030403029EB1018BF55020D60131A3D23BB156'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 6830 6830 6830 6830 35 35 35 1 1','0 0 2595444 2595444 2595444 2595444 2595711 2595711 2595711 2595739 2595739','0 0 169 169 169 169 108584 113037 199947 2578183 2595739',X'0C0808030808080308030403029EC001878C17A7520131A43A6E513C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 101615 101615 101615 101615 244 33 33 1 1','0 0 2999185 2999185 2999185 2999185 3019255 3019466 3019466 3019498 3019498','0 0 213 213 213 213 131035 136293 237357 2999333 3019498',X'0C080803080808030203040302D7C001B93E03F041A96D013303017C72B6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 26914 26914 26914 26914 87 87 73 1 1','0 0 3868553 3868553 3868553 3868553 3893568 3893568 3893582 3893609 3893609','0 0 387 387 387 387 172456 180121 311050 3869040 3893609',X'0C08080308080803080304040498C86B7EF347CC5A0132B678008A4646'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 97492 97492 97492 97492 410 410 44 1 1','0 0 4948831 4948831 4948831 4948831 5009456 5009456 5009822 5009865 5009865','0 0 751 751 751 751 226745 236274 399260 4980988 5009865',X'0C08080308080803080404030E565F03686C00F89CD001332A115479DC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 1782 1782 1782 1782 52 52 52 1 1','0 0 5190938 5190938 5190938 5190938 5191434 5191434 5191434 5191479 5191479','0 0 800 800 800 800 236362 246237 414618 5161779 5191479',X'0C08080308080803080304040EBD0F0268E064A6DB013242CB00875BAF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 4645 4645 4645 4645 17 17 17 1 1','0 0 6485214 6485214 6485214 6485214 6489339 6489339 6489339 6489349 6489349','0 0 1396 1396 1396 1396 317293 329836 538486 6453712 6489349',X'0C080804080808040803040300ABD9B000A69D33737CBB01328F6B0F6298'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 7173953 290196 290196 290196 290196 138 138 26 1 1','0 0 6734628 6734628 6734628 6734628 6744872 6744872 6744984 6745009 6745009','0 0 1641 1641 1641 1641 338986 352099 569319 6708651 6745009',X'0C080804080808030804040400FF5594018819010B3C670133294300B1674C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','7804279 630326 24310 1435 1435 1435 1 1 1 1 1','0 7173953 7763625 7786500 7786500 7786500 7787219 7787219 7787219 7787219 7787219','0 1 3518 4119 4119 4119 726018 753845 1215054 7745002 7787219',X'0C080904010808030204040400FF5594070357AB232800F2FA440133294600A90441'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 3718791 114188 114188 114188 114188 463 61 61 1 1','7804279 7804279 7809377 7809377 7809377 7809377 7864755 7865157 7865157 7865217 7865217','1 2 3751 4413 4413 4413 740133 768607 1233927 7822883 7865217',X'0C0908030808080302030403018A750213B2245416DF860131CB3A2879CC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 3718791 86108 86108 86108 86108 605 605 605 1 1','7804279 7804279 8403815 8403815 8403815 8403815 8463845 8463845 8463845 8464449 8464449','1 2 3805 4467 4467 4467 760796 789718 1255047 8421249 8464449',X'0C0908030808080308030403021FFC0DC36E1AD36901328E2F3D9128'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 3718791 60490 60490 60490 60490 44 44 44 1 1','7804279 7804279 9062901 9062901 9062901 9062901 9085056 9085056 9085056 9085089 9085089','1 2 3845 4507 4507 4507 778931 808217 1273550 9040805 9085089',X'0C0908030808080308040403029EB101C30B00E889140132697F092505'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 3718791 57304 57304 57304 57304 2 2 2 1 1','7804279 7804279 10328144 10328144 10328144 10328144 10382958 10382958 10382958 10382959 10382959','1 2 4106 4768 4768 4768 823966 853934 1319290 10336860 10382959',X'0C09080308080804080404040E565F00CE8C3100E7F68D0133517900B0B4CE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 3718791 174377 174377 174377 174377 81 81 66 1 1','7804279 7804279 11246252 11246252 11246252 11246252 11358749 11358749 11358764 11358829 11358829','1 2 4517 5179 5179 5179 867595 898252 1363807 11311829 11358829',X'0C090804080808030804040300FF55940E584300F2FA44013240670E2E89'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix3','3876548 157757 15066 15066 15066 15066 1 1 1 1 1','7804279 11523070 11657249 11657249 11657249 11657249 11672314 11672314 11672314 11672314 11672314','1 3 5503 6167 6167 6167 1025351 1059076 1524822 11625280 11672314',X'0C090904080808040203040300FF5594025D19032328337763013351F2277A3E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 4748 4629 4629 4629 4629 17 1 1 1','0 0 634880 634880 634880 634880 634880 639175 639191 639191 639191','0 0 779 907 907 907 907 415429 633684 633685 639191',X'0C0808030808080804030303018C4A013157983CE7FE05E54B6BB7FB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 4608 4608 4608 4608 4608 33 1 1 1','0 0 752580 752580 752580 752580 752580 755506 755538 755538 755538','0 0 936 1089 1089 1089 1089 491324 749126 749127 755538',X'0C0808030808080804030303018D4F0131A682512ECF029E6A70A9E9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 4776 4776 4776 4776 4776 27 1 1 1','0 0 762070 762070 762070 762070 762070 763357 763383 763383 763383','0 0 940 1097 1097 1097 1097 495628 756890 756891 763383',X'0C0808030808080804040303018D560132DB8800F3416D029EA654D9AC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5910 5910 5910 5910 5910 37 2 2 1','0 0 771353 771353 771353 771353 771353 775562 775597 775597 775598','0 0 946 1103 1103 1103 1103 501111 769013 769014 775598',X'0C0808030808080804030303018D610131CADE4C6E2D01D5860141A9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 1834 1834 1834 1834 1834 6 1 1 1','0 0 1296866 1296866 1296866 1296866 1296866 1297867 1297869 1297869 1297869','0 0 2621 2842 2842 2842 2842 857867 1287063 1287064 1297869',X'0C080803080808080403030301A6E30132419A1E1B7F0567EE2880C0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5007 3959 3959 3959 3959 25 1 1 1','0 0 2152400 2152400 2152400 2152400 2152400 2155551 2155575 2155575 2155575','0 0 5683 6304 6304 6304 6304 1442790 2140930 2140937 2155575',X'0C080803080808080404030301C3F901317CC701044CC7029E6834F7E2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 4768 4609 4609 4609 4609 26 1 1 1','0 0 2200466 2200466 2200466 2200466 2200466 2204364 2204389 2204389 2204389','0 0 5714 6370 6370 6370 6370 1470393 2189496 2189503 2204389',X'0C080803080808080403030301C4220131586B3EB735018A7567CE9E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5177 4669 4669 4669 4669 22 1 1 1','0 0 2234078 2234078 2234078 2234078 2234078 2238366 2238387 2238387 2238387','0 0 5743 6422 6422 6422 6422 1490145 2223355 2223362 2238387',X'0C080803080808080403030301C4490131573F4104F802D9CA67FD1E'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 7981 5546 5546 5546 5546 32 1 1 1','0 0 2239923 2239923 2239923 2239923 2239923 2243388 2243419 2243419 2243419','0 0 5746 6428 6428 6428 6428 1492784 2228358 2228365 2243419',X'0C080803080808080404030301C44E0131A4FE00FDCC04029E8175076B'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 351 336 336 336 336 1 1 1 1','0 0 2595725 2595725 2595725 2595725 2595725 2595739 2595739 2595739 2595739','0 0 6747 7717 7717 7717 7717 1732397 2578697 2578708 2595739',X'0C080803080808080404030301CCC901332A7700F17E5D0E5D6F523B01'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 6022 4942 4942 4942 4942 38 1 1 1','0 0 2648510 2648510 2648510 2648510 2648510 2652126 2652163 2652163 2652163','0 0 6934 7959 7959 7959 7959 1770411 2634884 2634898 2652163',X'0C080803080808080404030301CE8C01317DE800FE4E8B029E81458317'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 4752 1965 1965 1965 1965 1 1 1 1','0 0 3161780 3161780 3161780 3161780 3161780 3163744 3163744 3163744 3163744','0 0 9707 11219 11219 11219 11219 2143797 3143873 3143896 3163744',X'0C08080308080808040303030213B20130BC9216F939029E815B86EE'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5497 1880 1880 1880 1880 1 1 1 1','0 0 3167643 3167643 3167643 3167643 3167643 3169522 3169522 3169522 3169522','0 0 9709 11226 11226 11226 11226 2148088 3149632 3149655 3169522',X'0C08080308080808040303030213B50130BBC616FC6501C7A62A1BB2'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 2185 2126 2126 2126 2126 4 1 1 1','0 0 3891670 3891670 3891670 3891670 3891670 3893609 3893609 3893609 3893609','0 0 13596 15952 15953 15953 15953 2677069 3869700 3869732 3893609',X'0C080803080808080403030302BD5F01317CC81782F704C9D95EFF0C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5511 5355 5355 5355 5355 21 1 1 1','0 0 3931850 3931850 3931850 3931850 3931850 3936206 3936226 3936226 3936226','0 0 13793 16188 16189 16189 16189 2705655 3912091 3912125 3936226',X'0C080803080808080403030302C14C01317C514010FA01B64235E688'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5468 5115 5115 5115 5115 27 1 1 1','0 0 3939091 3939091 3939091 3939091 3939091 3943255 3943281 3943281 3943281','0 0 13803 16200 16201 16201 16201 2709082 3919099 3919133 3943281',X'0C080803080808080403030302C16401317CC348B67001C3EB6824BB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 5275 4792 4792 4792 4792 31 1 1 1','0 0 4590217 4590217 4590217 4590217 4590217 4591639 4591669 4591669 4591669','0 0 17456 20455 20456 20456 20456 3175906 4564022 4564064 4591669',X'0C0808030808080804040403049EE50132915200FA2F9300EA0DC50554E0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 339 339 339 339 339 2 1 1 1','0 0 5191258 5191258 5191258 5191258 5191258 5191478 5191479 5191479 5191479','0 0 20754 24230 24231 24231 24231 3601696 5160652 5160701 5191479',X'0C08080308080808040303030CEE930132671A1B8AFF01B6426386D0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 7173953 13 13 13 13 13 1 1 1 1','0 0 6489339 6489339 6489339 6489339 6489339 6489349 6489349 6489349 6489349','0 0 29449 33987 33989 33989 33989 4540005 6453309 6453378 6489349',X'0C08080408080808040303030091B3AB01321B5A4F26F2018A750B6686'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','7804279 630326 19 19 18 18 18 1 1 1 1','0 7173953 7787203 7787203 7787203 7787203 7787203 7787219 7787219 7787219 7787219','0 1 73522 83967 91688 91688 91688 5643606 7744920 7744997 7787219',X'0C080904080808080404030300FF69210132DB2900FB0715029EB573EB9F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','3876548 3718791 4598 4512 4512 4512 4512 38 1 1 1','7804279 7804279 8237877 8237877 8237877 8237877 8237877 8238986 8239023 8239023 8239023','1 2 76726 87349 95641 95641 95641 5923145 8195880 8195957 8239023',X'0C0908030808080804040404018D3F01332A780111068001FB6F840083BEF9'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','3876548 3718791 397 397 397 397 397 2 1 1 1','7804279 7804279 9084892 9084892 9084892 9084892 9084892 9085089 9085089 9085089 9085089','1 2 79826 90851 99143 99143 99143 6505397 9040540 9040617 9085089',X'0C090803080808080403030301CBAF0133028A4E35BE715A2A49098C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','3876548 3718791 141 141 141 141 141 2 1 1 1','7804279 7804279 10382921 10382921 10382921 10382921 10382921 10382958 10382959 10382959 10382959','1 2 87296 99145 107437 107437 107437 7432077 10336699 10336776 10382959',X'0C09080308080808040403030DB5C101332BF7010E37310EB97420BFF6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix2','3876548 157757 83 16 16 16 16 1 1 1 1','7804279 11523070 11587750 11587817 11587817 11587817 11587817 11587832 11587832 11587832 11587832','1 3 104655 118035 126343 126343 126343 8311754 11540721 11540798 11587832',X'0C090903020808080404030402A9D1232801332CC300EB7D35029E83008581B1'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 24157 24157 24157 24157 24157 133 1 1 1','0 0 1236590 1236590 1236590 1236590 1236590 1241150 1241282 1241282 1241282','0 0 3120 3120 3120 3120 4771 741878 1223262 1228239 1241282',X'0C08080308080804040408031A080400FF559401321BC20099C49F3BE84C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 1209 1209 1209 1209 1209 2 1 1 1','0 0 1296873 1296873 1296873 1296873 1296873 1297868 1297869 1297869 1297869','0 0 3203 3203 3203 3203 4902 763298 1279554 1284645 1297869',X'0C08080308080803040308031A215F04C9D901317D1501B0A355A290'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 12129 12129 12129 12129 9261 38 1 1 1','0 0 1790076 1790076 1790076 1790076 1790076 1791737 1791774 1791774 1791774','0 0 4938 4938 4938 4938 7561 1075153 1767990 1775629 1791774',X'0C08080308080803040408031CE87E029E6B01328F6100B473FD5BE552'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 273 273 273 273 273 1 1 1 1','0 0 2595625 2595625 2595625 2595625 2595625 2595739 2595739 2595739 2595739','0 0 7863 7863 7863 7863 12132 1580849 2562484 2575172 2595739',X'0C08080308080803040308032F020502DA0E013241A16B73DE01E021'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 7735 7735 7735 7735 7735 503 1 1 1','0 0 2924165 2924165 2924165 2924165 2924165 2931394 2931896 2931896 2931896','0 0 9123 9123 9123 9123 14045 1794002 2895440 2909856 2931896',X'0C080803080808040404080433776300FF55940133294301C56631008BCB5A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 360 360 360 360 229 1 1 1 1','0 0 3893374 3893374 3893374 3893374 3893505 3893609 3893609 3893609 3893609','0 0 13912 13912 13912 13912 21124 2420346 3846830 3866425 3893609',X'0C08080308080803040308034717710E070B01317F7102C73A396CE1'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 683 683 683 683 671 2 1 1 1','0 0 5191447 5191447 5191447 5191447 5191459 5191479 5191479 5191479 5191479','0 0 20361 20361 20361 20361 30776 3226670 5127525 5158962 5191479',X'0C08080308080803040308037370D10F00290132B59A018F7A694C9B'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 213354 213354 213354 213354 213354 5934 1 1 1','0 0 6102233 6102233 6102233 6102233 6102233 6154276 6155650 6155650 6155650','0 0 26812 26812 26812 26812 39489 3770219 6079715 6119855 6155650',X'0C080804080808040403080300F2FA4400FF55940132DF1A01C0C115D4D4'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 3675 3675 3675 3675 3675 14 1 1 1','0 0 6486701 6486701 6486701 6486701 6486701 6489347 6489349 6489349 6489349','0 0 28380 28380 28380 28380 41383 3868787 6409451 6452691 6489349',X'0C080804080808030403020300F6ABAC6C967D0132B672026C8D03E8155844'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 24063 24063 24063 24063 24063 1799 1 1 1','0 0 7080914 7080914 7080914 7080914 7080914 7103178 7104976 7104976 7104976','0 0 35724 35725 35725 35725 49845 4189282 7019641 7067879 7104976',X'0C0808040808080404040804010B0A5C00FF55940133294301D2C35700A877B5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 7173953 20284 20284 20284 20284 20284 1518 1 1 1','0 0 7107240 7107240 7107240 7107240 7107240 7124584 7126101 7126101 7126101','0 0 35764 35765 35765 35765 49886 4191089 7040717 7089004 7126101',X'0C0808040808080404040803010B3C6700FF55940133294501F0A829511573'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 630326 13288 11855 11855 11855 11855 5449 1 1 1','0 7173953 7671119 7671119 7671119 7671119 7671119 7676514 7676526 7676526 7676526','0 1 64320 65543 65543 65543 92453 4431581 7580039 7634401 7676526',X'0C080904080808040403080400F2FA4400FF5594013329430186CB00A866E4'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','7804279 630326 61 61 61 61 61 14 1 1 1','0 7173953 7787172 7787172 7787172 7787172 7787172 7787217 7787219 7787219 7787219','0 1 73272 75274 75274 75274 103642 4468650 7689369 7745002 7787219',X'0C0809040808080304030803010ABA910DD2420133068F05DE6223042F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 8657 8657 8657 8657 8657 18 1 1 1','7804279 7804279 8360485 8360485 8360485 8360485 8360485 8360977 8360994 8360994 8360994','1 2 75785 77865 77865 77865 106290 4756698 8258979 8317590 8360994',X'0C09080308080803040408031AD369021FFC0133517F01B017F259F6C3'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 33421 33421 33421 33421 33421 2221 1 1 1','7804279 7804279 8873934 8873934 8873934 8873934 8873934 8874868 8877088 8877088 8877088','1 2 76834 78914 78914 78914 107340 5041847 8770182 8832668 8877088',X'0C090803080808040404020333776300FF5594013351790241FEE4232825FB3D'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 2182 2182 2182 2182 2182 20 1 1 1','7804279 7804279 9083187 9083187 9083187 9083187 9083187 9085087 9085089 9085089 9085089','1 2 77227 79307 79307 79307 107733 5141706 8974619 9040316 9085089',X'0C09080308080803040308043AC92C021FFC0132B668018BAB00964778'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 6008 6008 6008 6008 6008 26 1 1 1','7804279 7804279 9124662 9124662 9124662 9124662 9124662 9128286 9128311 9128311 9128311','1 2 77300 79380 79380 79380 107806 5160088 9016921 9083451 9128311',X'0C09080308080804040408033C1C5C00F024880132DB2100B88E8A420C1B'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 6023 6023 6023 6023 6023 91 1 1 1','7804279 7804279 9393480 9393480 9393480 9393480 9393480 9396519 9396609 9396609 9396609','1 2 77893 79973 79973 79973 108402 5311949 9282988 9351281 9396609',X'0C09080308080803040408044CDD9A7E1C230132DE4200D105C800A087F7'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 79 79 79 79 79 1 1 1 1','7804279 7804279 10382946 10382946 10382946 10382946 10382946 10382959 10382959 10382959 10382959','1 2 80421 82501 82501 82501 110947 5821380 10258569 10336296 10382959',X'0C090804080808030403080300E9A10A0CC3160133505F0D25365733C6'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 8251 8251 8251 8251 8251 37 1 1 1','7804279 7804279 11067468 11067468 11067468 11067468 11067468 11068084 11068120 11068120 11068120','1 2 83449 85529 85529 85529 113989 6177561 10936213 11021086 11068120',X'0C090804080808040404080400FFA4A7008A66AD01332AD10170A8B10084054A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 44772 44772 44772 44772 44772 3018 1 1 1','7804279 7804279 11268036 11268036 11268036 11268036 11268036 11282829 11285846 11285846 11285846','1 2 85052 87132 87132 87132 115597 6281979 11151347 11238812 11285846',X'0C0908040808080404040804010B0A5C00FF5594013351720249087400B0523C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 53775 53775 53775 53775 53775 4069 1 1 1','7804279 7804279 11330929 11330929 11330929 11330929 11330929 11359035 11363103 11363103 11363103','1 2 85255 87335 87335 87335 115800 6292285 11227544 11316069 11363103',X'0C0908040808080404040804010BFA8100FF5594013351280252F8A000B01818'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 3718791 39430 39430 39430 39430 39430 3018 1 1 1','7804279 7804279 11458789 11458789 11458789 11458789 11458789 11468188 11471205 11471205 11471205','1 2 86422 88502 88502 88502 116970 6333877 11333316 11424171 11471205',X'0C09080408080804040408040113B99600FF559401335174024530C4008AC82C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix1','3876548 157757 5317 5317 5317 5317 5317 12 1 1 1','7804279 11523070 11652844 11652844 11652844 11652844 11652844 11658149 11658160 11658160 11658160','1 3 97969 100051 100051 100051 128567 6429914 11517744 11611126 11658160',X'0C0909040808080404040804010BFA8100FF559401332B2E01521E0B008447F4'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 24157 29 29 29 29 29 1 1 1','0 0 1236590 1251799 1251799 1251799 1251799 1251799 1251827 1251827 1251827','0 0 3120 62451 63798 63798 63798 63798 1238772 1238782 1251827',X'0C08080303080808080404031A0804029BB30131CD3700FF55942B1368'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 1209 129 129 129 129 129 1 1 1','0 0 1296873 1297744 1297744 1297744 1297744 1297744 1297869 1297869 1297869','0 0 3203 65280 66657 66657 66657 66657 1284635 1284645 1297869',X'0C08080303080808080403041A215F01B0A30131066F04C9D90087162A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 12129 604 604 604 604 604 1 1 1','0 0 1790076 1790076 1790076 1790076 1790076 1790076 1790679 1790679 1790679','0 0 4938 95334 97612 97612 97612 97612 1774566 1774578 1790679',X'0C08080303080808080403031CE87E01870001317C4D0CED622FE2E8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 273 5 5 5 5 5 1 1 1','0 0 2595625 2595738 2595738 2595738 2595738 2595738 2595739 2595739 2595739','0 0 7863 145612 149427 149427 149427 149427 2575145 2575172 2595739',X'0C08080303080808080403042F020502C73A0133049702DA0E00A711F8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 7735 29 29 29 29 29 1 1 1','0 0 2924165 2929754 2929754 2929754 2929754 2929754 2929782 2929782 2929782','0 0 9123 167852 172269 172269 172269 172269 2907715 2907742 2929782',X'0C080803030808080804040333776375928D0133294300FF55945A824F'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 360 6 6 6 6 6 1 1 1','0 0 3893374 3893607 3893607 3893607 3893607 3893607 3893609 3893609 3893609','0 0 13912 240908 247109 247109 247109 247109 3866384 3866425 3893609',X'0C080803030808080804030347177104AF8701317D220E070B687905'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 683 32 32 32 32 32 2 2 1','0 0 5191447 5191465 5191465 5191465 5191465 5191465 5191479 5191479 5191479','0 0 20361 336764 345696 345696 345696 345696 5158907 5158962 5191479',X'0C08080303080808080403037370D101884501328F690F002900A69C'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 213354 113 113 113 113 113 1 1 1','0 0 6102233 6155183 6155183 6155183 6155183 6155183 6155295 6155295 6155295','0 0 26812 421693 433202 433202 433202 433202 6119212 6119281 6155295',X'0C080804030808080804040300F2FA44019B6D0132406700FF5594714AE8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 3675 241 241 241 241 241 1 1 1','0 0 6486701 6489287 6489287 6489287 6489287 6489287 6489349 6489349 6489349','0 0 28380 450494 462953 462953 462953 462953 6452616 6452691 6489349',X'0C080804040808080804030300F6ABAC009F84B60132DBDD6C967D155A2A'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 24063 38 38 38 38 38 1 1 1','0 0 7080914 7102383 7102383 7102383 7102383 7102383 7102420 7102420 7102420','0 0 35724 528136 541855 541858 541858 541858 7065247 7065323 7102420',X'0C0808040408080808040403010B0A5C00CCD3EE0133294500FF559459DDCD'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 7173953 20284 38 38 38 38 38 1 1 1','0 0 7107240 7126609 7126609 7126609 7126609 7126609 7126646 7126646 7126646','0 0 35764 531673 545484 545487 545487 545487 7089473 7089549 7126646',X'0C0808040408080808040403010B3C670114CE730133294300FF55942225CC'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 630326 13288 5 1 1 1 1 1 1 1','0 7173953 7671119 7675167 7675171 7675171 7675171 7675171 7675171 7675171 7675171','0 1 64320 967583 993386 999414 999414 999414 7632969 7633046 7675171',X'0C080904030308080804040400F2FA4401D16F0183350132DEFE00FF5594009FA501'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','7804279 630326 61 1 1 1 1 1 1 1 1','0 7173953 7787172 7787219 7787219 7787219 7787219 7787219 7787219 7787219 7787219','0 1 73272 1068631 1096442 1107608 1107608 1107608 7744925 7745002 7787219',X'0C0809040408080808040304010ABA9100AA4C1F013351DB0DD242008BFFEF'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 8657 605 605 605 605 605 1 1 1','7804279 7804279 8360485 8364643 8364643 8364643 8364643 8364643 8365247 8365247 8365247','1 2 75785 1096159 1124446 1135923 1135923 1135923 8321766 8321843 8365247',X'0C09080303080808080403031AD3690DC36E01328E2F021FFC3D9128'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 33421 57 26 26 26 26 1 1 1','7804279 7804279 8873934 8891008 8891039 8891039 8891039 8891039 8891064 8891064 8891064','1 2 76834 1110063 1138607 1150084 1150084 1150084 8846567 8846644 8891064',X'0C09080303020808080404043377630CE166232801332A1800FF559400836DFB'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 2182 94 94 94 94 94 1 1 1','7804279 7804279 9083187 9085006 9085006 9085006 9085006 9085006 9085089 9085089 9085089','1 2 77227 1115805 1144438 1155915 1155915 1155915 9040239 9040316 9085089',X'0C09080303080808080403033AC92C04AF670132B5FC021FFC38DBD0'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 6008 277 277 277 277 277 1 1 1','7804279 7804279 9124662 9124662 9124662 9124662 9124662 9124662 9124938 9124938 9124938','1 2 77300 1116652 1145304 1156781 1156781 1156781 9080000 9080077 9124938',X'0C09080303080808080404033C1C5C01B49901328DDA00F024883D6052'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 6023 50 50 50 50 50 1 1 1','7804279 7804279 9393480 9395815 9395815 9395815 9395815 9395815 9395864 9395864 9395864','1 2 77893 1123924 1152663 1164140 1164140 1164140 9350459 9350536 9395864',X'0C09080303080808080403034CDD9A01C30D013290877E1C2303CC11'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 79 6 6 6 6 6 1 1 1','7804279 7804279 10382946 10382956 10382956 10382956 10382956 10382956 10382959 10382959 10382959','1 2 80421 1154920 1184197 1195674 1195674 1195674 10336219 10336296 10382959',X'0C090804030808080804030400E9A10A02A47201332C6C0CC31600ABCD60'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 8251 280 280 280 280 280 1 1 1','7804279 7804279 11067468 11072690 11072690 11072690 11072690 11072690 11072969 11072969 11072969','1 2 83449 1186373 1216159 1227636 1227636 1227636 11025858 11025935 11072969',X'0C090804040808080804040300FFA4A70089DBDD0132B5FF008A66AD6AE2B8'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 44772 58 58 58 58 58 1 1 1','7804279 7804279 11268036 11269261 11269261 11269261 11269261 11269261 11269318 11269318 11269318','1 2 85052 1199706 1229712 1241189 1241189 1241189 11222207 11222284 11269318',X'0C0908040308080808040404010B0A5C018ACD0133294300FF559400B0E291'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 53775 37 19 19 19 19 1 1 1','7804279 7804279 11330929 11355027 11355045 11355045 11355045 11355045 11355063 11355063 11355063','1 2 85255 1206165 1236304 1247781 1247781 1247781 11307952 11308029 11355063',X'0C0908040302080808040403010BFA81026C24232801332B2E00FF55941F8BB5'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 3718791 39430 39 39 39 39 39 1 1 1','7804279 7804279 11458789 11476757 11476757 11476757 11476757 11476757 11476795 11476795 11476795','1 2 86422 1219089 1249476 1260953 1260953 1260953 11429684 11429761 11476795',X'0C09080403080808080404030113B99602F6AF01332B2E00FF55941F8A54'); + INSERT INTO sqlite_stat4 VALUES('tx1','ix0','3876548 157757 5317 1 1 1 1 1 1 1 1','7804279 11523070 11652844 11658160 11658160 11658160 11658160 11658160 11658160 11658160 11658160','1 3 97969 1358780 1391643 1403122 1403122 1403122 11611049 11611126 11658160',X'0C0909040402080808040403010BFA8102594CCB2328013351E800FF55945B0F5D'); + ANALYZE sqlite_master; +} {} + +# Ensure that the query planner implements the GROUP BY using a separate sort +# +do_execsql_test whereJ-1.4 { + EXPLAIN QUERY PLAN + SELECT aid, sid, MAX(edate) edate + FROM tx1 + WHERE cid = 115790 + AND sid = 9100 + AND edate <= 20140430 AND edate >= 20120429 + GROUP BY aid; +} {/B-TREE/} + +############################################################################ +# Ensure that the sorting cost does not swamp the loop costs and cause +# distinctions between individual loop costs to get lost, and hence for +# sub-optimal loops to be chosen. +# +do_execsql_test whereJ-2.1 { + CREATE TABLE tab( + id INTEGER PRIMARY KEY, + minChild INTEGER REFERENCES t1, + maxChild INTEGER REFERENCES t1, + x INTEGER + ); + EXPLAIN QUERY PLAN + SELECT t4.x + FROM tab AS t0, tab AS t1, tab AS t2, tab AS t3, tab AS t4 + WHERE t0.id=0 + AND t1.id BETWEEN t0.minChild AND t0.maxChild + AND t2.id BETWEEN t1.minChild AND t1.maxChild + AND t3.id BETWEEN t2.minChild AND t2.maxChild + AND t4.id BETWEEN t3.minChild AND t3.maxChild + ORDER BY t4.x; +} {~/SCAN/} +do_execsql_test whereJ-2.2 { + EXPLAIN QUERY PLAN + SELECT t4.x + FROM tab AS t0a, tab AS t0b, + tab AS t1a, tab AS t1b, + tab AS t2a, tab AS t2b, + tab AS t3a, tab AS t3b, + tab AS t4 + WHERE 1 + AND t0a.id=1 + AND t1a.id BETWEEN t0a.minChild AND t0a.maxChild + AND t2a.id BETWEEN t1a.minChild AND t1a.maxChild + AND t3a.id BETWEEN t2a.minChild AND t2a.maxChild + AND t0b.id=2 + AND t1b.id BETWEEN t0b.minChild AND t0b.maxChild + AND t2b.id BETWEEN t1b.minChild AND t1b.maxChild + AND t3b.id BETWEEN t2b.minChild AND t2b.maxChild + AND t4.id BETWEEN t3a.minChild AND t3b.maxChild + ORDER BY t4.x; +} {~/SCAN/} + + +finish_test diff --git a/test/win32lock.test b/test/win32lock.test index 7241720..cff1ed3 100644 --- a/test/win32lock.test +++ b/test/win32lock.test @@ -24,7 +24,7 @@ db close sqlite3_shutdown test_sqlite3_log xLog proc xLog {error_code msg} { - lappend ::log $msg + lappend ::log $msg } sqlite3 db test.db db eval {PRAGMA mmap_size=0} @@ -128,7 +128,53 @@ while {1} { file_control_win32_av_retry db 10 25 sqlite3_test_control_pending_byte $old_pending_byte db close +forcedelete test.db + +sqlite3 db test.db +sqlite3 db2 test.db + +do_test win32lock-3.0 { + db eval { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1); + INSERT INTO t1 VALUES(2); + INSERT INTO t1 VALUES(3); + } +} {} + +do_test win32lock-3.1 { + db eval { + BEGIN EXCLUSIVE; + INSERT INTO t1 VALUES(4); + } +} {} + +do_test win32lock-3.2 { + catchsql { + BEGIN EXCLUSIVE; + INSERT INTO t1 VALUES(5); + COMMIT; + } db2 +} {1 {database is locked}} + +do_test win32lock-3.3 { + db eval { + COMMIT; + } +} {} + +do_test win32lock-3.4 { + set handle [lindex [file_control_win32_set_handle db 0] end] + list [catchsql { + BEGIN EXCLUSIVE; + INSERT INTO t1 VALUES(6); + COMMIT; + }] [file_control_win32_set_handle db $handle] [sqlite3_extended_errcode db] +} {{1 {disk I/O error}} {0 0} SQLITE_IOERR_LOCK} + +db2 close +db close sqlite3_shutdown -test_sqlite3_log +test_sqlite3_log sqlite3_initialize finish_test diff --git a/test/with2.test b/test/with2.test index d702f8c..eb06147 100644 --- a/test/with2.test +++ b/test/with2.test @@ -385,6 +385,33 @@ do_execsql_test 7.5 { ) } {14 28 42} +#------------------------------------------------------------------------- +# At one point the following was causing an assertion failure and a +# memory leak. +# +do_execsql_test 8.1 { + CREATE TABLE t7(y); + INSERT INTO t7 VALUES(NULL); + CREATE VIEW v AS SELECT * FROM t7 ORDER BY y; +} + +do_execsql_test 8.2 { + WITH q(a) AS ( + SELECT 1 + UNION + SELECT a+1 FROM q, v WHERE a<5 + ) + SELECT * FROM q; +} {1 2 3 4 5} + +do_execsql_test 8.3 { + WITH q(a) AS ( + SELECT 1 + UNION ALL + SELECT a+1 FROM q, v WHERE a<5 + ) + SELECT * FROM q; +} {1 2 3 4 5} finish_test diff --git a/test/without_rowid1.test b/test/without_rowid1.test index bdd03c5..9d7a643 100644 --- a/test/without_rowid1.test +++ b/test/without_rowid1.test @@ -213,5 +213,69 @@ do_execsql_test 4.1 { do_execsql_test 4.2 { SELECT t42.rowid FROM t42, t41; } {1} + + +#-------------------------------------------------------------------------- +# The following tests verify that the trailing PK fields added to each +# entry in an index on a WITHOUT ROWID table are used correctly. +# +do_execsql_test 5.0 { + CREATE TABLE t45(a PRIMARY KEY, b, c) WITHOUT ROWID; + CREATE INDEX i45 ON t45(b); + + INSERT INTO t45 VALUES(2, 'one', 'x'); + INSERT INTO t45 VALUES(4, 'one', 'x'); + INSERT INTO t45 VALUES(6, 'one', 'x'); + INSERT INTO t45 VALUES(8, 'one', 'x'); + INSERT INTO t45 VALUES(10, 'one', 'x'); + + INSERT INTO t45 VALUES(1, 'two', 'x'); + INSERT INTO t45 VALUES(3, 'two', 'x'); + INSERT INTO t45 VALUES(5, 'two', 'x'); + INSERT INTO t45 VALUES(7, 'two', 'x'); + INSERT INTO t45 VALUES(9, 'two', 'x'); +} + +do_eqp_test 5.1 { + SELECT * FROM t45 WHERE b=? AND a>? +} {/*USING INDEX i45 (b=? AND a>?)*/} + +do_execsql_test 5.2 { + SELECT * FROM t45 WHERE b='two' AND a>4 +} {5 two x 7 two x 9 two x} + +do_execsql_test 5.3 { + SELECT * FROM t45 WHERE b='one' AND a<8 +} { 2 one x 4 one x 6 one x } + +do_execsql_test 5.4 { + CREATE TABLE t46(a, b, c, d, PRIMARY KEY(a, b)) WITHOUT ROWID; + WITH r(x) AS ( + SELECT 1 UNION ALL SELECT x+1 FROM r WHERE x<100 + ) + INSERT INTO t46 SELECT x / 20, x % 20, x % 10, x FROM r; +} + +set queries { + 1 2 "c = 5 AND a = 1" {/*i46 (c=? AND a=?)*/} + 2 6 "c = 4 AND a < 3" {/*i46 (c=? AND a= 3" {/*i46 (c=? AND a>?)*/} + 4 1 "c = 2 AND a = 1 AND b<10" {/*i46 (c=? AND a=? AND b5" {/*i46 (c=? AND a=? AND b>?)*/} +} + +foreach {tn cnt where eqp} $queries { + do_execsql_test 5.5.$tn.1 "SELECT count(*) FROM t46 WHERE $where" $cnt +} + +do_execsql_test 5.6 { + CREATE INDEX i46 ON t46(c); +} + +foreach {tn cnt where eqp} $queries { + do_execsql_test 5.7.$tn.1 "SELECT count(*) FROM t46 WHERE $where" $cnt + do_eqp_test 5.7.$tn.2 "SELECT count(*) FROM t46 WHERE $where" $eqp +} + finish_test diff --git a/tool/build-all-msvc.bat b/tool/build-all-msvc.bat index 6e0aeb5..1fb61d4 100755 --- a/tool/build-all-msvc.bat +++ b/tool/build-all-msvc.bat @@ -146,6 +146,17 @@ IF NOT DEFINED CONFIGURATIONS ( %_VECHO% Configurations = '%CONFIGURATIONS%' +REM +REM NOTE: If the command used to invoke NMAKE is not already set, use the +REM default. +REM +IF NOT DEFINED NMAKE_CMD ( + SET NMAKE_CMD=nmake -B -f Makefile.msc +) + +%_VECHO% NmakeCmd = '%NMAKE_CMD%' +%_VECHO% NmakeArgs = '%NMAKE_ARGS%' + REM REM NOTE: Setup environment variables to translate between the MSVC platform REM names and the names to be used for the platform-specific binary @@ -238,6 +249,7 @@ GOTO set_vcvarsall_done :set_vcvarsall_phone SET VCVARSALL=%VCINSTALLDIR%\WPSDK\WP80\vcvarsphoneall.bat :set_vcvarsall_done +SET VCVARSALL=%VCVARSALL:\\=\% REM REM NOTE: This is the outer loop. There should be exactly one iteration per @@ -265,9 +277,11 @@ FOR %%P IN (%PLATFORMS%) DO ( REM and/or Visual Studio. This block may need to be updated in the REM future to account for additional environment variables. REM + CALL :fn_UnsetVariable CommandPromptType CALL :fn_UnsetVariable DevEnvDir CALL :fn_UnsetVariable ExtensionSdkDir CALL :fn_UnsetVariable Framework35Version + CALL :fn_UnsetVariable Framework40Version CALL :fn_UnsetVariable FrameworkDir CALL :fn_UnsetVariable FrameworkDir32 CALL :fn_UnsetVariable FrameworkVersion @@ -283,6 +297,8 @@ FOR %%P IN (%PLATFORMS%) DO ( CALL :fn_UnsetVariable WindowsSdkDir CALL :fn_UnsetVariable WindowsSdkDir_35 CALL :fn_UnsetVariable WindowsSdkDir_old + CALL :fn_UnsetVariable WindowsSDK_ExecutablePath_x86 + CALL :fn_UnsetVariable WindowsSDK_ExecutablePath_x64 REM REM NOTE: Reset the PATH here to the absolute bare minimum required. @@ -299,6 +315,8 @@ FOR %%P IN (%PLATFORMS%) DO ( REM environment variables to be picked up by the MSVC makefile REM itself. REM + %_AECHO% Building the %%B configuration for platform %%P with name %%D... + IF /I "%%B" == "Debug" ( SET DEBUG=2 SET MEMDEBUG=1 @@ -374,11 +392,12 @@ FOR %%P IN (%PLATFORMS%) DO ( REM REM NOTE: The Windows 8.1 SDK has a slightly different directory - REM naming convention. Currently, this tool assumes that - REM the Windows 8.1 SDK should only be used with MSVC 2013. + REM naming convention. REM - IF "%VisualStudioVersion%" == "12.0" ( + IF DEFINED USE_WINV63_NSDKLIBPATH ( CALL :fn_AppendVariable NSDKLIBPATH \lib\winv6.3\um\x86 + ) ELSE IF "%VisualStudioVersion%" == "12.0" ( + CALL :fn_AppendVariable NSDKLIBPATH \..\8.0\lib\win8\um\x86 ) ELSE ( CALL :fn_AppendVariable NSDKLIBPATH \lib\win8\um\x86 ) @@ -392,7 +411,7 @@ FOR %%P IN (%PLATFORMS%) DO ( REM file, etc. REM IF NOT DEFINED NOCLEAN ( - %__ECHO% nmake -f Makefile.msc clean + %__ECHO% %NMAKE_CMD% clean IF ERRORLEVEL 1 ( ECHO Failed to clean for platform %%P. @@ -404,6 +423,7 @@ FOR %%P IN (%PLATFORMS%) DO ( REM need to remove the build output for the files we are REM specifically wanting to build for each platform. REM + %_AECHO% Cleaning final output files only... %__ECHO% DEL /Q *.lo sqlite3.dll sqlite3.lib sqlite3.pdb ) @@ -414,7 +434,7 @@ FOR %%P IN (%PLATFORMS%) DO ( REM Also, disable looking for and/or linking to the native Tcl REM runtime library. REM - %__ECHO% nmake -f Makefile.msc sqlite3.dll XCOMPILE=1 USE_NATIVE_LIBPATHS=1 NO_TCL=1 %NMAKE_ARGS% + %__ECHO% %NMAKE_CMD% sqlite3.dll XCOMPILE=1 USE_NATIVE_LIBPATHS=1 NO_TCL=1 %NMAKE_ARGS% IF ERRORLEVEL 1 ( ECHO Failed to build %%B "sqlite3.dll" for platform %%P. diff --git a/tool/lemon.c b/tool/lemon.c index d7179ad..85e94f7 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -1183,8 +1183,7 @@ static int resolve_conflict( apx->type = SH_RESOLVED; }else{ assert( spx->prec==spy->prec && spx->assoc==NONE ); - apy->type = SRCONFLICT; - errcnt++; + apx->type = ERROR; } }else if( apx->type==REDUCE && apy->type==REDUCE ){ spx = apx->x.rp->precsym; diff --git a/tool/logest.c b/tool/logest.c index 8dad6cc..347fa68 100644 --- a/tool/logest.c +++ b/tool/logest.c @@ -17,13 +17,7 @@ ** ** ./LogEst ARGS ** -** Arguments: -** -** 'x' Multiple the top two elements of the stack -** '+' Add the top two elements of the stack -** NUM Convert NUM from integer to LogEst and push onto the stack -** ^NUM Interpret NUM as a LogEst and push onto stack. -** +** See the showHelp() routine for a description of valid arguments. ** Examples: ** ** To convert 123 from LogEst to integer: @@ -89,7 +83,8 @@ static LogEst logEstFromDouble(double x){ LogEst e; assert( sizeof(x)==8 && sizeof(a)==8 ); if( x<=0.0 ) return -32768; - if( x<1.0 ) return -logEstFromDouble(1/x); + if( x<0.01 ) return -logEstFromDouble(1.0/x); + if( x<1.0 ) return logEstFromDouble(100.0*x) - 66; if( x<1024.0 ) return logEstFromInteger((sqlite3_uint64)(1024.0*x)) - 100; if( x<=2000000000.0 ) return logEstFromInteger((sqlite3_uint64)x); memcpy(&a, &x, 8); @@ -97,12 +92,31 @@ static LogEst logEstFromDouble(double x){ return e*10; } +int isInteger(const char *z){ + while( z[0]>='0' && z[0]<='9' ) z++; + return z[0]==0; +} + int isFloat(const char *z){ - while( z[0] ){ - if( z[0]=='.' || z[0]=='E' || z[0]=='e' ) return 1; - z++; - } - return 0; + char c; + while( ((c=z[0])>='0' && c<='9') || c=='.' || c=='E' || c=='e' + || c=='+' || c=='-' ) z++; + return z[0]==0; +} + +static void showHelp(const char *zArgv0){ + printf("Usage: %s ARGS...\n", zArgv0); + printf("Arguments:\n" + " NUM Convert NUM from integer to LogEst and push onto the stack\n" + " ^NUM Interpret NUM as a LogEst and push onto stack\n" + " x Multiple the top two elements of the stack\n" + " + Add the top two elements of the stack\n" + " dup Dupliate the top element on the stack\n" + " inv Take the reciprocal of the top of stack. N = 1/N.\n" + " log Find the LogEst of the number on top of stack\n" + " nlogn Compute NlogN where N is the top of stack\n" + ); + exit(1); } int main(int argc, char **argv){ @@ -111,30 +125,45 @@ int main(int argc, char **argv){ LogEst a[100]; for(i=1; i=2 ){ a[n-2] = logEstAdd(a[n-2],a[n-1]); n--; } - }else if( z[0]=='x' ){ + }else if( strcmp(z,"x")==0 ){ if( n>=2 ){ a[n-2] = logEstMultiply(a[n-2],a[n-1]); n--; } + }else if( strcmp(z,"dup")==0 ){ + if( n>0 ){ + a[n] = a[n-1]; + n++; + } + }else if( strcmp(z,"log")==0 ){ + if( n>0 ) a[n-1] = logEstFromInteger(a[n-1]) - 33; + }else if( strcmp(z,"nlogn")==0 ){ + if( n>0 ) a[n-1] += logEstFromInteger(a[n-1]) - 33; + }else if( strcmp(z,"inv")==0 ){ + if( n>0 ) a[n-1] = -a[n-1]; }else if( z[0]=='^' ){ a[n++] = atoi(z+1); - }else if( isFloat(z) ){ + }else if( isInteger(z) ){ + a[n++] = logEstFromInteger(atoi(z)); + }else if( isFloat(z) && z[0]!='-' ){ a[n++] = logEstFromDouble(atof(z)); }else{ - a[n++] = logEstFromInteger(atoi(z)); + showHelp(argv[0]); } } for(i=n-1; i>=0; i--){ - if( a[i]<0 ){ - printf("%d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i])); + if( a[i]<-40 ){ + printf("%5d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i])); + }else if( a[i]<10 ){ + printf("%5d (%f)\n", a[i], logEstToInt(a[i]+100)/1024.0); }else{ sqlite3_uint64 x = logEstToInt(a[i]+100)*100/1024; - printf("%d (%lld.%02lld)\n", a[i], x/100, x%100); + printf("%5d (%lld.%02lld)\n", a[i], x/100, x%100); } } return 0; diff --git a/tool/mkkeywordhash.c b/tool/mkkeywordhash.c index a467931..721611f 100644 --- a/tool/mkkeywordhash.c +++ b/tool/mkkeywordhash.c @@ -370,7 +370,7 @@ int main(int argc, char **argv){ Keyword *p = &aKeywordTable[i]; p->len = (int)strlen(p->zName); assert( p->lenzOrigName) ); - strcpy(p->zOrigName, p->zName); + memcpy(p->zOrigName, p->zName, p->len+1); totalLen += p->len; p->hash = (UpperToLower[(int)p->zName[0]]*4) ^ (UpperToLower[(int)p->zName[p->len-1]]*3) ^ p->len; diff --git a/tool/mksqlite3c-noext.tcl b/tool/mksqlite3c-noext.tcl index 017ad62..ecb9cb0 100644 --- a/tool/mksqlite3c-noext.tcl +++ b/tool/mksqlite3c-noext.tcl @@ -99,6 +99,8 @@ foreach hdr { mutex.h opcodes.h os_common.h + os_setup.h + os_win.h os.h pager.h parse.h diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index 7a4fe1b..6420772 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -103,6 +103,8 @@ foreach hdr { mutex.h opcodes.h os_common.h + os_setup.h + os_win.h os.h pager.h parse.h @@ -168,7 +170,9 @@ proc copy_file {filename} { if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""} } } elseif {![info exists seen_hdr($hdr)]} { - set seen_hdr($hdr) 1 + if {![regexp {/\*\s+amalgamator:\s+dontcache\s+\*/} $line]} { + set seen_hdr($hdr) 1 + } puts $out $line } elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} { # This include file must be kept because there was a "keep" diff --git a/tool/mksqlite3internalh.tcl b/tool/mksqlite3internalh.tcl index 406ef5c..7e92b3a 100644 --- a/tool/mksqlite3internalh.tcl +++ b/tool/mksqlite3internalh.tcl @@ -60,6 +60,8 @@ foreach hdr { keywordhash.h opcodes.h os_common.h + os_setup.h + os_win.h os.h pager.h parse.h diff --git a/tool/mkvsix.tcl b/tool/mkvsix.tcl index 65fa731..208ce2b 100644 --- a/tool/mkvsix.tcl +++ b/tool/mkvsix.tcl @@ -65,12 +65,16 @@ # argument is optional and if present must contain the name of the directory # containing the root of the source tree for SQLite. The third argument is # optional and if present must contain the flavor the VSIX package to build. -# Currently, the only supported package flavors are "WinRT", "WinRT81", and -# "WP80". The fourth argument is optional and if present must be a string -# containing a list of platforms to include in the VSIX package. The format -# of the platform list string is "platform1,platform2,platform3". Typically, -# when on Windows, this script is executed using commands similar to the -# following from a normal Windows command prompt: +# Currently, the only supported package flavors are "WinRT", "WinRT81", "WP80", +# "WP81", and "Win32". The fourth argument is optional and if present must be +# a string containing a list of platforms to include in the VSIX package. The +# platform list is "platform1,platform2,platform3". The fifth argument is +# optional and if present must contain the version of Visual Studio required by +# the package. Currently, the only supported versions are "2012" and "2013". +# The package flavors "WinRT81" and "WP81" are only supported when the Visual +# Studio version is "2013". Typically, when on Windows, this script is +# executed using commands similar to the following from a normal Windows +# command prompt: # # CD /D C:\dev\sqlite\core # tclsh85 tool\mkvsix.tcl C:\Temp @@ -100,7 +104,7 @@ proc fail { {error ""} {usage false} } { puts stdout "usage:\ [file tail [info nameofexecutable]]\ [file tail [info script]] \[sourceDirectory\]\ -\[packageFlavor\] \[platformNames\]" +\[packageFlavor\] \[platformNames\] \[vsVersion\]" exit 1 } @@ -170,13 +174,81 @@ proc writeFile { fileName data } { return "" } -proc substFile { fileName } { +proc getMinVsVersionXmlChunk { vsVersion } { + switch -exact $vsVersion { + 2012 { + return [appendArgs \ + "\r\n " {MinVSVersion="11.0"}] + } + 2013 { + return [appendArgs \ + "\r\n " {MinVSVersion="12.0"}] + } + default { + return "" + } + } +} + +proc getMaxPlatformVersionXmlChunk { packageFlavor vsVersion } { # - # NOTE: Performs all Tcl command, variable, and backslash substitutions in - # the specified file and then rewrites the contents of that same file - # with the substituted data. + # NOTE: Only Visual Studio 2013 supports this SDK manifest attribute. # - return [writeFile $fileName [uplevel 1 [list subst [readFile $fileName]]]] + if {![string equal $vsVersion 2013]} then { + return "" + } + + switch -exact $packageFlavor { + WinRT { + return [appendArgs \ + "\r\n " {MaxPlatformVersion="8.0"}] + } + WinRT81 { + return [appendArgs \ + "\r\n " {MaxPlatformVersion="8.1"}] + } + WP80 { + return [appendArgs \ + "\r\n " {MaxPlatformVersion="8.0"}] + } + WP81 { + return [appendArgs \ + "\r\n " {MaxPlatformVersion="8.1"}] + } + default { + return "" + } + } +} + +proc getExtraFileListXmlChunk { packageFlavor vsVersion } { + # + # NOTE: Windows Phone 8.0 does not require any extra attributes in its VSIX + # package SDK manifests; however, it appears that Windows Phone 8.1 + # does. + # + if {[string equal $packageFlavor WP80]} then { + return "" + } + + set appliesTo [expr {[string equal $packageFlavor Win32] ? \ + "VisualC" : "WindowsAppContainer"}] + + switch -exact $vsVersion { + 2012 { + return [appendArgs \ + "\r\n " AppliesTo=\" $appliesTo \" \ + "\r\n " {DependsOn="Microsoft.VCLibs, version=11.0"}] + } + 2013 { + return [appendArgs \ + "\r\n " AppliesTo=\" $appliesTo \" \ + "\r\n " {DependsOn="Microsoft.VCLibs, version=12.0"}] + } + default { + return "" + } + } } proc replaceFileNameTokens { fileName name buildName platformName } { @@ -188,6 +260,15 @@ proc replaceFileNameTokens { fileName name buildName platformName } { $name] $fileName] } +proc substFile { fileName } { + # + # NOTE: Performs all Tcl command, variable, and backslash substitutions in + # the specified file and then rewrites the contents of that same file + # with the substituted data. + # + return [writeFile $fileName [uplevel 1 [list subst [readFile $fileName]]]] +} + # # NOTE: This is the entry point for this script. # @@ -206,7 +287,7 @@ set rootName [file rootname [file tail $script]] # NOTE: Process and verify all the command line arguments. # set argc [llength $argv] -if {$argc < 1 || $argc > 4} then {fail} +if {$argc < 1 || $argc > 5} then {fail} set binaryDirectory [lindex $argv 0] @@ -251,58 +332,123 @@ if {[string length $packageFlavor] == 0} then { fail "invalid package flavor" } -if {[string equal -nocase $packageFlavor WinRT]} then { - set shortName SQLite.WinRT - set displayName "SQLite for Windows Runtime" - set targetPlatformIdentifier Windows - set targetPlatformVersion v8.0 - set minVsVersion 11.0 - set extraSdkPath "" - set extraFileListAttributes [appendArgs \ - "\r\n " {AppliesTo="WindowsAppContainer"} \ - "\r\n " {DependsOn="Microsoft.VCLibs, version=11.0"}] -} elseif {[string equal -nocase $packageFlavor WinRT81]} then { - set shortName SQLite.WinRT81 - set displayName "SQLite for Windows Runtime (Windows 8.1)" - set targetPlatformIdentifier Windows - set targetPlatformVersion v8.1 - set minVsVersion 12.0 - set extraSdkPath "" - set extraFileListAttributes [appendArgs \ - "\r\n " {AppliesTo="WindowsAppContainer"} \ - "\r\n " {DependsOn="Microsoft.VCLibs, version=12.0"}] -} elseif {[string equal -nocase $packageFlavor WP80]} then { - set shortName SQLite.WP80 - set displayName "SQLite for Windows Phone" - set targetPlatformIdentifier "Windows Phone" - set targetPlatformVersion v8.0 - set minVsVersion 11.0 - set extraSdkPath "\\..\\$targetPlatformIdentifier" - set extraFileListAttributes "" -} elseif {[string equal -nocase $packageFlavor Win32]} then { - set shortName SQLite.Win32 - set displayName "SQLite for Windows" - set targetPlatformIdentifier Windows - set targetPlatformVersion v8.0 - set minVsVersion 11.0 - set extraSdkPath "" - set extraFileListAttributes [appendArgs \ - "\r\n " {AppliesTo="VisualC"} \ - "\r\n " {DependsOn="Microsoft.VCLibs, version=11.0"}] -} else { - fail "unsupported package flavor, must be one of: WinRT WinRT81 WP80 Win32" -} - if {$argc >= 4} then { set platformNames [list] foreach platformName [split [lindex $argv 3] ", "] { + set platformName [string trim $platformName] + if {[string length $platformName] > 0} then { lappend platformNames $platformName } } } +if {$argc >= 5} then { + set vsVersion [lindex $argv 4] +} else { + set vsVersion 2012 +} + +if {[string length $vsVersion] == 0} then { + fail "invalid Visual Studio version" +} + +if {![string equal $vsVersion 2012] && ![string equal $vsVersion 2013]} then { + fail [appendArgs \ + "unsupported Visual Studio version, must be one of: " \ + [list 2012 2013]] +} + +set shortNames(WinRT,2012) SQLite.WinRT +set shortNames(WinRT,2013) SQLite.WinRT.2013 +set shortNames(WinRT81,2013) SQLite.WinRT81 +set shortNames(WP80,2012) SQLite.WP80 +set shortNames(WP80,2013) SQLite.WP80.2013 +set shortNames(WP81,2013) SQLite.WP81 +set shortNames(Win32,2012) SQLite.Win32 +set shortNames(Win32,2013) SQLite.Win32.2013 + +set displayNames(WinRT,2012) "SQLite for Windows Runtime" +set displayNames(WinRT,2013) "SQLite for Windows Runtime" +set displayNames(WinRT81,2013) "SQLite for Windows Runtime (Windows 8.1)" +set displayNames(WP80,2012) "SQLite for Windows Phone" +set displayNames(WP80,2013) "SQLite for Windows Phone" +set displayNames(WP81,2013) "SQLite for Windows Phone 8.1" +set displayNames(Win32,2012) "SQLite for Windows" +set displayNames(Win32,2013) "SQLite for Windows" + +if {[string equal $packageFlavor WinRT]} then { + set shortName $shortNames($packageFlavor,$vsVersion) + set displayName $displayNames($packageFlavor,$vsVersion) + set targetPlatformIdentifier Windows + set targetPlatformVersion v8.0 + set minVsVersion [getMinVsVersionXmlChunk $vsVersion] + set maxPlatformVersion \ + [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] + set extraSdkPath "" + set extraFileListAttributes \ + [getExtraFileListXmlChunk $packageFlavor $vsVersion] +} elseif {[string equal $packageFlavor WinRT81]} then { + if {$vsVersion ne "2013"} then { + fail [appendArgs \ + "unsupported combination, package flavor " $packageFlavor \ + " is only supported with Visual Studio 2013"] + } + set shortName $shortNames($packageFlavor,$vsVersion) + set displayName $displayNames($packageFlavor,$vsVersion) + set targetPlatformIdentifier Windows + set targetPlatformVersion v8.1 + set minVsVersion [getMinVsVersionXmlChunk $vsVersion] + set maxPlatformVersion \ + [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] + set extraSdkPath "" + set extraFileListAttributes \ + [getExtraFileListXmlChunk $packageFlavor $vsVersion] +} elseif {[string equal $packageFlavor WP80]} then { + set shortName $shortNames($packageFlavor,$vsVersion) + set displayName $displayNames($packageFlavor,$vsVersion) + set targetPlatformIdentifier "Windows Phone" + set targetPlatformVersion v8.0 + set minVsVersion [getMinVsVersionXmlChunk $vsVersion] + set maxPlatformVersion \ + [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] + set extraSdkPath "\\..\\$targetPlatformIdentifier" + set extraFileListAttributes \ + [getExtraFileListXmlChunk $packageFlavor $vsVersion] +} elseif {[string equal $packageFlavor WP81]} then { + if {$vsVersion ne "2013"} then { + fail [appendArgs \ + "unsupported combination, package flavor " $packageFlavor \ + " is only supported with Visual Studio 2013"] + } + set shortName $shortNames($packageFlavor,$vsVersion) + set displayName $displayNames($packageFlavor,$vsVersion) + set targetPlatformIdentifier WindowsPhoneApp + set targetPlatformVersion v8.1 + set minVsVersion [getMinVsVersionXmlChunk $vsVersion] + set maxPlatformVersion \ + [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] + set extraSdkPath "\\..\\$targetPlatformIdentifier" + set extraFileListAttributes \ + [getExtraFileListXmlChunk $packageFlavor $vsVersion] +} elseif {[string equal $packageFlavor Win32]} then { + set shortName $shortNames($packageFlavor,$vsVersion) + set displayName $displayNames($packageFlavor,$vsVersion) + set targetPlatformIdentifier Windows + set targetPlatformVersion v8.0 + set minVsVersion [getMinVsVersionXmlChunk $vsVersion] + set maxPlatformVersion \ + [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] + set extraSdkPath "" + set extraFileListAttributes \ + [getExtraFileListXmlChunk $packageFlavor $vsVersion] +} else { + fail [appendArgs \ + "unsupported package flavor, must be one of: " \ + [list WinRT WinRT81 WP80 WP81 Win32]] +} + ############################################################################### # @@ -490,7 +636,7 @@ if {![info exists buildNames]} then { # overridden via the command line or the user-specific customizations # file. # -if {![info exists platformNames]} then { +if {![info exists platformNames] || [llength $platformNames] == 0} then { set platformNames [list x86 x64 ARM] } diff --git a/tool/showdb.c b/tool/showdb.c index 4d274a7..1a51e9d 100644 --- a/tool/showdb.c +++ b/tool/showdb.c @@ -9,6 +9,8 @@ #if !defined(_MSC_VER) #include +#else +#include #endif #include @@ -66,7 +68,7 @@ static unsigned char *getContent(int ofst, int nByte){ if( aData==0 ) out_of_memory(); memset(aData, 0, nByte+32); lseek(db, ofst, SEEK_SET); - read(db, aData, nByte); + if( read(db, aData, nByte)=nByte ){ sprintf(&zBuf[i], " "); @@ -148,7 +151,7 @@ static void print_decode_line( sprintf(&zBuf[i], " %02x", aData[ofst+j]); val = val*256 + aData[ofst+j]; } - i += strlen(&zBuf[i]); + i += (int)strlen(&zBuf[i]); } sprintf(&zBuf[i], " %9d", val); printf("%s %s\n", zBuf, zMsg); @@ -189,14 +192,14 @@ static void print_db_header(void){ /* ** Describe cell content. */ -static int describeContent( +static i64 describeContent( unsigned char *a, /* Cell content */ - int nLocal, /* Bytes in a[] */ + i64 nLocal, /* Bytes in a[] */ char *zDesc /* Write description here */ ){ - int nDesc = 0; - int n, i, j; - i64 x, v; + i64 nDesc = 0; + int n, j; + i64 i, x, v; const unsigned char *pData; const unsigned char *pLimit; char sep = ' '; @@ -236,15 +239,15 @@ static int describeContent( }else if( x==9 ){ sprintf(zDesc, "1"); }else if( x>=12 ){ - int size = (x-12)/2; + i64 size = (x-12)/2; if( (x&1)==0 ){ - sprintf(zDesc, "blob(%d)", size); + sprintf(zDesc, "blob(%lld)", size); }else{ - sprintf(zDesc, "txt(%d)", size); + sprintf(zDesc, "txt(%lld)", size); } pData += size; } - j = strlen(zDesc); + j = (int)strlen(zDesc); zDesc += j; nDesc += j; } @@ -255,11 +258,11 @@ static int describeContent( ** Compute the local payload size given the total payload size and ** the page size. */ -static int localPayload(i64 nPayload, char cType){ - int maxLocal; - int minLocal; - int surplus; - int nLocal; +static i64 localPayload(i64 nPayload, char cType){ + i64 maxLocal; + i64 minLocal; + i64 surplus; + i64 nLocal; if( cType==13 ){ /* Table leaf */ maxLocal = pagesize-35; @@ -287,19 +290,19 @@ static int localPayload(i64 nPayload, char cType){ ** ** The return value is the local cell size. */ -static int describeCell( +static i64 describeCell( unsigned char cType, /* Page type */ unsigned char *a, /* Cell content */ int showCellContent, /* Show cell content if true */ char **pzDesc /* Store description here */ ){ int i; - int nDesc = 0; + i64 nDesc = 0; int n = 0; int leftChild; i64 nPayload; i64 rowid; - int nLocal; + i64 nLocal; static char zDesc[1000]; i = 0; if( cType<=5 ){ @@ -341,6 +344,180 @@ static int describeCell( return nLocal+n; } +/* Print an offset followed by nByte bytes. Add extra white-space +** at the end so that subsequent text is aligned. +*/ +static void printBytes( + unsigned char *aData, /* Content being decoded */ + unsigned char *aStart, /* Start of content to be printed */ + int nByte /* Number of bytes to print */ +){ + int j; + printf(" %03x: ", (int)(aStart-aData)); + for(j=0; j<9; j++){ + if( j>=nByte ){ + printf(" "); + }else{ + printf("%02x ", aStart[j]); + } + } +} + + +/* +** Write a full decode on stdout for the cell at a[ofst]. +** Assume the page contains a header of size szPgHdr bytes. +*/ +static void decodeCell( + unsigned char *a, /* Page content (without the page-1 header) */ + unsigned pgno, /* Page number */ + int iCell, /* Cell index */ + int szPgHdr, /* Size of the page header. 0 or 100 */ + int ofst /* Cell begins at a[ofst] */ +){ + int i, j; + int leftChild; + i64 k; + i64 nPayload; + i64 rowid; + i64 nHdr; + i64 iType; + i64 nLocal; + unsigned char *x = a + ofst; + unsigned char *end; + unsigned char cType = a[0]; + int nCol = 0; + int szCol[2000]; + int ofstCol[2000]; + int typeCol[2000]; + + printf("Cell[%d]:\n", iCell); + if( cType<=5 ){ + leftChild = ((x[0]*256 + x[1])*256 + x[2])*256 + x[3]; + printBytes(a, x, 4); + printf("left child page:: %d\n", leftChild); + x += 4; + } + if( cType!=5 ){ + i = decodeVarint(x, &nPayload); + printBytes(a, x, i); + nLocal = localPayload(nPayload, cType); + if( nLocal==nPayload ){ + printf("payload-size: %lld\n", nPayload); + }else{ + printf("payload-size: %lld (%lld local, %lld overflow)\n", + nPayload, nLocal, nPayload-nLocal); + } + x += i; + }else{ + nPayload = nLocal = 0; + } + end = x + nLocal; + if( cType==5 || cType==13 ){ + i = decodeVarint(x, &rowid); + printBytes(a, x, i); + printf("rowid: %lld\n", rowid); + x += i; + } + if( nLocal>0 ){ + i = decodeVarint(x, &nHdr); + printBytes(a, x, i); + printf("record-header-size: %d\n", (int)nHdr); + j = i; + nCol = 0; + k = nHdr; + while( x+j=nCell ){ + printf("Page %d has only %d cells\n", pgno, nCell); + return; + } + printf("Header on btree page %d:\n", pgno); print_decode_line(a, 0, 1, zType); print_decode_line(a, 1, 2, "Offset to first freeblock"); print_decode_line(a, 3, 2, "Number of cells on this page"); - nCell = a[3]*256 + a[4]; print_decode_line(a, 5, 2, "Offset to cell content area"); print_decode_line(a, 7, 1, "Fragmented byte count"); if( a[0]==2 || a[0]==5 ){ print_decode_line(a, 8, 4, "Right child"); - iCellPtr = 12; - }else{ - iCellPtr = 8; } - if( nCell>0 ){ + if( cellToDecode==(-2) && nCell>0 ){ printf(" key: lx=left-child n=payload-size r=rowid\n"); } if( showMap ){ @@ -396,27 +588,32 @@ static void decode_btree_page( for(i=0; i=nByte ){ @@ -74,7 +73,7 @@ static unsigned print_decode_line( ** in global variables. */ static unsigned decode_journal_header(int iOfst){ - char *pHdr = read_content(64, iOfst); + unsigned char *pHdr = read_content(64, iOfst); unsigned nPage; printf("Header at offset %d:\n", iOfst); print_decode_line(pHdr, 0, 4, "Header part 1 (3654616569)"); @@ -101,12 +100,11 @@ static void print_page(int iOfst){ char zTitle[50]; aData = read_content(pageSize+8, iOfst); sprintf(zTitle, "page number for page at offset %d", iOfst); - print_decode_line(aData, 0, 4, zTitle); + print_decode_line(aData-iOfst, iOfst, 4, zTitle); free(aData); } int main(int argc, char **argv){ - int rc; int nPage, cnt; int iOfst; if( argc!=2 ){ @@ -136,4 +134,5 @@ int main(int argc, char **argv){ iOfst = (iOfst/sectorSize + 1)*sectorSize; } fclose(db); + return 0; } diff --git a/tool/showstat4.c b/tool/showstat4.c new file mode 100644 index 0000000..668d210 --- /dev/null +++ b/tool/showstat4.c @@ -0,0 +1,157 @@ +/* +** This utility program decodes and displays the content of the +** sqlite_stat4 table in the database file named on the command +** line. +*/ +#include +#include +#include +#include +#include "sqlite3.h" + +typedef sqlite3_int64 i64; /* 64-bit signed integer type */ + + +/* +** Convert the var-int format into i64. Return the number of bytes +** in the var-int. Write the var-int value into *pVal. +*/ +static int decodeVarint(const unsigned char *z, i64 *pVal){ + i64 v = 0; + int i; + for(i=0; i<8; i++){ + v = (v<<7) + (z[i]&0x7f); + if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; } + } + v = (v<<8) + (z[i]&0xff); + *pVal = v; + return 9; +} + + + +int main(int argc, char **argv){ + sqlite3 *db; + sqlite3_stmt *pStmt; + char *zIdx = 0; + int rc, j, x, y, mxHdr; + const unsigned char *aSample; + int nSample; + i64 iVal; + const char *zSep; + + if( argc!=2 ){ + fprintf(stderr, "Usage: %s DATABASE-FILE\n", argv[0]); + exit(1); + } + rc = sqlite3_open(argv[1], &db); + if( rc!=SQLITE_OK || db==0 ){ + fprintf(stderr, "Cannot open database file [%s]\n", argv[1]); + exit(1); + } + rc = sqlite3_prepare_v2(db, + "SELECT tbl||'.'||idx, nEq, nLT, nDLt, sample " + "FROM sqlite_stat4 ORDER BY 1", -1, + &pStmt, 0); + if( rc!=SQLITE_OK || pStmt==0 ){ + fprintf(stderr, "%s\n", sqlite3_errmsg(db)); + sqlite3_close(db); + exit(1); + } + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + if( zIdx==0 || strcmp(zIdx, (const char*)sqlite3_column_text(pStmt,0))!=0 ){ + if( zIdx ) printf("\n"); + sqlite3_free(zIdx); + zIdx = sqlite3_mprintf("%s", sqlite3_column_text(pStmt,0)); + printf("%s:\n", zIdx); + }else{ + printf(" -----------------------------------------------------------\n"); + } + printf(" nEq = %s\n", sqlite3_column_text(pStmt,1)); + printf(" nLt = %s\n", sqlite3_column_text(pStmt,2)); + printf(" nDLt = %s\n", sqlite3_column_text(pStmt,3)); + printf(" sample = x'"); + aSample = sqlite3_column_blob(pStmt,4); + nSample = sqlite3_column_bytes(pStmt,4); + for(j=0; jnSample ){ + printf(" \n"); + continue; + } + y = mxHdr = (int)iVal; + while( xmxHdr ) break; + if( iVal<0 ) break; + switch( iVal ){ + case 0: sz = 0; break; + case 1: sz = 1; break; + case 2: sz = 2; break; + case 3: sz = 3; break; + case 4: sz = 4; break; + case 5: sz = 6; break; + case 6: sz = 8; break; + case 7: sz = 8; break; + case 8: sz = 0; break; + case 9: sz = 0; break; + case 10: + case 11: sz = 0; break; + default: sz = (int)(iVal-12)/2; break; + } + if( y+sz>nSample ) break; + if( iVal==0 ){ + printf("%sNULL", zSep); + }else if( iVal==8 || iVal==9 ){ + printf("%s%d", zSep, ((int)iVal)-8); + }else if( iVal<=7 ){ + v = (signed char)aSample[y]; + for(j=1; j #include #include + +#if !defined(_MSC_VER) #include +#else +#include +#endif + #include #include @@ -172,7 +178,7 @@ static void print_decode_line( int val = aData[ofst]; char zBuf[100]; sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]); - i = strlen(zBuf); + i = (int)strlen(zBuf); for(j=1; j<4; j++){ if( j>=nByte ){ sprintf(&zBuf[i], " "); @@ -180,7 +186,7 @@ static void print_decode_line( sprintf(&zBuf[i], " %02x", aData[ofst+j]); val = val*256 + aData[ofst+j]; } - i += strlen(&zBuf[i]); + i += (int)strlen(&zBuf[i]); } if( asHex ){ sprintf(&zBuf[i], " 0x%08x", val); @@ -273,14 +279,14 @@ static void print_wal_header(Cksum *pCksum){ /* ** Describe cell content. */ -static int describeContent( +static i64 describeContent( unsigned char *a, /* Cell content */ - int nLocal, /* Bytes in a[] */ + i64 nLocal, /* Bytes in a[] */ char *zDesc /* Write description here */ ){ int nDesc = 0; - int n, i, j; - i64 x, v; + int n, j; + i64 i, x, v; const unsigned char *pData; const unsigned char *pLimit; char sep = ' '; @@ -320,15 +326,15 @@ static int describeContent( }else if( x==9 ){ sprintf(zDesc, "1"); }else if( x>=12 ){ - int size = (x-12)/2; + i64 size = (x-12)/2; if( (x&1)==0 ){ - sprintf(zDesc, "blob(%d)", size); + sprintf(zDesc, "blob(%lld)", size); }else{ - sprintf(zDesc, "txt(%d)", size); + sprintf(zDesc, "txt(%lld)", size); } pData += size; } - j = strlen(zDesc); + j = (int)strlen(zDesc); zDesc += j; nDesc += j; } @@ -339,11 +345,11 @@ static int describeContent( ** Compute the local payload size given the total payload size and ** the page size. */ -static int localPayload(i64 nPayload, char cType){ - int maxLocal; - int minLocal; - int surplus; - int nLocal; +static i64 localPayload(i64 nPayload, char cType){ + i64 maxLocal; + i64 minLocal; + i64 surplus; + i64 nLocal; if( cType==13 ){ /* Table leaf */ maxLocal = pagesize-35; @@ -370,19 +376,19 @@ static int localPayload(i64 nPayload, char cType){ ** ** The return value is the local cell size. */ -static int describeCell( +static i64 describeCell( unsigned char cType, /* Page type */ unsigned char *a, /* Cell content */ int showCellContent, /* Show cell content if true */ char **pzDesc /* Store description here */ ){ int i; - int nDesc = 0; + i64 nDesc = 0; int n = 0; int leftChild; i64 nPayload; i64 rowid; - int nLocal; + i64 nLocal; static char zDesc[1000]; i = 0; if( cType<=5 ){ @@ -479,17 +485,17 @@ static void decode_btree_page( for(i=0; i{g$5ol@^m8d++qwye?4jo zO3uFPQyk<-Y{=KC;+3{&e!19s;=k0|6WqJTE7>xKtFr96u81E7846FkGT&Hq+qfMY z4oW%deq%H@p6qD}J(E5*Trv~BC5AYRlBX0x_QrKGjKRR+E-HCPDfB8&yYiY|oRe Fe~f%8d|&_o delta 255 zcmVMe^U>kjA!q zd*GRU-67%$|iSn{ecsQ?ZJUKJjSQKiT|R1Px0~(I zvP%EQBn}7e62qRU7#l8`2|pr3=!WS{^giW=b<~Vr!(lKe`9S1Io>@>Wsccey$&nyA zub&RBn5F%=c4YeYLA>3*%l<0)7@FV@vkrS(1PD`I)IxguZuOIKe>DddVJ7e8ZO)Ue Fe~kXUe(L}L From 57e87926544083933360ac2bb5f3419679d2685f Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Tue, 30 Sep 2014 11:53:17 -0500 Subject: [PATCH 07/59] Remove extra block from merge --- configure | 3 --- 1 file changed, 3 deletions(-) diff --git a/configure b/configure index 3bcd9cc..9f542b4 100755 --- a/configure +++ b/configure @@ -1646,9 +1646,6 @@ _ACEOF exit fi -It was created by sqlcipher $as_me 3.8.6, which was -generated by GNU Autoconf 2.62. Invocation command line was - # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. From dcb021c5097fccec0a877f9adebdff888615179c Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Tue, 30 Sep 2014 11:53:49 -0500 Subject: [PATCH 08/59] Bump cipher_version to 3.2.0 --- src/crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto.h b/src/crypto.h index 6d22ddf..b24b85a 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -44,7 +44,7 @@ #define FILE_HEADER_SZ 16 #ifndef CIPHER_VERSION -#define CIPHER_VERSION "3.1.0" +#define CIPHER_VERSION "3.2.0" #endif #ifndef CIPHER From c0b9920fa38ebdf2751edc0775c88a5372ded0e2 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Tue, 30 Sep 2014 13:43:13 -0500 Subject: [PATCH 09/59] Change cipher_version test to match current version --- test/crypto.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/crypto.test b/test/crypto.test index 47086e3..629be5d 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -1541,7 +1541,7 @@ do_test verify-pragma-cipher-version { execsql { PRAGMA cipher_version; } -} {3.1.0} +} {3.2.0} db close file delete -force test.db From 82c0087c2faeafa9ff011abe97d089613637684f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 16 Oct 2014 23:38:10 -0400 Subject: [PATCH 10/59] SQLCipher headers are installed into ${includedir}/sqlcipher see line #163 of Makefile.in --- sqlcipher.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlcipher.pc.in b/sqlcipher.pc.in index 6ef1a0d..a8789bd 100644 --- a/sqlcipher.pc.in +++ b/sqlcipher.pc.in @@ -10,4 +10,4 @@ Description: SQL database engine Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lsqlcipher Libs.private: @LIBS@ -Cflags: -I${includedir} +Cflags: -I${includedir}/sqlcipher From b8455e0b01bc2c2172fa311765eacda66cbeecd0 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Sat, 1 Nov 2014 13:24:11 +0100 Subject: [PATCH 11/59] Fix dead link in README file Fix the link point to the issues page in the README.md file. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a0f4cea..cc15942 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ http://groups.google.com/group/sqlcipher Issues or support questions on using SQLCipher should be entered into the GitHub Issue tracker: -http://github.com/sjlombardo/sqlcipher/issues +https://github.com/sqlcipher/sqlcipher/issues Please DO NOT post issues, support questions, or other problems to blog posts about SQLCipher as we do not monitor them frequently. From adcd37c89aa3fab709a92671546ec6d5be20ca5e Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Wed, 3 Dec 2014 09:48:33 -0600 Subject: [PATCH 12/59] Adjust amalgamation to target OS X only --- sqlcipher.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sqlcipher.xcodeproj/project.pbxproj b/sqlcipher.xcodeproj/project.pbxproj index e984986..dcc71d8 100644 --- a/sqlcipher.xcodeproj/project.pbxproj +++ b/sqlcipher.xcodeproj/project.pbxproj @@ -296,6 +296,8 @@ GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; PRODUCT_NAME = amalgamation; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = macosx; }; name = Debug; }; @@ -306,6 +308,8 @@ COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; PRODUCT_NAME = amalgamation; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = macosx; ZERO_LINK = NO; }; name = Release; From e1663ef0034b7c8ce1b85c37f0c72cbd89134233 Mon Sep 17 00:00:00 2001 From: Billy Gray Date: Wed, 3 Dec 2014 11:18:10 -0500 Subject: [PATCH 13/59] Updates sqlcipher.xcodeproj ARCH settings for iOS builds to $(ARCHS_STANDARD) + armv7s --- sqlcipher.xcodeproj/project.pbxproj | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/sqlcipher.xcodeproj/project.pbxproj b/sqlcipher.xcodeproj/project.pbxproj index dcc71d8..5c66f77 100644 --- a/sqlcipher.xcodeproj/project.pbxproj +++ b/sqlcipher.xcodeproj/project.pbxproj @@ -247,8 +247,14 @@ 1DEB91F008733DB70010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; - "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; + "ARCHS[sdk=iphoneos*]" = ( + "$(ARCHS_STANDARD)", + armv7s, + ); + "ARCHS[sdk=iphonesimulator*]" = ( + "$(ARCHS_STANDARD)", + armv7s, + ); "ARCHS[sdk=macosx*]" = ( x86_64, i386, @@ -270,8 +276,14 @@ 1DEB91F108733DB70010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; - "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; + "ARCHS[sdk=iphoneos*]" = ( + "$(ARCHS_STANDARD)", + armv7s, + ); + "ARCHS[sdk=iphonesimulator*]" = ( + "$(ARCHS_STANDARD)", + armv7s, + ); "ARCHS[sdk=macosx*]" = ( i386, x86_64, From 7180cded4d200af6b1bd429a1b2a8da74c95b5d2 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Tue, 16 Dec 2014 16:19:35 -0600 Subject: [PATCH 14/59] Remove static modifier from codec password storage functions --- src/crypto.h | 6 +++--- src/crypto_impl.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/crypto.h b/src/crypto.h index b24b85a..905e0f8 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -216,9 +216,9 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx); int sqlcipher_codec_add_random(codec_ctx *ctx, const char *data, int random_sz); int sqlcipher_cipher_profile(sqlite3 *db, const char *destination); static void sqlcipher_profile_callback(void *file, const char *sql, sqlite3_uint64 run_time); -static int sqlcipher_codec_get_store_pass(codec_ctx *ctx); -static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey); -static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value); +int sqlcipher_codec_get_store_pass(codec_ctx *ctx); +void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey); +void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value); #endif #endif diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 9a77e0f..103259a 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -434,15 +434,15 @@ static int sqlcipher_cipher_ctx_set_keyspec(cipher_ctx *ctx, const unsigned char return SQLITE_OK; } -static int sqlcipher_codec_get_store_pass(codec_ctx *ctx) { +int sqlcipher_codec_get_store_pass(codec_ctx *ctx) { return ctx->read_ctx->store_pass; } -static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value) { +void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value) { ctx->read_ctx->store_pass = value; } -static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) { +void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) { *zKey = ctx->read_ctx->pass; *nKey = ctx->read_ctx->pass_sz; } From a31d65d7c8b2d8f7b1763d02d79ce29c5267f39c Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Thu, 29 Jan 2015 10:39:12 -0600 Subject: [PATCH 15/59] Add support for attaching databases with non-default page sizes --- src/crypto.c | 9 +++++++++ src/crypto.h | 3 +++ src/crypto_impl.c | 11 ++++++++++- test/crypto.test | 22 ++++++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/crypto.c b/src/crypto.c index c9814e3..c0109fb 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -186,6 +186,15 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef } } }else + if( sqlite3StrICmp(zLeft,"cipher_default_page_size")==0 ){ + if( zRight ) { + sqlcipher_set_default_pagesize(atoi(zRight)); + } else { + char *default_page_size = sqlite3_mprintf("%d", sqlcipher_get_default_pagesize()); + codec_vdbe_return_static_string(pParse, "cipher_default_page_size", default_page_size); + sqlite3_free(default_page_size); + } + }else if( sqlite3StrICmp(zLeft,"cipher_default_use_hmac")==0 ){ if( zRight ) { sqlcipher_set_default_use_hmac(sqlite3GetBoolean(zRight,1)); diff --git a/src/crypto.h b/src/crypto.h index 905e0f8..8a83a0b 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -180,6 +180,9 @@ int sqlcipher_codec_ctx_set_pagesize(codec_ctx *, int); int sqlcipher_codec_ctx_get_pagesize(codec_ctx *); int sqlcipher_codec_ctx_get_reservesize(codec_ctx *); +void sqlcipher_set_default_pagesize(int page_size); +int sqlcipher_get_default_pagesize(); + void sqlcipher_set_default_kdf_iter(int iter); int sqlcipher_get_default_kdf_iter(); diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 103259a..55fe7a6 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -70,6 +70,7 @@ typedef struct { static unsigned int default_flags = DEFAULT_CIPHER_FLAGS; static unsigned char hmac_salt_mask = HMAC_SALT_MASK; static int default_kdf_iter = PBKDF2_ITER; +static int default_page_size = SQLITE_DEFAULT_PAGE_SIZE; static unsigned int sqlcipher_activate_count = 0; static sqlite3_mutex* sqlcipher_provider_mutex = NULL; static sqlcipher_provider *default_provider = NULL; @@ -661,6 +662,14 @@ int sqlcipher_codec_ctx_get_pagesize(codec_ctx *ctx) { return ctx->page_sz; } +void sqlcipher_set_default_pagesize(int page_size) { + default_page_size = page_size; +} + +int sqlcipher_get_default_pagesize() { + return default_page_size; +} + int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_file *fd, const void *zKey, int nKey) { int rc; codec_ctx *ctx; @@ -691,7 +700,7 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f in encrypted and thus sqlite can't effectively determine the pagesize. this causes an issue in cases where bytes 16 & 17 of the page header are a power of 2 as reported by John Lehman */ - if((rc = sqlcipher_codec_ctx_set_pagesize(ctx, SQLITE_DEFAULT_PAGE_SIZE)) != SQLITE_OK) return rc; + if((rc = sqlcipher_codec_ctx_set_pagesize(ctx, default_page_size)) != SQLITE_OK) return rc; if((rc = sqlcipher_cipher_ctx_init(&ctx->read_ctx)) != SQLITE_OK) return rc; if((rc = sqlcipher_cipher_ctx_init(&ctx->write_ctx)) != SQLITE_OK) return rc; diff --git a/test/crypto.test b/test/crypto.test index 629be5d..7d6d5a5 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -2256,5 +2256,27 @@ do_test can-migrate-with-raw-hex-key { db close file delete -force test.db +do_test attach_database_with_non_default_page_size { + sqlite_orig db test2.db + execsql { + PRAGMA key = 'test'; + PRAGMA cipher_page_size = 4096; + CREATE TABLE t1(a,b); + INSERT INTO t1(a,b) values('one for the money', 'two for the show'); + INSERT INTO t1(a,b) values('three to get ready', 'now, go cat, go'); + } + db close + + sqlite_orig db test.db + execsql { + PRAGMA cipher_default_page_size = 4096; + PRAGMA key = 'test'; + ATTACH DATABASE 'test2.db' as test2 KEY 'test'; + SELECT count(*) FROM test2.t1; + } +} {2} +db close +file delete -force test.db test2.db + sqlite3_test_control_pending_byte $old_pending_byte finish_test From acb86dcc7e38e920da9450cec33471f1dea10099 Mon Sep 17 00:00:00 2001 From: Stephen Lombardo Date: Fri, 30 Jan 2015 17:00:13 -0500 Subject: [PATCH 16/59] adjust readme to explain why SQLITE_TEMP_STORE is omitted from example --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cc15942..70d972e 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,11 @@ an iPhone data vault and password manager (http://getstrip.com). Building SQLCipher is almost the same as compiling a regular version of SQLite with two small exceptions: - 1. You must define SQLITE_HAS_CODEC and SQLITE_TEMP_STORE=2 when building sqlcipher + 1. You *must* define SQLITE_HAS_CODEC and SQLITE_TEMP_STORE=2 when building sqlcipher. 2. You need to link against a OpenSSL's libcrypto -Example Static linking (replace /opt/local/lib with the path to libcrypto.a) +Example Static linking (replace /opt/local/lib with the path to libcrypto.a). Note in this +example, --enable-tempstore=yes is setting SQLITE_TEMP_STORE=2 for the build. $ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ LDFLAGS="/opt/local/lib/libcrypto.a" From a94d35c7dc345758fd9f6590c42880303ad4eee7 Mon Sep 17 00:00:00 2001 From: Like Ma Date: Tue, 3 Mar 2015 15:07:16 +0800 Subject: [PATCH 17/59] Fix building error by GCC 4.5.4 in AIX 5.1 GCC reported undefined mmap without _AIX macro. --- src/crypto_impl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 9a77e0f..bfd170e 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -36,7 +36,7 @@ #include "sqlcipher.h" #include "crypto.h" #ifndef OMIT_MEMLOCK -#if defined(__unix__) || defined(__APPLE__) +#if defined(__unix__) || defined(__APPLE__) || defined(_AIX) #include #elif defined(_WIN32) # include From f56a6acb88186280ea610af9992b9442d972c94f Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Wed, 4 Mar 2015 08:45:43 -0600 Subject: [PATCH 18/59] Initial work on changelog --- CHANGELOG.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..2156daa --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,69 @@ +# SQLCipher Change Log +All notable changes to this project will be documented in this file. + +## [Unreleased][unreleased] + +## [3.2.0] - 2014-09-30 +### Added +- Added PRAGMA cipher_store_pass + +### Changed +- Merged upstream SQLite 3.8.6 +- Renmed README to README.md + +## [3.1.0] - 2014-04-23 +### Added +- Added PRAGMA cipher_profile + +### Changed +- Merged upstream SQLite 3.8.4.3 + +## [3.0.1] - 2013-12-06 +### Added +- Add PRAGMA cipher_add_random to source external entropy + +### Changed +- Fix cipher_migrate to handle passphrases longer than 64 characters & raw keys +- Improvements to the libtomcrypt provider + +## [3.0.0] - 2013-11-05 +### Added +- Added PRAGMA cipher_migrate to migrate older database file formats + +### Changed +- Merged upstream SQLite 3.8.0.2 +- Remove usage of VirtualLock/Unlock on WinRT and Windows Phone +- Ignore HMAC read during Btree file copy +- Fix lib naming for pkg-config +- Use _v2 version of sqlite3_key and sqlite3_rekey +- Update xcodeproj file + +### Security +- Change KDF iteration length from 4,000 to 64,000 + +[unreleased]: https://github.com/sqlcipher/sqlcipher/compare/v3.2.0...prerelease +[3.2.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.1.0...v3.2.0 +[3.1.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.1...v3.1.0 +[3.0.1]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.0...v3.0.1 +[3.0.0]: https://github.com/sqlcipher/sqlcipher/compare/v2.2.0...v3.0.0 +[2.2.0]: https://github.com/sqlcipher/sqlcipher/compare/v2.1.1...v2.2.0 +[2.1.1]: https://github.com/sqlcipher/sqlcipher/compare/v2.1.0...v2.1.1 +[2.1.0]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.6...v2.1.0 +[2.0.6]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.5...v2.0.6 +[2.0.5]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.3...v2.0.5 +[2.0.3]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.0...v2.0.3 +[2.0.0]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.10...v2.0.0 +[1.1.10]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.9...v1.1.10 +[1.1.9]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.8...v1.1.9 +[1.1.8]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.7...v1.1.8 +[1.1.7]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.6...v1.1.7 +[1.1.6]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.5...v1.1.6 +[1.1.5]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.4...v1.1.5 +[1.1.4]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.3...v1.1.4 +[1.1.3]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.2...v1.1.3 +[1.1.2]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.1...v1.1.1 +[1.1.1]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.0...v1.1.1 +[1.1.0]: https://github.com/sqlcipher/sqlcipher/compare/617ed01...v1.1.0 + + + From 29b00cb2fc37c571078ee9ffbea320cecdffdb9c Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Tue, 10 Mar 2015 14:33:43 -0500 Subject: [PATCH 19/59] Initial FIPS integration --- Makefile.msc | 7 +++++++ src/crypto.c | 7 +++++++ src/crypto.h | 11 ++++++++--- src/crypto_cc.c | 5 +++++ src/crypto_impl.c | 3 +++ src/crypto_libtomcrypt.c | 5 +++++ src/crypto_openssl.c | 14 +++++++++++++- src/sqlcipher.h | 1 + 8 files changed, 49 insertions(+), 4 deletions(-) diff --git a/Makefile.msc b/Makefile.msc index 3a9fa29..046583c 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -664,6 +664,13 @@ LIBRESOBJS = # All of the source code files. # SRC = \ + $(TOP)\src\crypto.c \ + $(TOP)\src\crypto_cc.c \ + $(TOP)\src\crypto_impl.c \ + $(TOP)\src\crypto_libtomcrypt.c \ + $(TOP)\src\crypto_openssl.c \ + $(TOP)\src\crypto.h \ + $(TOP)\src\sqlcipher.h \ $(TOP)\src\alter.c \ $(TOP)\src\analyze.c \ $(TOP)\src\attach.c \ diff --git a/src/crypto.c b/src/crypto.c index c0109fb..976e19d 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -89,6 +89,13 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef CODEC_TRACE(("sqlcipher_codec_pragma: entered db=%p iDb=%d pParse=%p zLeft=%s zRight=%s ctx=%p\n", db, iDb, pParse, zLeft, zRight, ctx)); + if( sqlite3StrICmp(zLeft, "cipher_fips_status")== 0 && !zRight ){ + if(ctx) { + char *fips_mode_status = sqlite3_mprintf("%d", sqlcipher_codec_fips_status(ctx)); + codec_vdbe_return_static_string(pParse, "cipher_fips_status", fips_mode_status); + sqlite3_free(fips_mode_status); + } + } else if( sqlite3StrICmp(zLeft, "cipher_store_pass")==0 && zRight ) { sqlcipher_codec_set_store_pass(ctx, sqlite3GetBoolean(zRight, 1)); } else diff --git a/src/crypto.h b/src/crypto.h index 8a83a0b..0ce3737 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -44,8 +44,12 @@ #define FILE_HEADER_SZ 16 #ifndef CIPHER_VERSION +#ifdef SQLCIPHER_FIPS +#define CIPHER_VERSION "3.2.0 FIPS" +#else #define CIPHER_VERSION "3.2.0" #endif +#endif #ifndef CIPHER #define CIPHER "aes-256-cbc" @@ -219,9 +223,10 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx); int sqlcipher_codec_add_random(codec_ctx *ctx, const char *data, int random_sz); int sqlcipher_cipher_profile(sqlite3 *db, const char *destination); static void sqlcipher_profile_callback(void *file, const char *sql, sqlite3_uint64 run_time); -int sqlcipher_codec_get_store_pass(codec_ctx *ctx); -void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey); -void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value); +static int sqlcipher_codec_get_store_pass(codec_ctx *ctx); +static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey); +static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value); +int sqlcipher_codec_fips_status(codec_ctx *ctx); #endif #endif diff --git a/src/crypto_cc.c b/src/crypto_cc.c index 1e18dc7..8872424 100644 --- a/src/crypto_cc.c +++ b/src/crypto_cc.c @@ -120,6 +120,10 @@ static int sqlcipher_cc_ctx_free(void **ctx) { return SQLITE_OK; } +static int sqlcipher_cc_fips_status(void *ctx) { + return 0; +} + int sqlcipher_cc_setup(sqlcipher_provider *p) { p->random = sqlcipher_cc_random; p->get_provider_name = sqlcipher_cc_get_provider_name; @@ -137,6 +141,7 @@ int sqlcipher_cc_setup(sqlcipher_provider *p) { p->ctx_init = sqlcipher_cc_ctx_init; p->ctx_free = sqlcipher_cc_ctx_free; p->add_random = sqlcipher_cc_add_random; + p->fips_status = sqlcipher_cc_fips_status; return SQLITE_OK; } diff --git a/src/crypto_impl.c b/src/crypto_impl.c index b4bf052..8c891d5 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -1227,6 +1227,9 @@ static void sqlcipher_profile_callback(void *file, const char *sql, sqlite3_uint if( f ) fprintf(f, "Elapsed time:%.3f ms - %s\n", elapsed, sql); } +int sqlcipher_codec_fips_status(codec_ctx *ctx) { + return ctx->read_ctx->provider->fips_status(ctx->read_ctx); +} #endif /* END SQLCIPHER */ diff --git a/src/crypto_libtomcrypt.c b/src/crypto_libtomcrypt.c index 22f4efc..02dc845 100644 --- a/src/crypto_libtomcrypt.c +++ b/src/crypto_libtomcrypt.c @@ -227,6 +227,10 @@ static int sqlcipher_ltc_ctx_free(void **ctx) { return SQLITE_OK; } +static int sqlcipher_ltc_fips_status(void *ctx) { + return 0; +} + int sqlcipher_ltc_setup(sqlcipher_provider *p) { p->activate = sqlcipher_ltc_activate; p->deactivate = sqlcipher_ltc_deactivate; @@ -246,6 +250,7 @@ int sqlcipher_ltc_setup(sqlcipher_provider *p) { p->ctx_init = sqlcipher_ltc_ctx_init; p->ctx_free = sqlcipher_ltc_ctx_free; p->add_random = sqlcipher_ltc_add_random; + p->fips_status = sqlcipher_ltc_fips_status; return SQLITE_OK; } diff --git a/src/crypto_openssl.c b/src/crypto_openssl.c index 150ab92..92b3ca3 100644 --- a/src/crypto_openssl.c +++ b/src/crypto_openssl.c @@ -42,7 +42,7 @@ typedef struct { EVP_CIPHER *evp_cipher; } openssl_ctx; - +static int openssl_fips_status = 0; static unsigned int openssl_external_init = 0; static unsigned int openssl_init_count = 0; static sqlite3_mutex* openssl_rand_mutex = NULL; @@ -78,6 +78,13 @@ static int sqlcipher_openssl_activate(void *ctx) { } if(openssl_init_count == 0 && openssl_external_init == 0) { +#ifdef SQLCIPHER_FIPS + openssl_fips_status = FIPS_mode_set(1); + if(!openssl_fips_status){ + ERR_load_crypto_strings(); + ERR_print_errors_fp(stdout); + } +#endif /* if the library was not externally initialized, then should be now */ OpenSSL_add_all_algorithms(); } @@ -224,6 +231,10 @@ static int sqlcipher_openssl_ctx_free(void **ctx) { return SQLITE_OK; } +static int sqlcipher_openssl_fips_status(void *ctx) { + return openssl_fips_status; +} + int sqlcipher_openssl_setup(sqlcipher_provider *p) { p->activate = sqlcipher_openssl_activate; p->deactivate = sqlcipher_openssl_deactivate; @@ -243,6 +254,7 @@ int sqlcipher_openssl_setup(sqlcipher_provider *p) { p->ctx_init = sqlcipher_openssl_ctx_init; p->ctx_free = sqlcipher_openssl_ctx_free; p->add_random = sqlcipher_openssl_add_random; + p->fips_status = sqlcipher_openssl_fips_status; return SQLITE_OK; } diff --git a/src/sqlcipher.h b/src/sqlcipher.h index 37ecf3b..d73a551 100644 --- a/src/sqlcipher.h +++ b/src/sqlcipher.h @@ -55,6 +55,7 @@ typedef struct { int (*ctx_cmp)(void *c1, void *c2); int (*ctx_init)(void **ctx); int (*ctx_free)(void **ctx); + int (*fips_status)(void *ctx); } sqlcipher_provider; /* utility functions */ From 5fd8abafb001875fa3a2e9734775b8c121b8573f Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Tue, 17 Mar 2015 16:05:54 -0500 Subject: [PATCH 20/59] Adjust FIPS initialization and status query --- src/crypto_openssl.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/crypto_openssl.c b/src/crypto_openssl.c index 92b3ca3..7b82de0 100644 --- a/src/crypto_openssl.c +++ b/src/crypto_openssl.c @@ -42,7 +42,6 @@ typedef struct { EVP_CIPHER *evp_cipher; } openssl_ctx; -static int openssl_fips_status = 0; static unsigned int openssl_external_init = 0; static unsigned int openssl_init_count = 0; static sqlite3_mutex* openssl_rand_mutex = NULL; @@ -77,14 +76,16 @@ static int sqlcipher_openssl_activate(void *ctx) { openssl_external_init = 1; } - if(openssl_init_count == 0 && openssl_external_init == 0) { #ifdef SQLCIPHER_FIPS - openssl_fips_status = FIPS_mode_set(1); - if(!openssl_fips_status){ + if(!FIPS_mode()){ + if(!FIPS_mode_set(1)){ ERR_load_crypto_strings(); - ERR_print_errors_fp(stdout); + ERR_print_errors_fp(stderr); } + } #endif + + if(openssl_init_count == 0 && openssl_external_init == 0) { /* if the library was not externally initialized, then should be now */ OpenSSL_add_all_algorithms(); } @@ -232,7 +233,7 @@ static int sqlcipher_openssl_ctx_free(void **ctx) { } static int sqlcipher_openssl_fips_status(void *ctx) { - return openssl_fips_status; + return FIPS_mode(); } int sqlcipher_openssl_setup(sqlcipher_provider *p) { From d4954191b9be4a6b672fc87d24e0a3645af151ec Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 20 Mar 2015 09:04:26 -0500 Subject: [PATCH 21/59] Snapshot of upstream SQLite 3.8.8.3 --- Makefile.in | 82 +- Makefile.msc | 89 +- Makefile.vxworks | 2 + README.md | 24 +- VERSION | 2 +- autoconf/README.first | 62 +- autoconf/tea/Makefile.in | 1 + autoconf/tea/{configure.in => configure.ac} | 6 +- autoconf/tea/tclconfig/tcl.m4 | 21 +- config.h.in | 6 + configure | 130 +- configure.ac | 80 +- ext/fts3/fts3.c | 125 +- ext/fts3/fts3Int.h | 5 + ext/fts3/fts3_expr.c | 2 +- ext/fts3/fts3_porter.c | 2 +- ext/fts3/fts3_snippet.c | 52 +- ext/fts3/fts3_tokenize_vtab.c | 2 +- ext/fts3/fts3_write.c | 4 +- ext/misc/amatch.c | 2 +- ext/misc/eval.c | 122 + ext/misc/fuzzer.c | 3 +- ext/misc/showauth.c | 103 + ext/misc/spellfix.c | 24 +- ext/rtree/rtree.c | 16 +- ext/rtree/rtree6.test | 2 +- ext/rtree/rtreeF.test | 81 + ext/userauth/sqlite3userauth.h | 88 + ext/userauth/user-auth.txt | 164 ++ ext/userauth/userauth.c | 355 +++ main.mk | 35 +- manifest | 492 ++-- manifest.uuid | 2 +- mptest/mptest.c | 2 +- sqlite3.1 | 83 +- src/alter.c | 4 +- src/analyze.c | 121 +- src/attach.c | 11 + src/auth.c | 17 +- src/backup.c | 63 +- src/btmutex.c | 21 +- src/btree.c | 2063 +++++++++------ src/btree.h | 16 +- src/btreeInt.h | 38 +- src/build.c | 166 +- src/callback.c | 10 +- src/complete.c | 13 +- src/ctime.c | 227 +- src/date.c | 26 +- src/delete.c | 24 +- src/expr.c | 333 +-- src/fkey.c | 88 +- src/func.c | 247 +- src/global.c | 29 +- src/hash.c | 66 +- src/hash.h | 6 +- src/insert.c | 45 +- src/legacy.c | 8 +- src/lempar.c | 4 +- src/loadext.c | 18 +- src/main.c | 494 +++- src/malloc.c | 160 +- src/mem1.c | 8 +- src/mem2.c | 4 +- src/mem5.c | 2 +- src/memjournal.c | 2 +- src/msvc.h | 35 + src/mutex.c | 1 + src/mutex.h | 2 +- src/mutex_unix.c | 8 +- src/mutex_w32.c | 8 +- src/notify.c | 2 +- src/os.c | 4 + src/os.h | 2 +- src/os_unix.c | 107 +- src/os_win.c | 96 +- src/os_win.h | 10 + src/pager.c | 342 +-- src/pager.h | 3 + src/parse.y | 41 +- src/pcache.c | 473 ++-- src/pcache.h | 12 +- src/pcache1.c | 221 +- src/pragma.c | 94 +- src/prepare.c | 30 +- src/printf.c | 143 +- src/random.c | 14 +- src/resolve.c | 38 +- src/rowset.c | 6 +- src/select.c | 525 ++-- src/shell.c | 962 +++++-- src/sqlite.h.in | 917 ++++--- src/sqlite3ext.h | 34 +- src/sqliteInt.h | 333 ++- src/status.c | 16 +- src/table.c | 17 +- src/tclsqlite.c | 90 +- src/test1.c | 687 +++-- src/test2.c | 2 +- src/test8.c | 10 +- src/test_blob.c | 319 +++ src/test_config.c | 25 +- src/test_func.c | 4 +- src/test_intarray.c | 8 +- src/test_intarray.h | 4 +- src/test_journal.c | 7 +- src/test_malloc.c | 45 +- src/test_multiplex.c | 24 +- src/test_quota.c | 2 +- src/test_schema.c | 2 +- src/test_vfs.c | 4 +- src/threads.c | 265 ++ src/tokenize.c | 8 +- src/trigger.c | 19 +- src/update.c | 14 +- src/utf.c | 7 +- src/util.c | 70 +- src/vacuum.c | 4 +- src/vdbe.c | 698 +++-- src/vdbe.h | 10 +- src/vdbeInt.h | 73 +- src/vdbeapi.c | 355 ++- src/vdbeaux.c | 518 ++-- src/vdbeblob.c | 12 +- src/vdbemem.c | 491 ++-- src/vdbesort.c | 2585 ++++++++++++++----- src/vdbetrace.c | 119 +- src/vtab.c | 41 +- src/wal.c | 325 ++- src/walker.c | 2 +- src/where.c | 684 +++-- src/whereInt.h | 10 +- test/aggnested.test | 8 +- test/alter4.test | 2 +- test/analyze8.test | 8 +- test/analyze9.test | 46 + test/analyzeA.test | 23 +- test/analyzeD.test | 117 + test/analyzeE.test | 242 ++ test/auth.test | 274 +- test/auth2.test | 4 +- test/auth3.test | 2 +- test/autoindex1.test | 97 + test/autoindex2.test | 44 - test/autoindex3.test | 34 + test/autoindex4.test | 83 + test/backup.test | 1 + test/backup5.test | 65 + test/bigsort.test | 50 + test/btree01.test | 132 + test/capi3.test | 6 +- test/capi3c.test | 6 +- test/capi3d.test | 1 - test/colmeta.test | 40 +- test/corruptH.test | 1 - test/corruptI.test | 57 +- test/default.test | 28 + test/distinct.test | 30 + test/e_blobbytes.test | 76 + test/e_blobclose.test | 171 ++ test/e_blobopen.test | 549 ++++ test/e_blobwrite.test | 204 ++ test/e_changes.test | 441 ++++ test/e_createtable.test | 15 +- test/e_totalchanges.test | 213 ++ test/e_uri.test | 3 + test/e_wal.test | 229 ++ test/e_walauto.test | 202 ++ test/e_walckpt.test | 754 ++++++ test/e_walhook.test | 200 ++ test/eval.test | 12 + test/expr.test | 4 + test/fkey2.test | 2 +- test/fkey5.test | 6 +- test/fkey7.test | 17 + test/fkey8.test | 106 + test/fts3expr4.test | 31 +- test/fts3matchinfo.test | 17 + test/fts4aa.test | 2 +- test/fuzz2.test | 23 +- test/in5.test | 48 + test/index5.test | 5 +- test/index6.test | 28 + test/index7.test | 30 + test/ioerr2.test | 8 +- test/join5.test | 54 + test/lock5.test | 7 +- test/main.test | 20 + test/malloc.test | 42 + test/mallocA.test | 21 +- test/memsubsys1.test | 16 +- test/minmax4.test | 9 +- test/misc8.test | 98 + test/mmap1.test | 86 +- test/multiplex4.test | 114 + test/notify2.test | 41 +- test/orderby1.test | 14 + test/orderby8.test | 41 + test/oserror.test | 27 +- test/ovfl.test | 49 + test/percentile.test | 2 +- test/permutations.test | 32 +- test/pragma.test | 30 +- test/pragma3.test | 253 ++ test/printf2.test | 20 + test/releasetest.mk | 14 - test/releasetest.tcl | 455 +++- test/rollback.test | 4 +- test/rollback2.test | 157 ++ test/rollbackfault.test | 84 + test/rowid.test | 18 +- test/savepoint.test | 6 +- test/savepoint7.test | 10 +- test/scanstatus.test | 398 +++ test/selectG.test | 39 + test/sharedB.test | 60 + test/shared_err.test | 8 +- test/shell1.test | 59 +- test/shell2.test | 6 +- test/shell5.test | 42 +- test/skipscan1.test | 45 + test/skipscan3.test | 73 + test/skipscan5.test | 6 +- test/skipscan6.test | 200 ++ test/sort.test | 183 +- test/sort2.test | 84 + test/sort3.test | 67 + test/sort4.test | 195 ++ test/sort5.test | 45 + test/sortfault.test | 171 ++ test/speedtest1.c | 17 + test/spellfix.test | 16 + test/sqllimits1.test | 7 + test/subquery2.test | 45 + test/table.test | 18 +- test/tester.tcl | 2 + test/threadtest3.c | 262 +- test/threadtest4.c | 484 ++++ test/tkt-ba7cbfaedc.test | 65 + test/tkt-f777251dc7a.test | 3 +- test/trace.test | 16 + test/trans3.test | 2 +- test/trigger9.test | 33 + test/tt3_checkpoint.c | 6 +- test/tt3_index.c | 74 + test/tt3_lookaside1.c | 99 + test/tt3_stress.c | 368 +++ test/tt3_vacuum.c | 90 + test/update.test | 14 + test/userauth01.test | 257 ++ test/vtab1.test | 42 + test/vtab3.test | 2 +- test/wal5.test | 125 +- test/whereJ.test | 303 +++ test/without_rowid3.test | 2 +- test/without_rowid5.test | 3 +- test/without_rowid6.test | 41 + tool/lemon.c | 22 +- tool/mkautoconfamal.sh | 7 +- tool/mkpragmatab.tcl | 13 + tool/mksqlite3c-noext.tcl | 2 + tool/mksqlite3c.tcl | 4 +- tool/mksqlite3internalh.tcl | 1 + tool/showdb.c | 2 +- tool/showstat4.c | 9 +- tool/showwal.c | 8 +- tool/varint.c | 123 + tool/vdbe-compress.tcl | 5 + 268 files changed, 22774 insertions(+), 6664 deletions(-) rename autoconf/tea/{configure.in => configure.ac} (97%) create mode 100644 ext/misc/eval.c create mode 100644 ext/misc/showauth.c create mode 100644 ext/rtree/rtreeF.test create mode 100644 ext/userauth/sqlite3userauth.h create mode 100644 ext/userauth/user-auth.txt create mode 100644 ext/userauth/userauth.c create mode 100644 src/msvc.h create mode 100644 src/test_blob.c create mode 100644 src/threads.c create mode 100644 test/analyzeD.test create mode 100644 test/analyzeE.test create mode 100644 test/autoindex4.test create mode 100644 test/backup5.test create mode 100644 test/bigsort.test create mode 100644 test/btree01.test create mode 100644 test/e_blobbytes.test create mode 100644 test/e_blobclose.test create mode 100644 test/e_blobopen.test create mode 100644 test/e_blobwrite.test create mode 100644 test/e_changes.test create mode 100644 test/e_totalchanges.test create mode 100644 test/e_wal.test create mode 100644 test/e_walauto.test create mode 100644 test/e_walckpt.test create mode 100644 test/e_walhook.test create mode 100644 test/fkey8.test create mode 100644 test/misc8.test create mode 100644 test/multiplex4.test create mode 100644 test/orderby8.test create mode 100644 test/ovfl.test create mode 100644 test/pragma3.test delete mode 100644 test/releasetest.mk create mode 100644 test/rollback2.test create mode 100644 test/rollbackfault.test create mode 100644 test/scanstatus.test create mode 100644 test/selectG.test create mode 100644 test/sharedB.test create mode 100644 test/skipscan3.test create mode 100644 test/skipscan6.test create mode 100644 test/sort2.test create mode 100644 test/sort3.test create mode 100644 test/sort4.test create mode 100644 test/sort5.test create mode 100644 test/sortfault.test create mode 100644 test/threadtest4.c create mode 100644 test/tkt-ba7cbfaedc.test create mode 100644 test/tt3_index.c create mode 100644 test/tt3_lookaside1.c create mode 100644 test/tt3_stress.c create mode 100644 test/tt3_vacuum.c create mode 100644 test/userauth01.test create mode 100644 test/without_rowid6.test create mode 100644 tool/varint.c diff --git a/Makefile.in b/Makefile.in index cf17b02..3d6e0f2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -15,18 +15,22 @@ # The toplevel directory of the source tree. This is the directory # that contains this "Makefile.in" and the "configure.in" script. # -TOP = @srcdir@ +TOP = @abs_srcdir@ # C Compiler and options for use in building executables that # will run on the platform that is doing the build. # BCC = @BUILD_CC@ @BUILD_CFLAGS@ -# C Compile and options for use in building executables that +# TCC is the C Compile and options for use in building executables that # will run on the target platform. (BCC and TCC are usually the -# same unless your are cross-compiling.) +# same unless your are cross-compiling.) Separate CC and CFLAGS macros +# are provide so that these aspects of the build process can be changed +# on the "make" command-line. Ex: "make CC=clang CFLAGS=-fsanitize=undefined" # -TCC = @CC@ @CPPFLAGS@ @CFLAGS@ -I. -I${TOP}/src -I${TOP}/ext/rtree +CC = @CC@ +CFLAGS = @CPPFLAGS@ @CFLAGS@ +TCC = $(CC) $(CFLAGS) -I. -I${TOP}/src -I${TOP}/ext/rtree -I${TOP}/ext/fts3 # Define this for the autoconf-based build, so that the code knows it can # include the generated config.h @@ -37,7 +41,7 @@ TCC += -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite # Omitting the define will cause extra debugging code to be inserted and # includes extra comments when "EXPLAIN stmt" is used. # -TCC += @TARGET_DEBUG@ @XTHREADCONNECT@ +TCC += @TARGET_DEBUG@ # Compiler options needed for programs that use the TCL library. # @@ -177,7 +181,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \ notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \ - table.lo tokenize.lo trigger.lo \ + table.lo threads.lo tokenize.lo trigger.lo \ update.lo util.lo vacuum.lo \ vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo @@ -230,6 +234,7 @@ SRC = \ $(TOP)/src/mem3.c \ $(TOP)/src/mem5.c \ $(TOP)/src/memjournal.c \ + $(TOP)/src/msvc.h \ $(TOP)/src/mutex.c \ $(TOP)/src/mutex.h \ $(TOP)/src/mutex_noop.c \ @@ -263,6 +268,7 @@ SRC = \ $(TOP)/src/sqliteInt.h \ $(TOP)/src/sqliteLimit.h \ $(TOP)/src/table.c \ + $(TOP)/src/threads.c \ $(TOP)/src/tclsqlite.c \ $(TOP)/src/tokenize.c \ $(TOP)/src/trigger.c \ @@ -358,6 +364,7 @@ TESTSRC = \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ + $(TOP)/src/test_blob.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ @@ -393,6 +400,7 @@ TESTSRC = \ TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ + $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ @@ -456,6 +464,7 @@ HDR = \ $(TOP)/src/hash.h \ $(TOP)/src/hwtime.h \ keywordhash.h \ + $(TOP)/src/msvc.h \ $(TOP)/src/mutex.h \ opcodes.h \ $(TOP)/src/os.h \ @@ -527,6 +536,11 @@ mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c $(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \ $(TLIBS) -rpath "$(libdir)" +mptest: mptester$(EXE) + rm -f mptest1.db + ./mptester$(EXE) mptest1.db $(TOP)/mptest/crash01.test + rm -f mptest2.db + ./mptester$(EXE) mptest2.db $(TOP)/mptest/multiwrite01.test # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to @@ -737,6 +751,9 @@ status.lo: $(TOP)/src/status.c $(HDR) table.lo: $(TOP)/src/table.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/table.c +threads.lo: $(TOP)/src/threads.c $(HDR) + $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/threads.c + tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/tokenize.c @@ -915,19 +932,37 @@ testfixture$(TEXE): $(TESTFIXTURE_SRC) $(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \ -o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS) - +# A very detailed test running most or all test cases fulltest: testfixture$(TEXE) sqlite3$(TEXE) ./testfixture$(TEXE) $(TOP)/test/all.test +# Really really long testing soaktest: testfixture$(TEXE) sqlite3$(TEXE) ./testfixture$(TEXE) $(TOP)/test/all.test -soak=1 +# Do extra testing but not aeverything. fulltestonly: testfixture$(TEXE) sqlite3$(TEXE) ./testfixture$(TEXE) $(TOP)/test/full.test +# This is the common case. Run many tests but not those that take +# a really long time. +# test: testfixture$(TEXE) sqlite3$(TEXE) ./testfixture$(TEXE) $(TOP)/test/veryquick.test +# Run a test using valgrind. This can take a really long time +# because valgrind is so much slower than a native machine. +# +valgrindtest: testfixture$(TEXE) sqlite3$(TEXE) + OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind + +# A very fast test that checks basic sanity. The name comes from +# the 60s-era electronics testing: "Turn it on and see if smoke +# comes out." +# +smoketest: testfixture$(TEXE) + ./testfixture$(TEXE) $(TOP)/test/main.test + sqlite3_analyzer.c: sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl echo "#define TCLSH 2" > $@ cat sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c >> $@ @@ -963,6 +998,39 @@ wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.c speedtest1$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/test/speedtest1.c sqlite3.lo $(TLIBS) +# This target will fail if the SQLite amalgamation contains any exported +# symbols that do not begin with "sqlite3_". It is run as part of the +# releasetest.tcl script. +# +checksymbols: sqlite3.lo + nm -g --defined-only sqlite3.o | grep -v " sqlite3_" ; test $$? -ne 0 + echo '0 errors out of 1 tests' + +# Build the amalgamation-autoconf package. +# +amalgamation-tarball: sqlite3.c + TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh + +# The next two rules are used to support the "threadtest" target. Building +# threadtest runs a few thread-safety tests that are implemented in C. This +# target is invoked by the releasetest.tcl script. +# +THREADTEST3_SRC = $(TOP)/test/threadtest3.c \ + $(TOP)/test/tt3_checkpoint.c \ + $(TOP)/test/tt3_index.c \ + $(TOP)/test/tt3_vacuum.c \ + $(TOP)/test/tt3_stress.c \ + $(TOP)/test/tt3_lookaside1.c + +threadtest3$(TEXE): sqlite3.lo $(THREADTEST3_SRC) + $(LTLINK) $(TOP)/test/threadtest3.c sqlite3.lo -o $@ $(TLIBS) + +threadtest: threadtest3$(TEXE) + ./threadtest3$(TEXE) + +releasetest: + $(TCLSH_CMD) $(TOP)/test/releasetest.tcl + # Standard install and cleanup targets # lib_install: libsqlite3.la diff --git a/Makefile.msc b/Makefile.msc index 3a9fa29..4ebe9fd 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -16,6 +16,23 @@ TOP = . USE_AMALGAMATION = 1 !ENDIF +# Set this non-0 to enable full warnings (-W4, etc) when compiling. +# +!IFNDEF USE_FULLWARN +USE_FULLWARN = 0 +!ENDIF + +# If necessary, create a list of harmless compiler warnings to disable when +# compiling the build tools. For the SQLite source code itself, warnings, +# if any, will be disabled from within it. +# +!IFNDEF NO_WARN +!IF $(USE_FULLWARN)!=0 +NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4152 -wd4189 -wd4206 -wd4210 +NO_WARN = $(NO_WARN) -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706 +!ENDIF +!ENDIF + # Set this non-0 to use the library paths and other options necessary for # Windows Phone 8.1. # @@ -108,11 +125,12 @@ WIN32HEAP = 0 # levels. Currently, the recognized values for DEBUG are: # # 0 == NDEBUG: Disables assert() and other runtime diagnostics. -# 1 == Disables NDEBUG and all optimizations and then enables PDBs. -# 2 == SQLITE_DEBUG: Enables various diagnostics messages and code. -# 3 == SQLITE_WIN32_MALLOC_VALIDATE: Validate the Win32 native heap per call. -# 4 == SQLITE_DEBUG_OS_TRACE: Enables output from the OSTRACE() macros. -# 5 == SQLITE_ENABLE_IOTRACE: Enables output from the IOTRACE() macros. +# 1 == SQLITE_ENABLE_API_ARMOR: extra attempts to detect misuse of the API. +# 2 == Disables NDEBUG and all optimizations and then enables PDBs. +# 3 == SQLITE_DEBUG: Enables various diagnostics messages and code. +# 4 == SQLITE_WIN32_MALLOC_VALIDATE: Validate the Win32 native heap per call. +# 5 == SQLITE_DEBUG_OS_TRACE: Enables output from the OSTRACE() macros. +# 6 == SQLITE_ENABLE_IOTRACE: Enables output from the IOTRACE() macros. # !IFNDEF DEBUG DEBUG = 0 @@ -231,7 +249,11 @@ NSDKLIBPATH = $(NSDKLIBPATH:\\=\) # C compiler and options for use in building executables that # will run on the platform that is doing the build. # +!IF $(USE_FULLWARN)!=0 +BCC = $(NCC) -W4 +!ELSE BCC = $(NCC) -W3 +!ENDIF # Check if assembly code listings should be generated for the source # code files to be compiled. @@ -252,7 +274,13 @@ NLTLIBPATHS = "/LIBPATH:$(NCRTLIBPATH)" "/LIBPATH:$(NSDKLIBPATH)" # will run on the target platform. (BCC and TCC are usually the # same unless your are cross-compiling.) # -TCC = $(CC) -W3 -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src -fp:precise +!IF $(USE_FULLWARN)!=0 +TCC = $(CC) -W4 -DINCLUDE_MSVC_H=1 +!ELSE +TCC = $(CC) -W3 +!ENDIF + +TCC = $(TCC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src -fp:precise RCC = $(RC) -DSQLITE_OS_WIN=1 -I$(TOP) -I$(TOP)\src # Check if assembly code listings should be generated for the source @@ -280,7 +308,7 @@ RCC = $(RCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP # MSVC runtime library. # !IF $(FOR_WINRT)!=0 || $(USE_CRT_DLL)!=0 -!IF $(DEBUG)>0 +!IF $(DEBUG)>1 TCC = $(TCC) -MDd BCC = $(BCC) -MDd !ELSE @@ -288,7 +316,7 @@ TCC = $(TCC) -MD BCC = $(BCC) -MD !ENDIF !ELSE -!IF $(DEBUG)>0 +!IF $(DEBUG)>1 TCC = $(TCC) -MTd BCC = $(BCC) -MTd !ELSE @@ -313,7 +341,7 @@ RCC = $(RCC) -I$(TOP)\ext\rtree # options are necessary in order to allow debugging symbols to # work correctly with Visual Studio when using the amalgamation. # -!IF $(DEBUG)>0 +!IF $(DEBUG)>1 MKSQLITE3C_ARGS = --linemacros !ELSE MKSQLITE3C_ARGS = @@ -329,17 +357,22 @@ BCC = $(BCC) -DNDEBUG RCC = $(RCC) -DNDEBUG !ENDIF -!IF $(DEBUG)>1 +!IF $(DEBUG)>0 +TCC = $(TCC) -DSQLITE_ENABLE_API_ARMOR +RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR +!ENDIF + +!IF $(DEBUG)>2 TCC = $(TCC) -DSQLITE_DEBUG RCC = $(RCC) -DSQLITE_DEBUG !ENDIF -!IF $(DEBUG)>3 +!IF $(DEBUG)>4 TCC = $(TCC) -DSQLITE_DEBUG_OS_TRACE=1 RCC = $(RCC) -DSQLITE_DEBUG_OS_TRACE=1 !ENDIF -!IF $(DEBUG)>4 +!IF $(DEBUG)>5 TCC = $(TCC) -DSQLITE_ENABLE_IOTRACE RCC = $(RCC) -DSQLITE_ENABLE_IOTRACE !ENDIF @@ -371,7 +404,7 @@ RCC = $(RCC) -DSQLITE_WIN32_MALLOC=1 # Validate the heap on every call into the native Win32 heap subsystem? # -!IF $(DEBUG)>2 +!IF $(DEBUG)>3 TCC = $(TCC) -DSQLITE_WIN32_MALLOC_VALIDATE=1 RCC = $(RCC) -DSQLITE_WIN32_MALLOC_VALIDATE=1 !ENDIF @@ -482,7 +515,7 @@ RCC = $(RCC) $(OPTS) # If compiling for debugging, add some defines. # -!IF $(DEBUG)>0 +!IF $(DEBUG)>1 TCC = $(TCC) -D_DEBUG BCC = $(BCC) -D_DEBUG RCC = $(RCC) -D_DEBUG @@ -491,7 +524,7 @@ RCC = $(RCC) -D_DEBUG # If optimizations are enabled or disabled (either implicitly or # explicitly), add the necessary flags. # -!IF $(DEBUG)>0 || $(OPTIMIZATIONS)==0 +!IF $(DEBUG)>1 || $(OPTIMIZATIONS)==0 TCC = $(TCC) -Od BCC = $(BCC) -Od !ELSEIF $(OPTIMIZATIONS)>=3 @@ -507,7 +540,7 @@ BCC = $(BCC) -O1 # If symbols are enabled (or compiling for debugging), enable PDBs. # -!IF $(DEBUG)>0 || $(SYMBOLS)!=0 +!IF $(DEBUG)>1 || $(SYMBOLS)!=0 TCC = $(TCC) -Zi BCC = $(BCC) -Zi !ENDIF @@ -592,7 +625,7 @@ LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib # If either debugging or symbols are enabled, enable PDBs. # -!IF $(DEBUG)>0 || $(SYMBOLS)!=0 +!IF $(DEBUG)>1 || $(SYMBOLS)!=0 LDFLAGS = /DEBUG !ENDIF @@ -636,7 +669,7 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \ notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \ - table.lo tokenize.lo trigger.lo \ + table.lo threads.lo tokenize.lo trigger.lo \ update.lo util.lo vacuum.lo \ vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo @@ -700,6 +733,7 @@ SRC = \ $(TOP)\src\mem3.c \ $(TOP)\src\mem5.c \ $(TOP)\src\memjournal.c \ + $(TOP)\src\msvc.h \ $(TOP)\src\mutex.c \ $(TOP)\src\mutex.h \ $(TOP)\src\mutex_noop.c \ @@ -733,6 +767,7 @@ SRC = \ $(TOP)\src\sqliteInt.h \ $(TOP)\src\sqliteLimit.h \ $(TOP)\src\table.c \ + $(TOP)\src\threads.c \ $(TOP)\src\tclsqlite.c \ $(TOP)\src\tokenize.c \ $(TOP)\src\trigger.c \ @@ -827,6 +862,7 @@ TESTSRC = \ $(TOP)\src\test_autoext.c \ $(TOP)\src\test_async.c \ $(TOP)\src\test_backup.c \ + $(TOP)\src\test_blob.c \ $(TOP)\src\test_btree.c \ $(TOP)\src\test_config.c \ $(TOP)\src\test_demovfs.c \ @@ -862,6 +898,7 @@ TESTSRC = \ TESTEXT = \ $(TOP)\ext\misc\amatch.c \ $(TOP)\ext\misc\closure.c \ + $(TOP)\ext\misc\eval.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ $(TOP)\ext\misc\ieee754.c \ @@ -929,6 +966,7 @@ HDR = \ $(TOP)\src\hash.h \ $(TOP)\src\hwtime.h \ keywordhash.h \ + $(TOP)\src\msvc.h \ $(TOP)\src\mutex.h \ opcodes.h \ $(TOP)\src\os.h \ @@ -980,8 +1018,7 @@ libtclsqlite3.lib: tclsqlite.lo libsqlite3.lib $(LTLIB) $(LTLIBOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCL:tcl=tclstub) $(TLIBS) sqlite3.exe: $(TOP)\src\shell.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h - $(LTLINK) $(READLINE_FLAGS) \ - $(TOP)\src\shell.c \ + $(LTLINK) $(READLINE_FLAGS) $(TOP)\src\shell.c \ /link $(LTLINKOPTS) $(LTLIBPATHS) libsqlite3.lib $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) mptester.exe: $(TOP)\mptest\mptest.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h @@ -1031,7 +1068,8 @@ lempar.c: $(TOP)\src\lempar.c copy $(TOP)\src\lempar.c . lemon.exe: $(TOP)\tool\lemon.c lempar.c - $(BCC) -Daccess=_access -Fe$@ $(TOP)\tool\lemon.c /link $(NLTLINKOPTS) $(NLTLIBPATHS) + $(BCC) $(NO_WARN) -Daccess=_access \ + -Fe$@ $(TOP)\tool\lemon.c /link $(NLTLINKOPTS) $(NLTLIBPATHS) # Rules to build individual *.lo files from generated *.c files. This # applies to: @@ -1216,6 +1254,9 @@ status.lo: $(TOP)\src\status.c $(HDR) table.lo: $(TOP)\src\table.c $(HDR) $(LTCOMPILE) -c $(TOP)\src\table.c +threads.lo: $(TOP)\src\threads.c $(HDR) + $(LTCOMPILE) -c $(TOP)\src\threads.c + tokenize.lo: $(TOP)\src\tokenize.c keywordhash.h $(HDR) $(LTCOMPILE) -c $(TOP)\src\tokenize.c @@ -1299,7 +1340,8 @@ sqlite3.h: $(TOP)\src\sqlite.h.in $(TOP)\manifest.uuid $(TOP)\VERSION $(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > sqlite3.h mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c - $(BCC) -Fe$@ $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)\tool\mkkeywordhash.c /link $(NLTLINKOPTS) $(NLTLIBPATHS) + $(BCC) $(NO_WARN) -Fe$@ $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(OPTS) \ + $(TOP)\tool\mkkeywordhash.c /link $(NLTLINKOPTS) $(NLTLIBPATHS) keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe .\mkkeywordhash.exe > keywordhash.h @@ -1380,7 +1422,8 @@ rtree.lo: $(TOP)\ext\rtree\rtree.c $(HDR) $(EXTHDR) # hidden when the library is built via the amalgamation). # TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 -TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE +TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" +TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN) TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) libsqlite3.lib TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C) diff --git a/Makefile.vxworks b/Makefile.vxworks index 0d9c27f..706261f 100644 --- a/Makefile.vxworks +++ b/Makefile.vxworks @@ -253,6 +253,7 @@ SRC = \ $(TOP)/src/mem3.c \ $(TOP)/src/mem5.c \ $(TOP)/src/memjournal.c \ + $(TOP)/src/msvc.h \ $(TOP)/src/mutex.c \ $(TOP)/src/mutex.h \ $(TOP)/src/mutex_noop.c \ @@ -414,6 +415,7 @@ HDR = \ $(TOP)/src/hash.h \ $(TOP)/src/hwtime.h \ keywordhash.h \ + $(TOP)/src/msvc.h \ $(TOP)/src/mutex.h \ opcodes.h \ $(TOP)/src/os.h \ diff --git a/README.md b/README.md index 5e52dea..ff8dc34 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,10 @@ to the "sqlite3.dll" command line above. When debugging into the SQLite code, adding the "DEBUG=1" argument to one of the above command lines is recommended. -SQLite does not require Tcl to run, but a Tcl installation is required -by the makefiles (including those for MSVC). SQLite contains a lot of -generated code and Tcl is used to do much of that code generation. The -makefiles also require AWK. +SQLite does not require [Tcl](http://www.tcl.tk/) to run, but a Tcl installation +is required by the makefiles (including those for MSVC). SQLite contains +a lot of generated code and Tcl is used to do much of that code generation. +The makefiles also require AWK. ## Source Code Tour @@ -95,14 +95,14 @@ manually-edited files and automatically-generated files. The SQLite interface is defined by the **sqlite3.h** header file, which is generated from src/sqlite.h.in, ./manifest.uuid, and ./VERSION. The -Tcl script at tool/mksqlite3h.tcl does the conversion. The manifest.uuid -file contains the SHA1 hash of the particular check-in and is used to generate -the SQLITE_SOURCE_ID macro. The VERSION file contains the current SQLite -version number. The sqlite3.h header is really just a copy of src/sqlite.h.in -with the source-id and version number inserted at just the right spots. -Note that comment text in the sqlite3.h file is used to generate much of -the SQLite API documentation. The Tcl scripts used to generate that -documentation are in a separate source repository. +[Tcl script](http://www.tcl.tk) at tool/mksqlite3h.tcl does the conversion. +The manifest.uuid file contains the SHA1 hash of the particular check-in +and is used to generate the SQLITE\_SOURCE\_ID macro. The VERSION file +contains the current SQLite version number. The sqlite3.h header is really +just a copy of src/sqlite.h.in with the source-id and version number inserted +at just the right spots. Note that comment text in the sqlite3.h file is +used to generate much of the SQLite API documentation. The Tcl scripts +used to generate that documentation are in a separate source repository. The SQL language parser is **parse.c** which is generate from a grammar in the src/parse.y file. The conversion of "parse.y" into "parse.c" is done diff --git a/VERSION b/VERSION index 2e14a95..4982c85 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.8.6 +3.8.8.3 diff --git a/autoconf/README.first b/autoconf/README.first index 6676228..5c2ea0a 100644 --- a/autoconf/README.first +++ b/autoconf/README.first @@ -1,57 +1,11 @@ +This directory contains components use to build an autoconf-ready package +of the SQLite amalgamation: sqlite-autoconf-30XXXXXX.tar.gz -This file describes how to use the files in this directory to create a new -version of the "autoconf-amalgamation" package. - -1. The following files should have executable permission: - - chmod 755 install-sh - chmod 755 missing - chmod 755 depcomp - chmod 755 config.sub - chmod 755 config.guess - -2. Copy new versions of the following SQLite files into this directory: - - sqlite3.c - sqlite3.h - sqlite3ext.h - sqlite3.1 - sqlite3.pc.in - shell.c - -3. Update the SQLite version number in the AC_INIT macro in file - configure.ac: - - AC_INIT(sqlite, 3.6.3, http://www.sqlite.org) - -4. Run the following commands to push the version number change through - to the generated files. - - aclocal - autoconf - automake - -5. Create the tclsqlite3.c file in the tea/generic directory. As follows: - - mkdir -p tea/generic - echo "#ifdef USE_SYSTEM_SQLITE" > tea/generic/tclsqlite3.c - echo "# include " >> tea/generic/tclsqlite3.c - echo "#else" >> tea/generic/tclsqlite3.c - echo "#include \"../../sqlite3.c\"" >> tea/generic/tclsqlite3.c - echo "#endif" >> tea/generic/tclsqlite3.c - cat ../src/tclsqlite.c >> tea/generic/tclsqlite3.c - -6. Update the SQLite version in the AC_INIT macro in file tea/configure.in: - - AC_INIT([sqlite], [3.6.3]) - -7. From the 'tea' directory, run the following commands: - - autoconf - rm -rf autom4te.cache - -8. Run "./configure && make dist". This builds a distribution package - named something like "sqlite-3.6.3.tar.gz". Rename to - "sqlite-amalgamation-3.6.3.tar.gz" and use. +To build the autoconf amalgamation, run from the top-level: + ./configure + make amalgamation-tarball +The amalgamation-tarball target (also available in "main.mk") runs the +script tool/mkautoconfamal.sh which does the work. Refer to that script +for details. diff --git a/autoconf/tea/Makefile.in b/autoconf/tea/Makefile.in index 08b1a44..a870897 100644 --- a/autoconf/tea/Makefile.in +++ b/autoconf/tea/Makefile.in @@ -73,6 +73,7 @@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ +datarootdir = @datarootdir@ datadir = @datadir@ mandir = @mandir@ includedir = @includedir@ diff --git a/autoconf/tea/configure.in b/autoconf/tea/configure.ac similarity index 97% rename from autoconf/tea/configure.in rename to autoconf/tea/configure.ac index ec9c565..8df0af6 100644 --- a/autoconf/tea/configure.in +++ b/autoconf/tea/configure.ac @@ -166,8 +166,10 @@ AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) #-------------------------------------------------------------------- # Redefine fdatasync as fsync on systems that lack fdatasync #-------------------------------------------------------------------- - -AC_CHECK_FUNC(fdatasync, , AC_DEFINE(fdatasync, fsync)) +# +#AC_CHECK_FUNC(fdatasync, , AC_DEFINE(fdatasync, fsync)) +# Check for library functions that SQLite can optionally use. +AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r]) AC_FUNC_STRERROR_R diff --git a/autoconf/tea/tclconfig/tcl.m4 b/autoconf/tea/tclconfig/tcl.m4 index 66214e7..4b4bd1e 100644 --- a/autoconf/tea/tclconfig/tcl.m4 +++ b/autoconf/tea/tclconfig/tcl.m4 @@ -1641,6 +1641,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [ SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" TCL_SHLIB_LD_EXTRAS="-Wl,-soname=\$[@]" + TK_SHLIB_LD_EXTRAS="-Wl,-soname,\$[@]" SHLIB_SUFFIX=".so" LDFLAGS="" AS_IF([test $doRpath = yes], [ @@ -1651,11 +1652,15 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [ LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) - # Version numbers are dot-stripped by system policy. - TCL_TRIM_DOTS=`echo ${PACKAGE_VERSION} | tr -d .` - UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' - TCL_LIB_VERSIONS_OK=nodots + case $system in + FreeBSD-3.*) + # Version numbers are dot-stripped by system policy. + TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .` + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' + TCL_LIB_VERSIONS_OK=nodots + ;; + esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" @@ -1826,8 +1831,8 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [ SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" ], [ - SHLIB_CFLAGS="-Kpic -belf" - LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" + SHLIB_CFLAGS="-Kpic -belf" + LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" ]) SHLIB_LD="ld -G" SHLIB_LD_LIBS="" @@ -4158,8 +4163,6 @@ AC_DEFUN([TEA_PATH_CELIB], [ fi fi ]) - - # Local Variables: # mode: autoconf # End: diff --git a/config.h.in b/config.h.in index efc1d47..36fd607 100644 --- a/config.h.in +++ b/config.h.in @@ -27,6 +27,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `isnan' function. */ +#undef HAVE_ISNAN + /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R @@ -48,6 +51,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H +/* Define to 1 if you have the strchrnul() function */ +#undef HAVE_STRCHRNUL + /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H diff --git a/configure b/configure index 8748a98..5c8a189 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.8.6. +# Generated by GNU Autoconf 2.62 for sqlite 3.8.8.3. # # 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.8.6' -PACKAGE_STRING='sqlite 3.8.6' +PACKAGE_VERSION='3.8.8.3' +PACKAGE_STRING='sqlite 3.8.8.3' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. @@ -868,7 +868,6 @@ RELEASE VERSION_NUMBER BUILD_CC SQLITE_THREADSAFE -XTHREADCONNECT ALLOWRELEASE TEMP_STORE BUILD_EXEEXT @@ -906,9 +905,7 @@ enable_fast_install with_gnu_ld enable_libtool_lock enable_largefile -with_hints enable_threadsafe -enable_cross_thread_connections enable_releasemode enable_tempstore enable_tcl @@ -1483,7 +1480,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.8.6 to adapt to many kinds of systems. +\`configure' configures sqlite 3.8.8.3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1548,7 +1545,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.8.6:";; + short | recursive ) echo "Configuration of sqlite 3.8.8.3:";; esac cat <<\_ACEOF @@ -1562,9 +1559,7 @@ Optional Features: optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --disable-largefile omit support for large files - --enable-threadsafe Support threadsafe operation - --enable-cross-thread-connections - Allow connection sharing across threads + --disable-threadsafe Disable mutexing --enable-releasemode Support libtool link to release mode --enable-tempstore Use an in-ram database for temporary tables (never,no,yes,always) @@ -1573,7 +1568,8 @@ Optional Features: --enable-debug enable debugging & verbose explain --disable-amalgamation Disable the amalgamation and instead build all files separately - --enable-load-extension Enable loading of external extensions + --disable-load-extension + Disable loading of external extensions --enable-gcov Enable coverage testing using gcov Optional Packages: @@ -1582,7 +1578,6 @@ Optional Packages: --with-pic try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] - --with-hints=FILE Read configuration options from FILE --with-tcl=DIR directory containing tcl configuration (tclConfig.sh) --with-readline-lib specify readline library @@ -1664,7 +1659,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.8.6 +sqlite configure 3.8.8.3 generated by GNU Autoconf 2.62 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1678,7 +1673,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.8.6, which was +It was created by sqlite $as_me 3.8.8.3, which was generated by GNU Autoconf 2.62. Invocation command line was $ $0 $@ @@ -2058,9 +2053,6 @@ please regen with autoconf" >&2;} { (exit 1); exit 1; }; } fi -# The following RCS revision string applies to configure.in -# $Revision: 1.56 $ - ######### # Programs needed # @@ -3732,13 +3724,13 @@ if test "${lt_cv_nm_interface+set}" = set; then else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:3735: $ac_compile\"" >&5) + (eval echo "\"\$as_me:3727: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:3738: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:3730: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:3741: output\"" >&5) + (eval echo "\"\$as_me:3733: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -4960,7 +4952,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 4963 "configure"' > conftest.$ac_ext + echo '#line 4955 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -6829,11 +6821,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6832: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6824: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6836: \$? = $ac_status" >&5 + echo "$as_me:6828: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7168,11 +7160,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7171: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7163: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7175: \$? = $ac_status" >&5 + echo "$as_me:7167: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7273,11 +7265,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7276: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7268: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7280: \$? = $ac_status" >&5 + echo "$as_me:7272: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -7328,11 +7320,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7331: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7323: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7335: \$? = $ac_status" >&5 + echo "$as_me:7327: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -10141,7 +10133,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10144 "configure" +#line 10136 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10237,7 +10229,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10240 "configure" +#line 10232 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12146,7 +12138,9 @@ done -for ac_func in usleep fdatasync localtime_r gmtime_r localtime_s utime malloc_usable_size + + +for ac_func in fdatasync gmtime_r isnan localtime_r localtime_s malloc_usable_size strchrnul usleep utime do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -12342,45 +12336,6 @@ VERSION_NUMBER=`cat $srcdir/VERSION \ $as_echo "$as_me: Version number set to $VERSION_NUMBER" >&6;} -######### -# Check to see if the --with-hints=FILE option is used. If there is none, -# then check for a files named "$host.hints" and ../$hosts.hints where -# $host is the hostname of the build system. If still no hints are -# found, try looking in $system.hints and ../$system.hints where -# $system is the result of uname -s. -# - -# Check whether --with-hints was given. -if test "${with_hints+set}" = set; then - withval=$with_hints; hints=$withval -fi - -if test "$hints" = ""; then - host=`hostname | sed 's/\..*//'` - if test -r $host.hints; then - hints=$host.hints - else - if test -r ../$host.hints; then - hints=../$host.hints - fi - fi -fi -if test "$hints" = ""; then - sys=`uname -s` - if test -r $sys.hints; then - hints=$sys.hints - else - if test -r ../$sys.hints; then - hints=../$sys.hints - fi - fi -fi -if test "$hints" != ""; then - { $as_echo "$as_me:$LINENO: result: reading hints from $hints" >&5 -$as_echo "reading hints from $hints" >&6; } - . $hints -fi - ######### # Locate a compiler for the build machine. This compiler should # generate command-line programs that run on the build machine. @@ -12552,31 +12507,6 @@ fi fi -########## -# Do we want to allow a connection created in one thread to be used -# in another thread. This does not work on many Linux systems (ex: RedHat 9) -# due to bugs in the threading implementations. This is thus off by default. -# -# Check whether --enable-cross-thread-connections was given. -if test "${enable_cross_thread_connections+set}" = set; then - enableval=$enable_cross_thread_connections; -else - enable_xthreadconnect=no -fi - -{ $as_echo "$as_me:$LINENO: checking whether to allow connections to be shared across threads" >&5 -$as_echo_n "checking whether to allow connections to be shared across threads... " >&6; } -if test "$enable_xthreadconnect" = "no"; then - XTHREADCONNECT='' - { $as_echo "$as_me:$LINENO: result: no" >&5 -$as_echo "no" >&6; } -else - XTHREADCONNECT='-DSQLITE_ALLOW_XTHREAD_CONNECT=1' - { $as_echo "$as_me:$LINENO: result: yes" >&5 -$as_echo "yes" >&6; } -fi - - ########## # Do we want to support release # @@ -13427,7 +13357,7 @@ fi if test "${enable_load_extension+set}" = set; then enableval=$enable_load_extension; use_loadextension=$enableval else - use_loadextension=no + use_loadextension=yes fi if test "${use_loadextension}" = "yes" ; then @@ -14021,7 +13951,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.8.6, which was +This file was extended by sqlite $as_me 3.8.8.3, which was generated by GNU Autoconf 2.62. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14074,7 +14004,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ -sqlite config.status 3.8.6 +sqlite config.status 3.8.8.3 configured by $0, generated by GNU Autoconf 2.62, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.ac b/configure.ac index 2e70f2c..00ecf45 100644 --- a/configure.ac +++ b/configure.ac @@ -69,19 +69,6 @@ # The filename extension for executables on the # target platform. "" for Unix and ".exe" for windows. # -# The generated configure script will make an attempt to guess -# at all of the above parameters. You can override any of -# the guesses by setting the environment variable named -# "config_AAAA" where "AAAA" is the name of the parameter -# described above. (Exception: srcdir cannot be set this way.) -# If you have a file that sets one or more of these environment -# variables, you can invoke configure as follows: -# -# configure --with-hints=FILE -# -# where FILE is the name of the file that sets the environment -# variables. FILE should be an absolute pathname. -# # This configure.in file is easy to reuse on other projects. Just # change the argument to AC_INIT(). And disable any features that # you don't need (for example BLT) by erasing or commenting out @@ -98,11 +85,6 @@ AC_MSG_ERROR([configure script is out of date: please regen with autoconf]) fi -dnl Put the RCS revision string after AC_INIT so that it will also -dnl show in in configure. -# The following RCS revision string applies to configure.in -# $Revision: 1.56 $ - ######### # Programs needed # @@ -127,7 +109,7 @@ AC_CHECK_HEADERS([sys/types.h stdlib.h stdint.h inttypes.h malloc.h]) ######### # Figure out whether or not we have these functions # -AC_CHECK_FUNCS([usleep fdatasync localtime_r gmtime_r localtime_s utime malloc_usable_size]) +AC_CHECK_FUNCS([fdatasync gmtime_r isnan localtime_r localtime_s malloc_usable_size strchrnul usleep utime]) ######### # By default, we use the amalgamation (this may be changed below...) @@ -180,41 +162,6 @@ VERSION_NUMBER=[`cat $srcdir/VERSION \ AC_MSG_NOTICE(Version number set to $VERSION_NUMBER) AC_SUBST(VERSION_NUMBER) -######### -# Check to see if the --with-hints=FILE option is used. If there is none, -# then check for a files named "$host.hints" and ../$hosts.hints where -# $host is the hostname of the build system. If still no hints are -# found, try looking in $system.hints and ../$system.hints where -# $system is the result of uname -s. -# -AC_ARG_WITH(hints, - AC_HELP_STRING([--with-hints=FILE],[Read configuration options from FILE]), - hints=$withval) -if test "$hints" = ""; then - host=`hostname | sed 's/\..*//'` - if test -r $host.hints; then - hints=$host.hints - else - if test -r ../$host.hints; then - hints=../$host.hints - fi - fi -fi -if test "$hints" = ""; then - sys=`uname -s` - if test -r $sys.hints; then - hints=$sys.hints - else - if test -r ../$sys.hints; then - hints=../$sys.hints - fi - fi -fi -if test "$hints" != ""; then - AC_MSG_RESULT(reading hints from $hints) - . $hints -fi - ######### # Locate a compiler for the build machine. This compiler should # generate command-line programs that run on the build machine. @@ -236,7 +183,7 @@ AC_SUBST(BUILD_CC) # Do we want to support multithreaded use of sqlite # AC_ARG_ENABLE(threadsafe, -AC_HELP_STRING([--enable-threadsafe],[Support threadsafe operation]),,enable_threadsafe=yes) +AC_HELP_STRING([--disable-threadsafe],[Disable mutexing]),,enable_threadsafe=yes) AC_MSG_CHECKING([whether to support threadsafe operation]) if test "$enable_threadsafe" = "no"; then SQLITE_THREADSAFE=0 @@ -251,23 +198,6 @@ if test "$SQLITE_THREADSAFE" = "1"; then AC_SEARCH_LIBS(pthread_create, pthread) fi -########## -# Do we want to allow a connection created in one thread to be used -# in another thread. This does not work on many Linux systems (ex: RedHat 9) -# due to bugs in the threading implementations. This is thus off by default. -# -AC_ARG_ENABLE(cross-thread-connections, -AC_HELP_STRING([--enable-cross-thread-connections],[Allow connection sharing across threads]),,enable_xthreadconnect=no) -AC_MSG_CHECKING([whether to allow connections to be shared across threads]) -if test "$enable_xthreadconnect" = "no"; then - XTHREADCONNECT='' - AC_MSG_RESULT([no]) -else - XTHREADCONNECT='-DSQLITE_ALLOW_XTHREAD_CONNECT=1' - AC_MSG_RESULT([yes]) -fi -AC_SUBST(XTHREADCONNECT) - ########## # Do we want to support release # @@ -605,9 +535,9 @@ AC_SUBST(USE_AMALGAMATION) ######### # See whether we should allow loadable extensions -AC_ARG_ENABLE(load-extension, AC_HELP_STRING([--enable-load-extension], - [Enable loading of external extensions]), - [use_loadextension=$enableval],[use_loadextension=no]) +AC_ARG_ENABLE(load-extension, AC_HELP_STRING([--disable-load-extension], + [Disable loading of external extensions]), + [use_loadextension=$enableval],[use_loadextension=yes]) if test "${use_loadextension}" = "yes" ; then OPT_FEATURE_FLAGS="" AC_SEARCH_LIBS(dlopen, dl) diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 4f4b667..ec9f0d3 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -1853,7 +1853,7 @@ static int fts3SelectLeaf( sqlite3_int64 *piLeaf, /* Selected leaf node */ sqlite3_int64 *piLeaf2 /* Selected leaf node */ ){ - int rc; /* Return code */ + int rc = SQLITE_OK; /* Return code */ int iHeight; /* Height of this node in tree */ assert( piLeaf || piLeaf2 ); @@ -1864,7 +1864,7 @@ static int fts3SelectLeaf( if( rc==SQLITE_OK && iHeight>1 ){ char *zBlob = 0; /* Blob read from %_segments table */ - int nBlob; /* Size of zBlob in bytes */ + int nBlob = 0; /* Size of zBlob in bytes */ if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){ rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0); @@ -3086,7 +3086,7 @@ static int fts3FilterMethod( int nVal, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ - int rc; + int rc = SQLITE_OK; char *zSql; /* SQL statement used to access %_content */ int eSearch; Fts3Table *p = (Fts3Table *)pCursor->pVtab; @@ -3116,6 +3116,7 @@ static int fts3FilterMethod( /* In case the cursor has been used before, clear it now. */ sqlite3_finalize(pCsr->pStmt); sqlite3_free(pCsr->aDoclist); + sqlite3_free(pCsr->aMatchinfo); sqlite3Fts3ExprFree(pCsr->pExpr); memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); @@ -4426,7 +4427,7 @@ static int fts3EvalIncrPhraseNext( bMaxSet = 1; } } - assert( rc!=SQLITE_OK || a[p->nToken-1].bIgnore==0 ); + assert( rc!=SQLITE_OK || (p->nToken>=1 && a[p->nToken-1].bIgnore==0) ); assert( rc!=SQLITE_OK || bMaxSet ); /* Keep advancing iterators until they all point to the same document */ @@ -5019,6 +5020,22 @@ static void fts3EvalNextRow( } pExpr->iDocid = pLeft->iDocid; pExpr->bEof = (pLeft->bEof || pRight->bEof); + if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){ + if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){ + Fts3Doclist *pDl = &pRight->pPhrase->doclist; + while( *pRc==SQLITE_OK && pRight->bEof==0 ){ + memset(pDl->pList, 0, pDl->nList); + fts3EvalNextRow(pCsr, pRight, pRc); + } + } + if( pLeft->pPhrase && pLeft->pPhrase->doclist.aAll ){ + Fts3Doclist *pDl = &pLeft->pPhrase->doclist; + while( *pRc==SQLITE_OK && pLeft->bEof==0 ){ + memset(pDl->pList, 0, pDl->nList); + fts3EvalNextRow(pCsr, pLeft, pRc); + } + } + } } break; } @@ -5391,6 +5408,7 @@ static void fts3EvalRestart( } pPhrase->doclist.pNextDocid = 0; pPhrase->doclist.iDocid = 0; + pPhrase->pOrPoslist = 0; } pExpr->iDocid = 0; @@ -5636,6 +5654,7 @@ int sqlite3Fts3EvalPhrasePoslist( iDocid = pExpr->iDocid; pIter = pPhrase->doclist.pList; if( iDocid!=pCsr->iPrevId || pExpr->bEof ){ + int rc = SQLITE_OK; int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */ int iMul; /* +1 if csr dir matches index dir, else -1 */ int bOr = 0; @@ -5661,72 +5680,43 @@ int sqlite3Fts3EvalPhrasePoslist( ** an incremental phrase. Load the entire doclist for the phrase ** into memory in this case. */ if( pPhrase->bIncr ){ - int rc = SQLITE_OK; - int bEofSave = pExpr->bEof; - fts3EvalRestart(pCsr, pExpr, &rc); - while( rc==SQLITE_OK && !pExpr->bEof ){ - fts3EvalNextRow(pCsr, pExpr, &rc); - if( bEofSave==0 && pExpr->iDocid==iDocid ) break; + int bEofSave = pNear->bEof; + fts3EvalRestart(pCsr, pNear, &rc); + while( rc==SQLITE_OK && !pNear->bEof ){ + fts3EvalNextRow(pCsr, pNear, &rc); + if( bEofSave==0 && pNear->iDocid==iDocid ) break; } - pIter = pPhrase->doclist.pList; assert( rc!=SQLITE_OK || pPhrase->bIncr==0 ); - if( rc!=SQLITE_OK ) return rc; } - - iMul = ((pCsr->bDesc==bDescDoclist) ? 1 : -1); - while( bTreeEof==1 - && pNear->bEof==0 - && (DOCID_CMP(pNear->iDocid, pCsr->iPrevId) * iMul)<0 - ){ - int rc = SQLITE_OK; - fts3EvalNextRow(pCsr, pExpr, &rc); - if( rc!=SQLITE_OK ) return rc; - iDocid = pExpr->iDocid; - pIter = pPhrase->doclist.pList; - } - - bEof = (pPhrase->doclist.nAll==0); - assert( bDescDoclist==0 || bDescDoclist==1 ); - assert( pCsr->bDesc==0 || pCsr->bDesc==1 ); - - if( bEof==0 ){ - if( pCsr->bDesc==bDescDoclist ){ - int dummy; - if( pNear->bEof ){ - /* This expression is already at EOF. So position it to point to the - ** last entry in the doclist at pPhrase->doclist.aAll[]. Variable - ** iDocid is already set for this entry, so all that is required is - ** to set pIter to point to the first byte of the last position-list - ** in the doclist. - ** - ** It would also be correct to set pIter and iDocid to zero. In - ** this case, the first call to sqltie3Fts4DoclistPrev() below - ** would also move the iterator to point to the last entry in the - ** doclist. However, this is expensive, as to do so it has to - ** iterate through the entire doclist from start to finish (since - ** it does not know the docid for the last entry). */ - pIter = &pPhrase->doclist.aAll[pPhrase->doclist.nAll-1]; - fts3ReversePoslist(pPhrase->doclist.aAll, &pIter); - } - while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){ - sqlite3Fts3DoclistPrev( - bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll, - &pIter, &iDocid, &dummy, &bEof - ); - } - }else{ - if( pNear->bEof ){ - pIter = 0; - iDocid = 0; - } - while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){ - sqlite3Fts3DoclistNext( - bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll, - &pIter, &iDocid, &bEof - ); - } + if( bTreeEof ){ + while( rc==SQLITE_OK && !pNear->bEof ){ + fts3EvalNextRow(pCsr, pNear, &rc); } } + if( rc!=SQLITE_OK ) return rc; + + pIter = pPhrase->pOrPoslist; + iDocid = pPhrase->iOrDocid; + if( pCsr->bDesc==bDescDoclist ){ + bEof = (pIter >= (pPhrase->doclist.aAll + pPhrase->doclist.nAll)); + while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){ + sqlite3Fts3DoclistNext( + bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll, + &pIter, &iDocid, &bEof + ); + } + }else{ + bEof = !pPhrase->doclist.nAll || (pIter && pIter<=pPhrase->doclist.aAll); + while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){ + int dummy; + sqlite3Fts3DoclistPrev( + bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll, + &pIter, &iDocid, &dummy, &bEof + ); + } + } + pPhrase->pOrPoslist = pIter; + pPhrase->iOrDocid = iDocid; if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0; } @@ -5740,10 +5730,13 @@ int sqlite3Fts3EvalPhrasePoslist( } while( iThispExpr, fts3SnippetFindPositions, (void *)&sIter); + rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter); + if( rc==SQLITE_OK ){ - /* Set the *pmSeen output variable. */ - for(i=0; iiCol = iCol; - while( !fts3SnippetNextCandidate(&sIter) ){ - int iPos; - int iScore; - u64 mCover; - u64 mHighlight; - fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover, &mHighlight); - assert( iScore>=0 ); - if( iScore>iBestScore ){ - pFragment->iPos = iPos; - pFragment->hlmask = mHighlight; - pFragment->covered = mCover; - iBestScore = iScore; + /* Loop through all candidate snippets. Store the best snippet in + ** *pFragment. Store its associated 'score' in iBestScore. + */ + pFragment->iCol = iCol; + while( !fts3SnippetNextCandidate(&sIter) ){ + int iPos; + int iScore; + u64 mCover; + u64 mHighlite; + fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover,&mHighlite); + assert( iScore>=0 ); + if( iScore>iBestScore ){ + pFragment->iPos = iPos; + pFragment->hlmask = mHighlite; + pFragment->covered = mCover; + iBestScore = iScore; + } } - } + *piScore = iBestScore; + } sqlite3_free(sIter.aPhrase); - *piScore = iBestScore; - return SQLITE_OK; + return rc; } diff --git a/ext/fts3/fts3_tokenize_vtab.c b/ext/fts3/fts3_tokenize_vtab.c index 364852e..fb99f8b 100644 --- a/ext/fts3/fts3_tokenize_vtab.c +++ b/ext/fts3/fts3_tokenize_vtab.c @@ -163,7 +163,7 @@ static int fts3tokConnectMethod( sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ char **pzErr /* OUT: sqlite3_malloc'd error message */ ){ - Fts3tokTable *pTab; + Fts3tokTable *pTab = 0; const sqlite3_tokenizer_module *pMod = 0; sqlite3_tokenizer *pTok = 0; int rc; diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 0da08c6..09294bc 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -3082,8 +3082,8 @@ static int fts3PromoteSegments( if( bOk ){ int iIdx = 0; - sqlite3_stmt *pUpdate1; - sqlite3_stmt *pUpdate2; + sqlite3_stmt *pUpdate1 = 0; + sqlite3_stmt *pUpdate2 = 0; if( rc==SQLITE_OK ){ rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0); diff --git a/ext/misc/amatch.c b/ext/misc/amatch.c index d869dbd..98c0143 100644 --- a/ext/misc/amatch.c +++ b/ext/misc/amatch.c @@ -398,7 +398,7 @@ static amatch_avl *amatchAvlInsert(amatch_avl **ppHead, amatch_avl *pNew){ */ static void amatchAvlRemove(amatch_avl **ppHead, amatch_avl *pOld){ amatch_avl **ppParent; - amatch_avl *pBalance; + amatch_avl *pBalance = 0; /* assert( amatchAvlSearch(*ppHead, pOld->zKey)==pOld ); */ ppParent = amatchAvlFromPtr(pOld, ppHead); if( pOld->pBefore==0 && pOld->pAfter==0 ){ diff --git a/ext/misc/eval.c b/ext/misc/eval.c new file mode 100644 index 0000000..71b6b69 --- /dev/null +++ b/ext/misc/eval.c @@ -0,0 +1,122 @@ +/* +** 2014-11-10 +** +** 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 SQLite extension implements SQL function eval() which runs +** SQL statements recursively. +*/ +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 +#include + +/* +** Structure used to accumulate the output +*/ +struct EvalResult { + char *z; /* Accumulated output */ + const char *zSep; /* Separator */ + int szSep; /* Size of the separator string */ + sqlite3_int64 nAlloc; /* Number of bytes allocated for z[] */ + sqlite3_int64 nUsed; /* Number of bytes of z[] actually used */ +}; + +/* +** Callback from sqlite_exec() for the eval() function. +*/ +static int callback(void *pCtx, int argc, char **argv, char **colnames){ + struct EvalResult *p = (struct EvalResult*)pCtx; + int i; + for(i=0; inUsed+p->szSep+1 > p->nAlloc ){ + char *zNew; + p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; + /* Using sqlite3_realloc64() would be better, but it is a recent + ** addition and will cause a segfault if loaded by an older version + ** of SQLite. */ + zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0; + if( zNew==0 ){ + sqlite3_free(p->z); + memset(p, 0, sizeof(*p)); + return 1; + } + p->z = zNew; + } + if( p->nUsed>0 ){ + memcpy(&p->z[p->nUsed], p->zSep, p->szSep); + p->nUsed += p->szSep; + } + memcpy(&p->z[p->nUsed], z, sz); + p->nUsed += sz; + } + return 0; +} + +/* +** Implementation of the eval(X) and eval(X,Y) SQL functions. +** +** Evaluate the SQL text in X. Return the results, using string +** Y as the separator. If Y is omitted, use a single space character. +*/ +static void sqlEvalFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zSql; + sqlite3 *db; + char *zErr = 0; + int rc; + struct EvalResult x; + + memset(&x, 0, sizeof(x)); + x.zSep = " "; + zSql = (const char*)sqlite3_value_text(argv[0]); + if( zSql==0 ) return; + if( argc>1 ){ + x.zSep = (const char*)sqlite3_value_text(argv[1]); + if( x.zSep==0 ) return; + } + x.szSep = (int)strlen(x.zSep); + db = sqlite3_context_db_handle(context); + rc = sqlite3_exec(db, zSql, callback, &x, &zErr); + if( rc!=SQLITE_OK ){ + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + }else if( x.zSep==0 ){ + sqlite3_result_error_nomem(context); + sqlite3_free(x.z); + }else{ + sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free); + } +} + + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_eval_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + rc = sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, + sqlEvalFunc, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, + sqlEvalFunc, 0, 0); + } + return rc; +} diff --git a/ext/misc/fuzzer.c b/ext/misc/fuzzer.c index fe41cda..dc03161 100644 --- a/ext/misc/fuzzer.c +++ b/ext/misc/fuzzer.c @@ -342,7 +342,8 @@ static int fuzzerLoadOneRule( rc = SQLITE_NOMEM; }else{ memset(pRule, 0, sizeof(*pRule)); - pRule->zFrom = &pRule->zTo[nTo+1]; + pRule->zFrom = pRule->zTo; + pRule->zFrom += nTo + 1; pRule->nFrom = nFrom; memcpy(pRule->zFrom, zFrom, nFrom+1); memcpy(pRule->zTo, zTo, nTo+1); diff --git a/ext/misc/showauth.c b/ext/misc/showauth.c new file mode 100644 index 0000000..87a9a68 --- /dev/null +++ b/ext/misc/showauth.c @@ -0,0 +1,103 @@ +/* +** 2014-09-21 +** +** 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 SQLite extension adds a debug "authorizer" callback to the database +** connection. The callback merely writes the authorization request to +** standard output and returns SQLITE_OK. +** +** This extension can be used (for example) in the command-line shell to +** trace the operation of the authorizer. +*/ +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 +#include + +/* +** Display the authorization request +*/ +static int authCallback( + void *pClientData, + int op, + const char *z1, + const char *z2, + const char *z3, + const char *z4 +){ + const char *zOp; + char zOpSpace[50]; + switch( op ){ + case SQLITE_CREATE_INDEX: zOp = "CREATE_INDEX"; break; + case SQLITE_CREATE_TABLE: zOp = "CREATE_TABLE"; break; + case SQLITE_CREATE_TEMP_INDEX: zOp = "CREATE_TEMP_INDEX"; break; + case SQLITE_CREATE_TEMP_TABLE: zOp = "CREATE_TEMP_TABLE"; break; + case SQLITE_CREATE_TEMP_TRIGGER: zOp = "CREATE_TEMP_TRIGGER"; break; + case SQLITE_CREATE_TEMP_VIEW: zOp = "CREATE_TEMP_VIEW"; break; + case SQLITE_CREATE_TRIGGER: zOp = "CREATE_TRIGGER"; break; + case SQLITE_CREATE_VIEW: zOp = "CREATE_VIEW"; break; + case SQLITE_DELETE: zOp = "DELETE"; break; + case SQLITE_DROP_INDEX: zOp = "DROP_INDEX"; break; + case SQLITE_DROP_TABLE: zOp = "DROP_TABLE"; break; + case SQLITE_DROP_TEMP_INDEX: zOp = "DROP_TEMP_INDEX"; break; + case SQLITE_DROP_TEMP_TABLE: zOp = "DROP_TEMP_TABLE"; break; + case SQLITE_DROP_TEMP_TRIGGER: zOp = "DROP_TEMP_TRIGGER"; break; + case SQLITE_DROP_TEMP_VIEW: zOp = "DROP_TEMP_VIEW"; break; + case SQLITE_DROP_TRIGGER: zOp = "DROP_TRIGGER"; break; + case SQLITE_DROP_VIEW: zOp = "DROP_VIEW"; break; + case SQLITE_INSERT: zOp = "INSERT"; break; + case SQLITE_PRAGMA: zOp = "PRAGMA"; break; + case SQLITE_READ: zOp = "READ"; break; + case SQLITE_SELECT: zOp = "SELECT"; break; + case SQLITE_TRANSACTION: zOp = "TRANSACTION"; break; + case SQLITE_UPDATE: zOp = "UPDATE"; break; + case SQLITE_ATTACH: zOp = "ATTACH"; break; + case SQLITE_DETACH: zOp = "DETACH"; break; + case SQLITE_ALTER_TABLE: zOp = "ALTER_TABLE"; break; + case SQLITE_REINDEX: zOp = "REINDEX"; break; + case SQLITE_ANALYZE: zOp = "ANALYZE"; break; + case SQLITE_CREATE_VTABLE: zOp = "CREATE_VTABLE"; break; + case SQLITE_DROP_VTABLE: zOp = "DROP_VTABLE"; break; + case SQLITE_FUNCTION: zOp = "FUNCTION"; break; + case SQLITE_SAVEPOINT: zOp = "SAVEPOINT"; break; + case SQLITE_COPY: zOp = "COPY"; break; + case SQLITE_RECURSIVE: zOp = "RECURSIVE"; break; + + + default: { + sqlite3_snprintf(sizeof(zOpSpace), zOpSpace, "%d", op); + zOp = zOpSpace; + break; + } + } + if( z1==0 ) z1 = "NULL"; + if( z2==0 ) z2 = "NULL"; + if( z3==0 ) z3 = "NULL"; + if( z4==0 ) z4 = "NULL"; + printf("AUTH: %s,%s,%s,%s,%s\n", zOp, z1, z2, z3, z4); + return SQLITE_OK; +} + + + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_showauth_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + rc = sqlite3_set_authorizer(db, authCallback, 0); + return rc; +} diff --git a/ext/misc/spellfix.c b/ext/misc/spellfix.c index 2e6743e..a6f7805 100644 --- a/ext/misc/spellfix.c +++ b/ext/misc/spellfix.c @@ -356,7 +356,7 @@ static int substituteCost(char cPrev, char cFrom, char cTo){ static int editdist1(const char *zA, const char *zB, int *pnMatch){ int nA, nB; /* Number of characters in zA[] and zB[] */ int xA, xB; /* Loop counters for zA[] and zB[] */ - char cA, cB; /* Current character of zA and zB */ + char cA = 0, cB; /* Current character of zA and zB */ char cAprev, cBprev; /* Previous character of zA and zB */ char cAnext, cBnext; /* Next character in zA and zB */ int d; /* North-west cost value */ @@ -2736,12 +2736,22 @@ static int spellfix1Update( return SQLITE_NOMEM; } if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ - spellfix1DbExec(&rc, db, - "INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) " - "VALUES(%d,%d,%Q,%Q,%Q)", - p->zDbName, p->zTableName, - iRank, iLang, zWord, zK1, zK2 - ); + if( sqlite3_value_type(argv[1])==SQLITE_NULL ){ + spellfix1DbExec(&rc, db, + "INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) " + "VALUES(%d,%d,%Q,%Q,%Q)", + p->zDbName, p->zTableName, + iRank, iLang, zWord, zK1, zK2 + ); + }else{ + newRowid = sqlite3_value_int64(argv[1]); + spellfix1DbExec(&rc, db, + "INSERT INTO \"%w\".\"%w_vocab\"(id,rank,langid,word,k1,k2) " + "VALUES(%lld,%d,%d,%Q,%Q,%Q)", + p->zDbName, p->zTableName, + newRowid, iRank, iLang, zWord, zK1, zK2 + ); + } *pRowid = sqlite3_last_insert_rowid(db); }else{ rowid = sqlite3_value_int64(argv[0]); diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index 8150538..201d3cf 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -369,13 +369,12 @@ static int readInt16(u8 *p){ return (p[0]<<8) + p[1]; } static void readCoord(u8 *p, RtreeCoord *pCoord){ - u32 i = ( + pCoord->u = ( (((u32)p[0]) << 24) + (((u32)p[1]) << 16) + (((u32)p[2]) << 8) + (((u32)p[3]) << 0) ); - *(u32 *)pCoord = i; } static i64 readInt64(u8 *p){ return ( @@ -404,7 +403,7 @@ static int writeCoord(u8 *p, RtreeCoord *pCoord){ u32 i; assert( sizeof(RtreeCoord)==4 ); assert( sizeof(u32)==4 ); - i = *(u32 *)pCoord; + i = pCoord->u; p[0] = (i>>24)&0xFF; p[1] = (i>>16)&0xFF; p[2] = (i>> 8)&0xFF; @@ -735,14 +734,13 @@ static void nodeGetCell( RtreeCell *pCell /* OUT: Write the cell contents here */ ){ u8 *pData; - u8 *pEnd; RtreeCoord *pCoord; + int ii; pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell); pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell); - pEnd = pData + pRtree->nDim*8; pCoord = pCell->aCoord; - for(; pDatanDim*2; ii++){ + readCoord(&pData[ii*4], &pCoord[ii]); } } @@ -1182,7 +1180,7 @@ static RtreeSearchPoint *rtreeEnqueue( pNew = pCur->aPoint + i; pNew->rScore = rScore; pNew->iLevel = iLevel; - assert( iLevel>=0 && iLevel<=RTREE_MAX_DEPTH ); + assert( iLevel<=RTREE_MAX_DEPTH ); while( i>0 ){ RtreeSearchPoint *pParent; j = (i-1)/2; @@ -2806,6 +2804,8 @@ static int rtreeUpdate( rtreeReference(pRtree); assert(nData>=1); + cell.iRowid = 0; /* Used only to suppress a compiler warning */ + /* Constraint handling. A write operation on an r-tree table may return ** SQLITE_CONSTRAINT for two reasons: ** diff --git a/ext/rtree/rtree6.test b/ext/rtree/rtree6.test index cec3a8d..c9c87e8 100644 --- a/ext/rtree/rtree6.test +++ b/ext/rtree/rtree6.test @@ -102,7 +102,7 @@ do_eqp_test rtree6.2.4.2 { SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10 } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1} - 0 1 1 {SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?)} + 0 1 1 {SEARCH TABLE t2 USING AUTOMATIC PARTIAL COVERING INDEX (v=?)} } do_eqp_test rtree6.2.5 { diff --git a/ext/rtree/rtreeF.test b/ext/rtree/rtreeF.test new file mode 100644 index 0000000..c9620d3 --- /dev/null +++ b/ext/rtree/rtreeF.test @@ -0,0 +1,81 @@ +# 2014-08-21 +# +# 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 contains tests for the r-tree module. +# +# This file contains test cases for the ticket +# [369d57fb8e5ccdff06f197a37147a88f9de95cda] (2014-08-21) +# +# The following SQL causes an assertion fault while running +# sqlite3_prepare() on the DELETE statement: +# +# CREATE TABLE t1(x); +# CREATE TABLE t2(y); +# CREATE VIRTUAL TABLE t3 USING rtree(a,b,c); +# CREATE TRIGGER t2del AFTER DELETE ON t2 WHEN (SELECT 1 from t1) BEGIN +# DELETE FROM t3 WHERE a=old.y; +# END; +# DELETE FROM t2 WHERE y=1; +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source $testdir/tester.tcl +ifcapable !rtree { finish_test ; return } + +do_execsql_test rtreeF-1.1 { + CREATE TABLE t1(x); + CREATE TABLE t2(y); + CREATE VIRTUAL TABLE t3 USING rtree(a,b,c); + CREATE TRIGGER t2dwl AFTER DELETE ON t2 WHEN (SELECT 1 from t1) BEGIN + DELETE FROM t3 WHERE a=old.y; + END; + + INSERT INTO t1(x) VALUES(999); + INSERT INTO t2(y) VALUES(1),(2),(3),(4),(5); + INSERT INTO t3(a,b,c) VALUES(1,2,3),(2,3,4),(3,4,5),(4,5,6),(5,6,7); + + SELECT a FROM t3 ORDER BY a; + SELECT '|'; + SELECT y FROM t2 ORDER BY y; +} {1 2 3 4 5 | 1 2 3 4 5} +do_execsql_test rtreeF-1.2 { + DELETE FROM t2 WHERE y=3; + + SELECT a FROM t3 ORDER BY a; + SELECT '|'; + SELECT y FROM t2 ORDER BY y; +} {1 2 4 5 | 1 2 4 5} +do_execsql_test rtreeF-1.3 { + DELETE FROM t1; + DELETE FROM t2 WHERE y=5; + + SELECT a FROM t3 ORDER BY a; + SELECT '|'; + SELECT y FROM t2 ORDER BY y; +} {1 2 4 5 | 1 2 4} +do_execsql_test rtreeF-1.4 { + INSERT INTO t1 DEFAULT VALUES; + DELETE FROM t2 WHERE y=5; + + SELECT a FROM t3 ORDER BY a; + SELECT '|'; + SELECT y FROM t2 ORDER BY y; +} {1 2 4 5 | 1 2 4} +do_execsql_test rtreeF-1.5 { + DELETE FROM t2 WHERE y=2; + + SELECT a FROM t3 ORDER BY a; + SELECT '|'; + SELECT y FROM t2 ORDER BY y; +} {1 4 5 | 1 4} + +finish_test diff --git a/ext/userauth/sqlite3userauth.h b/ext/userauth/sqlite3userauth.h new file mode 100644 index 0000000..619477c --- /dev/null +++ b/ext/userauth/sqlite3userauth.h @@ -0,0 +1,88 @@ +/* +** 2014-09-08 +** +** 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 contains the application interface definitions for the +** user-authentication extension feature. +** +** To compile with the user-authentication feature, append this file to +** end of an SQLite amalgamation header file ("sqlite3.h"), then add +** the SQLITE_USER_AUTHENTICATION compile-time option. See the +** user-auth.txt file in the same source directory as this file for +** additional information. +*/ +#ifdef SQLITE_USER_AUTHENTICATION + +/* +** If a database contains the SQLITE_USER table, then the +** sqlite3_user_authenticate() interface must be invoked with an +** appropriate username and password prior to enable read and write +** access to the database. +** +** Return SQLITE_OK on success or SQLITE_ERROR if the username/password +** combination is incorrect or unknown. +** +** If the SQLITE_USER table is not present in the database file, then +** this interface is a harmless no-op returnning SQLITE_OK. +*/ +int sqlite3_user_authenticate( + sqlite3 *db, /* The database connection */ + const char *zUsername, /* Username */ + const char *aPW, /* Password or credentials */ + int nPW /* Number of bytes in aPW[] */ +); + +/* +** The sqlite3_user_add() interface can be used (by an admin user only) +** to create a new user. When called on a no-authentication-required +** database, this routine converts the database into an authentication- +** required database, automatically makes the added user an +** administrator, and logs in the current connection as that user. +** The sqlite3_user_add() interface only works for the "main" database, not +** for any ATTACH-ed databases. Any call to sqlite3_user_add() by a +** non-admin user results in an error. +*/ +int sqlite3_user_add( + sqlite3 *db, /* Database connection */ + const char *zUsername, /* Username to be added */ + const char *aPW, /* Password or credentials */ + int nPW, /* Number of bytes in aPW[] */ + int isAdmin /* True to give new user admin privilege */ +); + +/* +** The sqlite3_user_change() interface can be used to change a users +** login credentials or admin privilege. Any user can change their own +** login credentials. Only an admin user can change another users login +** credentials or admin privilege setting. No user may change their own +** admin privilege setting. +*/ +int sqlite3_user_change( + sqlite3 *db, /* Database connection */ + const char *zUsername, /* Username to change */ + const char *aPW, /* New password or credentials */ + int nPW, /* Number of bytes in aPW[] */ + int isAdmin /* Modified admin privilege for the user */ +); + +/* +** The sqlite3_user_delete() interface can be used (by an admin user only) +** to delete a user. The currently logged-in user cannot be deleted, +** which guarantees that there is always an admin user and hence that +** the database cannot be converted into a no-authentication-required +** database. +*/ +int sqlite3_user_delete( + sqlite3 *db, /* Database connection */ + const char *zUsername /* Username to remove */ +); + +#endif /* SQLITE_USER_AUTHENTICATION */ diff --git a/ext/userauth/user-auth.txt b/ext/userauth/user-auth.txt new file mode 100644 index 0000000..ba4eabc --- /dev/null +++ b/ext/userauth/user-auth.txt @@ -0,0 +1,164 @@ +Activate the user authentication logic by including the +ext/userauth/userauth.c source code file in the build and +adding the -DSQLITE_USER_AUTHENTICATION compile-time option. +The ext/userauth/sqlite3userauth.h header file is available to +applications to define the interface. + +When using the SQLite amalgamation, it is sufficient to append +the ext/userauth/userauth.c source file onto the end of the +amalgamation. + +The following new APIs are available when user authentication is +activated: + + int sqlite3_user_authenticate( + sqlite3 *db, /* The database connection */ + const char *zUsername, /* Username */ + const char *aPW, /* Password or credentials */ + int nPW /* Number of bytes in aPW[] */ + ); + + int sqlite3_user_add( + sqlite3 *db, /* Database connection */ + const char *zUsername, /* Username to be added */ + const char *aPW, /* Password or credentials */ + int nPW, /* Number of bytes in aPW[] */ + int isAdmin /* True to give new user admin privilege */ + ); + + int sqlite3_user_change( + sqlite3 *db, /* Database connection */ + const char *zUsername, /* Username to change */ + const void *aPW, /* Modified password or credentials */ + int nPW, /* Number of bytes in aPW[] */ + int isAdmin /* Modified admin privilege for the user */ + ); + + int sqlite3_user_delete( + sqlite3 *db, /* Database connection */ + const char *zUsername /* Username to remove */ + ); + +With this extension, a database can be marked as requiring authentication. +By default a database does not require authentication. + +The sqlite3_open(), sqlite3_open16(), and sqlite3_open_v2() interfaces +work as before: they open a new database connection. However, if the +database being opened requires authentication, then attempts to read +or write from the database will fail with an SQLITE_AUTH error until +after sqlite3_user_authenticate() has been called successfully. The +sqlite3_user_authenticate() call will return SQLITE_OK if the +authentication credentials are accepted and SQLITE_ERROR if not. + +Calling sqlite3_user_authenticate() on a no-authentication-required +database connection is a harmless no-op. + +If the database is encrypted, then sqlite3_key_v2() must be called first, +with the correct decryption key, prior to invoking sqlite3_user_authenticate(). + +To recapitulate: When opening an existing unencrypted authentication- +required database, the call sequence is: + + sqlite3_open_v2() + sqlite3_user_authenticate(); + /* Database is now usable */ + +To open an existing, encrypted, authentication-required database, the +call sequence is: + + sqlite3_open_v2(); + sqlite3_key_v2(); + sqlite3_user_authenticate(); + /* Database is now usable */ + +When opening a no-authentication-required database, the database +connection is treated as if it was authenticated as an admin user. + +When ATTACH-ing new database files to a connection, each newly attached +database that is an authentication-required database is checked using +the same username and password as supplied to the main database. If that +check fails, then the ATTACH command fails with an SQLITE_AUTH error. + +The sqlite3_user_add() interface can be used (by an admin user only) +to create a new user. When called on a no-authentication-required +database and when A is true, the sqlite3_user_add(D,U,P,N,A) routine +converts the database into an authentication-required database and +logs in the database connection D as user U with password P,N. +To convert a no-authentication-required database into an authentication- +required database, the isAdmin parameter must be true. If +sqlite3_user_add(D,U,P,N,A) is called on a no-authentication-required +database and A is false, then the call fails with an SQLITE_AUTH error. + +Any call to sqlite3_user_add() by a non-admin user results in an error. + +Hence, to create a new, unencrypted, authentication-required database, +the call sequence is: + + sqlite3_open_v2(); + sqlite3_user_add(); + +And to create a new, encrypted, authentication-required database, the call +sequence is: + + sqlite3_open_v2(); + sqlite3_key_v2(); + sqlite3_user_add(); + +The sqlite3_user_delete() interface can be used (by an admin user only) +to delete a user. The currently logged-in user cannot be deleted, +which guarantees that there is always an admin user and hence that +the database cannot be converted into a no-authentication-required +database. + +The sqlite3_user_change() interface can be used to change a users +login credentials or admin privilege. Any user can change their own +password. Only an admin user can change another users login +credentials or admin privilege setting. No user may change their own +admin privilege setting. + +The sqlite3_set_authorizer() callback is modified to take a 7th parameter +which is the username of the currently logged in user, or NULL for a +no-authentication-required database. + +----------------------------------------------------------------------------- +Implementation notes: + +An authentication-required database is identified by the presence of a +new table: + + CREATE TABLE sqlite_user( + uname TEXT PRIMARY KEY, + isAdmin BOOLEAN, + pw BLOB + ) WITHOUT ROWID; + +The sqlite_user table is inaccessible (unreadable and unwriteable) to +non-admin users and is read-only for admin users. However, if the same +database file is opened by a version of SQLite that omits +the -DSQLITE_USER_AUTHENTICATION compile-time option, then the sqlite_user +table will be readable by anybody and writeable by anybody if +the "PRAGMA writable_schema=ON" statement is run first. + +The sqlite_user.pw field is encoded by a built-in SQL function +"sqlite_crypt(X,Y)". The two arguments are both BLOBs. The first argument +is the plaintext password supplied to the sqlite3_user_authenticate() +interface. The second argument is the sqlite_user.pw value and is supplied +so that the function can extract the "salt" used by the password encoder. +The result of sqlite_crypt(X,Y) is another blob which is the value that +ends up being stored in sqlite_user.pw. To verify credentials X supplied +by the sqlite3_user_authenticate() routine, SQLite runs: + + sqlite_user.pw == sqlite_crypt(X, sqlite_user.pw) + +To compute an appropriate sqlite_user.pw value from a new or modified +password X, sqlite_crypt(X,NULL) is run. A new random salt is selected +when the second argument is NULL. + +The built-in version of of sqlite_crypt() uses a simple Ceasar-cypher +which prevents passwords from being revealed by searching the raw database +for ASCII text, but is otherwise trivally broken. For better password +security, the database should be encrypted using the SQLite Encryption +Extension or similar technology. Or, the application can use the +sqlite3_create_function() interface to provide an alternative +implementation of sqlite_crypt() that computes a stronger password hash, +perhaps using a cryptographic hash function like SHA1. diff --git a/ext/userauth/userauth.c b/ext/userauth/userauth.c new file mode 100644 index 0000000..6ce9905 --- /dev/null +++ b/ext/userauth/userauth.c @@ -0,0 +1,355 @@ +/* +** 2014-09-08 +** +** 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 contains the bulk of the implementation of the +** user-authentication extension feature. Some parts of the user- +** authentication code are contained within the SQLite core (in the +** src/ subdirectory of the main source code tree) but those parts +** that could reasonable be separated out are moved into this file. +** +** To compile with the user-authentication feature, append this file to +** end of an SQLite amalgamation, then add the SQLITE_USER_AUTHENTICATION +** compile-time option. See the user-auth.txt file in the same source +** directory as this file for additional information. +*/ +#ifdef SQLITE_USER_AUTHENTICATION +#ifndef _SQLITEINT_H_ +# include "sqliteInt.h" +#endif + +/* +** Prepare an SQL statement for use by the user authentication logic. +** Return a pointer to the prepared statement on success. Return a +** NULL pointer if there is an error of any kind. +*/ +static sqlite3_stmt *sqlite3UserAuthPrepare( + sqlite3 *db, + const char *zFormat, + ... +){ + sqlite3_stmt *pStmt; + char *zSql; + int rc; + va_list ap; + int savedFlags = db->flags; + + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( zSql==0 ) return 0; + db->flags |= SQLITE_WriteSchema; + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + db->flags = savedFlags; + sqlite3_free(zSql); + if( rc ){ + sqlite3_finalize(pStmt); + pStmt = 0; + } + return pStmt; +} + +/* +** Check to see if the sqlite_user table exists in database zDb. +*/ +static int userTableExists(sqlite3 *db, const char *zDb){ + int rc; + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + if( db->init.busy==0 ){ + char *zErr = 0; + sqlite3Init(db, &zErr); + sqlite3DbFree(db, zErr); + } + rc = sqlite3FindTable(db, "sqlite_user", zDb)!=0; + sqlite3BtreeLeaveAll(db); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** Check to see if database zDb has a "sqlite_user" table and if it does +** whether that table can authenticate zUser with nPw,zPw. Write one of +** the UAUTH_* user authorization level codes into *peAuth and return a +** result code. +*/ +static int userAuthCheckLogin( + sqlite3 *db, /* The database connection to check */ + const char *zDb, /* Name of specific database to check */ + u8 *peAuth /* OUT: One of UAUTH_* constants */ +){ + sqlite3_stmt *pStmt; + int rc; + + *peAuth = UAUTH_Unknown; + if( !userTableExists(db, "main") ){ + *peAuth = UAUTH_Admin; /* No sqlite_user table. Everybody is admin. */ + return SQLITE_OK; + } + if( db->auth.zAuthUser==0 ){ + *peAuth = UAUTH_Fail; + return SQLITE_OK; + } + pStmt = sqlite3UserAuthPrepare(db, + "SELECT pw=sqlite_crypt(?1,pw), isAdmin FROM \"%w\".sqlite_user" + " WHERE uname=?2", zDb); + if( pStmt==0 ) return SQLITE_NOMEM; + sqlite3_bind_blob(pStmt, 1, db->auth.zAuthPW, db->auth.nAuthPW,SQLITE_STATIC); + sqlite3_bind_text(pStmt, 2, db->auth.zAuthUser, -1, SQLITE_STATIC); + rc = sqlite3_step(pStmt); + if( rc==SQLITE_ROW && sqlite3_column_int(pStmt,0) ){ + *peAuth = sqlite3_column_int(pStmt, 1) + UAUTH_User; + }else{ + *peAuth = UAUTH_Fail; + } + return sqlite3_finalize(pStmt); +} +int sqlite3UserAuthCheckLogin( + sqlite3 *db, /* The database connection to check */ + const char *zDb, /* Name of specific database to check */ + u8 *peAuth /* OUT: One of UAUTH_* constants */ +){ + int rc; + u8 savedAuthLevel; + assert( zDb!=0 ); + assert( peAuth!=0 ); + savedAuthLevel = db->auth.authLevel; + db->auth.authLevel = UAUTH_Admin; + rc = userAuthCheckLogin(db, zDb, peAuth); + db->auth.authLevel = savedAuthLevel; + return rc; +} + +/* +** If the current authLevel is UAUTH_Unknown, the take actions to figure +** out what authLevel should be +*/ +void sqlite3UserAuthInit(sqlite3 *db){ + if( db->auth.authLevel==UAUTH_Unknown ){ + u8 authLevel = UAUTH_Fail; + sqlite3UserAuthCheckLogin(db, "main", &authLevel); + db->auth.authLevel = authLevel; + if( authLevelflags &= ~SQLITE_WriteSchema; + } +} + +/* +** Implementation of the sqlite_crypt(X,Y) function. +** +** If Y is NULL then generate a new hash for password X and return that +** hash. If Y is not null, then generate a hash for password X using the +** same salt as the previous hash Y and return the new hash. +*/ +void sqlite3CryptFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + const char *zIn; + int nIn, ii; + u8 *zOut; + char zSalt[8]; + zIn = sqlite3_value_blob(argv[0]); + nIn = sqlite3_value_bytes(argv[0]); + if( sqlite3_value_type(argv[1])==SQLITE_BLOB + && sqlite3_value_bytes(argv[1])==nIn+sizeof(zSalt) + ){ + memcpy(zSalt, sqlite3_value_blob(argv[1]), sizeof(zSalt)); + }else{ + sqlite3_randomness(sizeof(zSalt), zSalt); + } + zOut = sqlite3_malloc( nIn+sizeof(zSalt) ); + if( zOut==0 ){ + sqlite3_result_error_nomem(context); + }else{ + memcpy(zOut, zSalt, sizeof(zSalt)); + for(ii=0; iiauth.authLevel = UAUTH_Unknown; + sqlite3_free(db->auth.zAuthUser); + sqlite3_free(db->auth.zAuthPW); + memset(&db->auth, 0, sizeof(db->auth)); + db->auth.zAuthUser = sqlite3_mprintf("%s", zUsername); + if( db->auth.zAuthUser==0 ) return SQLITE_NOMEM; + db->auth.zAuthPW = sqlite3_malloc( nPW+1 ); + if( db->auth.zAuthPW==0 ) return SQLITE_NOMEM; + memcpy(db->auth.zAuthPW,zPW,nPW); + db->auth.nAuthPW = nPW; + rc = sqlite3UserAuthCheckLogin(db, "main", &authLevel); + db->auth.authLevel = authLevel; + sqlite3ExpirePreparedStatements(db); + if( rc ){ + return rc; /* OOM error, I/O error, etc. */ + } + if( authLevelauth.authLevelauth.zAuthUser==0 ){ + assert( isAdmin!=0 ); + sqlite3_user_authenticate(db, zUsername, aPW, nPW); + } + return SQLITE_OK; +} + +/* +** The sqlite3_user_change() interface can be used to change a users +** login credentials or admin privilege. Any user can change their own +** login credentials. Only an admin user can change another users login +** credentials or admin privilege setting. No user may change their own +** admin privilege setting. +*/ +int sqlite3_user_change( + sqlite3 *db, /* Database connection */ + const char *zUsername, /* Username to change */ + const char *aPW, /* Modified password or credentials */ + int nPW, /* Number of bytes in aPW[] */ + int isAdmin /* Modified admin privilege for the user */ +){ + sqlite3_stmt *pStmt; + int rc; + u8 authLevel; + + authLevel = db->auth.authLevel; + if( authLevelauth.zAuthUser, zUsername)!=0 ){ + if( db->auth.authLevelauth.authLevel = UAUTH_Admin; + if( !userTableExists(db, "main") ){ + /* This routine is a no-op if the user to be modified does not exist */ + }else{ + pStmt = sqlite3UserAuthPrepare(db, + "UPDATE sqlite_user SET isAdmin=%d, pw=sqlite_crypt(?1,NULL)" + " WHERE uname=%Q", isAdmin, zUsername); + if( pStmt==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_bind_blob(pStmt, 1, aPW, nPW, SQLITE_STATIC); + sqlite3_step(pStmt); + rc = sqlite3_finalize(pStmt); + } + } + db->auth.authLevel = authLevel; + return rc; +} + +/* +** The sqlite3_user_delete() interface can be used (by an admin user only) +** to delete a user. The currently logged-in user cannot be deleted, +** which guarantees that there is always an admin user and hence that +** the database cannot be converted into a no-authentication-required +** database. +*/ +int sqlite3_user_delete( + sqlite3 *db, /* Database connection */ + const char *zUsername /* Username to remove */ +){ + sqlite3_stmt *pStmt; + if( db->auth.authLevelauth.zAuthUser, zUsername)==0 ){ + /* Cannot delete self */ + return SQLITE_AUTH; + } + if( !userTableExists(db, "main") ){ + /* This routine is a no-op if the user to be deleted does not exist */ + return SQLITE_OK; + } + pStmt = sqlite3UserAuthPrepare(db, + "DELETE FROM sqlite_user WHERE uname=%Q", zUsername); + if( pStmt==0 ) return SQLITE_NOMEM; + sqlite3_step(pStmt); + return sqlite3_finalize(pStmt); +} + +#endif /* SQLITE_USER_AUTHENTICATION */ diff --git a/main.mk b/main.mk index 718cf5c..429945b 100644 --- a/main.mk +++ b/main.mk @@ -46,7 +46,7 @@ # TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP) TCCX += -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3 -TCCX += -I$(TOP)/ext/async +TCCX += -I$(TOP)/ext/async -I$(TOP)/ext/userauth # Object files for the SQLite library. # @@ -66,8 +66,8 @@ LIBOBJ+= vdbe.o parse.o \ notify.o opcodes.o os.o os_unix.o os_win.o \ pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \ random.o resolve.o rowset.o rtree.o select.o status.o \ - table.o tokenize.o trigger.o \ - update.o util.o vacuum.o \ + table.o threads.o tokenize.o trigger.o \ + update.o userauth.o util.o vacuum.o \ vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \ vdbetrace.o wal.o walker.o where.o utf.o vtab.o @@ -112,6 +112,7 @@ SRC = \ $(TOP)/src/mem3.c \ $(TOP)/src/mem5.c \ $(TOP)/src/memjournal.c \ + $(TOP)/src/msvc.h \ $(TOP)/src/mutex.c \ $(TOP)/src/mutex.h \ $(TOP)/src/mutex_noop.c \ @@ -146,6 +147,7 @@ SRC = \ $(TOP)/src/sqliteLimit.h \ $(TOP)/src/table.c \ $(TOP)/src/tclsqlite.c \ + $(TOP)/src/threads.c \ $(TOP)/src/tokenize.c \ $(TOP)/src/trigger.c \ $(TOP)/src/utf.c \ @@ -213,7 +215,9 @@ SRC += \ $(TOP)/ext/rtree/sqlite3rtree.h \ $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/rtree.c - +SRC += \ + $(TOP)/ext/userauth/userauth.c \ + $(TOP)/ext/userauth/sqlite3userauth.h # Generated source code files # @@ -243,6 +247,7 @@ TESTSRC = \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ + $(TOP)/src/test_blob.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ @@ -277,6 +282,7 @@ TESTSRC = \ TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ + $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ @@ -315,6 +321,7 @@ TESTSRC2 = \ $(TOP)/src/pcache.c \ $(TOP)/src/pcache1.c \ $(TOP)/src/select.c \ + $(TOP)/src/threads.c \ $(TOP)/src/tokenize.c \ $(TOP)/src/utf.c \ $(TOP)/src/util.c \ @@ -339,6 +346,7 @@ HDR = \ $(TOP)/src/hash.h \ $(TOP)/src/hwtime.h \ keywordhash.h \ + $(TOP)/src/msvc.h \ $(TOP)/src/mutex.h \ opcodes.h \ $(TOP)/src/os.h \ @@ -375,6 +383,8 @@ EXTHDR += \ $(TOP)/ext/rtree/rtree.h EXTHDR += \ $(TOP)/ext/icu/sqliteicu.h +EXTHDR += \ + $(TOP)/ext/userauth/sqlite3userauth.h # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. @@ -556,6 +566,9 @@ fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c +userauth.o: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR) + $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c + # Rules for building test programs and for running tests # @@ -614,9 +627,15 @@ test: testfixture$(EXE) sqlite3$(EXE) # threadtest runs a few thread-safety tests that are implemented in C. This # target is invoked by the releasetest.tcl script. # -threadtest3$(EXE): sqlite3.o $(TOP)/test/threadtest3.c $(TOP)/test/tt3_checkpoint.c - $(TCCX) -O2 sqlite3.o $(TOP)/test/threadtest3.c \ - -o threadtest3$(EXE) $(THREADLIB) +THREADTEST3_SRC = $(TOP)/test/threadtest3.c \ + $(TOP)/test/tt3_checkpoint.c \ + $(TOP)/test/tt3_index.c \ + $(TOP)/test/tt3_vacuum.c \ + $(TOP)/test/tt3_stress.c \ + $(TOP)/test/tt3_lookaside1.c + +threadtest3$(EXE): sqlite3.o $(THREADTEST3_SRC) + $(TCCX) $(TOP)/test/threadtest3.c sqlite3.o -o $@ $(THREADLIB) threadtest: threadtest3$(EXE) ./threadtest3$(EXE) @@ -671,7 +690,7 @@ checksymbols: sqlite3.o # Build the amalgamation-autoconf package. # -dist: sqlite3.c +amalgamation-tarball: sqlite3.c TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh diff --git a/manifest b/manifest index 28b547a..828d587 100644 --- a/manifest +++ b/manifest @@ -1,12 +1,12 @@ -C Version\s3.8.6 -D 2014-08-15T11:46:33.931 +C Version\s3.8.8.3 +D 2015-02-25T13:29:11.692 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 +F Makefile.in 5407a688f4d77a05c18a8142be8ae5a2829dd610 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc 5b04e657cf08a9ac7fc47d876c5c8be962c47d6b -F Makefile.vxworks 034289efa9d591b04b1a73598623119c306cbba0 -F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8 -F VERSION 1c877615a9db323e3cd301e3d57d853f9d5c4a07 +F Makefile.msc 4c057774e6138b9023fc16ec05639ddd3329b152 +F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858 +F README.md d58e3bebc0a4145e0f2a87994015fdb575a8e866 +F VERSION 0de46a30a2d0a7a6a686fd35186fbad0ac06ff71 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 @@ -15,7 +15,7 @@ F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2 F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903 F autoconf/Makefile.am 8fc2972d92769cf20ab8e4a73ea901b84d69bf44 F autoconf/README 14458f1046c118efa721aadec5f227e876d3cd38 -F autoconf/README.first 47dd53221023b18c836ab00dba6e00bd86132453 +F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7 F autoconf/config.guess 94cc57e2a3fdb9c235b362ace86d77e89d188cad x F autoconf/config.sub 1efb390a8fb4bfafd74783a15a8fb5311c84300e x F autoconf/configure.ac ba3e99ba1a8171d0682b68443517088fc5d6f13a @@ -23,23 +23,23 @@ F autoconf/depcomp 0b26f101e3bc9fd1ff0be1da9fb4a82371142f92 x F autoconf/install-sh 06ee6336e63bb845c8439d777c32eb2eccc4fbf1 x F autoconf/ltmain.sh 7a658a24028f02331c1d2446562758083c5eadd1 F autoconf/missing d7c9981a81af13370d4ed152b24c0a82b7028585 x -F autoconf/tea/Makefile.in 5c3b0bdfb66c20d55ebff59d1718864461570ca9 +F autoconf/tea/Makefile.in d55bcc63832caf0309c2ff80358756116618cfca F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873 F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43 -F autoconf/tea/configure.in e0466b881b53f31f5a4a69e7a91ad130902fb359 +F autoconf/tea/configure.ac 93d43c79e936fb16556e22498177d7e8571efa04 F autoconf/tea/doc/sqlite3.n e1fe45d4f5286ee3d0ccc877aca2a0def488e9bb F autoconf/tea/license.terms 13bd403c9610fd2b76ece0ab50c4c5eda933d523 F autoconf/tea/pkgIndex.tcl.in 3ef61715cf1c7bdcff56947ffadb26bc991ca39d F autoconf/tea/tclconfig/install-sh bdd5e293591621ae60d9824d86a4b1c5f22c3d00 -F autoconf/tea/tclconfig/tcl.m4 f035b86539a5ab30689e997a11ae9e7fd2e65570 +F autoconf/tea/tclconfig/tcl.m4 66ddf0a5d5e4b1d29bff472c0985fd7fa89d0fb5 F autoconf/tea/win/makefile.vc f89d0184d0eee5f7e356ea407964dcd139939928 F autoconf/tea/win/nmakehlp.c 2070e086f39866b353a482d3a14dedaf26196506 F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 -F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de +F config.h.in 42b71ad3fe21c9e88fa59e8458ca1a6bc72eb0c0 F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 -F configure 513f1e2464c3673bcdb5471b13d98e7eeb6f5ca2 x -F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a +F configure 444b4cd66ec94631b2b624cf24d01142c9aac0ae x +F configure.ac 6a8d145aea6d81f0b90013340780e43ed74fd5f4 F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1 F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710 @@ -78,25 +78,25 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 2f5e925bdb9d6d3e488c5a981af60cad4f9cdfe7 +F ext/fts3/fts3.c 845f20440dacac6e09f5c7735205609b9a86536b F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h 53d4eca1fb23eab00681fb028fb82eb5705c1e21 +F ext/fts3/fts3Int.h 394858c12a17740f7a1f6bd372c4606d4425a8d1 F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365 -F ext/fts3/fts3_expr.c 351395fad6fcb16ecfc61db0861008a70101330c +F ext/fts3/fts3_expr.c 40123785eaa3ebd4c45c9b23407cc44ac0c49905 F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60 F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5 -F ext/fts3/fts3_porter.c 7f8b4bf5af7c0f20f73b8e87e14fa9298f52e290 -F ext/fts3/fts3_snippet.c 51beb5c1498176fd9caccaf1c75b55cb803a985a +F ext/fts3/fts3_porter.c 3565faf04b626cddf85f03825e86056a4562c009 +F ext/fts3/fts3_snippet.c 55c126e07158b2a705f52dee2cdc57208d3e999a F ext/fts3/fts3_term.c a521f75132f9a495bdca1bdd45949b3191c52763 F ext/fts3/fts3_test.c 8a3a78c4458b2d7c631fcf4b152a5cd656fa7038 -F ext/fts3/fts3_tokenize_vtab.c 011170fe9eba5ff062f1a31d3188e00267716706 +F ext/fts3/fts3_tokenize_vtab.c becc661223db7898b213f9e8a23d75bac02408c9 F ext/fts3/fts3_tokenizer.c bbdc731bc91338050675c6d1da9ab82147391e16 F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3 F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004 F ext/fts3/fts3_unicode.c a93f5edc0aff44ef8b06d7cb55b52026541ca145 F ext/fts3/fts3_unicode2.c c3d01968d497bd7001e7dc774ba75b372738c057 -F ext/fts3/fts3_write.c 8260388626516a7005d06a9dce94f9e55c6c2a41 +F ext/fts3/fts3_write.c 9b3a32cbecf40a1f41cb08c00df8c066c23c7a25 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/fts3/tool/fts3view.c 3986531f2fc0ceca0c89c31ec7d0589b6adb19d6 @@ -106,30 +106,32 @@ F ext/fts3/unicode/mkunicode.tcl a2567f9d6ad6779879a2e394c120ad8718557e65 F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 F ext/icu/icu.c d415ccf984defeb9df2c0e1afcfaa2f6dc05eacb F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 -F ext/misc/amatch.c 678056a4bfcd83c4e82dea81d37543cd1d6dbee1 +F ext/misc/amatch.c 17ba78dc9b33601a40d2a7bc54c748b6f3eb7176 F ext/misc/closure.c 636024302cde41b2bf0c542f81c40c624cfb7012 F ext/misc/compress.c 76e45655f4046e756064ab10c62e18f2eb846b9f +F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2 F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f -F ext/misc/fuzzer.c 136533c53cfce0957f0b48fa11dba27e21c5c01d +F ext/misc/fuzzer.c e3e18f47252c151b5553d7e806f38e757d37c4cc F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342 F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63 F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a -F ext/misc/spellfix.c cb016c2dab951ffd7b819a7bc8a750ebd6c26c0f +F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52 +F ext/misc/spellfix.c 25810dda37fc904b0772a13efd8ca072fb09e355 F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512 F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95 F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/rtree.c 57bec53e1a677ab74217fe1f20a58c3a47261d6b +F ext/rtree/rtree.c 14e6239434d4e3f65d3e90320713f26aa24e167f F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e F ext/rtree/rtree1.test 541bbcab74613907fea08b2ecdcdd5b7aa724cc9 F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0 F ext/rtree/rtree5.test 6a510494f12454bf57ef28f45bc7764ea279431e -F ext/rtree/rtree6.test 0cfbdf27ee086bf16a3da2c6f2d5b3d6473cb27e +F ext/rtree/rtree6.test 773a90db2dce6a8353dd0d5b64bca69b29761196 F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971 F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a F ext/rtree/rtree9.test d86ebf08ff6328895613ed577dd8a2a37c472c34 @@ -138,15 +140,19 @@ F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e F ext/rtree/rtreeC.test df158dcc81f1a43ce7eef361af03c48ec91f1e06 F ext/rtree/rtreeD.test 636630357638f5983701550b37f0f5867130d2ca F ext/rtree/rtreeE.test 388c1c8602c3ce55c15f03b509e9cf545fb7c41f +F ext/rtree/rtreeF.test 66deb9fd1611c7ca2e374adba63debdc2dbb12b4 F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195 F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea F ext/rtree/sqlite3rtree.h 83349d519fe5f518b3ea025d18dd1fe51b1684bd F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 +F ext/userauth/sqlite3userauth.h 19cb6f0e31316d0ee4afdfb7a85ef9da3333a220 +F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04 +F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 036a65c9042b2f5013baf85c82629d700fe031c4 +F main.mk e392561ffe17fc4dad945eef852400d5bf2911a0 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -154,119 +160,121 @@ F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 F mptest/crash01.test cce8e306d8596d5a2e497e27112dae1f6e5e3538 F mptest/crash02.subtest f4ef05adcd15d60e5d2bd654204f2c008b519df8 -F mptest/mptest.c 499a74af4be293b7c1c7c3d40f332b67227dd739 +F mptest/mptest.c 24c5f72415df2eab7088ef8c9f99f163aed590c8 F mptest/multiwrite01.test 499ad0310da8dff8e8f98d2e272fc2a8aa741b2e F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b -F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494 +F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1 -F src/analyze.c f98a351908da29f7b44741cfeb9eb20dda648ba0 -F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52 -F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 -F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53 +F src/alter.c ba266a779bc7ce10e52e59e7d3dc79fa342e8fdb +F src/analyze.c 91540f835163d5369ccbae78e2e6c74d0dd53c1d +F src/attach.c 7f6b3fafa2290b407e4a94dcf1afda7ec0fe394b +F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 +F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb -F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c fa057e30794bfd867963b44a3a42710a45c335a1 -F src/btree.h 4245a349bfe09611d7ff887dbc3a80cee8b7955a -F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3 -F src/build.c 5abf794fe8a605f2005b422e98a3cedad9b9ef5b -F src/callback.c fcff28cf0df2403dd2f313bb8d1b8f31f6f3cd64 -F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac -F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a -F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 -F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c f749009cf4a8534efb5e0d5cd7c9fb1fb0f2836c +F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 +F src/btree.c 4c098bb6e8678e4596983862abf78f7a0fcb807e +F src/btree.h 94277c1d30c0b75705974bcc8b0c05e79c03d474 +F src/btreeInt.h a3d0ae1d511365e1a2b76ad10960dbe55c286f34 +F src/build.c f5cfd7b32216f695b995bbc7c1a395f6d451d11f +F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 +F src/complete.c 198a0066ba60ab06fc00fba1998d870a4d575463 +F src/ctime.c 98f89724adc891a1a4c655bee04e33e716e05887 +F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac +F src/delete.c bd1a91ddd247ce13004075251e0b7fe2bf9925ef +F src/expr.c 7be80f7dc337329a24df45c2f3bdb2ea3b64c90e F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb -F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 -F src/func.c bbb724b74ed96ca42675a7274646a71dd52bcda7 -F src/global.c 1e4bd956dc2f608f87d2a929abc4a20db65f30e4 -F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd -F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 +F src/fkey.c e0444b61bed271a76840cbe6182df93a9baa3f12 +F src/func.c 6d3c4ebd72aa7923ce9b110a7dc15f9b8c548430 +F src/global.c 12561d70a1b25f67b21154622bb1723426724f75 +F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 +F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c 991e4964e9295da3993e2c0f81c7faf642371848 +F src/insert.c 5b9243a33726008cc4132897d2be371db12a13be F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d -F src/legacy.c febc2a9e7ad6c1a6191c7b5b9170b325d263f343 -F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b -F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303 -F src/main.c 1cf92c5c6468f2b6ed99b638706781ccc9c60b42 -F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be +F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e +F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 +F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660 +F src/main.c 341fcc5601a8ca84389fa32bcf5a857f65af8dd0 +F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 -F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b -F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f +F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987 +F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3 F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534 -F src/mem5.c 74670012946c4adc8a6ad84d03acc80959c3e529 -F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785 -F src/mutex.c 84a073c9a23a8d7bdd2ea832522d1730df18812c -F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea +F src/mem5.c 61eeb90134f9a5be6c2e68d8daae7628b25953fb +F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85 +F src/msvc.h e78002098966e39b2fd9915bd70b7bc3ec8398b7 +F src/mutex.c 19bf9acba69ca2f367c3761080f8a9f0cf4670a8 +F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85 F src/mutex_noop.c f3f09fd7a2eb4287cfc799753ffc30380e7b71a1 -F src/mutex_unix.c 1b10d5413dfc794364a8adf3eb3a192926b43fa3 -F src/mutex_w32.c c50939b72368f1cfbddb58520372081a50558548 -F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 -F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace -F src/os.h 60d419395e32a8029fa380a80a3da2e9030f635e +F src/mutex_unix.c 551e2f25f0fa0ee8fd7a43f50fc3d8be00e95dde +F src/mutex_w32.c df48fe07562a45c5c927c45b8d5873a27f98bbb0 +F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7 +F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8 +F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa -F src/os_unix.c bd7df3094a60915c148517504c76df4fca24e542 -F src/os_win.c 1c936c7b0659d0eb12b868e2cd710a570e78873e -F src/os_win.h 057344a6720b4c8405d9bd98f58cb37a6ee46c25 -F src/pager.c f6bb1fa6cdf2062f2d8aec3e64db302bca519ab8 -F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 -F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0 -F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2 -F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 -F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c -F src/pragma.c d10ef67c4de79f78188b965b4b7988aff1d66f2e -F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337 -F src/printf.c af06f66927919730f03479fed6ae9854f73419f4 -F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece -F src/resolve.c 0ea356d32a5e884add23d1b9b4e8736681dd5697 -F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be -F src/select.c ea48e891406ccdf748f3eb02893e056d134a0fea -F src/shell.c 75bb7bd2c80bb44861598f322a417c4bafe98fd7 -F src/sqlite.h.in ed9d35990c61f0388ca6405706455c4095310553 +F src/os_unix.c aefeaf915aaef9f81aa2645e0d5d06fa1bd83beb +F src/os_win.c 91d3d08e33ec0258d180d4c8255492f47d15e007 +F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 +F src/pager.c 4120a49ecd37697e28f5ed807f470b9c0b88410c +F src/pager.h c3476e7c89cdf1c6914e50a11f3714e30b4e0a77 +F src/parse.y c5d0d964f9ac023e8154cad512e54b0b6058e086 +F src/pcache.c d210cf90d04365a74f85d21374dded65af67b0cb +F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 +F src/pcache1.c 1e77432b40b7d3288327d9cdf399dcdfd2b6d3bf +F src/pragma.c ba149bbbc90783f84815636c509ced8eac11bbcf +F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9 +F src/printf.c ea82bcb1b83273b4c67177c233c1f78c81fc42f9 +F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 +F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada +F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e +F src/select.c a4e8fda24c8eab2682a058bdda0d5d68cfe3919c +F src/shell.c ee1a80bf2b0e9e0c2b93db8f0f82b841289b2641 +F src/sqlite.h.in 9dfc99d6533d36d6a549c4f3f01cacc8be956ada F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad -F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 641f8fbb65ca2084c8df95b525f6f82c7a1e91ae +F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d +F src/sqliteInt.h eaf210295b551d4e40e622aec1b2261c0b28f844 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d -F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 -F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e -F src/tclsqlite.c e87c99e28a145943666b51b212dacae35fcea0bd -F src/test1.c 14409a611e9c27c6c522c610bbff5561f05c1558 -F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 +F src/status.c 81712116e826b0089bb221b018929536b2b5406f +F src/table.c e7a09215315a978057fb42c640f890160dbcc45e +F src/tclsqlite.c 0bbb44543175ef2033d39780a233f98bf354eff9 +F src/test1.c 093d8b5b54b829dcfebae3181d4406edcc935d90 +F src/test2.c 577961fe48961b2f2e5c8b56ee50c3f459d3359d F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df F src/test5.c 5a34feec76d9b3a86aab30fd4f6cc9c48cbab4c1 F src/test6.c 41cacf3b0dd180823919bf9e1fbab287c9266723 F src/test7.c 72b732baa5642f795655ba1126ea032af46ecfd2 -F src/test8.c 54ccd7b1df5062f0ecbf50a8f7b618f8b1f13b20 +F src/test8.c df8dd4c99c1dd2225cb2a6f334299cddc5dcf1f1 F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60 F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8 F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12 F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e +F src/test_blob.c 1f2e3e25255b731c4fcf15ee7990d06347cb6c09 F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f -F src/test_config.c 42fb068a038c8684741522f551325228b1389e63 +F src/test_config.c e7b2e1634324d746aa5e1c7e0929470e8be27953 F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f -F src/test_func.c d3013ce36f19ac72a99c73864930fd1fa41832f8 +F src/test_func.c 14e543ae4d905ee31dc322b2f8d31bfac1769d45 F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd F src/test_init.c 66b33120ffe9cd853b5a905ec850d51151337b32 -F src/test_intarray.c 87847c71c3c36889c0bcc9c4baf9d31881665d61 -F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d -F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64 +F src/test_intarray.c 6c610a21ab8edde85a3a2c7f2b069244ecf4d834 +F src/test_intarray.h 9dc57417fb65bc7835cc18548852cc08cc062202 +F src/test_journal.c 5360fbe1d1e4416ca36290562fd5a2e3f70f32aa F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4 -F src/test_malloc.c 1ff5b1243d96124c9a180f3b89424820a1f337f3 -F src/test_multiplex.c ca90057438b63bf0840ebb84d0ef050624519a76 +F src/test_malloc.c b9495384e74923aefde8311de974bf9b0f5ba570 +F src/test_multiplex.c 72c0ad1e97af3d6d19975bbd81813072b40c7290 F src/test_multiplex.h c08e4e8f8651f0c5e0509b138ff4d5b43ed1f5d3 F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f F src/test_onefile.c 0396f220561f3b4eedc450cef26d40c593c69a25 F src/test_osinst.c 3d0340bc31a9f3d8a3547e0272373e80f78dde25 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c 65f6348fec0f2b3020c907247fb47556b214abb9 +F src/test_quota.c 180813f43683be5725458fc1ff13ac455d8e722d F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d F src/test_rtree.c fdd8d29ca5165c7857987a2ba263fac5c69e231f -F src/test_schema.c cd12a2223c3a394f4d07bb93bdf6d344c5c121b6 +F src/test_schema.c 2bdba21b82f601da69793e1f1d11bf481a79b091 F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e F src/test_stat.c 9898687a6c2beca733b0dd6fe19163d987826d31 @@ -274,39 +282,40 @@ F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd F src/test_syscall.c 2e21ca7f7dc54a028f1967b63f1e76155c356f9b F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb -F src/test_vfs.c f84075a388527892ff184988f43b69ce69b8083c +F src/test_vfs.c 8ee7be45fe773a150b4015ef957da960179ee43a F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 -F src/tokenize.c ae45399d6252b4d736af43bee1576ce7bff86aec -F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb -F src/update.c ea336ce7b8b3fc5e316ba8f082e6445babf81059 -F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05 -F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e -F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c f7f4066e4d6e3858878d76ce9288ea603e12ddf6 -F src/vdbe.h c63fad052c9e7388d551e556e119c0bcf6bebdf8 -F src/vdbeInt.h f5513f2b5ac1e2c5128996c7ea23add256a301df -F src/vdbeapi.c 24e40422382beb774daab11fe9fe9d37e8a04949 -F src/vdbeaux.c 25d62ef82cf1be2a1255eacac636fa0d943d8b3d -F src/vdbeblob.c 9205ce9d3b064d9600f8418a897fc88b5687d9ac -F src/vdbemem.c d90a1e8acf8b63dc9d14cbbea12bfec6cec31394 -F src/vdbesort.c f7f5563bf7d4695ca8f3203f3bf9de96d04ed0b3 -F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 -F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd -F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a +F src/threads.c 2fb3ea4d70d5acf68b539c2489b4adace61cc01b +F src/tokenize.c e00458c9938072b0ea711c850b8dcf4ddcb5fe18 +F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f +F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 +F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c +F src/util.c 98a7627ca48ad3265b6940915a1d08355eb3fc7e +F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c +F src/vdbe.c ddfc977981cd6324668aa6b114045eb1c677421a +F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 +F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 +F src/vdbeapi.c 4bc511a46b9839392ae0e90844a71dc96d9dbd71 +F src/vdbeaux.c f06d38c71d7f533348c09869d69fd1b647042a5b +F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778 +F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f +F src/vdbesort.c 6d64c5448b64851b99931ede980addc3af70d5e2 +F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 +F src/vtab.c c08ec66f45919eaa726bf88aa53eb08379d607f9 +F src/wal.c 39303f2c9db02a4e422cd8eb2c8760420c6a51fe F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 -F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45 -F src/where.c ab20f9c24a422ee8900831b343c3d1e5e7aca87b -F src/whereInt.h 923820bee9726033a501a08d2fc69b9c1ee4feb3 +F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 +F src/where.c 88509f19a64a36e1c22a1dbdac74ee1a62d99dc3 +F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 -F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 +F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783 F test/alter.test 547dc2d292644301ac9a7dda22b319b74f9c08d2 F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060 F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d -F test/alter4.test d6c011fa0d6227abba762498cafbb607c9609e93 +F test/alter4.test c461150723ac957f3b2214aa0b11552cd72023ec F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4 @@ -315,11 +324,13 @@ F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213 F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4 F test/analyze6.test f1c552ce39cca4ec922a7e4e0e5d0203d6b3281f F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f -F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88 -F test/analyze9.test 3ef1b471247308e710a794b6e50a6ab536c5604b -F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944 +F test/analyze8.test c05a461d0a6b05991106467d0c47480f2e709c82 +F test/analyze9.test 72795c8113604b5dcd47a1498a61d6d7fb5d041a +F test/analyzeA.test 3335697f6700c7052295cfd0067fc5b2aacddf9a F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93 +F test/analyzeD.test 08f9d0bee4e118a66fff3a32d02dbe0ee0a2b594 +F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7 @@ -331,20 +342,22 @@ F test/attach2.test 0ec5defa340363de6cd50fd595046465e9aaba2d F test/attach3.test 359eb65d00102cdfcef6fa4e81dc1648f8f80b27 F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0 -F test/auth.test 5bdf154eb28c0e4bbc0473f335858c0d96171768 -F test/auth2.test c3b415b76c033bedb81292118fb7c01f5f10cbcd -F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 +F test/auth.test 855233ef26eb3601b6886567ea4e326c72959360 +F test/auth2.test 264c6af53cad9aba5218c68bbe18036e39007bfa +F test/auth3.test 5cfa94ed90c6617c42b7ba4b133fd79678b251c7 F test/autoinc.test c58912526998a39e11f66b533e23cfabea7f25b7 -F test/autoindex1.test 762ff3f8e25d852aae55c6462ca166a80c0cde61 -F test/autoindex2.test 60d2fc6f38364308ce73a9beb01b47ded38697de -F test/autoindex3.test 8254f689c3241081fad52b7bea18ba53e07e14a2 +F test/autoindex1.test 6ff78b94f43a59616c06c11c55b12935173506d7 +F test/autoindex2.test af7e595c6864cc6ef5fc38d5db579a3e34940cb8 +F test/autoindex3.test a3be0d1a53a7d2edff208a5e442312957047e972 +F test/autoindex4.test 49d3cd791a9baa16fb461d7ea3de80d019a819cf F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 F test/backcompat.test 19a1f337c68419b020a7481dd272a472c4ad8ef4 -F test/backup.test c9cdd23a495864b9edf75a9fa66f5cb7e10fcf62 +F test/backup.test b79299a536a4c6d919094786595b95be56d02014 F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf F test/backup4.test 2a2e4a64388090b152de753fd9e123f28f6a3bd4 +F test/backup5.test ee5da6d7fe5082f5b9b0bbfa31d016f52412a2e4 F test/backup_ioerr.test 4c3c7147cee85b024ecf6e150e090c32fdbb5135 F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450 F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f @@ -354,6 +367,7 @@ F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747 +F test/bigsort.test 8299fa9298f4f1e02fc7d2712e8b77d6cd60e5a2 F test/bind.test 3c7b320969000c441a70952b0b15938fbb66237c F test/bindxfer.test efecd12c580c14df5f4ad3b3e83c667744a4f7e0 F test/bitvec.test 75894a880520164d73b1305c1c3f96882615e142 @@ -366,14 +380,15 @@ F test/boundary3.tcl 23361e108a125dca9c4080c2feb884fe54d69243 F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45 F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983 F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b +F test/btree01.test e08b3613540145b353f20c81cb18ead54ff12e0f F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3 F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0 F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738 -F test/capi3.test 71bcf2fbd36a9732f617766dfd752552c8e491b5 +F test/capi3.test f0718f4f90d0efdc980119bfbdf1d7f1541ee5ef F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 -F test/capi3c.test a21869e4d50d5dbb7e566e328fc0bc7c2efa6a32 -F test/capi3d.test c84af0c49267f9c3fbf4c1c46aa647646023811e +F test/capi3c.test fdc0d67a2cb8e8fc400d5b7735e330161ea057a2 +F test/capi3d.test a82b6321c50a1cfc848e386fa2c851893606f68c F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 F test/check.test 5831ddb6f2c687782eaf2e1a07b6e17f24c4f763 @@ -390,7 +405,7 @@ F test/collate7.test 8ec29d98f3ee4ccebce6e16ce3863fb6b8c7b868 F test/collate8.test df26649cfcbddf109c04122b340301616d3a88f6 F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6 -F test/colmeta.test 087c42997754b8c648819832241daf724f813322 +F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1 F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b F test/conflict.test 841bcf7cabbfca39c577eb8411ea8601843b46a8 F test/conflict2.test 0d3af4fb534fa1bd020c79960bb56e4d52655f09 @@ -412,8 +427,8 @@ F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040 F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4 F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804 -F test/corruptH.test 88ed71a086e13591c917aac6de32750e7c7281cb -F test/corruptI.test 0afbba50bfae006094cc548b4605f521c1179502 +F test/corruptH.test 5dd4fa98c6c1ed33b178f9e8a48c4fdd3cfc9067 +F test/corruptI.test 221ad8b7f0a9ac6b80fc577e73b5ad8cdea31243 F test/cost.test 19d314526616ce4473eb4e4e450fcb94499ce318 F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5 F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62 @@ -432,7 +447,7 @@ F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47 F test/date.test 42973251b9429f2c41b77eb98a7b0b0ba2d3b2c0 F test/dbstatus.test 8de104bb5606f19537d23cd553b41349b5ab1204 F test/dbstatus2.test 10418e62b3db5dca070f0c3eef3ea13946f339c2 -F test/default.test 792c3c70836f1901e2a8cb34fa0880ed71e2c1a9 +F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d F test/delete.test a065b05d2ebf60fd16639c579a4adfb7c381c701 F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab @@ -440,9 +455,14 @@ F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240 F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2 F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e -F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77 +F test/distinct.test 175d49ee783febaf368192dfe7f5afbc68910230 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 -F test/e_createtable.test 181653f6f45e3adde73f8686600ce5ad7515466b +F test/e_blobbytes.test 9bea1d3e2b20f3010b04abba58f6ba172301f49f +F test/e_blobclose.test df756753f571bc30e42e3a6cba2807576e49e716 +F test/e_blobopen.test 234f960d90235a9b51ec3ca1e062e8541dd558d8 +F test/e_blobwrite.test 615b405f29feb2cfb5a1f03dab7933258294fa26 +F test/e_changes.test fd66105385153dbf21fdb35eb8ef6c3e1eade579 +F test/e_createtable.test c7e67b49e6cf92473c8fb30ab26143e9e2128cf7 F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412 F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306 @@ -454,32 +474,38 @@ F test/e_reindex.test 396b7b4f0a66863b4e95116a67d93b227193e589 F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6 F test/e_select.test 52692ff3849541e828ad4661fe3773a9b8711763 F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f +F test/e_totalchanges.test b12ee5809d3e63aeb83238dd501a7bca7fd72c10 F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52 -F test/e_uri.test a2c92d80093a7efdcfbb11093651cbea87097b6b +F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585 F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9 +F test/e_wal.test 0967f0b8f1dfda871dc7b9b5574198f1f4f7d69a +F test/e_walauto.test ca70cf75c07a6cb1874ced101dd426da76625649 +F test/e_walckpt.test 65e29b6631e51f210f83e4ff11571e647ba93608 +F test/e_walhook.test da3ea8b3483d1af72190337bda50155a91a4b664 F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473 F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40 F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020 F test/eqp.test 85873fa5816c48915c82c4e74cb5c35a5b48160f F test/errmsg.test f31592a594b44ee121371d25ddd5d63497bb3401 -F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3 +F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75 F test/exclusive2.test 32798111aae78a5deec980eee383213f189df308 F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30 -F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d +F test/expr.test c4b9bf0cc60b26862475e19999fbd2609ca8259c F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9 F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7 F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146 F test/fkey1.test e1d1fa84cde579185ea01358436839703e415a5b -F test/fkey2.test 32ca728bcb854feed72d1406ea375fe423eebff2 +F test/fkey2.test 1db212cda86b0d3ce72714001f7b6381c321341c F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49 F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d -F test/fkey5.test 8a1fde4e7721ae00b05b3178888833726ca2df8d +F test/fkey5.test 488601fbda8350619b3029487e56830447056fd2 F test/fkey6.test abb59f866c1b44926fd02d1fdd217d831fe04f48 -F test/fkey7.test e31d0e71a41c1d29349a16448d6c420e2c53a8fc +F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13 +F test/fkey8.test 8f08203458321e6c19a263829de4cfc936274ab0 F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749 F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c @@ -554,13 +580,13 @@ F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851 F test/fts3expr.test 3401d47b229c4504424caf362cc4ff704cad4162 F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a F test/fts3expr3.test 9e91b8edbcb197bf2e92161aa7696446d96dce5f -F test/fts3expr4.test 0713d94ab951ed88a8c3629a4889a48c55c4067c +F test/fts3expr4.test e1be1248566f43c252d4404d52914f1fc4bfa065 F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660 F test/fts3fault2.test 3198eef2804deea7cac8403e771d9cbcb752d887 F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641 F test/fts3join.test 53e66a0c21eb568580674a43b21c059acb26f499 F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6 -F test/fts3matchinfo.test ff423e73faab8fc6d7adeefedf74dd8e2b0b14e0 +F test/fts3matchinfo.test 58544fa4d254000fa4e7f494b0a832f7ba61d45e F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905 F test/fts3prefix.test b36d4f00b128a51e7b386cc013a874246d9d7dc1 F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce @@ -572,7 +598,7 @@ F test/fts3sort.test ed34c716a11cc2009a35210e84ad5f9c102362ca F test/fts3tok1.test c551043de056b0b1582a54e878991f57bad074bc F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d F test/fts3varint.test 752c08ed5d32c5d7dc211b056f4ed68a76b7e36e -F test/fts4aa.test 0c3152322c7f0b548cc942ad763eaba0da87ccca +F test/fts4aa.test 10aac8e9d62c7357590acfabe3fad01e9a9ce1cb F test/fts4check.test 74d77f6cdb768ac49df5afda575cef14ae3d239a F test/fts4content.test 2e7252557d6d24afa101d9ba1de710d6140e6d06 F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01 @@ -594,7 +620,7 @@ F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f F test/func5.test cdd224400bc3e48d891827cc913a57051a426fa4 F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74 F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1 -F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167 +F test/fuzz2.test b34fe575aa10292135421ff4bf315de4cde7824a F test/fuzz3.test efd384b896c647b61a2c1848ba70d42aad60a7b3 F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26 @@ -608,7 +634,7 @@ F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068 -F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3 +F test/in5.test 1de657472fa9ac2924be25c2c959ac5ca1aae554 F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328 F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600 F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4 @@ -623,9 +649,9 @@ F test/index.test 4d990005a67a36984e4f1a5f1bdccea8d08da4ee F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index3.test 55a90cff99834305e8141df7afaef39674b57062 F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 -F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33 -F test/index6.test fb370966ac3cd0989053dd5385757b5c3e24ab6a -F test/index7.test a3baf9a625bda7fd49471e99aeae04095fbfeecf +F test/index5.test 25b0b451aceed4ac5f7d49f856f6de7257470b3e +F test/index6.test c56852451b574ad5b2a1789e566e62e6ab244f42 +F test/index7.test 917cf1e1c7439bb155abbeabec511b28945e157b F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 @@ -640,7 +666,7 @@ F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc F test/intpkey.test 7506090fc08e028712a8bf47e5f54111947e3844 F test/io.test 3a7abcef18727cc0f2399e04b0e8903eccae50f8 F test/ioerr.test 2a24bd6ed5a8b062e64bfe1f6cf94fb25e92210d -F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d +F test/ioerr2.test 2593563599e2cc6b6b4fcf5878b177bdd5d8df26 F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 @@ -649,7 +675,7 @@ F test/join.test 52d4d49f86d0cf46926672878c4eaf0da399104a F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 -F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe +F test/join5.test 5df23eba184f159ed9705a954957e765a10c141d F test/join6.test cfe6503791ceb0cbb509966740286ec423cbf10b F test/journal1.test 69abc726c51b4a0409189f9a85191205297c0577 F test/journal2.test ae06f566c28552c313ded3fee79a6c69e6d049b1 @@ -669,14 +695,14 @@ F test/lock.test 87af515b0c4cf928576d0f89946d67d7c265dfb4 F test/lock2.test 5242d8ac4e2d59c403aebff606af449b455aceff F test/lock3.test f271375930711ae044080f4fe6d6eda930870d00 F test/lock4.test e175ae13865bc87680607563bafba21f31a26f12 -F test/lock5.test 5ad6a1f536036ff1be915cfdd41481aeafda3273 +F test/lock5.test c6c5e0ebcb21c61a572870cc86c0cb9f14cede38 F test/lock6.test ad5b387a3a8096afd3c68a55b9535056431b0cf5 F test/lock7.test 49f1eaff1cdc491cc5dee3669f3c671d9f172431 F test/lock_common.tcl 0c270b121d40959fa2f3add382200c27045b3d95 F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2 -F test/main.test 39c4bb8a157f57298ed1659d6df89d9f35aaf2c8 +F test/main.test 16131264ea0c2b93b95201f0c92958e85f2ba11a F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9 -F test/malloc.test 4eb83876dfe4915766c179b687b8640437f14abf +F test/malloc.test 96939d2d1a6f39667bbebe5bc27c6525f2ab614e F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a F test/malloc4.test 957337613002b7058a85116493a262f679f3a261 F test/malloc5.test fafce0aa9157060445cd1a56ad50fc79d82f28c3 @@ -684,7 +710,7 @@ F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151 F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d F test/malloc9.test 2307c6ee3703b0a21391f3ea92388b4b73f9105e -F test/mallocA.test 1ba0367fb5434e7bc2fa4afcb30b14174d91b160 +F test/mallocA.test 672cd7dedb63771bade3a6f557f851a4ad161d4a F test/mallocAll.test 98f1be74bc9f49a858bc4f361fc58e26486798be F test/mallocB.test bc475ab850cda896142ab935bbfbc74c24e51ed6 F test/mallocC.test 3dffe16532f109293ce1ccecd0c31dca55ef08c4 @@ -702,12 +728,12 @@ F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f F test/memdb.test fcb5297b321b562084fc79d64d5a12a1cd2b639b F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2 -F test/memsubsys1.test f97cfd0b30e85c2f1ed16d642e7ac58006be84b2 +F test/memsubsys1.test 690d142525a7d31efb638b0d232e25fac3afeb1a F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9 F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 -F test/minmax4.test 536a3360470633a177e42fbc19660d146b51daef +F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f F test/misc1.test 1201a037c24f982cc0e956cdaa34fcaf6439c417 F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d @@ -715,33 +741,37 @@ F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2 +F test/misc8.test fc2754d38892f7dac30c22db3616c2764f117d66 F test/misuse.test 3c34719944ba045cc6c188a4852ba04680728912 -F test/mmap1.test 93d167b328255cbe6679fe1e1a23be1b1197d07b +F test/mmap1.test 1bfd611b9841eafb44f7d83c0788e146d84a33c9 F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3 F test/multiplex.test efd015ca0b5b4a57dc9535b8feb1273eebeadb60 F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101 +F test/multiplex4.test d3e8a5a522c51cbf3ed1c5b0bd496be02c29d7b1 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41 F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660 F test/nan.test e9648b9d007c7045242af35e11a984d4b169443a F test/nolock.test 0540dd96f39b8876e3ffdd8814fad0ea425efeee F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf -F test/notify2.test ce23eb522c9e1fff6443f96376fe67872202061c +F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161 F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934 F test/notnull.test f8fcf58669ddba79274daa2770d61dfad8274f62 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 -F test/orderby1.test 12426f99518cde45f34215ca6a0ebc0e9bc5c77a +F test/orderby1.test eb246e377612b21a418fbea57047ba8ea88aaa6b F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04 F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99 F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4 F test/orderby5.test 8f08a54836d21fb7c70245360751aedd1c2286fb F test/orderby6.test 8b38138ab0972588240b3fca0985d2e400432859 F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da -F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3 +F test/orderby8.test 23ef1a5d72bd3adcc2f65561c654295d1b8047bd +F test/oserror.test 14fec2796c2b6fe431c7823750e8a18a761176d7 +F test/ovfl.test 4f7ca651cba5c059a12d8c67dddd49bec5747799 F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71 F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f @@ -753,12 +783,13 @@ F test/pageropt.test 6b8f6a123a5572c195ad4ae40f2987007923bbd6 F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 -F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54 -F test/permutations.test bc474bafb022cc5014ef3a9c3d5ab61d6d6f587c -F test/pragma.test 19d0241a007bcdd77fc2606ec60fc60357e7fc8b +F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff +F test/permutations.test f9cc1dd987986c9d4949211c7a4ed55ec9aecba1 +F test/pragma.test aa16dedfe01c02c8895169012f7dfde9c163f0d5 F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 +F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 -F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1 +F test/printf2.test b4acd4bf8734243257f01ddefa17c4fb090acc8a F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca @@ -772,21 +803,23 @@ F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df F test/rdonly.test dd30a4858d8e0fbad2304c2bd74a33d4df36412a F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 -F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a -F test/releasetest.tcl a0df0dfc5e3ee83ade87b9cc96db41b52d590b9e +F test/releasetest.tcl 13f401c10dd4fe1a2fb811ae6ed27fd7d1300d3c F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a -F test/rollback.test e9504a009a202c3ed711da2e6879ff60c5a4669c +F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea +F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14 +F test/rollbackfault.test 6a004f71087cc399296cffbb5429ea6da655ae65 F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 -F test/rowid.test b78b30afb9537a73788ca1233a23a32190a3bb1f +F test/rowid.test 742b5741584a8a44fd83e856cc2896688401d645 F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09 -F test/savepoint.test 6c53f76dffe5df0dd87646efe3e7aa159c36e07b +F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7 F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 -F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423 +F test/savepoint7.test db3db281486c925095f305aad09fe806e5188ff3 +F test/scanstatus.test 5253c219e331318a437f436268e0e82345700285 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 @@ -809,6 +842,7 @@ F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977 F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394 F test/selectE.test fc02a1eb04c8eb537091482644b7d778ae8759b7 F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3 +F test/selectG.test e8600e379589e85e9fefd2fe4d44a4cdd63f6982 F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118 F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746 F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879 @@ -819,23 +853,31 @@ F test/shared7.test a81e99f83e6c51b02ac99c96fb3a2a7b5978c956 F test/shared8.test 00a07bf5e1337ecf72e94542bdefdc330d7a2538 F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21 F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5 -F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa +F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e +F test/shared_err.test 2f2aee20db294b9924e81f6ccbe60f19e21e8506 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 -F test/shell1.test d60946b5fde4d85fe06db7331dfe89011f564350 -F test/shell2.test c57da3a381c099b02c813ba156298d5c2f5c93a3 +F test/shell1.test cdeb849acc2c37aada70d084564b0cc0a2c7df08 +F test/shell2.test 12b8bf901b0e3a8ac58cf5c0c63a0a388d4d1862 F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29 F test/shell4.test 8a9c08976291e6c6c808b4d718f4a8b299f339f5 -F test/shell5.test 15a419cc1df21c892ed64f5596ae7a501f2816f2 +F test/shell5.test 81aba4793fa7441b1300daae1aec4f7e4b5741c1 F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5 F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868 F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 -F test/skipscan1.test 28c7faa41a0d7265040ecb0a0abd90c0904270b2 +F test/skipscan1.test 2ddfe5d168462170c4487f534e2a99fb006b2076 F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a -F test/skipscan5.test d8b9692b702745a0e41c23f9da6beac81df01196 +F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5 +F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2 +F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24 -F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5 +F test/sort.test 3f492e5b7be1d3f756728d2ff6edf4f6091e84cb +F test/sort2.test 37afbc03f5559f2eb0f18940b55d38dfbb5172ac +F test/sort3.test 6178ade30810ac9166fcdf14b7065e49c0f534e2 +F test/sort4.test d5e8903194ae551551349ce25dc8d0b40ca2b9c3 +F test/sort5.test a448240a42b49239edc00f85d6d7ac7a1b261e1f +F test/sortfault.test d4ccf606a0c77498e2beb542764fd9394acb4d66 F test/speed1.test f2974a91d79f58507ada01864c0e323093065452 F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb F test/speed1p.test b180e98609c7677382cf618c0ec9b69f789033a8 @@ -844,27 +886,27 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523 F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715 F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b -F test/speedtest1.c d29c8048beb7ea9254191f3fde9414709166a920 -F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe -F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298 +F test/speedtest1.c e4e2aa37ff66bad9f414a50a8cb9edfaac65c9e5 +F test/spellfix.test 24f676831acddd2f4056a598fd731a72c6311f49 +F test/sqllimits1.test 9014524e7ab16e2a4976b13397db4c29cc29c6d9 F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9 F test/subquery.test 666fdecceac258f5fd84bed09a64e49d9f37edd9 -F test/subquery2.test 91e1e364072aeff431d1f9689b15147e421d88c7 +F test/subquery2.test 438f8a7da1457277b22e4176510f7659b286995f F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4 F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85 F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6 -F test/table.test 2a1d2fa52c531de5915f28023747d9a8c27b6f31 +F test/table.test 06271d61eb13871490d38168433c1ef3dd82bb2a F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 -F test/tester.tcl b4ff83a8b069633f4aca788236d10a7086112a49 +F test/tester.tcl ed77454e6c7b40eb501db7e79d1c6fbfd3eebbff F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -875,7 +917,8 @@ F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46 F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 -F test/threadtest3.c 0ed13e09690f6204d7455fac3b0e8ece490f6eef +F test/threadtest3.c 9ab4b168681c3a6f70f6c833ba08e0d48dd4af9b +F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925 F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 F test/tkt-2a5629202f.test 0521bd25658428baa26665aa53ffed9367d33af2 @@ -917,6 +960,7 @@ F test/tkt-b1d3a2e531.test 8f7576e41ca179289ee1a8fee28386fd8e4b0550 F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0 F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3 F test/tkt-b75a9ca6b0.test 97cc2d5eeaf82799eb42138c0a1ff64370238ce4 +F test/tkt-ba7cbfaedc.test e76d88e572e489ee0d64fe4caf4af18b3d1dc688 F test/tkt-bd484a090c.test 60460bf946f79a79712b71f202eda501ca99b898 F test/tkt-bdc6bbbb38.test fc38bb09bdd440e3513a1f5f98fc60a075182d7d F test/tkt-c48d99d690.test ba61977d62ab612fc515b3c488a6fbd6464a2447 @@ -926,7 +970,7 @@ F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09 F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30 F test/tkt-f3e5abed55.test d5a0126118142d13e27f6ce9f4c47096e9321c00 F test/tkt-f67b41381a.test a23bc124c981662db712167bacd0ed8ad11abac9 -F test/tkt-f777251dc7a.test af6531446c64bfd268416f07b4df7be7f9c749d2 +F test/tkt-f777251dc7a.test d1a8fc3eefb7a9e64d19ff24d5c8c94c34a632fb F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7 F test/tkt-f973c7ac31.test 28ef85c7f015477916795246d8286aeda39d4ead F test/tkt-fa7bf5ec.test 9102dfea58aa371d78969da735f9392c57e2e035 @@ -1017,11 +1061,11 @@ F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1 F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7 F test/tpch01.test 04adbf8d8300fa60a222f28d901abd76e7be6dd4 -F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5 +F test/trace.test 73a5508100f7fccfbc3f8018d5f6963ed478eea0 F test/trace2.test 93b47ca6996c66b47f57224cfb146f34e07df382 F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6 F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76 -F test/trans3.test 373ac5183cc56be69f48ae44090e7f672939f732 +F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94 F test/transitive1.test 03f532954f46cdf5608f7766bff0b0c52bf2a7cd F test/trigger1.test dc47573ac79ffe0ee3eecaa517d70d8dacbccd03 F test/trigger2.test 5cd7d69a7ba1143ee045e4ae2963ff32ae4c87a6 @@ -1031,13 +1075,17 @@ F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83 F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9 F test/trigger7.test b39e6dee1debe0ff9c2ef66326668f149f07c9c4 F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4 -F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31 +F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41 F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332 F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe F test/triggerC.test a68980c5955d62ee24be6f97129d824f199f9a4c F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650 F test/triggerE.test 355e9c5cbaed5cd039a60baad1fb2197caeb8e52 -F test/tt3_checkpoint.c 415eccce672d681b297485fc20f44cdf0eac93af +F test/tt3_checkpoint.c 9e75cf7c1c364f52e1c47fd0f14c4340a9db0fe1 +F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a +F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9 +F test/tt3_stress.c c57d804716165811d979d4a719e05baccd79277f +F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776 F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a @@ -1045,8 +1093,9 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264 F test/unique2.test 41e7f83c6827605991160a31380148a9fc5f1339 F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825 F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8 -F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb +F test/update.test 6c68446b8a0a33d522a7c72b320934596a2d7d32 F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b +F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9 F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d F test/vacuum2.test af432e6e3bfc0ea20a80cb86a03c7d9876d38324 @@ -1055,9 +1104,9 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 F test/view.test f311691d696a5cc27e3c1b875cec1b0866b4ccd9 -F test/vtab1.test b631d147b198cfd7903ab5fed028eb2a3d321dc6 +F test/vtab1.test 1cef14310144718812351a61c5cfb4ba8494a171 F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d -F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1 +F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275 F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391 F test/vtab6.test 5f5380c425e52993560ab4763db4f826d2ba7b09 @@ -1077,7 +1126,7 @@ F test/wal.test 885f32b2b390b30b4aa3dbb0e568f8f78d40f5cc F test/wal2.test 1f841d2048080d32f552942e333fd99ce541dada F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0 F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c -F test/wal5.test 8f888b50f66b78821e61ed0e233ded5de378224b +F test/wal5.test dba8f5f5de95178bc40521d6edf153b2e2829917 F test/wal6.test 527581f5527bf9c24394991e2be83000aace5f9e F test/wal64k.test 163655ecd2cb8afef4737cac2a40fdd2eeaf20b8 F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd @@ -1118,7 +1167,7 @@ F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7 F test/whereG.test 69f5ec4b15760a8c860f80e2d55525669390aab3 F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2 F test/whereI.test 1d89199697919d4930be05a71e7fe620f114e622 -F test/whereJ.test 35a40a50d0e13aa6b0de7cc5d4b204e5f9f9669f +F test/whereJ.test 55a3221706a7ab706293f17cc8f96da563bf0767 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c @@ -1129,9 +1178,10 @@ F test/with2.test ee227a663586aa09771cafd4fa269c5217eaf775 F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991 F test/without_rowid1.test 7862e605753c8d25329f665fa09072e842183151 F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99 -F test/without_rowid3.test eac3d5c8a1924725b58503a368f2cbd24fd6c8a0 +F test/without_rowid3.test 1081aabf60a1e1123b7f9a8f6ae19954351843b0 F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a -F test/without_rowid5.test b4a639a367f04d382d20e8f44fc1be4f2d57d107 +F test/without_rowid5.test 61256715b686359df48ca1742db50cc7e3e7b862 +F test/without_rowid6.test deddb78ef539c355bddec00cdfaea6c56efd8b3f F test/wordcount.c 9915e06cb33d8ca8109b8700791afe80d305afda F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F test/zerodamage.test cf6748bad89553cc1632be51a6f54e487e4039ac @@ -1145,18 +1195,18 @@ F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce -F tool/lemon.c 3ff0fec22f92dfb54e62eeb48772eddffdbeb0d6 +F tool/lemon.c 1864c4fe4a72b1bb28f1792b60504804fe82c5d2 F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 -F tool/mkautoconfamal.sh f8d8dbf7d62f409ebed5134998bf5b51d7266383 +F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e -F tool/mkpragmatab.tcl 78a77b2c554d534c6f2dc903130186ed15715460 +F tool/mkpragmatab.tcl 07a5124cf2dbafa1b375eefcf8ac4227028b0f8b F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 -F tool/mksqlite3c-noext.tcl 1712d3d71256ca1f297046619c89e77a4d7c8f6d -F tool/mksqlite3c.tcl ba274df71f5e6534b0a913c7c48eabfcbd0934b6 +F tool/mksqlite3c-noext.tcl 9ef48e1748dce7b844f67e2450ff9dfeb0fb4ab5 +F tool/mksqlite3c.tcl cfde806851c413db7689b9cb74a4eeb92539c601 F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12 -F tool/mksqlite3internalh.tcl b6514145a7d5321b47e64e19b8116cc44f973eb1 +F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b F tool/mkvsix.tcl 52a4c613707ac34ae9c226e5ccc69cb948556105 F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091 F tool/omittest.tcl 34d7ac01fe4fd18e3637f64abe12c40eca0f6b97 @@ -1164,10 +1214,10 @@ F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/showdb.c b9ee6b6c81a094bf33badbf7e9da34cdbc0cce25 +F tool/showdb.c bd073a78bce714a0e42d92ea474b3eb8cb53be5d F tool/showjournal.c 053eb1cc774710c6890b7dd6293300cc297b16a5 -F tool/showstat4.c c39279d6bd37cb999b634f0064f6f86ad7af008f -F tool/showwal.c 3209120269cdf9380f091459e47b776b4f81dfd3 +F tool/showstat4.c 9515faa8ec176599d4a8288293ba8ec61f7b728a +F tool/showwal.c 85cb36d4fe3e93e2fbd63e786e0d1ce42d0c4fad F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b F tool/spaceanal.tcl 8e50b217c56a6a086a1b47eac9d09c5cd65b996f @@ -1181,15 +1231,17 @@ F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43 F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d F tool/symbols.sh fec58532668296d7c7dc48be9c87f75ccdb5814f F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 -F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891 +F tool/varint.c 5d94cb5003db9dbbcbcc5df08d66f16071aee003 +F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 3f45b8192dad7fb1f027cbaa694046e3c1b3e278 -R be8bb3bca247e348b90f7388fee24972 +P ec27ab0eb3a1ee08a73dda23d2a0f9fb70962745 +R 7a9d6545656b7d4fe08d198e32a78d62 T +bgcolor * #d0c0ff T +sym-release * -T +sym-version-3.8.6 * +T +sym-version-3.8.8.3 * U drh -Z 74d8dd4d4aac0ae87245b4bcefd8b172 +Z 9dbdbd01efd2c5089344e2a1709c163b +# Remove this line to create a well-formed manifest. diff --git a/manifest.uuid b/manifest.uuid index 910d8f9..007138a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9491ba7d738528f168657adb43a198238abde19e +9d6c1880fb75660bbabd693175579529785f8a6b diff --git a/mptest/mptest.c b/mptest/mptest.c index 059ae10..7b56b61 100644 --- a/mptest/mptest.c +++ b/mptest/mptest.c @@ -1395,7 +1395,7 @@ int main(int argc, char **argv){ maybeClose(g.pLog); maybeClose(g.pErrLog); if( iClient==0 ){ - printf("Summary: %d errors in %d tests\n", g.nError, g.nTest); + printf("Summary: %d errors out of %d tests\n", g.nError, g.nTest); } return g.nError>0; } diff --git a/sqlite3.1 b/sqlite3.1 index 02df7f4..80353b0 100644 --- a/sqlite3.1 +++ b/sqlite3.1 @@ -2,7 +2,7 @@ .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) -.TH SQLITE3 1 "Mon Jan 31 11:14:00 2014" +.TH SQLITE3 1 "Fri Oct 31 10:41:31 EDT 2014" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: @@ -49,7 +49,7 @@ a table named "memos" and insert a couple of records into that table: $ .B sqlite3 mydata.db .br -SQLite version 3.8.3 +SQLite version 3.8.8 .br Enter ".help" for instructions .br @@ -107,26 +107,29 @@ the '.help' command. For example: sqlite> .B .help .nf -.cc | -.backup ?DB? FILE Backup DB (default "main") to FILE -.bail ON|OFF Stop after hitting an error. Default OFF -.databases List names and files of attached databases -.dump ?TABLE? ... Dump the database in an SQL text format +.tr %. +%backup ?DB? FILE Backup DB (default "main") to FILE +%bail on|off Stop after hitting an error. Default OFF +%clone NEWDB Clone data into NEWDB from the existing database +%databases List names and files of attached databases +%dump ?TABLE? ... Dump the database in an SQL text format If TABLE specified, only dump tables matching LIKE pattern TABLE. -.echo ON|OFF Turn command echo on or off -.exit Exit this program -.explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off. +%echo on|off Turn command echo on or off +%eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN +%exit Exit this program +%explain ?on|off? Turn output mode suitable for EXPLAIN on or off. With no args, it turns EXPLAIN on. -.header(s) ON|OFF Turn display of headers on or off -.help Show this message -.import FILE TABLE Import data from FILE into TABLE -.indices ?TABLE? Show names of all indices +%fullschema Show schema and the content of sqlite_stat tables +%headers on|off Turn display of headers on or off +%help Show this message +%import FILE TABLE Import data from FILE into TABLE +%indices ?TABLE? Show names of all indices If TABLE specified, only show indices for tables matching LIKE pattern TABLE. -.load FILE ?ENTRY? Load an extension library -.log FILE|off Turn logging on or off. FILE can be stderr/stdout -.mode MODE ?TABLE? Set output mode where MODE is one of: +%load FILE ?ENTRY? Load an extension library +%log FILE|off Turn logging on or off. FILE can be stderr/stdout +%mode MODE ?TABLE? Set output mode where MODE is one of: csv Comma-separated values column Left-aligned columns. (See .width) html HTML
    code @@ -135,31 +138,35 @@ sqlite> list Values delimited by .separator string tabs Tab-separated values tcl TCL list elements -.nullvalue STRING Use STRING in place of NULL values -.open ?FILENAME? Close existing database and reopen FILENAME -.output FILENAME Send output to FILENAME -.output stdout Send output to the screen -.print STRING... Print literal STRING -.prompt MAIN CONTINUE Replace the standard prompts -.quit Exit this program -.read FILENAME Execute SQL in FILENAME -.restore ?DB? FILE Restore content of DB (default "main") from FILE -.schema ?TABLE? Show the CREATE statements +%nullvalue STRING Use STRING in place of NULL values +%once FILENAME Output for the next SQL command only to FILENAME +%open ?FILENAME? Close existing database and reopen FILENAME +%output ?FILENAME? Send output to FILENAME or stdout +%print STRING... Print literal STRING +%prompt MAIN CONTINUE Replace the standard prompts +%quit Exit this program +%read FILENAME Execute SQL in FILENAME +%restore ?DB? FILE Restore content of DB (default "main") from FILE +%save FILE Write in-memory database into FILE +%schema ?TABLE? Show the CREATE statements If TABLE specified, only show tables matching LIKE pattern TABLE. -.separator STRING Change separator used by output mode and .import -.show Show the current values for various settings -.stats ON|OFF Turn stats on or off -.tables ?TABLE? List names of tables +%separator STRING ?NL? Change separator used by output mode and .import + NL is the end-of-line mark for CSV +%shell CMD ARGS... Run CMD ARGS... in a system shell +%show Show the current values for various settings +%stats on|off Turn stats on or off +%system CMD ARGS... Run CMD ARGS... in a system shell +%tables ?TABLE? List names of tables If TABLE specified, only list tables matching LIKE pattern TABLE. -.timeout MS Try opening locked tables for MS milliseconds -.trace FILE|off Output each SQL statement as it is run -.vfsname ?AUX? Print the name of the VFS stack -.width NUM1 NUM2 ... Set column widths for "column" mode -.timer ON|OFF Turn the CPU timer measurement on or off +%timeout MS Try opening locked tables for MS milliseconds +%timer on|off Turn SQL timer on or off +%trace FILE|off Output each SQL statement as it is run +%vfsname ?AUX? Print the name of the VFS stack +%width NUM1 NUM2 ... Set column widths for "column" mode + Negative values right-justify sqlite> -|cc . .sp .fi .SH OPTIONS @@ -269,7 +276,7 @@ o If the -init option is present, the specified file is processed. o All other command line options are processed. .SH SEE ALSO -http://www.sqlite.org/ +http://www.sqlite.org/cli.html .br The sqlite3-doc package. .SH AUTHOR diff --git a/src/alter.c b/src/alter.c index 64204b7..dd06024 100644 --- a/src/alter.c +++ b/src/alter.c @@ -174,8 +174,8 @@ static void renameTriggerFunc( UNUSED_PARAMETER(NotUsed); /* The principle used to locate the table name in the CREATE TRIGGER - ** statement is that the table name is the first token that is immediatedly - ** preceded by either TK_ON or TK_DOT and immediatedly followed by one + ** statement is that the table name is the first token that is immediately + ** preceded by either TK_ON or TK_DOT and immediately followed by one ** of TK_WHEN, TK_BEGIN or TK_FOR. */ if( zSql ){ diff --git a/src/analyze.c b/src/analyze.c index f9c03dc..fec2bdb 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -35,7 +35,7 @@ ** not possible to enable both STAT3 and STAT4 at the same time. If they ** are both enabled, then STAT4 takes precedence. ** -** For most applications, sqlite_stat1 provides all the statisics required +** For most applications, sqlite_stat1 provides all the statistics required ** for the query planner to make good choices. ** ** Format of sqlite_stat1: @@ -387,8 +387,9 @@ static void stat4Destructor(void *pOld){ ** original WITHOUT ROWID table as N==K as a special case. ** ** This routine allocates the Stat4Accum object in heap memory. The return -** value is a pointer to the the Stat4Accum object encoded as a blob (i.e. -** the size of the blob is sizeof(void*) bytes). +** value is a pointer to the Stat4Accum object. The datatype of the +** return value is BLOB, but it is really just a pointer to the Stat4Accum +** object. */ static void statInit( sqlite3_context *context, @@ -447,7 +448,7 @@ static void statInit( p->mxSample = mxSample; p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1); p->current.anLt = &p->current.anEq[nColUp]; - p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[2])*0xd0944565; + p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]); /* Set up the Stat4Accum.a[] and aBest[] arrays */ p->a = (struct Stat4Sample*)&p->current.anLt[nColUp]; @@ -466,8 +467,11 @@ static void statInit( } #endif - /* Return a pointer to the allocated object to the caller */ - sqlite3_result_blob(context, p, sizeof(p), stat4Destructor); + /* Return a pointer to the allocated object to the caller. Note that + ** only the pointer (the 2nd parameter) matters. The size of the object + ** (given by the 3rd parameter) is never used and can be any positive + ** value. */ + sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor); } static const FuncDef statInitFuncdef = { 2+IsStat34, /* nArg */ @@ -793,7 +797,7 @@ static const FuncDef statPushFuncdef = { ** Implementation of the stat_get(P,J) SQL function. This routine is ** used to query statistical information that has been gathered into ** the Stat4Accum object by prior calls to stat_push(). The P parameter -** is a BLOB which is decoded into a pointer to the Stat4Accum objects. +** has type BLOB but it is really just a pointer to the Stat4Accum object. ** The content to returned is determined by the parameter J ** which is one of the STAT_GET_xxxx values defined above. ** @@ -1197,7 +1201,8 @@ static void analyzeOneTable( /* Add the entry to the stat1 table. */ callStatGet(v, regStat4, STAT_GET_STAT1, regStat1); - sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "aaa", 0); + assert( "BBB"[0]==SQLITE_AFF_TEXT ); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); @@ -1260,7 +1265,8 @@ static void analyzeOneTable( sqlite3VdbeAddOp2(v, OP_Count, iTabCur, regStat1); jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); - sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "aaa", 0); + assert( "BBB"[0]==SQLITE_AFF_TEXT ); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); @@ -1431,7 +1437,7 @@ static void decodeIntArray( #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( z==0 ) z = ""; #else - if( NEVER(z==0) ) z = ""; + assert( z!=0 ); #endif for(i=0; *z && ibUnordered = 1; - }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){ - pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3)); - } + pIndex->bUnordered = 0; + pIndex->noSkipScan = 0; + while( z[0] ){ + if( sqlite3_strglob("unordered*", z)==0 ){ + pIndex->bUnordered = 1; + }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){ + pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3)); + }else if( sqlite3_strglob("noskipscan*", z)==0 ){ + pIndex->noSkipScan = 1; + } #ifdef SQLITE_ENABLE_COSTMULT - else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){ - pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9)); - } + else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){ + pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9)); + } #endif - while( z[0]!=0 && z[0]!=' ' ) z++; - while( z[0]==' ' ) z++; + while( z[0]!=0 && z[0]!=' ' ) z++; + while( z[0]==' ' ) z++; + } } } @@ -1510,8 +1519,17 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ z = argv[2]; if( pIndex ){ + int nCol = pIndex->nKeyCol+1; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + tRowcnt * const aiRowEst = pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero( + sizeof(tRowcnt) * nCol + ); + if( aiRowEst==0 ) pInfo->db->mallocFailed = 1; +#else + tRowcnt * const aiRowEst = 0; +#endif pIndex->bUnordered = 0; - decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex); + decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex); if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0]; }else{ Index fakeIdx; @@ -1570,25 +1588,39 @@ static void initAvgEq(Index *pIdx){ pIdx->aAvgEq[nCol] = 1; } for(iCol=0; iColnSample; int i; /* Used to iterate through samples */ tRowcnt sumEq = 0; /* Sum of the nEq values */ - tRowcnt nSum = 0; /* Number of terms contributing to sumEq */ tRowcnt avgEq = 0; - tRowcnt nDLt = pFinal->anDLt[iCol]; + tRowcnt nRow; /* Number of rows in index */ + i64 nSum100 = 0; /* Number of terms contributing to sumEq */ + i64 nDist100; /* Number of distinct values in index */ + + if( !pIdx->aiRowEst || iCol>=pIdx->nKeyCol || pIdx->aiRowEst[iCol+1]==0 ){ + nRow = pFinal->anLt[iCol]; + nDist100 = (i64)100 * pFinal->anDLt[iCol]; + nSample--; + }else{ + nRow = pIdx->aiRowEst[0]; + nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1]; + } + pIdx->nRowEst0 = nRow; /* Set nSum to the number of distinct (iCol+1) field prefixes that - ** occur in the stat4 table for this index before pFinal. Set - ** sumEq to the sum of the nEq values for column iCol for the same - ** set (adding the value only once where there exist dupicate - ** prefixes). */ - for(i=0; i<(pIdx->nSample-1); i++){ - if( aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){ + ** occur in the stat4 table for this index. Set sumEq to the sum of + ** the nEq values for column iCol for the same set (adding the value + ** only once where there exist duplicate prefixes). */ + for(i=0; inSample-1) + || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] + ){ sumEq += aSample[i].anEq[iCol]; - nSum++; + nSum100 += 100; } } - if( nDLt>nSum ){ - avgEq = (pFinal->anLt[iCol] - sumEq)/(nDLt - nSum); + + if( nDist100>nSum100 ){ + avgEq = ((i64)100 * (nRow - sumEq))/(nDist100 - nSum100); } if( avgEq==0 ) avgEq = 1; pIdx->aAvgEq[iCol] = avgEq; @@ -1834,12 +1866,17 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ /* Load the statistics from the sqlite_stat4 table. */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){ int lookasideEnabled = db->lookaside.bEnabled; db->lookaside.bEnabled = 0; rc = loadStat4(db, sInfo.zDatabase); db->lookaside.bEnabled = lookasideEnabled; } + for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ + Index *pIdx = sqliteHashData(i); + sqlite3_free(pIdx->aiRowEst); + pIdx->aiRowEst = 0; + } #endif if( rc==SQLITE_NOMEM ){ diff --git a/src/attach.c b/src/attach.c index 89050fd..de87429 100644 --- a/src/attach.c +++ b/src/attach.c @@ -150,6 +150,7 @@ static void attachFunc( "attached databases must use the same text encoding as main database"); rc = SQLITE_ERROR; } + sqlite3BtreeEnter(aNew->pBt); pPager = sqlite3BtreePager(aNew->pBt); sqlite3PagerLockingMode(pPager, db->dfltLockMode); sqlite3BtreeSecureDelete(aNew->pBt, @@ -157,6 +158,7 @@ static void attachFunc( #ifndef SQLITE_OMIT_PAGER_PRAGMAS sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK)); #endif + sqlite3BtreeLeave(aNew->pBt); } aNew->safety_level = 3; aNew->zName = sqlite3DbStrDup(db, zName); @@ -207,6 +209,15 @@ static void attachFunc( rc = sqlite3Init(db, &zErrDyn); sqlite3BtreeLeaveAll(db); } +#ifdef SQLITE_USER_AUTHENTICATION + if( rc==SQLITE_OK ){ + u8 newAuth = 0; + rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); + if( newAuthauth.authLevel ){ + rc = SQLITE_AUTH_USER; + } + } +#endif if( rc ){ int iDb = db->nDb - 1; assert( iDb>=2 ); diff --git a/src/auth.c b/src/auth.c index d38bb83..9768fc2 100644 --- a/src/auth.c +++ b/src/auth.c @@ -72,8 +72,11 @@ int sqlite3_set_authorizer( int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pArg ){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); - db->xAuth = xAuth; + db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; sqlite3ExpirePreparedStatements(db); sqlite3_mutex_leave(db->mutex); @@ -108,7 +111,11 @@ int sqlite3AuthReadCol( char *zDb = db->aDb[iDb].zName; /* Name of attached database */ int rc; /* Auth callback return code */ - rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext); + rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext +#ifdef SQLITE_USER_AUTHENTICATION + ,db->auth.zAuthUser +#endif + ); if( rc==SQLITE_DENY ){ if( db->nDb>2 || iDb!=0 ){ sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol); @@ -208,7 +215,11 @@ int sqlite3AuthCheck( if( db->xAuth==0 ){ return SQLITE_OK; } - rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext); + rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext +#ifdef SQLITE_USER_AUTHENTICATION + ,db->auth.zAuthUser +#endif + ); if( rc==SQLITE_DENY ){ sqlite3ErrorMsg(pParse, "not authorized"); pParse->rc = SQLITE_AUTH; diff --git a/src/backup.c b/src/backup.c index 4a6bc74..e3f8690 100644 --- a/src/backup.c +++ b/src/backup.c @@ -87,12 +87,12 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ int rc = 0; pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse)); if( pParse==0 ){ - sqlite3Error(pErrorDb, SQLITE_NOMEM, "out of memory"); + sqlite3ErrorWithMsg(pErrorDb, SQLITE_NOMEM, "out of memory"); rc = SQLITE_NOMEM; }else{ pParse->db = pDb; if( sqlite3OpenTempDatabase(pParse) ){ - sqlite3Error(pErrorDb, pParse->rc, "%s", pParse->zErrMsg); + sqlite3ErrorWithMsg(pErrorDb, pParse->rc, "%s", pParse->zErrMsg); rc = SQLITE_ERROR; } sqlite3DbFree(pErrorDb, pParse->zErrMsg); @@ -105,7 +105,7 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ } if( i<0 ){ - sqlite3Error(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb); + sqlite3ErrorWithMsg(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb); return 0; } @@ -122,6 +122,20 @@ static int setDestPgsz(sqlite3_backup *p){ return rc; } +/* +** Check that there is no open read-transaction on the b-tree passed as the +** second argument. If there is not, return SQLITE_OK. Otherwise, if there +** is an open read-transaction, return SQLITE_ERROR and leave an error +** message in database handle db. +*/ +static int checkReadTransaction(sqlite3 *db, Btree *p){ + if( sqlite3BtreeIsInReadTrans(p) ){ + sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use"); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + /* ** Create an sqlite3_backup process to copy the contents of zSrcDb from ** connection handle pSrcDb to zDestDb in pDestDb. If successful, return @@ -138,6 +152,13 @@ sqlite3_backup *sqlite3_backup_init( ){ sqlite3_backup *p; /* Value to return */ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(pSrcDb)||!sqlite3SafetyCheckOk(pDestDb) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + /* Lock the source database handle. The destination database ** handle is not locked in this routine, but it is locked in ** sqlite3_backup_step(). The user is required to ensure that no @@ -150,7 +171,7 @@ sqlite3_backup *sqlite3_backup_init( sqlite3_mutex_enter(pDestDb->mutex); if( pSrcDb==pDestDb ){ - sqlite3Error( + sqlite3ErrorWithMsg( pDestDb, SQLITE_ERROR, "source and destination must be distinct" ); p = 0; @@ -161,7 +182,7 @@ sqlite3_backup *sqlite3_backup_init( ** sqlite3_backup_finish(). */ p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup)); if( !p ){ - sqlite3Error(pDestDb, SQLITE_NOMEM, 0); + sqlite3Error(pDestDb, SQLITE_NOMEM); } } @@ -174,12 +195,15 @@ sqlite3_backup *sqlite3_backup_init( p->iNext = 1; p->isAttached = 0; - if( 0==p->pSrc || 0==p->pDest || setDestPgsz(p)==SQLITE_NOMEM ){ + if( 0==p->pSrc || 0==p->pDest + || setDestPgsz(p)==SQLITE_NOMEM + || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK + ){ /* One (or both) of the named databases did not exist or an OOM - ** error was hit. The error has already been written into the - ** pDestDb handle. All that is left to do here is free the - ** sqlite3_backup structure. - */ + ** error was hit. Or there is a transaction open on the destination + ** database. The error has already been written into the pDestDb + ** handle. All that is left to do here is free the sqlite3_backup + ** structure. */ sqlite3_free(p); p = 0; } @@ -334,6 +358,9 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ int pgszSrc = 0; /* Source page size */ int pgszDest = 0; /* Destination page size */ +#ifdef SQLITE_ENABLE_API_ARMOR + if( p==0 ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); if( p->pDestDb ){ @@ -597,12 +624,12 @@ int sqlite3_backup_finish(sqlite3_backup *p){ } /* If a transaction is still open on the Btree, roll it back. */ - sqlite3BtreeRollback(p->pDest, SQLITE_OK); + sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); /* Set the error code of the destination database handle. */ rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; if( p->pDestDb ){ - sqlite3Error(p->pDestDb, rc, 0); + sqlite3Error(p->pDestDb, rc); /* Exit the mutexes and free the backup context structure. */ sqlite3LeaveMutexAndCloseZombie(p->pDestDb); @@ -623,6 +650,12 @@ int sqlite3_backup_finish(sqlite3_backup *p){ ** call to sqlite3_backup_step(). */ int sqlite3_backup_remaining(sqlite3_backup *p){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( p==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif return p->nRemaining; } @@ -631,6 +664,12 @@ int sqlite3_backup_remaining(sqlite3_backup *p){ ** recent call to sqlite3_backup_step(). */ int sqlite3_backup_pagecount(sqlite3_backup *p){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( p==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif return p->nPagecount; } diff --git a/src/btmutex.c b/src/btmutex.c index d87d4d5..f9fe5b3 100644 --- a/src/btmutex.c +++ b/src/btmutex.c @@ -38,7 +38,7 @@ static void lockBtreeMutex(Btree *p){ ** Release the BtShared mutex associated with B-Tree handle p and ** clear the p->locked boolean. */ -static void unlockBtreeMutex(Btree *p){ +static void SQLITE_NOINLINE unlockBtreeMutex(Btree *p){ BtShared *pBt = p->pBt; assert( p->locked==1 ); assert( sqlite3_mutex_held(pBt->mutex) ); @@ -49,6 +49,9 @@ static void unlockBtreeMutex(Btree *p){ p->locked = 0; } +/* Forward reference */ +static void SQLITE_NOINLINE btreeLockCarefully(Btree *p); + /* ** Enter a mutex on the given BTree object. ** @@ -66,8 +69,6 @@ static void unlockBtreeMutex(Btree *p){ ** subsequent Btrees that desire a lock. */ void sqlite3BtreeEnter(Btree *p){ - Btree *pLater; - /* Some basic sanity checking on the Btree. The list of Btrees ** connected by pNext and pPrev should be in sorted order by ** Btree.pBt value. All elements of the list should belong to @@ -92,9 +93,20 @@ void sqlite3BtreeEnter(Btree *p){ if( !p->sharable ) return; p->wantToLock++; if( p->locked ) return; + btreeLockCarefully(p); +} + +/* This is a helper function for sqlite3BtreeLock(). By moving +** complex, but seldom used logic, out of sqlite3BtreeLock() and +** into this routine, we avoid unnecessary stack pointer changes +** and thus help the sqlite3BtreeLock() routine to run much faster +** in the common case. +*/ +static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){ + Btree *pLater; /* In most cases, we should be able to acquire the lock we - ** want without having to go throught the ascending lock + ** want without having to go through the ascending lock ** procedure that follows. Just be sure not to block. */ if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){ @@ -124,6 +136,7 @@ void sqlite3BtreeEnter(Btree *p){ } } + /* ** Exit the recursive mutex on a Btree. */ diff --git a/src/btree.c b/src/btree.c index 60bc7de..f9f76c2 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file implements a external (disk-based) database using BTrees. +** This file implements an external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ @@ -487,7 +487,9 @@ static void invalidateIncrblobCursors( BtShared *pBt = pBtree->pBt; assert( sqlite3BtreeHoldsMutex(pBtree) ); for(p=pBt->pCursor; p; p=p->pNext){ - if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){ + if( (p->curFlags & BTCF_Incrblob)!=0 + && (isClearTable || p->info.nKey==iRow) + ){ p->eState = CURSOR_INVALID; } } @@ -606,7 +608,7 @@ static int saveCursorPosition(BtCursor *pCur){ ** data. */ if( 0==pCur->apPage[0]->intKey ){ - void *pKey = sqlite3Malloc( (int)pCur->nKey ); + void *pKey = sqlite3Malloc( pCur->nKey ); if( pKey ){ rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ @@ -629,16 +631,42 @@ static int saveCursorPosition(BtCursor *pCur){ return rc; } +/* Forward reference */ +static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*); + /* ** Save the positions of all cursors (except pExcept) that are open on -** the table with root-page iRoot. Usually, this is called just before cursor -** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()). +** the table with root-page iRoot. "Saving the cursor position" means that +** the location in the btree is remembered in such a way that it can be +** moved back to the same spot after the btree has been modified. This +** routine is called just before cursor pExcept is used to modify the +** table, for example in BtreeDelete() or BtreeInsert(). +** +** Implementation note: This routine merely checks to see if any cursors +** need to be saved. It calls out to saveCursorsOnList() in the (unusual) +** event that cursors are in need to being saved. */ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ BtCursor *p; assert( sqlite3_mutex_held(pBt->mutex) ); assert( pExcept==0 || pExcept->pBt==pBt ); for(p=pBt->pCursor; p; p=p->pNext){ + if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ) break; + } + return p ? saveCursorsOnList(p, iRoot, pExcept) : SQLITE_OK; +} + +/* This helper routine to saveAllCursors does the actual work of saving +** the cursors if and when a cursor is found that actually requires saving. +** The common case is that no cursors need to be saved, so this routine is +** broken out from its caller to avoid unnecessary stack pointer movement. +*/ +static int SQLITE_NOINLINE saveCursorsOnList( + BtCursor *p, /* The first cursor that needs saving */ + Pgno iRoot, /* Only save cursor with this iRoot. Save all if zero */ + BtCursor *pExcept /* Do not save this cursor */ +){ + do{ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){ if( p->eState==CURSOR_VALID ){ int rc = saveCursorPosition(p); @@ -650,7 +678,8 @@ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ btreeReleaseAllCursorPages(p); } } - } + p = p->pNext; + }while( p ); return SQLITE_OK; } @@ -735,37 +764,48 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){ SQLITE_OK) /* -** Determine whether or not a cursor has moved from the position it -** was last placed at. Cursors can move when the row they are pointing -** at is deleted out from under them. +** Determine whether or not a cursor has moved from the position where +** it was last placed, or has been invalidated for any other reason. +** Cursors can move when the row they are pointing at is deleted out +** from under them, for example. Cursor might also move if a btree +** is rebalanced. ** -** This routine returns an error code if something goes wrong. The -** integer *pHasMoved is set as follows: +** Calling this routine with a NULL cursor pointer returns false. ** -** 0: The cursor is unchanged -** 1: The cursor is still pointing at the same row, but the pointers -** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch() -** might now be invalid because of a balance() or other change to the -** b-tree. -** 2: The cursor is no longer pointing to the row. The row might have -** been deleted out from under the cursor. +** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor +** back to where it ought to be if this routine returns true. */ -int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){ +int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ + return pCur->eState!=CURSOR_VALID; +} + +/* +** This routine restores a cursor back to its original position after it +** has been moved by some outside activity (such as a btree rebalance or +** a row having been deleted out from under the cursor). +** +** On success, the *pDifferentRow parameter is false if the cursor is left +** pointing at exactly the same row. *pDifferntRow is the row the cursor +** was pointing to has been deleted, forcing the cursor to point to some +** nearby row. +** +** This routine should only be called for a cursor that just returned +** TRUE from sqlite3BtreeCursorHasMoved(). +*/ +int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){ int rc; - if( pCur->eState==CURSOR_VALID ){ - *pHasMoved = 0; - return SQLITE_OK; - } + assert( pCur!=0 ); + assert( pCur->eState!=CURSOR_VALID ); rc = restoreCursorPosition(pCur); if( rc ){ - *pHasMoved = 2; + *pDifferentRow = 1; return rc; } if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){ - *pHasMoved = 2; + *pDifferentRow = 1; }else{ - *pHasMoved = 1; + *pDifferentRow = 0; } return SQLITE_OK; } @@ -930,47 +970,44 @@ static u8 *findOverflowCell(MemPage *pPage, int iCell){ ** are two versions of this function. btreeParseCell() takes a ** cell index as the second argument and btreeParseCellPtr() ** takes a pointer to the body of the cell as its second argument. -** -** Within this file, the parseCell() macro can be called instead of -** btreeParseCellPtr(). Using some compilers, this will be faster. */ static void btreeParseCellPtr( MemPage *pPage, /* Page containing the cell */ u8 *pCell, /* Pointer to the cell text. */ CellInfo *pInfo /* Fill in this structure */ ){ - u16 n; /* Number bytes in cell content header */ + u8 *pIter; /* For scanning through pCell */ u32 nPayload; /* Number of bytes of cell payload */ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - - pInfo->pCell = pCell; assert( pPage->leaf==0 || pPage->leaf==1 ); - n = pPage->childPtrSize; - assert( n==4-4*pPage->leaf ); - if( pPage->intKey ){ - if( pPage->hasData ){ - assert( n==0 ); - n = getVarint32(pCell, nPayload); - }else{ - nPayload = 0; - } - n += getVarint(&pCell[n], (u64*)&pInfo->nKey); - pInfo->nData = nPayload; + if( pPage->intKeyLeaf ){ + assert( pPage->childPtrSize==0 ); + pIter = pCell + getVarint32(pCell, nPayload); + pIter += getVarint(pIter, (u64*)&pInfo->nKey); + }else if( pPage->noPayload ){ + assert( pPage->childPtrSize==4 ); + pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey); + pInfo->nPayload = 0; + pInfo->nLocal = 0; + pInfo->iOverflow = 0; + pInfo->pPayload = 0; + return; }else{ - pInfo->nData = 0; - n += getVarint32(&pCell[n], nPayload); + pIter = pCell + pPage->childPtrSize; + pIter += getVarint32(pIter, nPayload); pInfo->nKey = nPayload; } pInfo->nPayload = nPayload; - pInfo->nHeader = n; + pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==pPage->maxLocal+1 ); - if( likely(nPayload<=pPage->maxLocal) ){ + if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ - if( (pInfo->nSize = (u16)(n+nPayload))<4 ) pInfo->nSize = 4; + pInfo->nSize = nPayload + (u16)(pIter - pCell); + if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; pInfo->iOverflow = 0; }else{ @@ -997,18 +1034,16 @@ static void btreeParseCellPtr( }else{ pInfo->nLocal = (u16)minLocal; } - pInfo->iOverflow = (u16)(pInfo->nLocal + n); + pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell); pInfo->nSize = pInfo->iOverflow + 4; } } -#define parseCell(pPage, iCell, pInfo) \ - btreeParseCellPtr((pPage), findCell((pPage), (iCell)), (pInfo)) static void btreeParseCell( MemPage *pPage, /* Page containing the cell */ int iCell, /* The cell index. First cell is 0 */ CellInfo *pInfo /* Fill in this structure */ ){ - parseCell(pPage, iCell, pInfo); + btreeParseCellPtr(pPage, findCell(pPage, iCell), pInfo); } /* @@ -1018,8 +1053,9 @@ static void btreeParseCell( ** the space used by the cell pointer. */ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ - u8 *pIter = &pCell[pPage->childPtrSize]; - u32 nSize; + u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */ + u8 *pEnd; /* End mark for a varint */ + u32 nSize; /* Size value to return */ #ifdef SQLITE_DEBUG /* The value returned by this function should always be the same as @@ -1030,26 +1066,34 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ btreeParseCellPtr(pPage, pCell, &debuginfo); #endif + if( pPage->noPayload ){ + pEnd = &pIter[9]; + while( (*pIter++)&0x80 && pIterchildPtrSize==4 ); + return (u16)(pIter - pCell); + } + nSize = *pIter; + if( nSize>=0x80 ){ + pEnd = &pIter[9]; + nSize &= 0x7f; + do{ + nSize = (nSize<<7) | (*++pIter & 0x7f); + }while( *(pIter)>=0x80 && pIterintKey ){ - u8 *pEnd; - if( pPage->hasData ){ - pIter += getVarint32(pIter, nSize); - }else{ - nSize = 0; - } - /* pIter now points at the 64-bit integer key value, a variable length ** integer. The following block moves pIter to point at the first byte ** past the end of the key value. */ pEnd = &pIter[9]; while( (*pIter++)&0x80 && pItermaxLocal ); testcase( nSize==pPage->maxLocal+1 ); - if( nSize>pPage->maxLocal ){ + if( nSize<=pPage->maxLocal ){ + nSize += (u32)(pIter - pCell); + if( nSize<4 ) nSize = 4; + }else{ int minLocal = pPage->minLocal; nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); testcase( nSize==pPage->maxLocal ); @@ -1057,16 +1101,9 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ if( nSize>pPage->maxLocal ){ nSize = minLocal; } - nSize += 4; + nSize += 4 + (u16)(pIter - pCell); } - nSize += (u32)(pIter - pCell); - - /* The minimum size of any cell is 4 bytes. */ - if( nSize<4 ){ - nSize = 4; - } - - assert( nSize==debuginfo.nSize ); + assert( nSize==debuginfo.nSize || CORRUPT_DB ); return (u16)nSize; } @@ -1089,7 +1126,6 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){ if( *pRC ) return; assert( pCell!=0 ); btreeParseCellPtr(pPage, pCell, &info); - assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); if( info.iOverflow ){ Pgno ovfl = get4byte(&pCell[info.iOverflow]); ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC); @@ -1103,10 +1139,15 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){ ** end of the page and all free space is collected into one ** big FreeBlk that occurs in between the header and cell ** pointer array and the cell content area. +** +** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a +** b-tree page so that there are no freeblocks or fragment bytes, all +** unused bytes are contained in the unallocated space region, and all +** cells are packed tightly at the end of the page. */ static int defragmentPage(MemPage *pPage){ int i; /* Loop counter */ - int pc; /* Address of a i-th cell */ + int pc; /* Address of the i-th cell */ int hdr; /* Offset to the page header */ int size; /* Size of a cell */ int usableSize; /* Number of usable bytes on a page */ @@ -1115,6 +1156,7 @@ static int defragmentPage(MemPage *pPage){ int nCell; /* Number of cells on the page */ unsigned char *data; /* The page data */ unsigned char *temp; /* Temp area for cell content */ + unsigned char *src; /* Source of content */ int iCellFirst; /* First allowable cell index */ int iCellLast; /* Last possible cell index */ @@ -1124,15 +1166,13 @@ static int defragmentPage(MemPage *pPage){ assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); assert( pPage->nOverflow==0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - temp = sqlite3PagerTempSpace(pPage->pBt->pPager); - data = pPage->aData; + temp = 0; + src = data = pPage->aData; hdr = pPage->hdrOffset; cellOffset = pPage->cellOffset; nCell = pPage->nCell; assert( nCell==get2byte(&data[hdr+3]) ); usableSize = pPage->pBt->usableSize; - cbrk = get2byte(&data[hdr+5]); - memcpy(&temp[cbrk], &data[cbrk], usableSize - cbrk); cbrk = usableSize; iCellFirst = cellOffset + 2*nCell; iCellLast = usableSize - 4; @@ -1151,7 +1191,7 @@ static int defragmentPage(MemPage *pPage){ } #endif assert( pc>=iCellFirst && pc<=iCellLast ); - size = cellSizePtr(pPage, &temp[pc]); + size = cellSizePtr(pPage, &src[pc]); cbrk -= size; #if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK) if( cbrk=iCellFirst ); testcase( cbrk+size==usableSize ); testcase( pc+size==usableSize ); - memcpy(&data[cbrk], &temp[pc], size); put2byte(pAddr, cbrk); + if( temp==0 ){ + int x; + if( cbrk==pc ) continue; + temp = sqlite3PagerTempSpace(pPage->pBt->pPager); + x = get2byte(&data[hdr+5]); + memcpy(&temp[x], &data[x], (cbrk+size) - x); + src = temp; + } + memcpy(&data[cbrk], &src[pc], size); } assert( cbrk>=iCellFirst ); put2byte(&data[hdr+5], cbrk); @@ -1181,6 +1229,69 @@ static int defragmentPage(MemPage *pPage){ return SQLITE_OK; } +/* +** Search the free-list on page pPg for space to store a cell nByte bytes in +** size. If one can be found, return a pointer to the space and remove it +** from the free-list. +** +** If no suitable space can be found on the free-list, return NULL. +** +** This function may detect corruption within pPg. If corruption is +** detected then *pRc is set to SQLITE_CORRUPT and NULL is returned. +** +** If a slot of at least nByte bytes is found but cannot be used because +** there are already at least 60 fragmented bytes on the page, return NULL. +** In this case, if pbDefrag parameter is not NULL, set *pbDefrag to true. +*/ +static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc, int *pbDefrag){ + const int hdr = pPg->hdrOffset; + u8 * const aData = pPg->aData; + int iAddr; + int pc; + int usableSize = pPg->pBt->usableSize; + + for(iAddr=hdr+1; (pc = get2byte(&aData[iAddr]))>0; iAddr=pc){ + int size; /* Size of the free slot */ + /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of + ** increasing offset. */ + if( pc>usableSize-4 || pc=nByte ){ + int x = size - nByte; + testcase( x==4 ); + testcase( x==3 ); + if( x<4 ){ + /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total + ** number of bytes in fragments may not exceed 60. */ + if( aData[hdr+7]>=60 ){ + if( pbDefrag ) *pbDefrag = 1; + return 0; + } + /* Remove the slot from the free-list. Update the number of + ** fragmented bytes within the page. */ + memcpy(&aData[iAddr], &aData[pc], 2); + aData[hdr+7] += (u8)x; + }else if( size+pc > usableSize ){ + *pRc = SQLITE_CORRUPT_BKPT; + return 0; + }else{ + /* The slot remains on the free-list. Reduce its size to account + ** for the portion used by the new allocation. */ + put2byte(&aData[pc+2], x); + } + return &aData[pc + x]; + } + } + + return 0; +} + /* ** Allocate nByte bytes of space from within the B-Tree page passed ** as the first argument. Write into *pIdx the index into pPage->aData[] @@ -1197,11 +1308,9 @@ static int defragmentPage(MemPage *pPage){ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */ u8 * const data = pPage->aData; /* Local cache of pPage->aData */ - int nFrag; /* Number of fragmented bytes on pPage */ int top; /* First byte of cell content area */ + int rc = SQLITE_OK; /* Integer return code */ int gap; /* First byte of gap between cell pointers and cell content */ - int rc; /* Integer return code */ - int usableSize; /* Usable size of the page */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt ); @@ -1209,62 +1318,45 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ assert( nByte>=0 ); /* Minimum cell size is 4 */ assert( pPage->nFree>=nByte ); assert( pPage->nOverflow==0 ); - usableSize = pPage->pBt->usableSize; - assert( nByte < usableSize-8 ); + assert( nByte < (int)(pPage->pBt->usableSize-8) ); - nFrag = data[hdr+7]; assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf ); gap = pPage->cellOffset + 2*pPage->nCell; + assert( gap<=65536 ); + /* EVIDENCE-OF: R-29356-02391 If the database uses a 65536-byte page size + ** and the reserved space is zero (the usual value for reserved space) + ** then the cell content offset of an empty page wants to be 65536. + ** However, that integer is too large to be stored in a 2-byte unsigned + ** integer, so a value of 0 is used in its place. */ top = get2byteNotZero(&data[hdr+5]); if( gap>top ) return SQLITE_CORRUPT_BKPT; + + /* If there is enough space between gap and top for one more cell pointer + ** array entry offset, and if the freelist is not empty, then search the + ** freelist looking for a free slot big enough to satisfy the request. + */ testcase( gap+2==top ); testcase( gap+1==top ); testcase( gap==top ); - - if( nFrag>=60 ){ - /* Always defragment highly fragmented pages */ - rc = defragmentPage(pPage); + if( gap+2<=top && (data[hdr+1] || data[hdr+2]) ){ + int bDefrag = 0; + u8 *pSpace = pageFindSlot(pPage, nByte, &rc, &bDefrag); if( rc ) return rc; - top = get2byteNotZero(&data[hdr+5]); - }else if( gap+2<=top ){ - /* Search the freelist looking for a free slot big enough to satisfy - ** the request. The allocation is made from the first free slot in - ** the list that is large enough to accommodate it. - */ - int pc, addr; - for(addr=hdr+1; (pc = get2byte(&data[addr]))>0; addr=pc){ - int size; /* Size of the free slot */ - if( pc>usableSize-4 || pc=nByte ){ - int x = size - nByte; - testcase( x==4 ); - testcase( x==3 ); - if( x<4 ){ - /* Remove the slot from the free-list. Update the number of - ** fragmented bytes within the page. */ - memcpy(&data[addr], &data[pc], 2); - data[hdr+7] = (u8)(nFrag + x); - }else if( size+pc > usableSize ){ - return SQLITE_CORRUPT_BKPT; - }else{ - /* The slot remains on the free-list. Reduce its size to account - ** for the portion used by the new allocation. */ - put2byte(&data[pc+2], x); - } - *pIdx = pc + x; - return SQLITE_OK; - } + if( bDefrag ) goto defragment_page; + if( pSpace ){ + assert( pSpace>=data && (pSpace - data)<65536 ); + *pIdx = (int)(pSpace - data); + return SQLITE_OK; } } - /* Check to make sure there is enough space in the gap to satisfy - ** the allocation. If not, defragment. + /* The request could not be fulfilled using a freelist slot. Check + ** to see if defragmentation is necessary. */ testcase( gap+2+nByte==top ); if( gap+2+nByte>top ){ + defragment_page: + assert( pPage->nCell>0 || CORRUPT_DB ); rc = defragmentPage(pPage); if( rc ) return rc; top = get2byteNotZero(&data[hdr+5]); @@ -1287,90 +1379,100 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ /* ** Return a section of the pPage->aData to the freelist. -** The first byte of the new free block is pPage->aDisk[start] -** and the size of the block is "size" bytes. +** The first byte of the new free block is pPage->aData[iStart] +** and the size of the block is iSize bytes. ** -** Most of the effort here is involved in coalesing adjacent -** free blocks into a single big free block. +** Adjacent freeblocks are coalesced. +** +** Note that even though the freeblock list was checked by btreeInitPage(), +** that routine will not detect overlap between cells or freeblocks. Nor +** does it detect cells or freeblocks that encrouch into the reserved bytes +** at the end of the page. So do additional corruption checks inside this +** routine and return SQLITE_CORRUPT if any problems are found. */ -static int freeSpace(MemPage *pPage, int start, int size){ - int addr, pbegin, hdr; - int iLast; /* Largest possible freeblock offset */ - unsigned char *data = pPage->aData; +static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ + u16 iPtr; /* Address of ptr to next freeblock */ + u16 iFreeBlk; /* Address of the next freeblock */ + u8 hdr; /* Page header size. 0 or 100 */ + u8 nFrag = 0; /* Reduction in fragmentation */ + u16 iOrigSize = iSize; /* Original value of iSize */ + u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */ + u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ + unsigned char *data = pPage->aData; /* Page content */ assert( pPage->pBt!=0 ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); - assert( start>=pPage->hdrOffset+6+pPage->childPtrSize ); - assert( (start + size) <= (int)pPage->pBt->usableSize ); + assert( iStart>=pPage->hdrOffset+6+pPage->childPtrSize ); + assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - assert( size>=0 ); /* Minimum cell size is 4 */ + assert( iSize>=4 ); /* Minimum cell size is 4 */ + assert( iStart<=iLast ); + /* Overwrite deleted information with zeros when the secure_delete + ** option is enabled */ if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){ - /* Overwrite deleted information with zeros when the secure_delete - ** option is enabled */ - memset(&data[start], 0, size); + memset(&data[iStart], 0, iSize); } - /* Add the space back into the linked list of freeblocks. Note that - ** even though the freeblock list was checked by btreeInitPage(), - ** btreeInitPage() did not detect overlapping cells or - ** freeblocks that overlapped cells. Nor does it detect when the - ** cell content area exceeds the value in the page header. If these - ** situations arise, then subsequent insert operations might corrupt - ** the freelist. So we do need to check for corruption while scanning - ** the freelist. + /* The list of freeblocks must be in ascending order. Find the + ** spot on the list where iStart should be inserted. */ hdr = pPage->hdrOffset; - addr = hdr + 1; - iLast = pPage->pBt->usableSize - 4; - assert( start<=iLast ); - while( (pbegin = get2byte(&data[addr]))0 ){ - if( pbegin0 && iFreeBlkiLast ){ - return SQLITE_CORRUPT_BKPT; - } - assert( pbegin>addr || pbegin==0 ); - put2byte(&data[addr], start); - put2byte(&data[start], pbegin); - put2byte(&data[start+2], size); - pPage->nFree = pPage->nFree + (u16)size; - - /* Coalesce adjacent free blocks */ - addr = hdr + 1; - while( (pbegin = get2byte(&data[addr]))>0 ){ - int pnext, psize, x; - assert( pbegin>addr ); - assert( pbegin <= (int)pPage->pBt->usableSize-4 ); - pnext = get2byte(&data[pbegin]); - psize = get2byte(&data[pbegin+2]); - if( pbegin + psize + 3 >= pnext && pnext>0 ){ - int frag = pnext - (pbegin+psize); - if( (frag<0) || (frag>(int)data[hdr+7]) ){ - return SQLITE_CORRUPT_BKPT; + if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT; + assert( iFreeBlk>iPtr || iFreeBlk==0 ); + + /* At this point: + ** iFreeBlk: First freeblock after iStart, or zero if none + ** iPtr: The address of a pointer iFreeBlk + ** + ** Check to see if iFreeBlk should be coalesced onto the end of iStart. + */ + if( iFreeBlk && iEnd+3>=iFreeBlk ){ + nFrag = iFreeBlk - iEnd; + if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT; + iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); + iSize = iEnd - iStart; + iFreeBlk = get2byte(&data[iFreeBlk]); + } + + /* If iPtr is another freeblock (that is, if iPtr is not the freelist + ** pointer in the page header) then check to see if iStart should be + ** coalesced onto the end of iPtr. + */ + if( iPtr>hdr+1 ){ + int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); + if( iPtrEnd+3>=iStart ){ + if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT; + nFrag += iStart - iPtrEnd; + iSize = iEnd - iPtr; + iStart = iPtr; } - data[hdr+7] -= (u8)frag; - x = get2byte(&data[pnext]); - put2byte(&data[pbegin], x); - x = pnext + get2byte(&data[pnext+2]) - pbegin; - put2byte(&data[pbegin+2], x); - }else{ - addr = pbegin; } + if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT; + data[hdr+7] -= nFrag; } - - /* If the cell content area begins with a freeblock, remove it. */ - if( data[hdr+1]==data[hdr+5] && data[hdr+2]==data[hdr+6] ){ - int top; - pbegin = get2byte(&data[hdr+1]); - memcpy(&data[hdr+1], &data[pbegin], 2); - top = get2byte(&data[hdr+5]) + get2byte(&data[pbegin+2]); - put2byte(&data[hdr+5], top); + if( iStart==get2byte(&data[hdr+5]) ){ + /* The new freeblock is at the beginning of the cell content area, + ** so just extend the cell content area rather than create another + ** freelist entry */ + if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_BKPT; + put2byte(&data[hdr+1], iFreeBlk); + put2byte(&data[hdr+5], iEnd); + }else{ + /* Insert the new freeblock into the freelist */ + put2byte(&data[iPtr], iStart); + put2byte(&data[iStart], iFreeBlk); + put2byte(&data[iStart+2], iSize); } - assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + pPage->nFree += iOrigSize; return SQLITE_OK; } @@ -1396,16 +1498,32 @@ static int decodeFlags(MemPage *pPage, int flagByte){ pPage->childPtrSize = 4-4*pPage->leaf; pBt = pPage->pBt; if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){ + /* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior + ** table b-tree page. */ + assert( (PTF_LEAFDATA|PTF_INTKEY)==5 ); + /* EVIDENCE-OF: R-20501-61796 A value of 13 means the page is a leaf + ** table b-tree page. */ + assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 ); pPage->intKey = 1; - pPage->hasData = pPage->leaf; + pPage->intKeyLeaf = pPage->leaf; + pPage->noPayload = !pPage->leaf; pPage->maxLocal = pBt->maxLeaf; pPage->minLocal = pBt->minLeaf; }else if( flagByte==PTF_ZERODATA ){ + /* EVIDENCE-OF: R-27225-53936 A value of 2 means the page is an interior + ** index b-tree page. */ + assert( (PTF_ZERODATA)==2 ); + /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf + ** index b-tree page. */ + assert( (PTF_ZERODATA|PTF_LEAF)==10 ); pPage->intKey = 0; - pPage->hasData = 0; + pPage->intKeyLeaf = 0; + pPage->noPayload = 0; pPage->maxLocal = pBt->maxLocal; pPage->minLocal = pBt->minLocal; }else{ + /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is + ** an error. */ return SQLITE_CORRUPT_BKPT; } pPage->max1bytePayload = pBt->max1bytePayload; @@ -1445,21 +1563,33 @@ static int btreeInitPage(MemPage *pPage){ hdr = pPage->hdrOffset; data = pPage->aData; + /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating + ** the b-tree page type. */ if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT; assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); pPage->nOverflow = 0; usableSize = pBt->usableSize; - pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf; + pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize; pPage->aDataEnd = &data[usableSize]; pPage->aCellIdx = &data[cellOffset]; + /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates + ** the start of the cell content area. A zero value for this integer is + ** interpreted as 65536. */ top = get2byteNotZero(&data[hdr+5]); + /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the + ** number of cells on the page. */ pPage->nCell = get2byte(&data[hdr+3]); if( pPage->nCell>MX_CELL(pBt) ){ /* To many cells for a single page. The page must be corrupt */ return SQLITE_CORRUPT_BKPT; } testcase( pPage->nCell==MX_CELL(pBt) ); + /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only + ** possible for a root page of a table that contains no rows) then the + ** offset to the cell content area will equal the page size minus the + ** bytes of reserved space. */ + assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB ); /* A malformed database page might cause us to read past the end ** of page when parsing a cell. @@ -1493,13 +1623,20 @@ static int btreeInitPage(MemPage *pPage){ } #endif - /* Compute the total free space on the page */ + /* Compute the total free space on the page + ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the + ** start of the first freeblock on the page, or is zero if there are no + ** freeblocks. */ pc = get2byte(&data[hdr+1]); - nFree = data[hdr+7] + top; + nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */ while( pc>0 ){ u16 next, size; if( pciCellLast ){ - /* Start of free block is off the page */ + /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will + ** always be at least one cell before the first freeblock. + ** + ** Or, the freeblock is off the end of the page + */ return SQLITE_CORRUPT_BKPT; } next = get2byte(&data[pc]); @@ -1905,6 +2042,9 @@ int sqlite3BtreeOpen( #ifdef SQLITE_SECURE_DELETE pBt->btsFlags |= BTS_SECURE_DELETE; #endif + /* EVIDENCE-OF: R-51873-39618 The page size for a database file is + ** determined by the 2-byte integer located at an offset of 16 bytes from + ** the beginning of the database file. */ pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16); if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){ @@ -1923,6 +2063,9 @@ int sqlite3BtreeOpen( #endif nReserve = 0; }else{ + /* EVIDENCE-OF: R-37497-42412 The size of the reserved region is + ** determined by the one-byte unsigned integer found at an offset of 20 + ** into the database file header. */ nReserve = zDbHeader[20]; pBt->btsFlags |= BTS_PAGESIZE_FIXED; #ifndef SQLITE_OMIT_AUTOVACUUM @@ -2057,7 +2200,8 @@ static int removeFromSharingList(BtShared *pBt){ /* ** Make sure pBt->pTmpSpace points to an allocation of -** MX_CELL_SIZE(pBt) bytes. +** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child +** pointer. */ static void allocateTempSpace(BtShared *pBt){ if( !pBt->pTmpSpace ){ @@ -2072,8 +2216,16 @@ static void allocateTempSpace(BtShared *pBt){ ** it into a database page. This is not actually a problem, but it ** does cause a valgrind error when the 1 or 2 bytes of unitialized ** data is passed to system call write(). So to avoid this error, - ** zero the first 4 bytes of temp space here. */ - if( pBt->pTmpSpace ) memset(pBt->pTmpSpace, 0, 4); + ** zero the first 4 bytes of temp space here. + ** + ** Also: Provide four bytes of initialized space before the + ** beginning of pTmpSpace as an area available to prepend the + ** left-child pointer to the beginning of a cell. + */ + if( pBt->pTmpSpace ){ + memset(pBt->pTmpSpace, 0, 8); + pBt->pTmpSpace += 4; + } } } @@ -2081,8 +2233,11 @@ static void allocateTempSpace(BtShared *pBt){ ** Free the pBt->pTmpSpace allocation */ static void freeTempSpace(BtShared *pBt){ - sqlite3PageFree( pBt->pTmpSpace); - pBt->pTmpSpace = 0; + if( pBt->pTmpSpace ){ + pBt->pTmpSpace -= 4; + sqlite3PageFree(pBt->pTmpSpace); + pBt->pTmpSpace = 0; + } } /* @@ -2108,7 +2263,7 @@ int sqlite3BtreeClose(Btree *p){ ** The call to sqlite3BtreeRollback() drops any table-locks held by ** this handle. */ - sqlite3BtreeRollback(p, SQLITE_OK); + sqlite3BtreeRollback(p, SQLITE_OK, 0); sqlite3BtreeLeave(p); /* If there are still other outstanding references to the shared-btree @@ -2420,6 +2575,9 @@ static int lockBtree(BtShared *pBt){ u32 usableSize; u8 *page1 = pPage1->aData; rc = SQLITE_NOTADB; + /* EVIDENCE-OF: R-43737-39999 Every valid SQLite database file begins + ** with the following 16 bytes (in hex): 53 51 4c 69 74 65 20 66 6f 72 6d + ** 61 74 20 33 00. */ if( memcmp(page1, zMagicHeader, 16)!=0 ){ goto page1_init_failed; } @@ -2460,15 +2618,21 @@ static int lockBtree(BtShared *pBt){ } #endif - /* The maximum embedded fraction must be exactly 25%. And the minimum - ** embedded fraction must be 12.5% for both leaf-data and non-leaf-data. + /* EVIDENCE-OF: R-15465-20813 The maximum and minimum embedded payload + ** fractions and the leaf payload fraction values must be 64, 32, and 32. + ** ** The original design allowed these amounts to vary, but as of ** version 3.6.0, we require them to be fixed. */ if( memcmp(&page1[21], "\100\040\040",3)!=0 ){ goto page1_init_failed; } + /* EVIDENCE-OF: R-51873-39618 The page size for a database file is + ** determined by the 2-byte integer located at an offset of 16 bytes from + ** the beginning of the database file. */ pageSize = (page1[16]<<8) | (page1[17]<<16); + /* EVIDENCE-OF: R-25008-21688 The size of a page is a power of two + ** between 512 and 65536 inclusive. */ if( ((pageSize-1)&pageSize)!=0 || pageSize>SQLITE_MAX_PAGE_SIZE || pageSize<=256 @@ -2476,6 +2640,13 @@ static int lockBtree(BtShared *pBt){ goto page1_init_failed; } assert( (pageSize & 7)==0 ); + /* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte + ** integer at offset 20 is the number of bytes of space at the end of + ** each page to reserve for extensions. + ** + ** EVIDENCE-OF: R-37497-42412 The size of the reserved region is + ** determined by the one-byte unsigned integer found at an offset of 20 + ** into the database file header. */ usableSize = pageSize - page1[20]; if( (u32)pageSize!=pBt->pageSize ){ /* After reading the first page of the database assuming a page size @@ -2496,6 +2667,9 @@ static int lockBtree(BtShared *pBt){ rc = SQLITE_CORRUPT_BKPT; goto page1_init_failed; } + /* EVIDENCE-OF: R-28312-64704 However, the usable size is not allowed to + ** be less than 480. In other words, if the page size is 512, then the + ** reserved space size cannot exceed 32. */ if( usableSize<480 ){ goto page1_init_failed; } @@ -2550,7 +2724,7 @@ page1_init_failed: ** false then all cursors are counted. ** ** For the purposes of this routine, a cursor is any cursor that -** is capable of reading or writing to the databse. Cursors that +** is capable of reading or writing to the database. Cursors that ** have been tripped into the CURSOR_FAULT state are not counted. */ static int countValidCursors(BtShared *pBt, int wrOnly){ @@ -2576,11 +2750,11 @@ static void unlockBtreeIfUnused(BtShared *pBt){ assert( sqlite3_mutex_held(pBt->mutex) ); assert( countValidCursors(pBt,0)==0 || pBt->inTransaction>TRANS_NONE ); if( pBt->inTransaction==TRANS_NONE && pBt->pPage1!=0 ){ - assert( pBt->pPage1->aData ); + MemPage *pPage1 = pBt->pPage1; + assert( pPage1->aData ); assert( sqlite3PagerRefcount(pBt->pPager)==1 ); - assert( pBt->pPage1->aData ); - releasePage(pBt->pPage1); pBt->pPage1 = 0; + releasePage(pPage1); } } @@ -3014,7 +3188,7 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); ** calling this function again), return SQLITE_DONE. Or, if an error ** occurs, return some other error code. ** -** More specificly, this function attempts to re-organize the database so +** More specifically, this function attempts to re-organize the database so ** that the last page of the file currently in use is no longer in use. ** ** Parameter nFin is the number of pages that this database would contain @@ -3022,7 +3196,7 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); ** ** If the bCommit parameter is non-zero, this function assumes that the ** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE -** or an error. bCommit is passed true for an auto-vacuum-on-commmit +** or an error. bCommit is passed true for an auto-vacuum-on-commit ** operation, or false for an incremental vacuum. */ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ @@ -3376,6 +3550,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){ sqlite3BtreeLeave(p); return rc; } + p->iDataVersion--; /* Compensate for pPager->iDataVersion++; */ pBt->inTransaction = TRANS_READ; btreeClearHasContent(pBt); } @@ -3401,60 +3576,91 @@ int sqlite3BtreeCommit(Btree *p){ /* ** This routine sets the state to CURSOR_FAULT and the error -** code to errCode for every cursor on BtShared that pBtree -** references. +** code to errCode for every cursor on any BtShared that pBtree +** references. Or if the writeOnly flag is set to 1, then only +** trip write cursors and leave read cursors unchanged. ** -** Every cursor is tripped, including cursors that belong -** to other database connections that happen to be sharing -** the cache with pBtree. +** Every cursor is a candidate to be tripped, including cursors +** that belong to other database connections that happen to be +** sharing the cache with pBtree. ** -** This routine gets called when a rollback occurs. -** All cursors using the same cache must be tripped -** to prevent them from trying to use the btree after -** the rollback. The rollback may have deleted tables -** or moved root pages, so it is not sufficient to -** save the state of the cursor. The cursor must be -** invalidated. +** This routine gets called when a rollback occurs. If the writeOnly +** flag is true, then only write-cursors need be tripped - read-only +** cursors save their current positions so that they may continue +** following the rollback. Or, if writeOnly is false, all cursors are +** tripped. In general, writeOnly is false if the transaction being +** rolled back modified the database schema. In this case b-tree root +** pages may be moved or deleted from the database altogether, making +** it unsafe for read cursors to continue. +** +** If the writeOnly flag is true and an error is encountered while +** saving the current position of a read-only cursor, all cursors, +** including all read-cursors are tripped. +** +** SQLITE_OK is returned if successful, or if an error occurs while +** saving a cursor position, an SQLite error code. */ -void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){ +int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ BtCursor *p; - if( pBtree==0 ) return; - sqlite3BtreeEnter(pBtree); - for(p=pBtree->pBt->pCursor; p; p=p->pNext){ - int i; - sqlite3BtreeClearCursor(p); - p->eState = CURSOR_FAULT; - p->skipNext = errCode; - for(i=0; i<=p->iPage; i++){ - releasePage(p->apPage[i]); - p->apPage[i] = 0; + int rc = SQLITE_OK; + + assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 ); + if( pBtree ){ + sqlite3BtreeEnter(pBtree); + for(p=pBtree->pBt->pCursor; p; p=p->pNext){ + int i; + if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ + if( p->eState==CURSOR_VALID ){ + rc = saveCursorPosition(p); + if( rc!=SQLITE_OK ){ + (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0); + break; + } + } + }else{ + sqlite3BtreeClearCursor(p); + p->eState = CURSOR_FAULT; + p->skipNext = errCode; + } + for(i=0; i<=p->iPage; i++){ + releasePage(p->apPage[i]); + p->apPage[i] = 0; + } } + sqlite3BtreeLeave(pBtree); } - sqlite3BtreeLeave(pBtree); + return rc; } /* -** Rollback the transaction in progress. All cursors will be -** invalided by this operation. Any attempt to use a cursor -** that was open at the beginning of this operation will result -** in an error. +** Rollback the transaction in progress. +** +** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). +** Only write cursors are tripped if writeOnly is true but all cursors are +** tripped if writeOnly is false. Any attempt to use +** a tripped cursor will result in an error. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ -int sqlite3BtreeRollback(Btree *p, int tripCode){ +int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ int rc; BtShared *pBt = p->pBt; MemPage *pPage1; + assert( writeOnly==1 || writeOnly==0 ); + assert( tripCode==SQLITE_ABORT_ROLLBACK || tripCode==SQLITE_OK ); sqlite3BtreeEnter(p); if( tripCode==SQLITE_OK ){ rc = tripCode = saveAllCursors(pBt, 0, 0); + if( rc ) writeOnly = 0; }else{ rc = SQLITE_OK; } if( tripCode ){ - sqlite3BtreeTripAllCursors(p, tripCode); + int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); + assert( rc==SQLITE_OK || (writeOnly==0 && rc2==SQLITE_OK) ); + if( rc2!=SQLITE_OK ) rc = rc2; } btreeIntegrity(p); @@ -3489,7 +3695,7 @@ int sqlite3BtreeRollback(Btree *p, int tripCode){ } /* -** Start a statement subtransaction. The subtransaction can can be rolled +** Start a statement subtransaction. The subtransaction can be rolled ** back independently of the main transaction. You must start a transaction ** before starting a subtransaction. The subtransaction is ended automatically ** if the main transaction commits or rolls back. @@ -3621,6 +3827,10 @@ static int btreeCursor( if( NEVER(wrFlag && (pBt->btsFlags & BTS_READ_ONLY)!=0) ){ return SQLITE_READONLY; } + if( wrFlag ){ + allocateTempSpace(pBt); + if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM; + } if( iTable==1 && btreePagecount(pBt)==0 ){ assert( wrFlag==0 ); iTable = 0; @@ -3704,7 +3914,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ releasePage(pCur->apPage[i]); } unlockBtreeIfUnused(pBt); - sqlite3DbFree(pBtree->db, pCur->aOverflow); + sqlite3_free(pCur->aOverflow); /* sqlite3_free(pCur); */ sqlite3BtreeLeave(pBtree); } @@ -3723,7 +3933,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ ** compiler to crash when getCellInfo() is implemented as a macro. ** But there is a measureable speed advantage to using the macro on gcc ** (when less compiler optimizations like -Os or -O0 are used and the -** compiler is not doing agressive inlining.) So we use a real function +** compiler is not doing aggressive inlining.) So we use a real function ** for MSVC and a macro for everything else. Ticket #2457. */ #ifndef NDEBUG @@ -3785,13 +3995,9 @@ int sqlite3BtreeCursorIsValid(BtCursor *pCur){ */ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ assert( cursorHoldsMutex(pCur) ); - assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); - if( pCur->eState!=CURSOR_VALID ){ - *pSize = 0; - }else{ - getCellInfo(pCur); - *pSize = pCur->info.nKey; - } + assert( pCur->eState==CURSOR_VALID ); + getCellInfo(pCur); + *pSize = pCur->info.nKey; return SQLITE_OK; } @@ -3810,8 +4016,9 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); + assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 ); getCellInfo(pCur); - *pSize = pCur->info.nData; + *pSize = pCur->info.nPayload; return SQLITE_OK; } @@ -3940,7 +4147,7 @@ static int copyPayload( ** ** If the current cursor entry uses one or more overflow pages and the ** eOp argument is not 2, this function may allocate space for and lazily -** popluates the overflow page-list cache array (BtCursor.aOverflow). +** populates the overflow page-list cache array (BtCursor.aOverflow). ** Subsequent calls use this cache to make seeking to the supplied offset ** more efficient. ** @@ -3962,30 +4169,28 @@ static int accessPayload( ){ unsigned char *aPayload; int rc = SQLITE_OK; - u32 nKey; int iIdx = 0; MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ #ifdef SQLITE_DIRECT_OVERFLOW_READ - int bEnd; /* True if reading to end of data */ + unsigned char * const pBufStart = pBuf; + int bEnd; /* True if reading to end of data */ #endif assert( pPage ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->aiIdx[pCur->iPage]nCell ); assert( cursorHoldsMutex(pCur) ); - assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */ + assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */ getCellInfo(pCur); - aPayload = pCur->info.pCell + pCur->info.nHeader; - nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey); + aPayload = pCur->info.pPayload; #ifdef SQLITE_DIRECT_OVERFLOW_READ - bEnd = (offset+amt==nKey+pCur->info.nData); + bEnd = offset+amt==pCur->info.nPayload; #endif + assert( offset+amt <= pCur->info.nPayload ); - if( NEVER(offset+amt > nKey+pCur->info.nData) - || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] - ){ + if( &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){ /* Trying to read or write past the end of the data is an error */ return SQLITE_CORRUPT_BKPT; } @@ -4004,6 +4209,7 @@ static int accessPayload( offset -= pCur->info.nLocal; } + if( rc==SQLITE_OK && amt>0 ){ const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */ Pgno nextPage; @@ -4021,8 +4227,8 @@ static int accessPayload( if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; if( nOvfl>pCur->nOvflAlloc ){ - Pgno *aNew = (Pgno*)sqlite3DbRealloc( - pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno) + Pgno *aNew = (Pgno*)sqlite3Realloc( + pCur->aOverflow, nOvfl*2*sizeof(Pgno) ); if( aNew==0 ){ rc = SQLITE_NOMEM; @@ -4041,7 +4247,9 @@ static int accessPayload( ** entry for the first required overflow page is valid, skip ** directly to it. */ - if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){ + if( (pCur->curFlags & BTCF_ValidOvfl)!=0 + && pCur->aOverflow[offset/ovflSize] + ){ iIdx = (offset/ovflSize); nextPage = pCur->aOverflow[iIdx]; offset = (offset%ovflSize); @@ -4067,6 +4275,7 @@ static int accessPayload( */ assert( eOp!=2 ); assert( pCur->curFlags & BTCF_ValidOvfl ); + assert( pCur->pBtree->db==pBt->db ); if( pCur->aOverflow[iIdx+1] ){ nextPage = pCur->aOverflow[iIdx+1]; }else{ @@ -4094,6 +4303,7 @@ static int accessPayload( ** 4) there is no open write-transaction, and ** 5) the database is not a WAL database, ** 6) all data from the page is being read. + ** 7) at least 4 bytes have already been read into the output buffer ** ** then data can be read directly from the database file into the ** output buffer, bypassing the page-cache altogether. This speeds @@ -4105,9 +4315,11 @@ static int accessPayload( && pBt->inTransaction==TRANS_READ /* (4) */ && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */ && pBt->pPage1->aData[19]==0x01 /* (5) */ + && &pBuf[-4]>=pBufStart /* (7) */ ){ u8 aSave[4]; u8 *aWrite = &pBuf[-4]; + assert( aWrite>=pBufStart ); /* hence (7) */ memcpy(aSave, aWrite, 4); rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1)); nextPage = get4byte(aWrite); @@ -4142,7 +4354,7 @@ static int accessPayload( /* ** Read part of the key associated with cursor pCur. Exactly -** "amt" bytes will be transfered into pBuf[]. The transfer +** "amt" bytes will be transferred into pBuf[]. The transfer ** begins at "offset". ** ** The caller must ensure that pCur is pointing to a valid row @@ -4219,7 +4431,7 @@ static const void *fetchPayload( assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); assert( pCur->info.nSize>0 ); *pAmt = pCur->info.nLocal; - return (void*)(pCur->info.pCell + pCur->info.nHeader); + return (void*)pCur->info.pPayload; } @@ -4462,17 +4674,16 @@ static int moveToRightmost(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ + while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); pCur->aiIdx[pCur->iPage] = pPage->nCell; rc = moveToChild(pCur, pgno); + if( rc ) return rc; } - if( rc==SQLITE_OK ){ - pCur->aiIdx[pCur->iPage] = pPage->nCell-1; - pCur->info.nSize = 0; - pCur->curFlags &= ~BTCF_ValidNKey; - } - return rc; + pCur->aiIdx[pCur->iPage] = pPage->nCell-1; + assert( pCur->info.nSize==0 ); + assert( (pCur->curFlags & BTCF_ValidNKey)==0 ); + return SQLITE_OK; } /* Move the cursor to the first entry in the table. Return SQLITE_OK @@ -4603,7 +4814,7 @@ int sqlite3BtreeMovetoUnpacked( if( pIdxKey ){ xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); - pIdxKey->isCorrupt = 0; + pIdxKey->errCode = 0; assert( pIdxKey->default_rc==1 || pIdxKey->default_rc==0 || pIdxKey->default_rc==-1 @@ -4648,7 +4859,7 @@ int sqlite3BtreeMovetoUnpacked( for(;;){ i64 nCellKey; pCell = findCell(pPage, idx) + pPage->childPtrSize; - if( pPage->hasData ){ + if( pPage->intKeyLeaf ){ while( 0x80 <= *(pCell++) ){ if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT; } @@ -4696,14 +4907,14 @@ int sqlite3BtreeMovetoUnpacked( ** single byte varint and the record fits entirely on the main ** b-tree page. */ testcase( pCell+nCell+1==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey, 0); + c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ testcase( pCell+nCell+2==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey, 0); + c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* The record flows over onto one or more overflow pages. In ** this case the whole cell needs to be parsed, a buffer allocated @@ -4724,10 +4935,13 @@ int sqlite3BtreeMovetoUnpacked( sqlite3_free(pCellKey); goto moveto_finish; } - c = xRecordCompare(nCell, pCellKey, pIdxKey, 0); + c = xRecordCompare(nCell, pCellKey, pIdxKey); sqlite3_free(pCellKey); } - assert( pIdxKey->isCorrupt==0 || c==0 ); + assert( + (pIdxKey->errCode!=SQLITE_CORRUPT || c==0) + && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed) + ); if( c<0 ){ lwr = idx+1; }else if( c>0 ){ @@ -4737,7 +4951,7 @@ int sqlite3BtreeMovetoUnpacked( *pRes = 0; rc = SQLITE_OK; pCur->aiIdx[pCur->iPage] = (u16)idx; - if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT; + if( pIdxKey->errCode ) rc = SQLITE_CORRUPT; goto moveto_finish; } if( lwr>upr ) break; @@ -4792,6 +5006,12 @@ int sqlite3BtreeEof(BtCursor *pCur){ ** was already pointing to the last entry in the database before ** this routine was called, then set *pRes=1. ** +** The main entry point is sqlite3BtreeNext(). That routine is optimized +** for the common case of merely incrementing the cell counter BtCursor.aiIdx +** to the next cell on the current page. The (slower) btreeNext() helper +** routine is called when it is necessary to move to a different page or +** to restore the cursor. +** ** The calling function will set *pRes to 0 or 1. The initial *pRes value ** will be 1 if the cursor being stepped corresponds to an SQL index and ** if this routine could have been skipped if that SQL index had been @@ -4801,20 +5021,18 @@ int sqlite3BtreeEof(BtCursor *pCur){ ** SQLite btree implementation does not. (Note that the comdb2 btree ** implementation does use this hint, however.) */ -int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ +static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ int rc; int idx; MemPage *pPage; assert( cursorHoldsMutex(pCur) ); - assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); + assert( *pRes==0 ); if( pCur->eState!=CURSOR_VALID ){ - invalidateOverflowCache(pCur); + assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ - *pRes = 0; return rc; } if( CURSOR_INVALID==pCur->eState ){ @@ -4826,7 +5044,6 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ pCur->eState = CURSOR_VALID; if( pCur->skipNext>0 ){ pCur->skipNext = 0; - *pRes = 0; return SQLITE_OK; } pCur->skipNext = 0; @@ -4844,18 +5061,11 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ ** page into more than one b-tree structure. */ testcase( idx>pPage->nCell ); - pCur->info.nSize = 0; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); if( idx>=pPage->nCell ){ if( !pPage->leaf ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); - if( rc ){ - *pRes = 0; - return rc; - } - rc = moveToLeftmost(pCur); - *pRes = 0; - return rc; + if( rc ) return rc; + return moveToLeftmost(pCur); } do{ if( pCur->iPage==0 ){ @@ -4866,22 +5076,39 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ moveToParent(pCur); pPage = pCur->apPage[pCur->iPage]; }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell ); - *pRes = 0; if( pPage->intKey ){ - rc = sqlite3BtreeNext(pCur, pRes); + return sqlite3BtreeNext(pCur, pRes); }else{ - rc = SQLITE_OK; + return SQLITE_OK; } - return rc; } - *pRes = 0; if( pPage->leaf ){ return SQLITE_OK; + }else{ + return moveToLeftmost(pCur); + } +} +int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ + MemPage *pPage; + assert( cursorHoldsMutex(pCur) ); + assert( pRes!=0 ); + assert( *pRes==0 || *pRes==1 ); + assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); + pCur->info.nSize = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + *pRes = 0; + if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes); + pPage = pCur->apPage[pCur->iPage]; + if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){ + pCur->aiIdx[pCur->iPage]--; + return btreeNext(pCur, pRes); + } + if( pPage->leaf ){ + return SQLITE_OK; + }else{ + return moveToLeftmost(pCur); } - rc = moveToLeftmost(pCur); - return rc; } - /* ** Step the cursor to the back to the previous entry in the database. If @@ -4889,6 +5116,12 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ ** was already pointing to the first entry in the database before ** this routine was called, then set *pRes=1. ** +** The main entry point is sqlite3BtreePrevious(). That routine is optimized +** for the common case of merely decrementing the cell counter BtCursor.aiIdx +** to the previous cell on the current page. The (slower) btreePrevious() +** helper routine is called when it is necessary to move to a different page +** or to restore the cursor. +** ** The calling function will set *pRes to 0 or 1. The initial *pRes value ** will be 1 if the cursor being stepped corresponds to an SQL index and ** if this routine could have been skipped if that SQL index had been @@ -4898,22 +5131,20 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ ** SQLite btree implementation does not. (Note that the comdb2 btree ** implementation does use this hint, however.) */ -int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ +static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ int rc; MemPage *pPage; assert( cursorHoldsMutex(pCur) ); assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); + assert( *pRes==0 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); - pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl); + assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 ); + assert( pCur->info.nSize==0 ); if( pCur->eState!=CURSOR_VALID ){ - if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){ - rc = btreeRestoreCursorPosition(pCur); - if( rc!=SQLITE_OK ){ - *pRes = 0; - return rc; - } + rc = restoreCursorPosition(pCur); + if( rc!=SQLITE_OK ){ + return rc; } if( CURSOR_INVALID==pCur->eState ){ *pRes = 1; @@ -4924,7 +5155,6 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ pCur->eState = CURSOR_VALID; if( pCur->skipNext<0 ){ pCur->skipNext = 0; - *pRes = 0; return SQLITE_OK; } pCur->skipNext = 0; @@ -4936,10 +5166,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ if( !pPage->leaf ){ int idx = pCur->aiIdx[pCur->iPage]; rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); - if( rc ){ - *pRes = 0; - return rc; - } + if( rc ) return rc; rc = moveToRightmost(pCur); }else{ while( pCur->aiIdx[pCur->iPage]==0 ){ @@ -4950,8 +5177,8 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ } moveToParent(pCur); } - pCur->info.nSize = 0; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + assert( pCur->info.nSize==0 ); + assert( (pCur->curFlags & (BTCF_ValidNKey|BTCF_ValidOvfl))==0 ); pCur->aiIdx[pCur->iPage]--; pPage = pCur->apPage[pCur->iPage]; @@ -4961,9 +5188,25 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ rc = SQLITE_OK; } } - *pRes = 0; return rc; } +int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ + assert( cursorHoldsMutex(pCur) ); + assert( pRes!=0 ); + assert( *pRes==0 || *pRes==1 ); + assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); + *pRes = 0; + pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); + pCur->info.nSize = 0; + if( pCur->eState!=CURSOR_VALID + || pCur->aiIdx[pCur->iPage]==0 + || pCur->apPage[pCur->iPage]->leaf==0 + ){ + return btreePrevious(pCur, pRes); + } + pCur->aiIdx[pCur->iPage]--; + return SQLITE_OK; +} /* ** Allocate a new page from the database file. @@ -5007,6 +5250,8 @@ static int allocateBtreePage( assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) ); pPage1 = pBt->pPage1; mxPage = btreePagecount(pBt); + /* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36 + ** stores stores the total number of pages on the freelist. */ n = get4byte(&pPage1->aData[36]); testcase( n==mxPage-1 ); if( n>=mxPage ){ @@ -5053,8 +5298,14 @@ static int allocateBtreePage( do { pPrevTrunk = pTrunk; if( pPrevTrunk ){ + /* EVIDENCE-OF: R-01506-11053 The first integer on a freelist trunk page + ** is the page number of the next freelist trunk page in the list or + ** zero if this is the last freelist trunk page. */ iTrunk = get4byte(&pPrevTrunk->aData[0]); }else{ + /* EVIDENCE-OF: R-59841-13798 The 4-byte big-endian integer at offset 32 + ** stores the page number of the first page of the freelist, or zero if + ** the freelist is empty. */ iTrunk = get4byte(&pPage1->aData[32]); } testcase( iTrunk==mxPage ); @@ -5069,8 +5320,9 @@ static int allocateBtreePage( } assert( pTrunk!=0 ); assert( pTrunk->aData!=0 ); - - k = get4byte(&pTrunk->aData[4]); /* # of leaves on this trunk page */ + /* EVIDENCE-OF: R-13523-04394 The second integer on a freelist trunk page + ** is the number of leaf page pointers to follow. */ + k = get4byte(&pTrunk->aData[4]); if( k==0 && !searchList ){ /* The trunk has no leaves and the list is not being searched. ** So extract the trunk page itself and use it as the newly @@ -5204,7 +5456,7 @@ static int allocateBtreePage( memcpy(&aData[8+closest*4], &aData[4+k*4], 4); } put4byte(&aData[4], k-1); - noContent = !btreeGetHasContent(pBt, *pPgno) ? PAGER_GET_NOCONTENT : 0; + noContent = !btreeGetHasContent(pBt, *pPgno)? PAGER_GET_NOCONTENT : 0; rc = btreeGetPage(pBt, *pPgno, ppPage, noContent); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite((*ppPage)->pDbPage); @@ -5237,7 +5489,7 @@ static int allocateBtreePage( ** here are confined to those pages that lie between the end of the ** database image and the end of the database file. */ - int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate)) ? PAGER_GET_NOCONTENT : 0; + int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate))? PAGER_GET_NOCONTENT:0; rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); if( rc ) return rc; @@ -5388,6 +5640,11 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ ** for now. At some point in the future (once everyone has upgraded ** to 3.6.0 or later) we should consider fixing the conditional above ** to read "usableSize/4-2" instead of "usableSize/4-8". + ** + ** EVIDENCE-OF: R-19920-11576 However, newer versions of SQLite still + ** avoid using the last six entries in the freelist trunk page array in + ** order that database files created by newer versions of SQLite can be + ** read by older versions of SQLite. */ rc = sqlite3PagerWrite(pTrunk->pDbPage); if( rc==SQLITE_OK ){ @@ -5436,9 +5693,15 @@ static void freePage(MemPage *pPage, int *pRC){ } /* -** Free any overflow pages associated with the given Cell. +** Free any overflow pages associated with the given Cell. Write the +** local Cell size (the number of bytes on the original page, omitting +** overflow) into *pnSize. */ -static int clearCell(MemPage *pPage, unsigned char *pCell){ +static int clearCell( + MemPage *pPage, /* The page that contains the Cell */ + unsigned char *pCell, /* First byte of the Cell */ + u16 *pnSize /* Write the size of the Cell here */ +){ BtShared *pBt = pPage->pBt; CellInfo info; Pgno ovflPgno; @@ -5448,6 +5711,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); btreeParseCellPtr(pPage, pCell, &info); + *pnSize = info.nSize; if( info.iOverflow==0 ){ return SQLITE_OK; /* No overflow pages. Return without doing anything */ } @@ -5531,7 +5795,6 @@ static int fillInCell( BtShared *pBt = pPage->pBt; Pgno pgnoOvfl = 0; int nHeader; - CellInfo info; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); @@ -5541,23 +5804,17 @@ static int fillInCell( || sqlite3PagerIswriteable(pPage->pDbPage) ); /* Fill in the header. */ - nHeader = 0; - if( !pPage->leaf ){ - nHeader += 4; - } - if( pPage->hasData ){ - nHeader += putVarint32(&pCell[nHeader], nData+nZero); + nHeader = pPage->childPtrSize; + nPayload = nData + nZero; + if( pPage->intKeyLeaf ){ + nHeader += putVarint32(&pCell[nHeader], nPayload); }else{ - nData = nZero = 0; + assert( nData==0 ); + assert( nZero==0 ); } nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); - btreeParseCellPtr(pPage, pCell, &info); - assert( info.nHeader==nHeader ); - assert( info.nKey==nKey ); - assert( info.nData==(u32)(nData+nZero) ); - /* Fill in the payload */ - nPayload = nData + nZero; + /* Fill in the payload size */ if( pPage->intKey ){ pSrc = pData; nSrc = nData; @@ -5566,15 +5823,55 @@ static int fillInCell( if( NEVER(nKey>0x7fffffff || pKey==0) ){ return SQLITE_CORRUPT_BKPT; } - nPayload += (int)nKey; + nPayload = (int)nKey; pSrc = pKey; nSrc = (int)nKey; } - *pnSize = info.nSize; - spaceLeft = info.nLocal; + if( nPayload<=pPage->maxLocal ){ + n = nHeader + nPayload; + testcase( n==3 ); + testcase( n==4 ); + if( n<4 ) n = 4; + *pnSize = n; + spaceLeft = nPayload; + pPrior = pCell; + }else{ + int mn = pPage->minLocal; + n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4); + testcase( n==pPage->maxLocal ); + testcase( n==pPage->maxLocal+1 ); + if( n > pPage->maxLocal ) n = mn; + spaceLeft = n; + *pnSize = n + nHeader + 4; + pPrior = &pCell[nHeader+n]; + } pPayload = &pCell[nHeader]; - pPrior = &pCell[info.iOverflow]; + /* At this point variables should be set as follows: + ** + ** nPayload Total payload size in bytes + ** pPayload Begin writing payload here + ** spaceLeft Space available at pPayload. If nPayload>spaceLeft, + ** that means content must spill into overflow pages. + ** *pnSize Size of the local cell (not counting overflow pages) + ** pPrior Where to write the pgno of the first overflow page + ** + ** Use a call to btreeParseCellPtr() to verify that the values above + ** were computed correctly. + */ +#if SQLITE_DEBUG + { + CellInfo info; + btreeParseCellPtr(pPage, pCell, &info); + assert( nHeader=(int)(info.pPayload - pCell) ); + assert( info.nKey==nKey ); + assert( *pnSize == info.nSize ); + assert( spaceLeft == info.nLocal ); + assert( pPrior == &pCell[info.iOverflow] ); + } +#endif + + /* Write the payload into the local Cell and any extra into overflow pages */ while( nPayload>0 ){ if( spaceLeft==0 ){ #ifndef SQLITE_OMIT_AUTOVACUUM @@ -5699,9 +5996,17 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ return; } pPage->nCell--; - memmove(ptr, ptr+2, 2*(pPage->nCell - idx)); - put2byte(&data[hdr+3], pPage->nCell); - pPage->nFree += 2; + if( pPage->nCell==0 ){ + memset(&data[hdr+1], 0, 4); + data[hdr+7] = 0; + put2byte(&data[hdr+5], pPage->pBt->usableSize); + pPage->nFree = pPage->pBt->usableSize - pPage->hdrOffset + - pPage->childPtrSize - 8; + }else{ + memmove(ptr, ptr+2, 2*(pPage->nCell - idx)); + put2byte(&data[hdr+3], pPage->nCell); + pPage->nFree += 2; + } } /* @@ -5715,11 +6020,6 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. -** -** If nSkip is non-zero, then do not copy the first nSkip bytes of the -** cell. The caller will overwrite them after this function returns. If -** nSkip is non-zero, then pCell may not point to an invalid memory location -** (but pCell+nSkip is always valid). */ static void insertCell( MemPage *pPage, /* Page into which we are copying */ @@ -5736,7 +6036,6 @@ static void insertCell( int ins; /* Index in data[] where new cell pointer is inserted */ int cellOffset; /* Address of first cell pointer in data[] */ u8 *data; /* The content of the whole page */ - int nSkip = (iChild ? 4 : 0); if( *pRC ) return; @@ -5754,7 +6053,7 @@ static void insertCell( assert( sz==cellSizePtr(pPage, pCell) || (sz==8 && iChild>0) ); if( pPage->nOverflow || sz+2>pPage->nFree ){ if( pTemp ){ - memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip); + memcpy(pTemp, pCell, sz); pCell = pTemp; } if( iChild ){ @@ -5783,7 +6082,7 @@ static void insertCell( assert( idx+sz <= (int)pPage->pBt->usableSize ); pPage->nCell++; pPage->nFree -= (u16)(2 + sz); - memcpy(&data[idx+nSkip], pCell+nSkip, sz-nSkip); + memcpy(&data[idx], pCell, sz); if( iChild ){ put4byte(&data[idx], iChild); } @@ -5802,45 +6101,271 @@ static void insertCell( } /* -** Add a list of cells to a page. The page should be initially empty. -** The cells are guaranteed to fit on the page. +** Array apCell[] contains pointers to nCell b-tree page cells. The +** szCell[] array contains the size in bytes of each cell. This function +** replaces the current contents of page pPg with the contents of the cell +** array. +** +** Some of the cells in apCell[] may currently be stored in pPg. This +** function works around problems caused by this by making a copy of any +** such cells before overwriting the page data. +** +** The MemPage.nFree field is invalidated by this function. It is the +** responsibility of the caller to set it correctly. */ -static void assemblePage( - MemPage *pPage, /* The page to be assemblied */ - int nCell, /* The number of cells to add to this page */ - u8 **apCell, /* Pointers to cell bodies */ - u16 *aSize /* Sizes of the cells */ +static void rebuildPage( + MemPage *pPg, /* Edit this page */ + int nCell, /* Final number of cells on page */ + u8 **apCell, /* Array of cells */ + u16 *szCell /* Array of cell sizes */ ){ - int i; /* Loop counter */ - u8 *pCellptr; /* Address of next cell pointer */ - int cellbody; /* Address of next cell body */ - u8 * const data = pPage->aData; /* Pointer to data for pPage */ - const int hdr = pPage->hdrOffset; /* Offset of header on pPage */ - const int nUsable = pPage->pBt->usableSize; /* Usable size of page */ + const int hdr = pPg->hdrOffset; /* Offset of header on pPg */ + u8 * const aData = pPg->aData; /* Pointer to data for pPg */ + const int usableSize = pPg->pBt->usableSize; + u8 * const pEnd = &aData[usableSize]; + int i; + u8 *pCellptr = pPg->aCellIdx; + u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); + u8 *pData; - assert( pPage->nOverflow==0 ); - assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - assert( nCell>=0 && nCell<=(int)MX_CELL(pPage->pBt) - && (int)MX_CELL(pPage->pBt)<=10921); - assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + i = get2byte(&aData[hdr+5]); + memcpy(&pTmp[i], &aData[i], usableSize - i); - /* Check that the page has just been zeroed by zeroPage() */ - assert( pPage->nCell==0 ); - assert( get2byteNotZero(&data[hdr+5])==nUsable ); - - pCellptr = &pPage->aCellIdx[nCell*2]; - cellbody = nUsable; - for(i=nCell-1; i>=0; i--){ - u16 sz = aSize[i]; - pCellptr -= 2; - cellbody -= sz; - put2byte(pCellptr, cellbody); - memcpy(&data[cellbody], apCell[i], sz); + pData = pEnd; + for(i=0; iaData && pCellnFree -= (nCell*2 + nUsable - cellbody); - pPage->nCell = (u16)nCell; + + /* The pPg->nFree field is now set incorrectly. The caller will fix it. */ + pPg->nCell = nCell; + pPg->nOverflow = 0; + + put2byte(&aData[hdr+1], 0); + put2byte(&aData[hdr+3], pPg->nCell); + put2byte(&aData[hdr+5], pData - aData); + aData[hdr+7] = 0x00; +} + +/* +** Array apCell[] contains nCell pointers to b-tree cells. Array szCell +** contains the size in bytes of each such cell. This function attempts to +** add the cells stored in the array to page pPg. If it cannot (because +** the page needs to be defragmented before the cells will fit), non-zero +** is returned. Otherwise, if the cells are added successfully, zero is +** returned. +** +** Argument pCellptr points to the first entry in the cell-pointer array +** (part of page pPg) to populate. After cell apCell[0] is written to the +** page body, a 16-bit offset is written to pCellptr. And so on, for each +** cell in the array. It is the responsibility of the caller to ensure +** that it is safe to overwrite this part of the cell-pointer array. +** +** When this function is called, *ppData points to the start of the +** content area on page pPg. If the size of the content area is extended, +** *ppData is updated to point to the new start of the content area +** before returning. +** +** Finally, argument pBegin points to the byte immediately following the +** end of the space required by this page for the cell-pointer area (for +** all cells - not just those inserted by the current call). If the content +** area must be extended to before this point in order to accomodate all +** cells in apCell[], then the cells do not fit and non-zero is returned. +*/ +static int pageInsertArray( + MemPage *pPg, /* Page to add cells to */ + u8 *pBegin, /* End of cell-pointer array */ + u8 **ppData, /* IN/OUT: Page content -area pointer */ + u8 *pCellptr, /* Pointer to cell-pointer area */ + int nCell, /* Number of cells to add to pPg */ + u8 **apCell, /* Array of cells */ + u16 *szCell /* Array of cell sizes */ +){ + int i; + u8 *aData = pPg->aData; + u8 *pData = *ppData; + const int bFreelist = aData[1] || aData[2]; + assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */ + for(i=0; iaData; + u8 * const pEnd = &aData[pPg->pBt->usableSize]; + u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize]; + int nRet = 0; + int i; + u8 *pFree = 0; + int szFree = 0; + + for(i=0; i=pStart && pCellaData && (pFree - aData)<65536 ); + freeSpace(pPg, (u16)(pFree - aData), szFree); + } + pFree = pCell; + szFree = sz; + if( pFree+sz>pEnd ) return 0; + }else{ + pFree = pCell; + szFree += sz; + } + nRet++; + } + } + if( pFree ){ + assert( pFree>aData && (pFree - aData)<65536 ); + freeSpace(pPg, (u16)(pFree - aData), szFree); + } + return nRet; +} + +/* +** apCell[] and szCell[] contains pointers to and sizes of all cells in the +** pages being balanced. The current page, pPg, has pPg->nCell cells starting +** with apCell[iOld]. After balancing, this page should hold nNew cells +** starting at apCell[iNew]. +** +** This routine makes the necessary adjustments to pPg so that it contains +** the correct cells after being balanced. +** +** The pPg->nFree field is invalid when this function returns. It is the +** responsibility of the caller to set it correctly. +*/ +static void editPage( + MemPage *pPg, /* Edit this page */ + int iOld, /* Index of first cell currently on page */ + int iNew, /* Index of new first cell on page */ + int nNew, /* Final number of cells on page */ + u8 **apCell, /* Array of cells */ + u16 *szCell /* Array of cell sizes */ +){ + u8 * const aData = pPg->aData; + const int hdr = pPg->hdrOffset; + u8 *pBegin = &pPg->aCellIdx[nNew * 2]; + int nCell = pPg->nCell; /* Cells stored on pPg */ + u8 *pData; + u8 *pCellptr; + int i; + int iOldEnd = iOld + pPg->nCell + pPg->nOverflow; + int iNewEnd = iNew + nNew; + +#ifdef SQLITE_DEBUG + u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); + memcpy(pTmp, aData, pPg->pBt->usableSize); +#endif + + /* Remove cells from the start and end of the page */ + if( iOldaCellIdx, &pPg->aCellIdx[nShift*2], nCell*2); + nCell -= nShift; + } + if( iNewEnd < iOldEnd ){ + nCell -= pageFreeArray( + pPg, iOldEnd-iNewEnd, &apCell[iNewEnd], &szCell[iNewEnd] + ); + } + + pData = &aData[get2byteNotZero(&aData[hdr+5])]; + if( pDataaCellIdx; + memmove(&pCellptr[nAdd*2], pCellptr, nCell*2); + if( pageInsertArray( + pPg, pBegin, &pData, pCellptr, + nAdd, &apCell[iNew], &szCell[iNew] + ) ) goto editpage_fail; + nCell += nAdd; + } + + /* Add any overflow cells */ + for(i=0; inOverflow; i++){ + int iCell = (iOld + pPg->aiOvfl[i]) - iNew; + if( iCell>=0 && iCellaCellIdx[iCell * 2]; + memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); + nCell++; + if( pageInsertArray( + pPg, pBegin, &pData, pCellptr, + 1, &apCell[iCell + iNew], &szCell[iCell + iNew] + ) ) goto editpage_fail; + } + } + + /* Append cells to the end of the page */ + pCellptr = &pPg->aCellIdx[nCell*2]; + if( pageInsertArray( + pPg, pBegin, &pData, pCellptr, + nNew-nCell, &apCell[iNew+nCell], &szCell[iNew+nCell] + ) ) goto editpage_fail; + + pPg->nCell = nNew; + pPg->nOverflow = 0; + + put2byte(&aData[hdr+3], pPg->nCell); + put2byte(&aData[hdr+5], pData - aData); + +#ifdef SQLITE_DEBUG + for(i=0; iaCellIdx[i*2]); + if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){ + pCell = &pTmp[pCell - aData]; + } + assert( 0==memcmp(pCell, &aData[iOff], szCell[i+iNew]) ); + } +#endif + + return; + editpage_fail: + /* Unable to edit this page. Rebuild it from scratch instead. */ + rebuildPage(pPg, nNew, &apCell[iNew], &szCell[iNew]); } /* @@ -5894,7 +6419,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ assert( pPage->nOverflow==1 ); /* This error condition is now caught prior to reaching this function */ - if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; + if( NEVER(pPage->nCell==0) ) return SQLITE_CORRUPT_BKPT; /* Allocate a new page. This page will become the right-sibling of ** pPage. Make the parent page writable, so that the new divider cell @@ -5912,7 +6437,8 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ assert( sqlite3PagerIswriteable(pNew->pDbPage) ); assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) ); zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF); - assemblePage(pNew, 1, &pCell, &szCell); + rebuildPage(pNew, 1, &pCell, &szCell); + pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell; /* If this is an auto-vacuum database, update the pointer map ** with entries for the new page, and any pointer from the @@ -6131,17 +6657,22 @@ static int balance_nonroot( int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */ int szScratch; /* Size of scratch memory requested */ MemPage *apOld[NB]; /* pPage and up to two siblings */ - MemPage *apCopy[NB]; /* Private copies of apOld[] pages */ MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */ u8 *pRight; /* Location in parent of right-sibling pointer */ u8 *apDiv[NB-1]; /* Divider cells in pParent */ int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */ - int szNew[NB+2]; /* Combined size of cells place on i-th page */ + int cntOld[NB+2]; /* Old index in aCell[] after i-th page */ + int szNew[NB+2]; /* Combined size of cells placed on i-th page */ u8 **apCell = 0; /* All cells begin balanced */ u16 *szCell; /* Local size of all cells in apCell[] */ u8 *aSpace1; /* Space for copies of dividers cells */ Pgno pgno; /* Temp var to store a page number in */ + u8 abDone[NB+2]; /* True after i'th new page is populated */ + Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */ + Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */ + u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */ + memset(abDone, 0, sizeof(abDone)); pBt = pParent->pBt; assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); @@ -6250,12 +6781,14 @@ static int balance_nonroot( /* ** Allocate space for memory structures */ - k = pBt->pageSize + ROUND8(sizeof(MemPage)); szScratch = nMaxCells*sizeof(u8*) /* apCell */ + nMaxCells*sizeof(u16) /* szCell */ - + pBt->pageSize /* aSpace1 */ - + k*nOld; /* Page copies (apCopy) */ + + pBt->pageSize; /* aSpace1 */ + + /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer + ** that is more than 6 times the database page size. */ + assert( szScratch<=6*(int)pBt->pageSize ); apCell = sqlite3ScratchMalloc( szScratch ); if( apCell==0 ){ rc = SQLITE_NOMEM; @@ -6268,8 +6801,8 @@ static int balance_nonroot( /* ** Load pointers to all cells on sibling pages and the divider cells ** into the local apCell[] array. Make copies of the divider cells - ** into space obtained from aSpace1[] and remove the divider cells - ** from pParent. + ** into space obtained from aSpace1[]. The divider cells have already + ** been removed from pParent. ** ** If the siblings are on leaf pages, then the child pointers of the ** divider cells are stripped from the cells before they are copied @@ -6282,18 +6815,10 @@ static int balance_nonroot( ** leafData: 1 if pPage holds key+data and pParent holds only keys. */ leafCorrection = apOld[0]->leaf*4; - leafData = apOld[0]->hasData; + leafData = apOld[0]->intKeyLeaf; for(i=0; ipageSize + k*i]; - memcpy(pOld, apOld[i], sizeof(MemPage)); - pOld->aData = (void*)&pOld[1]; - memcpy(pOld->aData, apOld[i]->aData, pBt->pageSize); + MemPage *pOld = apOld[i]; limit = pOld->nCell+pOld->nOverflow; if( pOld->nOverflow>0 ){ @@ -6314,6 +6839,7 @@ static int balance_nonroot( nCell++; } } + cntOld[i] = nCell; if( i usableSpace ){ - szNew[k] = subtotal - szCell[i]; + szNew[k] = subtotal - szCell[i] - 2; cntNew[k] = i; if( leafData ){ i--; } subtotal = 0; @@ -6379,9 +6909,10 @@ static int balance_nonroot( /* ** The packing computed by the previous block is biased toward the siblings - ** on the left side. The left siblings are always nearly full, while the - ** right-most sibling might be nearly empty. This block of code attempts - ** to adjust the packing of siblings to get a better balance. + ** on the left side (siblings with smaller keys). The left siblings are + ** always nearly full, while the right-most sibling might be nearly empty. + ** The next block of code attempts to adjust the packing of siblings to + ** get a better balance. ** ** This adjustment is more than an optimization. The packing above might ** be so out of balance as to be illegal. For example, the right-most @@ -6410,22 +6941,18 @@ static int balance_nonroot( szNew[i-1] = szLeft; } - /* Either we found one or more cells (cntnew[0])>0) or pPage is - ** a virtual root page. A virtual root page is when the real root - ** page is page 1 and we are the only child of that page. - ** - ** UPDATE: The assert() below is not necessarily true if the database - ** file is corrupt. The corruption will be detected and reported later - ** in this procedure so there is no need to act upon it now. + /* Sanity check: For a non-corrupt database file one of the follwing + ** must be true: + ** (1) We found one or more cells (cntNew[0])>0), or + ** (2) pPage is a virtual root page. A virtual root page is when + ** the real root page is page 1 and we are the only child of + ** that page. */ -#if 0 - assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) ); -#endif - - TRACE(("BALANCE: old: %d %d %d ", - apOld[0]->pgno, - nOld>=2 ? apOld[1]->pgno : 0, - nOld>=3 ? apOld[2]->pgno : 0 + assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB); + TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\n", + apOld[0]->pgno, apOld[0]->nCell, + nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0, + nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0 )); /* @@ -6448,8 +6975,10 @@ static int balance_nonroot( assert( i>0 ); rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0); if( rc ) goto balance_cleanup; + zeroPage(pNew, pageFlags); apNew[i] = pNew; nNew++; + cntOld[i] = nCell; /* Set the pointer-map entry for the new sibling page. */ if( ISAUTOVACUUM ){ @@ -6461,135 +6990,247 @@ static int balance_nonroot( } } - /* Free any old pages that were not reused as new pages. - */ - while( ipgno; - int minI = i; - for(j=i+1; jpgno<(unsigned)minV ){ - minI = j; - minV = apNew[j]->pgno; + for(i=0; ipgno; + aPgFlags[i] = apNew[i]->pDbPage->flags; + for(j=0; ji ){ - MemPage *pT; - pT = apNew[i]; - apNew[i] = apNew[minI]; - apNew[minI] = pT; + } + for(i=0; ii ){ + sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0); + } + sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]); + apNew[i]->pgno = pgno; } } - TRACE(("new: %d(%d) %d(%d) %d(%d) %d(%d) %d(%d)\n", - apNew[0]->pgno, szNew[0], + + TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) " + "%d(%d nc=%d) %d(%d nc=%d)\n", + apNew[0]->pgno, szNew[0], cntNew[0], nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0, + nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0, nNew>=3 ? apNew[2]->pgno : 0, nNew>=3 ? szNew[2] : 0, + nNew>=3 ? cntNew[2] - cntNew[1] - !leafData : 0, nNew>=4 ? apNew[3]->pgno : 0, nNew>=4 ? szNew[3] : 0, - nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0)); + nNew>=4 ? cntNew[3] - cntNew[2] - !leafData : 0, + nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0, + nNew>=5 ? cntNew[4] - cntNew[3] - !leafData : 0 + )); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); put4byte(pRight, apNew[nNew-1]->pgno); - /* - ** Evenly distribute the data in apCell[] across the new pages. - ** Insert divider cells into pParent as necessary. + /* If the sibling pages are not leaves, ensure that the right-child pointer + ** of the right-most new sibling page is set to the value that was + ** originally in the same field of the right-most old sibling page. */ + if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){ + MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1]; + memcpy(&apNew[nNew-1]->aData[8], &pOld->aData[8], 4); + } + + /* Make any required updates to pointer map entries associated with + ** cells stored on sibling pages following the balance operation. Pointer + ** map entries associated with divider cells are set by the insertCell() + ** routine. The associated pointer map entries are: + ** + ** a) if the cell contains a reference to an overflow chain, the + ** entry associated with the first page in the overflow chain, and + ** + ** b) if the sibling pages are not leaves, the child page associated + ** with the cell. + ** + ** If the sibling pages are not leaves, then the pointer map entry + ** associated with the right-child of each sibling may also need to be + ** updated. This happens below, after the sibling pages have been + ** populated, not here. */ - j = 0; - for(i=0; inCell>0 || (nNew==1 && cntNew[0]==0) ); - assert( pNew->nOverflow==0 ); + if( ISAUTOVACUUM ){ + MemPage *pNew = apNew[0]; + u8 *aOld = pNew->aData; + int cntOldNext = pNew->nCell + pNew->nOverflow; + int usableSize = pBt->usableSize; + int iNew = 0; + int iOld = 0; - j = cntNew[i]; + for(i=0; inCell + pOld->nOverflow + !leafData; + aOld = pOld->aData; + } + if( i==cntNew[iNew] ){ + pNew = apNew[++iNew]; + if( !leafData ) continue; + } - /* If the sibling page assembled above was not the right-most sibling, - ** insert a divider cell into the parent page. - */ - assert( ileaf ){ - memcpy(&pNew->aData[8], pCell, 4); - }else if( leafData ){ - /* If the tree is a leaf-data tree, and the siblings are leaves, - ** then there is no divider cell in apCell[]. Instead, the divider - ** cell consists of the integer key for the right-most cell of - ** the sibling-page assembled above only. - */ - CellInfo info; - j--; - btreeParseCellPtr(pNew, apCell[j], &info); - pCell = pTemp; - sz = 4 + putVarint(&pCell[4], info.nKey); - pTemp = 0; - }else{ - pCell -= 4; - /* Obscure case for non-leaf-data trees: If the cell at pCell was - ** previously stored on a leaf node, and its reported size was 4 - ** bytes, then it may actually be smaller than this - ** (see btreeParseCellPtr(), 4 bytes is the minimum size of - ** any cell). But it is important to pass the correct size to - ** insertCell(), so reparse the cell now. - ** - ** Note that this can never happen in an SQLite data file, as all - ** cells are at least 4 bytes. It only happens in b-trees used - ** to evaluate "IN (SELECT ...)" and similar clauses. - */ - if( szCell[j]==4 ){ - assert(leafCorrection==4); - sz = cellSizePtr(pParent, pCell); + /* Cell pCell is destined for new sibling page pNew. Originally, it + ** was either part of sibling page iOld (possibly an overflow cell), + ** or else the divider cell to the left of sibling page iOld. So, + ** if sibling page iOld had the same page number as pNew, and if + ** pCell really was a part of sibling page iOld (not a divider or + ** overflow cell), we can skip updating the pointer map entries. */ + if( iOld>=nNew + || pNew->pgno!=aPgno[iOld] + || pCell=&aOld[usableSize] + ){ + if( !leafCorrection ){ + ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc); + } + if( szCell[i]>pNew->minLocal ){ + ptrmapPutOvflPtr(pNew, pCell, &rc); } } - iOvflSpace += sz; - assert( sz<=pBt->maxLocal+23 ); - assert( iOvflSpace <= (int)pBt->pageSize ); - insertCell(pParent, nxDiv, pCell, sz, pTemp, pNew->pgno, &rc); - if( rc!=SQLITE_OK ) goto balance_cleanup; - assert( sqlite3PagerIswriteable(pParent->pDbPage) ); - - j++; - nxDiv++; } } - assert( j==nCell ); + + /* Insert new divider cells into pParent. */ + for(i=0; ileaf ){ + memcpy(&pNew->aData[8], pCell, 4); + }else if( leafData ){ + /* If the tree is a leaf-data tree, and the siblings are leaves, + ** then there is no divider cell in apCell[]. Instead, the divider + ** cell consists of the integer key for the right-most cell of + ** the sibling-page assembled above only. + */ + CellInfo info; + j--; + btreeParseCellPtr(pNew, apCell[j], &info); + pCell = pTemp; + sz = 4 + putVarint(&pCell[4], info.nKey); + pTemp = 0; + }else{ + pCell -= 4; + /* Obscure case for non-leaf-data trees: If the cell at pCell was + ** previously stored on a leaf node, and its reported size was 4 + ** bytes, then it may actually be smaller than this + ** (see btreeParseCellPtr(), 4 bytes is the minimum size of + ** any cell). But it is important to pass the correct size to + ** insertCell(), so reparse the cell now. + ** + ** Note that this can never happen in an SQLite data file, as all + ** cells are at least 4 bytes. It only happens in b-trees used + ** to evaluate "IN (SELECT ...)" and similar clauses. + */ + if( szCell[j]==4 ){ + assert(leafCorrection==4); + sz = cellSizePtr(pParent, pCell); + } + } + iOvflSpace += sz; + assert( sz<=pBt->maxLocal+23 ); + assert( iOvflSpace <= (int)pBt->pageSize ); + insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc); + if( rc!=SQLITE_OK ) goto balance_cleanup; + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + } + + /* Now update the actual sibling pages. The order in which they are updated + ** is important, as this code needs to avoid disrupting any page from which + ** cells may still to be read. In practice, this means: + ** + ** (1) If cells are moving left (from apNew[iPg] to apNew[iPg-1]) + ** then it is not safe to update page apNew[iPg] until after + ** the left-hand sibling apNew[iPg-1] has been updated. + ** + ** (2) If cells are moving right (from apNew[iPg] to apNew[iPg+1]) + ** then it is not safe to update page apNew[iPg] until after + ** the right-hand sibling apNew[iPg+1] has been updated. + ** + ** If neither of the above apply, the page is safe to update. + ** + ** The iPg value in the following loop starts at nNew-1 goes down + ** to 0, then back up to nNew-1 again, thus making two passes over + ** the pages. On the initial downward pass, only condition (1) above + ** needs to be tested because (2) will always be true from the previous + ** step. On the upward pass, both conditions are always true, so the + ** upwards pass simply processes pages that were missed on the downward + ** pass. + */ + for(i=1-nNew; i=0 && iPg=0 /* On the upwards pass, or... */ + || cntOld[iPg-1]>=cntNew[iPg-1] /* Condition (1) is true */ + ){ + int iNew; + int iOld; + int nNewCell; + + /* Verify condition (1): If cells are moving left, update iPg + ** only after iPg-1 has already been updated. */ + assert( iPg==0 || cntOld[iPg-1]>=cntNew[iPg-1] || abDone[iPg-1] ); + + /* Verify condition (2): If cells are moving right, update iPg + ** only after iPg+1 has already been updated. */ + assert( cntNew[iPg]>=cntOld[iPg] || abDone[iPg+1] ); + + if( iPg==0 ){ + iNew = iOld = 0; + nNewCell = cntNew[0]; + }else{ + iOld = iPgnFree = usableSpace-szNew[iPg]; + assert( apNew[iPg]->nOverflow==0 ); + assert( apNew[iPg]->nCell==nNewCell ); + } + } + + /* All pages have been processed exactly once */ + assert( memcmp(abDone, "\01\01\01\01\01", nNew)==0 ); + assert( nOld>0 ); assert( nNew>0 ); - if( (pageFlags & PTF_LEAF)==0 ){ - u8 *zChild = &apCopy[nOld-1]->aData[8]; - memcpy(&apNew[nNew-1]->aData[8], zChild, 4); - } if( isRoot && pParent->nCell==0 && pParent->hdrOffset<=apNew[0]->nFree ){ /* The root page of the b-tree now contains no cells. The only sibling @@ -6602,126 +7243,50 @@ static int balance_nonroot( ** sets all pointer-map entries corresponding to database image pages ** for which the pointer is stored within the content being copied. ** - ** The second assert below verifies that the child page is defragmented - ** (it must be, as it was just reconstructed using assemblePage()). This - ** is important if the parent page happens to be page 1 of the database - ** image. */ + ** It is critical that the child page be defragmented before being + ** copied into the parent, because if the parent is page 1 then it will + ** by smaller than the child due to the database header, and so all the + ** free space needs to be up front. + */ assert( nNew==1 ); + rc = defragmentPage(apNew[0]); + testcase( rc!=SQLITE_OK ); assert( apNew[0]->nFree == - (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) + (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) + || rc!=SQLITE_OK ); copyNodeContent(apNew[0], pParent, &rc); freePage(apNew[0], &rc); - }else if( ISAUTOVACUUM ){ - /* Fix the pointer-map entries for all the cells that were shifted around. - ** There are several different types of pointer-map entries that need to - ** be dealt with by this routine. Some of these have been set already, but - ** many have not. The following is a summary: - ** - ** 1) The entries associated with new sibling pages that were not - ** siblings when this function was called. These have already - ** been set. We don't need to worry about old siblings that were - ** moved to the free-list - the freePage() code has taken care - ** of those. - ** - ** 2) The pointer-map entries associated with the first overflow - ** page in any overflow chains used by new divider cells. These - ** have also already been taken care of by the insertCell() code. - ** - ** 3) If the sibling pages are not leaves, then the child pages of - ** cells stored on the sibling pages may need to be updated. - ** - ** 4) If the sibling pages are not internal intkey nodes, then any - ** overflow pages used by these cells may need to be updated - ** (internal intkey nodes never contain pointers to overflow pages). - ** - ** 5) If the sibling pages are not leaves, then the pointer-map - ** entries for the right-child pages of each sibling may need - ** to be updated. - ** - ** Cases 1 and 2 are dealt with above by other code. The next - ** block deals with cases 3 and 4 and the one after that, case 5. Since - ** setting a pointer map entry is a relatively expensive operation, this - ** code only sets pointer map entries for child or overflow pages that have - ** actually moved between pages. */ - MemPage *pNew = apNew[0]; - MemPage *pOld = apCopy[0]; - int nOverflow = pOld->nOverflow; - int iNextOld = pOld->nCell + nOverflow; - int iOverflow = (nOverflow ? pOld->aiOvfl[0] : -1); - j = 0; /* Current 'old' sibling page */ - k = 0; /* Current 'new' sibling page */ - for(i=0; inCell + pOld->nOverflow; - if( pOld->nOverflow ){ - nOverflow = pOld->nOverflow; - iOverflow = i + !leafData + pOld->aiOvfl[0]; - } - isDivider = !leafData; - } - - assert(nOverflow>0 || iOverflowaiOvfl[0]==pOld->aiOvfl[1]-1); - assert(nOverflow<3 || pOld->aiOvfl[1]==pOld->aiOvfl[2]-1); - if( i==iOverflow ){ - isDivider = 1; - if( (--nOverflow)>0 ){ - iOverflow++; - } - } - - if( i==cntNew[k] ){ - /* Cell i is the cell immediately following the last cell on new - ** sibling page k. If the siblings are not leaf pages of an - ** intkey b-tree, then cell i is a divider cell. */ - pNew = apNew[++k]; - if( !leafData ) continue; - } - assert( jpgno!=pNew->pgno ){ - if( !leafCorrection ){ - ptrmapPut(pBt, get4byte(apCell[i]), PTRMAP_BTREE, pNew->pgno, &rc); - } - if( szCell[i]>pNew->minLocal ){ - ptrmapPutOvflPtr(pNew, apCell[i], &rc); - } - } + }else if( ISAUTOVACUUM && !leafCorrection ){ + /* Fix the pointer map entries associated with the right-child of each + ** sibling page. All other pointer map entries have already been taken + ** care of. */ + for(i=0; iaData[8]); + ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc); } + } - if( !leafCorrection ){ - for(i=0; iaData[8]); - ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc); - } - } + assert( pParent->isInit ); + TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n", + nOld, nNew, nCell)); + + /* Free any old pages that were not reused as new pages. + */ + for(i=nNew; iisInit ){ /* The ptrmapCheckPages() contains assert() statements that verify that ** all pointer map pages are set correctly. This is helpful while ** debugging. This is usually disabled because a corrupt database may ** cause an assert() statement to fail. */ ptrmapCheckPages(apNew, nNew); ptrmapCheckPages(&pParent, 1); -#endif } - - assert( pParent->isInit ); - TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n", - nOld, nNew, nCell)); +#endif /* ** Cleanup before returning. @@ -6858,7 +7423,7 @@ static int balance(BtCursor *pCur){ rc = sqlite3PagerWrite(pParent->pDbPage); if( rc==SQLITE_OK ){ #ifndef SQLITE_OMIT_QUICKBALANCE - if( pPage->hasData + if( pPage->intKeyLeaf && pPage->nOverflow==1 && pPage->aiOvfl[0]==pPage->nCell && pParent->pgno!=1 @@ -6867,7 +7432,7 @@ static int balance(BtCursor *pCur){ /* Call balance_quick() to create a new sibling of pPage on which ** to store the overflow cell. balance_quick() inserts a new cell ** into pParent, which may cause pParent overflow. If this - ** happens, the next interation of the do-loop will balance pParent + ** happens, the next iteration of the do-loop will balance pParent ** use either balance_nonroot() or balance_deeper(). Until this ** happens, the overflow cell is stored in the aBalanceQuickSpace[] ** buffer. @@ -6944,7 +7509,7 @@ static int balance(BtCursor *pCur){ ** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already ** been performed. seekResult is the search result returned (a negative ** number if pCur points at an entry that is smaller than (pKey, nKey), or -** a positive value if pCur points at an etry that is larger than +** a positive value if pCur points at an entry that is larger than ** (pKey, nKey)). ** ** If the seekResult parameter is non-zero, then the caller guarantees that @@ -6977,7 +7542,8 @@ int sqlite3BtreeInsert( } assert( cursorHoldsMutex(pCur) ); - assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE + assert( (pCur->curFlags & BTCF_WriteFlag)!=0 + && pBt->inTransaction==TRANS_WRITE && (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); @@ -7010,7 +7576,8 @@ int sqlite3BtreeInsert( /* If the cursor is currently on the last row and we are appending a ** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto() ** call */ - if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){ + if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 + && pCur->info.nKey==nKey-1 ){ loc = -1; } } @@ -7029,9 +7596,8 @@ int sqlite3BtreeInsert( pCur->pgnoRoot, nKey, nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); assert( pPage->isInit ); - allocateTempSpace(pBt); newCell = pBt->pTmpSpace; - if( newCell==0 ) return SQLITE_NOMEM; + assert( newCell!=0 ); rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew); if( rc ) goto end_insert; assert( szNew==cellSizePtr(pPage, newCell) ); @@ -7048,8 +7614,7 @@ int sqlite3BtreeInsert( if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } - szOld = cellSizePtr(pPage, oldCell); - rc = clearCell(pPage, oldCell); + rc = clearCell(pPage, oldCell, &szOld); dropCell(pPage, idx, szOld, &rc); if( rc ) goto end_insert; }else if( loc<0 && pPage->nCell>0 ){ @@ -7101,7 +7666,7 @@ end_insert: /* ** Delete the entry that the cursor is pointing to. The cursor -** is left pointing at a arbitrary location. +** is left pointing at an arbitrary location. */ int sqlite3BtreeDelete(BtCursor *pCur){ Btree *p = pCur->pBtree; @@ -7111,6 +7676,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ unsigned char *pCell; /* Pointer to cell to delete */ int iCellIdx; /* Index of cell to delete */ int iCellDepth; /* Depth of node containing pCell */ + u16 szCell; /* Size of the cell being deleted */ assert( cursorHoldsMutex(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); @@ -7159,8 +7725,8 @@ int sqlite3BtreeDelete(BtCursor *pCur){ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; - rc = clearCell(pPage, pCell); - dropCell(pPage, iCellIdx, cellSizePtr(pPage, pCell), &rc); + rc = clearCell(pPage, pCell, &szCell); + dropCell(pPage, iCellIdx, szCell, &rc); if( rc ) return rc; /* If the cell deleted was not located on a leaf page, then the cursor @@ -7177,10 +7743,8 @@ int sqlite3BtreeDelete(BtCursor *pCur){ pCell = findCell(pLeaf, pLeaf->nCell-1); nCell = cellSizePtr(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); - - allocateTempSpace(pBt); pTmp = pBt->pTmpSpace; - + assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); @@ -7392,6 +7956,7 @@ static int clearDatabasePage( unsigned char *pCell; int i; int hdr; + u16 szCell; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ @@ -7407,7 +7972,7 @@ static int clearDatabasePage( rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); if( rc ) goto cleardatabasepage_out; } - rc = clearCell(pPage, pCell); + rc = clearCell(pPage, pCell, &szCell); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ @@ -7613,6 +8178,13 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ ** The schema layer numbers meta values differently. At the schema ** layer (and the SetCookie and ReadCookie opcodes) the number of ** free pages is not visible. So Cookie[0] is the same as Meta[1]. +** +** This routine treats Meta[BTREE_DATA_VERSION] as a special case. Instead +** of reading the value out of the header, it instead loads the "DataVersion" +** from the pager. The BTREE_DATA_VERSION value is not actually stored in the +** database file. It is a number computed by the pager. But its access +** pattern is the same as header meta values, and so it is convenient to +** read it from this routine. */ void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ BtShared *pBt = p->pBt; @@ -7623,7 +8195,11 @@ void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ assert( pBt->pPage1 ); assert( idx>=0 && idx<=15 ); - *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]); + if( idx==BTREE_DATA_VERSION ){ + *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion; + }else{ + *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]); + } /* If auto-vacuum is disabled in this build and this is an auto-vacuum ** database, mark the database as read-only. */ @@ -7714,7 +8290,7 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ if( pCur->iPage==0 ){ /* All pages of the b-tree have been visited. Return successfully. */ *pnEntry = nEntry; - return SQLITE_OK; + return moveToRoot(pCur); } moveToParent(pCur); }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell ); @@ -7753,11 +8329,11 @@ Pager *sqlite3BtreePager(Btree *p){ */ static void checkAppendMsg( IntegrityCk *pCheck, - char *zMsg1, const char *zFormat, ... ){ va_list ap; + char zBuf[200]; if( !pCheck->mxErr ) return; pCheck->mxErr--; pCheck->nErr++; @@ -7765,8 +8341,9 @@ static void checkAppendMsg( if( pCheck->errMsg.nChar ){ sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1); } - if( zMsg1 ){ - sqlite3StrAccumAppendAll(&pCheck->errMsg, zMsg1); + if( pCheck->zPfx ){ + sqlite3_snprintf(sizeof(zBuf), zBuf, pCheck->zPfx, pCheck->v1, pCheck->v2); + sqlite3StrAccumAppendAll(&pCheck->errMsg, zBuf); } sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap); va_end(ap); @@ -7799,19 +8376,19 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){ /* ** Add 1 to the reference count for page iPage. If this is the second ** reference to the page, add an error message to pCheck->zErrMsg. -** Return 1 if there are 2 ore more references to the page and 0 if +** Return 1 if there are 2 or more references to the page and 0 if ** if this is the first reference to the page. ** ** Also check that the page number is in bounds. */ -static int checkRef(IntegrityCk *pCheck, Pgno iPage, char *zContext){ +static int checkRef(IntegrityCk *pCheck, Pgno iPage){ if( iPage==0 ) return 1; if( iPage>pCheck->nPage ){ - checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage); + checkAppendMsg(pCheck, "invalid page number %d", iPage); return 1; } if( getPageReferenced(pCheck, iPage) ){ - checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage); + checkAppendMsg(pCheck, "2nd reference to page %d", iPage); return 1; } setPageReferenced(pCheck, iPage); @@ -7828,8 +8405,7 @@ static void checkPtrmap( IntegrityCk *pCheck, /* Integrity check context */ Pgno iChild, /* Child page number */ u8 eType, /* Expected pointer map type */ - Pgno iParent, /* Expected pointer map parent page number */ - char *zContext /* Context description (used for error msg) */ + Pgno iParent /* Expected pointer map parent page number */ ){ int rc; u8 ePtrmapType; @@ -7838,12 +8414,12 @@ static void checkPtrmap( rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->mallocFailed = 1; - checkAppendMsg(pCheck, zContext, "Failed to read ptrmap key=%d", iChild); + checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild); return; } if( ePtrmapType!=eType || iPtrmapParent!=iParent ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", iChild, eType, iParent, ePtrmapType, iPtrmapParent); } @@ -7858,8 +8434,7 @@ static void checkList( IntegrityCk *pCheck, /* Integrity checking context */ int isFreeList, /* True for a freelist. False for overflow page list */ int iPage, /* Page number for first page in the list */ - int N, /* Expected number of pages in the list */ - char *zContext /* Context for error messages */ + int N /* Expected number of pages in the list */ ){ int i; int expected = N; @@ -7868,14 +8443,14 @@ static void checkList( DbPage *pOvflPage; unsigned char *pOvflData; if( iPage<1 ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "%d of %d pages missing from overflow list starting at %d", N+1, expected, iFirst); break; } - if( checkRef(pCheck, iPage, zContext) ) break; + if( checkRef(pCheck, iPage) ) break; if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage) ){ - checkAppendMsg(pCheck, zContext, "failed to get page %d", iPage); + checkAppendMsg(pCheck, "failed to get page %d", iPage); break; } pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage); @@ -7883,11 +8458,11 @@ static void checkList( int n = get4byte(&pOvflData[4]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pCheck->pBt->autoVacuum ){ - checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0, zContext); + checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0); } #endif if( n>(int)pCheck->pBt->usableSize/4-2 ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "freelist leaf count too big on page %d", iPage); N--; }else{ @@ -7895,10 +8470,10 @@ static void checkList( Pgno iFreePage = get4byte(&pOvflData[8+i*4]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pCheck->pBt->autoVacuum ){ - checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0, zContext); + checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0); } #endif - checkRef(pCheck, iFreePage, zContext); + checkRef(pCheck, iFreePage); } N -= n; } @@ -7911,7 +8486,7 @@ static void checkList( */ if( pCheck->pBt->autoVacuum && N>0 ){ i = get4byte(pOvflData); - checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage, zContext); + checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage); } } #endif @@ -7943,7 +8518,6 @@ static void checkList( static int checkTreePage( IntegrityCk *pCheck, /* Context for the sanity check */ int iPage, /* Page number of the page to check */ - char *zParentContext, /* Parent context */ i64 *pnParentMinKey, i64 *pnParentMaxKey ){ @@ -7954,23 +8528,26 @@ static int checkTreePage( u8 *data; BtShared *pBt; int usableSize; - char zContext[100]; char *hit = 0; i64 nMinKey = 0; i64 nMaxKey = 0; - - sqlite3_snprintf(sizeof(zContext), zContext, "Page %d: ", iPage); + const char *saved_zPfx = pCheck->zPfx; + int saved_v1 = pCheck->v1; + int saved_v2 = pCheck->v2; /* Check that the page exists */ pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; - if( checkRef(pCheck, iPage, zParentContext) ) return 0; + if( checkRef(pCheck, iPage) ) return 0; + pCheck->zPfx = "Page %d: "; + pCheck->v1 = iPage; if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "unable to get the page. error code=%d", rc); - return 0; + depth = -1; + goto end_of_check; } /* Clear MemPage.isInit to make sure the corruption detection code in @@ -7978,10 +8555,11 @@ static int checkTreePage( pPage->isInit = 0; if( (rc = btreeInitPage(pPage))!=0 ){ assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "btreeInitPage() returns error code %d", rc); releasePage(pPage); - return 0; + depth = -1; + goto end_of_check; } /* Check out all the cells. @@ -7994,23 +8572,23 @@ static int checkTreePage( /* Check payload overflow pages */ - sqlite3_snprintf(sizeof(zContext), zContext, - "On tree page %d cell %d: ", iPage, i); + pCheck->zPfx = "On tree page %d cell %d: "; + pCheck->v1 = iPage; + pCheck->v2 = i; pCell = findCell(pPage,i); btreeParseCellPtr(pPage, pCell, &info); - sz = info.nData; - if( !pPage->intKey ) sz += (int)info.nKey; + sz = info.nPayload; /* For intKey pages, check that the keys are in order. */ - else if( i==0 ) nMinKey = nMaxKey = info.nKey; - else{ - if( info.nKey <= nMaxKey ){ - checkAppendMsg(pCheck, zContext, - "Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey); + if( pPage->intKey ){ + if( i==0 ){ + nMinKey = nMaxKey = info.nKey; + }else if( info.nKey <= nMaxKey ){ + checkAppendMsg(pCheck, + "Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey); } nMaxKey = info.nKey; } - assert( sz==info.nPayload ); if( (sz>info.nLocal) && (&pCell[info.iOverflow]<=&pPage->aData[pBt->usableSize]) ){ @@ -8018,10 +8596,10 @@ static int checkTreePage( Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage, zContext); + checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage); } #endif - checkList(pCheck, 0, pgnoOvfl, nPage, zContext); + checkList(pCheck, 0, pgnoOvfl, nPage); } /* Check sanity of left child page. @@ -8030,12 +8608,12 @@ static int checkTreePage( pgno = get4byte(pCell); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext); + checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); } #endif - d2 = checkTreePage(pCheck, pgno, zContext, &nMinKey, i==0 ? NULL : &nMaxKey); + d2 = checkTreePage(pCheck, pgno, &nMinKey, i==0?NULL:&nMaxKey); if( i>0 && d2!=depth ){ - checkAppendMsg(pCheck, zContext, "Child page depth differs"); + checkAppendMsg(pCheck, "Child page depth differs"); } depth = d2; } @@ -8043,37 +8621,39 @@ static int checkTreePage( if( !pPage->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); - sqlite3_snprintf(sizeof(zContext), zContext, - "On page %d at right child: ", iPage); + pCheck->zPfx = "On page %d at right child: "; + pCheck->v1 = iPage; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext); + checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); } #endif - checkTreePage(pCheck, pgno, zContext, NULL, !pPage->nCell ? NULL : &nMaxKey); + checkTreePage(pCheck, pgno, NULL, !pPage->nCell?NULL:&nMaxKey); } /* For intKey leaf pages, check that the min/max keys are in order ** with any left/parent/right pages. */ + pCheck->zPfx = "Page %d: "; + pCheck->v1 = iPage; if( pPage->leaf && pPage->intKey ){ /* if we are a left child page */ if( pnParentMinKey ){ /* if we are the left most child page */ if( !pnParentMaxKey ){ if( nMaxKey > *pnParentMinKey ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "Rowid %lld out of order (max larger than parent min of %lld)", nMaxKey, *pnParentMinKey); } }else{ if( nMinKey <= *pnParentMinKey ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "Rowid %lld out of order (min less than parent min of %lld)", nMinKey, *pnParentMinKey); } if( nMaxKey > *pnParentMaxKey ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "Rowid %lld out of order (max larger than parent max of %lld)", nMaxKey, *pnParentMaxKey); } @@ -8082,7 +8662,7 @@ static int checkTreePage( /* else if we're a right child page */ } else if( pnParentMaxKey ){ if( nMinKey <= *pnParentMaxKey ){ - checkAppendMsg(pCheck, zContext, + checkAppendMsg(pCheck, "Rowid %lld out of order (min less than parent max of %lld)", nMinKey, *pnParentMaxKey); } @@ -8094,6 +8674,7 @@ static int checkTreePage( data = pPage->aData; hdr = pPage->hdrOffset; hit = sqlite3PageMalloc( pBt->pageSize ); + pCheck->zPfx = 0; if( hit==0 ){ pCheck->mallocFailed = 1; }else{ @@ -8101,8 +8682,14 @@ static int checkTreePage( assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */ memset(hit+contentOffset, 0, usableSize-contentOffset); memset(hit, 1, contentOffset); + /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the + ** number of cells on the page. */ nCell = get2byte(&data[hdr+3]); + /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page + ** immediately follows the b-tree page header. */ cellStart = hdr + 12 - 4*pPage->leaf; + /* EVIDENCE-OF: R-02776-14802 The cell pointer array consists of K 2-byte + ** integer offsets to the cell contents. */ for(i=0; i=usableSize ){ - checkAppendMsg(pCheck, 0, + pCheck->zPfx = 0; + checkAppendMsg(pCheck, "Corruption detected in cell %d on page %d",i,iPage); }else{ for(j=pc+size-1; j>=pc; j--) hit[j]++; } } + /* EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header + ** is the offset of the first freeblock, or zero if there are no + ** freeblocks on the page. */ i = get2byte(&data[hdr+1]); while( i>0 ){ int size, j; @@ -8124,7 +8715,13 @@ static int checkTreePage( size = get2byte(&data[i+2]); assert( i+size<=usableSize ); /* Enforced by btreeInitPage() */ for(j=i+size-1; j>=i; j--) hit[j]++; + /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a + ** big-endian integer which is the offset in the b-tree page of the next + ** freeblock in the chain, or zero if the freeblock is the last on the + ** chain. */ j = get2byte(&data[i]); + /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of + ** increasing offset. */ assert( j==0 || j>i+size ); /* Enforced by btreeInitPage() */ assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */ i = j; @@ -8133,19 +8730,29 @@ static int checkTreePage( if( hit[i]==0 ){ cnt++; }else if( hit[i]>1 ){ - checkAppendMsg(pCheck, 0, + checkAppendMsg(pCheck, "Multiple uses for byte %d of page %d", i, iPage); break; } } + /* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments + ** is stored in the fifth field of the b-tree page header. + ** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the + ** number of fragmented free bytes within the cell content area. + */ if( cnt!=data[hdr+7] ){ - checkAppendMsg(pCheck, 0, + checkAppendMsg(pCheck, "Fragmentation of %d bytes reported as %d on page %d", cnt, data[hdr+7], iPage); } } sqlite3PageFree(hit); releasePage(pPage); + +end_of_check: + pCheck->zPfx = saved_zPfx; + pCheck->v1 = saved_v1; + pCheck->v2 = saved_v2; return depth+1; } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -8186,6 +8793,9 @@ char *sqlite3BtreeIntegrityCheck( sCheck.mxErr = mxErr; sCheck.nErr = 0; sCheck.mallocFailed = 0; + sCheck.zPfx = 0; + sCheck.v1 = 0; + sCheck.v2 = 0; *pnErr = 0; if( sCheck.nPage==0 ){ sqlite3BtreeLeave(p); @@ -8205,8 +8815,10 @@ char *sqlite3BtreeIntegrityCheck( /* Check the integrity of the freelist */ + sCheck.zPfx = "Main freelist: "; checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), - get4byte(&pBt->pPage1->aData[36]), "Main freelist: "); + get4byte(&pBt->pPage1->aData[36])); + sCheck.zPfx = 0; /* Check all the tables. */ @@ -8214,10 +8826,12 @@ char *sqlite3BtreeIntegrityCheck( if( aRoot[i]==0 ) continue; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum && aRoot[i]>1 ){ - checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0, 0); + checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); } #endif - checkTreePage(&sCheck, aRoot[i], "List of tree roots: ", NULL, NULL); + sCheck.zPfx = "List of tree roots: "; + checkTreePage(&sCheck, aRoot[i], NULL, NULL); + sCheck.zPfx = 0; } /* Make sure every page in the file is referenced @@ -8225,7 +8839,7 @@ char *sqlite3BtreeIntegrityCheck( for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ #ifdef SQLITE_OMIT_AUTOVACUUM if( getPageReferenced(&sCheck, i)==0 ){ - checkAppendMsg(&sCheck, 0, "Page %d is never used", i); + checkAppendMsg(&sCheck, "Page %d is never used", i); } #else /* If the database supports auto-vacuum, make sure no tables contain @@ -8233,11 +8847,11 @@ char *sqlite3BtreeIntegrityCheck( */ if( getPageReferenced(&sCheck, i)==0 && (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ - checkAppendMsg(&sCheck, 0, "Page %d is never used", i); + checkAppendMsg(&sCheck, "Page %d is never used", i); } if( getPageReferenced(&sCheck, i)!=0 && (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ - checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i); + checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); } #endif } @@ -8247,7 +8861,7 @@ char *sqlite3BtreeIntegrityCheck( ** of the integrity check. */ if( NEVER(nRef != sqlite3PagerRefcount(pBt->pPager)) ){ - checkAppendMsg(&sCheck, 0, + checkAppendMsg(&sCheck, "Outstanding page count goes from %d to %d during this analysis", nRef, sqlite3PagerRefcount(pBt->pPager) ); @@ -8443,7 +9057,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ ** required in case any of them are holding references to an xFetch ** version of the b-tree page modified by the accessPayload call below. ** - ** Note that pCsr must be open on a BTREE_INTKEY table and saveCursorPosition() + ** Note that pCsr must be open on a INTKEY table and saveCursorPosition() ** and hence saveAllCursors() cannot fail on a BTREE_INTKEY table, hence ** saveAllCursors can only return SQLITE_OK. */ @@ -8528,3 +9142,8 @@ void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){ int sqlite3BtreeIsReadonly(Btree *p){ return (p->pBt->btsFlags & BTS_READ_ONLY)!=0; } + +/* +** Return the size of the header added to each page by this module. +*/ +int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } diff --git a/src/btree.h b/src/btree.h index 7118534..b57d500 100644 --- a/src/btree.h +++ b/src/btree.h @@ -19,7 +19,7 @@ /* TODO: This definition is just included so other modules compile. It ** needs to be revisited. */ -#define SQLITE_N_BTREE_META 10 +#define SQLITE_N_BTREE_META 16 /* ** If defined as non-zero, auto-vacuum is enabled by default. Otherwise @@ -83,7 +83,7 @@ int sqlite3BtreeBeginTrans(Btree*,int); int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); int sqlite3BtreeCommitPhaseTwo(Btree*, int); int sqlite3BtreeCommit(Btree*); -int sqlite3BtreeRollback(Btree*,int); +int sqlite3BtreeRollback(Btree*,int,int); int sqlite3BtreeBeginStmt(Btree*,int); int sqlite3BtreeCreateTable(Btree*, int*, int flags); int sqlite3BtreeIsInTrans(Btree*); @@ -116,7 +116,7 @@ int sqlite3BtreeIncrVacuum(Btree *); int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, int*); int sqlite3BtreeClearTableOfCursor(BtCursor*); -void sqlite3BtreeTripAllCursors(Btree*, int); +int sqlite3BtreeTripAllCursors(Btree*, int, int); void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); @@ -134,6 +134,11 @@ int sqlite3BtreeNewDb(Btree *p); ** For example, the free-page-count field is located at byte offset 36 of ** the database file header. The incr-vacuum-flag field is located at ** byte offset 64 (== 36+4*7). +** +** The BTREE_DATA_VERSION value is not really a value stored in the header. +** It is a read-only number computed by the pager. But we merge it with +** the header value access routines since its access pattern is the same. +** Call it a "virtual meta value". */ #define BTREE_FREE_PAGE_COUNT 0 #define BTREE_SCHEMA_VERSION 1 @@ -144,6 +149,7 @@ int sqlite3BtreeNewDb(Btree *p); #define BTREE_USER_VERSION 6 #define BTREE_INCR_VACUUM 7 #define BTREE_APPLICATION_ID 8 +#define BTREE_DATA_VERSION 15 /* A virtual meta-value */ /* ** Values that may be OR'd together to form the second argument of an @@ -169,7 +175,8 @@ int sqlite3BtreeMovetoUnpacked( int bias, int *pRes ); -int sqlite3BtreeCursorHasMoved(BtCursor*, int*); +int sqlite3BtreeCursorHasMoved(BtCursor*); +int sqlite3BtreeCursorRestore(BtCursor*, int*); int sqlite3BtreeDelete(BtCursor*); int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, const void *pData, int nData, @@ -195,6 +202,7 @@ void sqlite3BtreeClearCursor(BtCursor *); int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask); int sqlite3BtreeIsReadonly(Btree *pBt); +int sqlite3HeaderSizeBtree(void); #ifndef NDEBUG int sqlite3BtreeCursorIsValid(BtCursor*); diff --git a/src/btreeInt.h b/src/btreeInt.h index d1cdd46..ed4d75e 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file implements a external (disk-based) database using BTrees. +** This file implements an external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: @@ -135,7 +135,7 @@ ** ** The flags define the format of this btree page. The leaf flag means that ** this page has no children. The zerodata flag means that this page carries -** only keys and no data. The intkey flag means that the key is a integer +** only keys and no data. The intkey flag means that the key is an integer ** which is stored in the key size entry of the cell header rather than in ** the payload area. ** @@ -273,9 +273,10 @@ typedef struct BtLock BtLock; struct MemPage { u8 isInit; /* True if previously initialized. MUST BE FIRST! */ u8 nOverflow; /* Number of overflow cell bodies in aCell[] */ - u8 intKey; /* True if intkey flag is set */ - u8 leaf; /* True if leaf flag is set */ - u8 hasData; /* True if this page stores data */ + u8 intKey; /* True if table b-trees. False for index b-trees */ + u8 intKeyLeaf; /* True if the leaf of an intKey table */ + u8 noPayload; /* True if internal intKey page (thus w/o data) */ + u8 leaf; /* True if a leaf page */ u8 hdrOffset; /* 100 for page 1. 0 otherwise */ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ u8 max1bytePayload; /* min(maxLocal,127) */ @@ -350,6 +351,7 @@ struct Btree { u8 locked; /* True if db currently has pBt locked */ int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */ int nBackup; /* Number of backup operations reading this btree */ + u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */ Btree *pNext; /* List of other sharable Btrees from the same db */ Btree *pPrev; /* Back pointer of the same list */ #ifndef SQLITE_OMIT_SHARED_CACHE @@ -435,7 +437,7 @@ struct BtShared { BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ #endif - u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */ + u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ }; /* @@ -456,12 +458,10 @@ struct BtShared { */ typedef struct CellInfo CellInfo; struct CellInfo { - i64 nKey; /* The key for INTKEY tables, or number of bytes in key */ - u8 *pCell; /* Pointer to the start of cell content */ - u32 nData; /* Number of bytes of data */ - u32 nPayload; /* Total amount of payload */ - u16 nHeader; /* Size of the cell content header in bytes */ - u16 nLocal; /* Amount of payload held locally */ + i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */ + u8 *pPayload; /* Pointer to the start of payload */ + u32 nPayload; /* Bytes of payload */ + u16 nLocal; /* Amount of payload held locally, not on overflow */ u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */ u16 nSize; /* Size of the cell content on the main b-tree page */ }; @@ -490,6 +490,11 @@ struct CellInfo { ** ** Fields in this structure are accessed under the BtShared.mutex ** found at self->pBt->mutex. +** +** skipNext meaning: +** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op. +** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op. +** eState==FAULT: Cursor fault with skipNext as error code. */ struct BtCursor { Btree *pBtree; /* The Btree to which this cursor belongs */ @@ -502,7 +507,8 @@ struct BtCursor { void *pKey; /* Saved key that was cursor last known position */ Pgno pgnoRoot; /* The root page of this tree */ int nOvflAlloc; /* Allocated size of aOverflow[] array */ - int skipNext; /* Prev() is noop if negative. Next() is noop if positive */ + int skipNext; /* Prev() is noop if negative. Next() is noop if positive. + ** Error code if eState==CURSOR_FAULT */ u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 hints; /* As configured by CursorSetHints() */ @@ -544,11 +550,11 @@ struct BtCursor { ** seek the cursor to the saved position. ** ** CURSOR_FAULT: -** A unrecoverable error (an I/O error or a malloc failure) has occurred +** An unrecoverable error (an I/O error or a malloc failure) has occurred ** on a different connection that shares the BtShared cache with this ** cursor. The error has left the cache in an inconsistent state. ** Do nothing else with this cursor. Any attempt to use the cursor -** should return the error code stored in BtCursor.skip +** should return the error code stored in BtCursor.skipNext */ #define CURSOR_INVALID 0 #define CURSOR_VALID 1 @@ -658,6 +664,8 @@ struct IntegrityCk { int mxErr; /* Stop accumulating errors when this reaches zero */ int nErr; /* Number of messages written to zErrMsg so far */ int mallocFailed; /* A memory allocation error has occurred */ + const char *zPfx; /* Error message prefix */ + int v1, v2; /* Values for up to two %d fields in zPfx */ StrAccum errMsg; /* Accumulate the error message text here */ }; diff --git a/src/build.c b/src/build.c index a9a8f21..f02989b 100644 --- a/src/build.c +++ b/src/build.c @@ -156,6 +156,17 @@ void sqlite3FinishCoding(Parse *pParse){ while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){} sqlite3VdbeAddOp0(v, OP_Halt); +#if SQLITE_USER_AUTHENTICATION + if( pParse->nTableLock>0 && db->init.busy==0 ){ + sqlite3UserAuthInit(db); + if( db->auth.authLevelrc = SQLITE_AUTH_USER; + sqlite3ErrorMsg(pParse, "user not authenticated"); + return; + } + } +#endif + /* The cookie mask contains one bit for each database file open. ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are ** set for each database that is used. Generate code to start a @@ -271,6 +282,16 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ pParse->nested--; } +#if SQLITE_USER_AUTHENTICATION +/* +** Return TRUE if zTable is the name of the system table that stores the +** list of users and their access credentials. +*/ +int sqlite3UserAuthTable(const char *zTable){ + return sqlite3_stricmp(zTable, "sqlite_user")==0; +} +#endif + /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the @@ -286,16 +307,25 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ Table *p = 0; int i; - int nName; - assert( zName!=0 ); - nName = sqlite3Strlen30(zName); + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return 0; +#endif + /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); +#if SQLITE_USER_AUTHENTICATION + /* Only the admin user is allowed to know that the sqlite_user table + ** exists */ + if( db->auth.authLevelnDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); - p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, nName); + p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); if( p ) break; } return p; @@ -335,6 +365,12 @@ Table *sqlite3LocateTable( } pParse->checkSchema = 1; } +#if SQLITE_USER_AUTHENICATION + else if( pParse->db->auth.authLevelnDb; i++){ @@ -387,7 +422,7 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){ assert( pSchema ); if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); - p = sqlite3HashFind(&pSchema->idxHash, zName, nName); + p = sqlite3HashFind(&pSchema->idxHash, zName); if( p ) break; } return p; @@ -400,10 +435,12 @@ static void freeIndex(sqlite3 *db, Index *p){ #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(db, p); #endif - if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo); sqlite3ExprDelete(db, p->pPartIdxWhere); sqlite3DbFree(db, p->zColAff); if( p->isResized ) sqlite3DbFree(db, p->azColl); +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + sqlite3_free(p->aiRowEst); +#endif sqlite3DbFree(db, p); } @@ -415,13 +452,11 @@ static void freeIndex(sqlite3 *db, Index *p){ */ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ Index *pIndex; - int len; Hash *pHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pHash = &db->aDb[iDb].pSchema->idxHash; - len = sqlite3Strlen30(zIdxName); - pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0); + pIndex = sqlite3HashInsert(pHash, zIdxName, 0); if( ALWAYS(pIndex) ){ if( pIndex->pTable->pIndex==pIndex ){ pIndex->pTable->pIndex = pIndex->pNext; @@ -581,7 +616,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ if( !db || db->pnBytesFreed==0 ){ char *zName = pIndex->zName; TESTONLY ( Index *pOld = ) sqlite3HashInsert( - &pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0 + &pIndex->pSchema->idxHash, zName, 0 ); assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); assert( pOld==pIndex || pOld==0 ); @@ -624,8 +659,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */ pDb = &db->aDb[iDb]; - p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, - sqlite3Strlen30(zTabName),0); + p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); sqlite3DeleteTable(db, p); db->flags |= SQLITE_InternChanges; } @@ -1149,7 +1183,7 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){ ** estimate is scaled so that the size of an integer is 1. */ if( pszEst ){ *pszEst = 1; /* default size is approx 4 bytes */ - if( aff<=SQLITE_AFF_NONE ){ + if( affpNewTable; if( p!=0 ){ pCol = &(p->aCol[p->nCol-1]); - if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr) ){ + if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){ sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", pCol->zName); }else{ @@ -1520,8 +1554,8 @@ static char *createTableStmt(sqlite3 *db, Table *p){ zStmt[k++] = '('; for(pCol=p->aCol, i=0; inCol; i++, pCol++){ static const char * const azType[] = { - /* SQLITE_AFF_TEXT */ " TEXT", /* SQLITE_AFF_NONE */ "", + /* SQLITE_AFF_TEXT */ " TEXT", /* SQLITE_AFF_NUMERIC */ " NUM", /* SQLITE_AFF_INTEGER */ " INT", /* SQLITE_AFF_REAL */ " REAL" @@ -1533,15 +1567,15 @@ static char *createTableStmt(sqlite3 *db, Table *p){ k += sqlite3Strlen30(&zStmt[k]); zSep = zSep2; identPut(zStmt, &k, pCol->zName); - assert( pCol->affinity-SQLITE_AFF_TEXT >= 0 ); - assert( pCol->affinity-SQLITE_AFF_TEXT < ArraySize(azType) ); - testcase( pCol->affinity==SQLITE_AFF_TEXT ); + assert( pCol->affinity-SQLITE_AFF_NONE >= 0 ); + assert( pCol->affinity-SQLITE_AFF_NONE < ArraySize(azType) ); testcase( pCol->affinity==SQLITE_AFF_NONE ); + testcase( pCol->affinity==SQLITE_AFF_TEXT ); testcase( pCol->affinity==SQLITE_AFF_NUMERIC ); testcase( pCol->affinity==SQLITE_AFF_INTEGER ); testcase( pCol->affinity==SQLITE_AFF_REAL ); - zType = azType[pCol->affinity - SQLITE_AFF_TEXT]; + zType = azType[pCol->affinity - SQLITE_AFF_NONE]; len = sqlite3Strlen30(zType); assert( pCol->affinity==SQLITE_AFF_NONE || pCol->affinity==sqlite3AffinityType(zType, 0) ); @@ -1625,7 +1659,7 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){ ** no rowid btree for a WITHOUT ROWID. Instead, the canonical ** data storage is a covering index btree. ** (2) Bypass the creation of the sqlite_master table entry -** for the PRIMARY KEY as the the primary key index is now +** for the PRIMARY KEY as the primary key index is now ** identified by the sqlite_master table entry of the table itself. ** (3) Set the Index.tnum of the PRIMARY KEY Index object in the ** schema to the rootpage from the main table. @@ -1646,7 +1680,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ Vdbe *v = pParse->pVdbe; /* Convert the OP_CreateTable opcode that would normally create the - ** root-page for the table into a OP_CreateIndex opcode. The index + ** root-page for the table into an OP_CreateIndex opcode. The index ** created will become the PRIMARY KEY index. */ if( pParse->addrCrTab ){ @@ -1679,6 +1713,19 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ pTab->iPKey = -1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); + /* + ** Remove all redundant columns from the PRIMARY KEY. For example, change + ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later + ** code assumes the PRIMARY KEY contains no repeated columns. + */ + for(i=j=1; inKeyCol; i++){ + if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){ + pPk->nColumn--; + }else{ + pPk->aiColumn[j++] = pPk->aiColumn[i]; + } + } + pPk->nKeyCol = j; } pPk->isCovering = 1; assert( pPk!=0 ); @@ -1947,8 +1994,7 @@ void sqlite3EndTable( Table *pOld; Schema *pSchema = p->pSchema; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, - sqlite3Strlen30(p->zName),p); + pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p); if( pOld ){ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ db->mallocFailed = 1; @@ -2059,7 +2105,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ int nErr = 0; /* Number of errors encountered */ int n; /* Temporarily holds the number of cursors assigned */ sqlite3 *db = pParse->db; /* Database connection for malloc errors */ - int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); + sqlite3_xauth xAuth; /* Saved xAuth pointer */ assert( pTable ); @@ -2598,7 +2644,7 @@ void sqlite3CreateForeignKey( assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) ); pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash, - pFKey->zTo, sqlite3Strlen30(pFKey->zTo), (void *)pFKey + pFKey->zTo, (void *)pFKey ); if( pNextTo==pFKey ){ db->mallocFailed = 1; @@ -2661,7 +2707,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ int iPartIdxLabel; /* Jump to this label to skip a row */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ - int regRecord; /* Register holding assemblied index record */ + int regRecord; /* Register holding assembled index record */ sqlite3 *db = pParse->db; /* The database connection */ int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); @@ -2686,7 +2732,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ /* Open the sorter cursor if we are to use one. */ iSorter = pParse->nTab++; - sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*) + sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*) sqlite3KeyInfoRef(pKey), P4_KEYINFO); /* Open the table. Loop through all rows of the table, inserting index @@ -2717,7 +2763,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ }else{ addr2 = sqlite3VdbeCurrentAddr(v); } - sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord); + sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); @@ -2874,6 +2920,10 @@ Index *sqlite3CreateIndex( assert( pTab!=0 ); assert( pParse->nErr==0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 + && db->init.busy==0 +#if SQLITE_USER_AUTHENTICATION + && sqlite3UserAuthTable(pTab->zName)==0 +#endif && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; @@ -3035,7 +3085,7 @@ Index *sqlite3CreateIndex( pParse->checkSchema = 1; goto exit_create_index; } - assert( pTab->nCol<=0x7fff && j<=0x7fff ); + assert( j<=0x7fff ); pIndex->aiColumn[i] = (i16)j; if( pListItem->pExpr ){ int nColl; @@ -3146,8 +3196,7 @@ Index *sqlite3CreateIndex( Index *p; assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); p = sqlite3HashInsert(&pIndex->pSchema->idxHash, - pIndex->zName, sqlite3Strlen30(pIndex->zName), - pIndex); + pIndex->zName, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ db->mallocFailed = 1; @@ -3262,7 +3311,7 @@ exit_create_index: ** Fill the Index.aiRowEst[] array with default information - information ** to be used when we have not run the ANALYZE command. ** -** aiRowEst[0] is suppose to contain the number of elements in the index. +** aiRowEst[0] is supposed to contain the number of elements in the index. ** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the ** number of rows in the table that match any particular value of the ** first column of the index. aiRowEst[2] is an estimate of the number @@ -3641,7 +3690,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ ** if this is the first term of the FROM clause. pTable and pDatabase ** are the name of the table and database named in the FROM clause term. ** pDatabase is NULL if the database name qualifier is missing - the -** usual case. If the term has a alias, then pAlias points to the +** usual case. If the term has an alias, then pAlias points to the ** alias token. If the term is a subquery, then pSubquery is the ** SELECT statement that the subquery encodes. The pTable and ** pDatabase parameters are NULL for subqueries. The pOn and pUsing @@ -4153,40 +4202,31 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ ** when it has finished using it. */ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ + int i; + int nCol = pIdx->nColumn; + int nKey = pIdx->nKeyCol; + KeyInfo *pKey; if( pParse->nErr ) return 0; -#ifndef SQLITE_OMIT_SHARED_CACHE - if( pIdx->pKeyInfo && pIdx->pKeyInfo->db!=pParse->db ){ - sqlite3KeyInfoUnref(pIdx->pKeyInfo); - pIdx->pKeyInfo = 0; + if( pIdx->uniqNotNull ){ + pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey); + }else{ + pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0); } -#endif - if( pIdx->pKeyInfo==0 ){ - int i; - int nCol = pIdx->nColumn; - int nKey = pIdx->nKeyCol; - KeyInfo *pKey; - if( pIdx->uniqNotNull ){ - pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey); - }else{ - pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0); + if( pKey ){ + assert( sqlite3KeyInfoIsWriteable(pKey) ); + for(i=0; iazColl[i]; + assert( zColl!=0 ); + pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 : + sqlite3LocateCollSeq(pParse, zColl); + pKey->aSortOrder[i] = pIdx->aSortOrder[i]; } - if( pKey ){ - assert( sqlite3KeyInfoIsWriteable(pKey) ); - for(i=0; iazColl[i]; - assert( zColl!=0 ); - pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 : - sqlite3LocateCollSeq(pParse, zColl); - pKey->aSortOrder[i] = pIdx->aSortOrder[i]; - } - if( pParse->nErr ){ - sqlite3KeyInfoUnref(pKey); - }else{ - pIdx->pKeyInfo = pKey; - } + if( pParse->nErr ){ + sqlite3KeyInfoUnref(pKey); + pKey = 0; } } - return sqlite3KeyInfoRef(pIdx->pKeyInfo); + return pKey; } #ifndef SQLITE_OMIT_CTE diff --git a/src/callback.c b/src/callback.c index 46fbe2c..cd213b4 100644 --- a/src/callback.c +++ b/src/callback.c @@ -142,7 +142,7 @@ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ ** ** Each pointer stored in the sqlite3.aCollSeq hash table contains an ** array of three CollSeq structures. The first is the collation sequence -** prefferred for UTF-8, the second UTF-16le, and the third UTF-16be. +** preferred for UTF-8, the second UTF-16le, and the third UTF-16be. ** ** Stored immediately after the three collation sequences is a copy of ** the collation sequence name. A pointer to this string is stored in @@ -154,11 +154,11 @@ static CollSeq *findCollSeqEntry( int create /* Create a new entry if true */ ){ CollSeq *pColl; - int nName = sqlite3Strlen30(zName); - pColl = sqlite3HashFind(&db->aCollSeq, zName, nName); + pColl = sqlite3HashFind(&db->aCollSeq, zName); if( 0==pColl && create ){ - pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1 ); + int nName = sqlite3Strlen30(zName); + pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1); if( pColl ){ CollSeq *pDel = 0; pColl[0].zName = (char*)&pColl[3]; @@ -169,7 +169,7 @@ static CollSeq *findCollSeqEntry( pColl[2].enc = SQLITE_UTF16BE; memcpy(pColl[0].zName, zName, nName); pColl[0].zName[nName] = 0; - pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl); + pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl); /* If a malloc() failure occurred in sqlite3HashInsert(), it will ** return the pColl pointer to be deleted (because it wasn't added diff --git a/src/complete.c b/src/complete.c index 9e91400..f7a35cc 100644 --- a/src/complete.c +++ b/src/complete.c @@ -70,7 +70,7 @@ extern const char sqlite3IsEbcdicIdChar[]; ** a statement. ** ** (4) CREATE The keyword CREATE has been seen at the beginning of a -** statement, possibly preceeded by EXPLAIN and/or followed by +** statement, possibly preceded by EXPLAIN and/or followed by ** TEMP or TEMPORARY ** ** (5) TRIGGER We are in the middle of a trigger definition that must be @@ -80,7 +80,7 @@ extern const char sqlite3IsEbcdicIdChar[]; ** the end of a trigger definition. ** ** (7) END We've seen the ";END" of the ";END;" that occurs at the end -** of a trigger difinition. +** of a trigger definition. ** ** Transitions between states above are determined by tokens extracted ** from the input. The following tokens are significant: @@ -123,7 +123,7 @@ int sqlite3_complete(const char *zSql){ }; #else /* If triggers are not supported by this compile then the statement machine - ** used to detect the end of a statement is much simplier + ** used to detect the end of a statement is much simpler */ static const u8 trans[3][3] = { /* Token: */ @@ -134,6 +134,13 @@ int sqlite3_complete(const char *zSql){ }; #endif /* SQLITE_OMIT_TRIGGER */ +#ifdef SQLITE_ENABLE_API_ARMOR + if( zSql==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + while( *zSql ){ switch( *zSql ){ case ';': { /* A semicolon */ diff --git a/src/ctime.c b/src/ctime.c index 286f66e..4f98ffe 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -33,88 +33,91 @@ static const char * const azCompileOpt[] = { #define CTIMEOPT_VAL_(opt) #opt #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) -#ifdef SQLITE_32BIT_ROWID +#if SQLITE_32BIT_ROWID "32BIT_ROWID", #endif -#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC +#if SQLITE_4_BYTE_ALIGNED_MALLOC "4_BYTE_ALIGNED_MALLOC", #endif -#ifdef SQLITE_CASE_SENSITIVE_LIKE +#if SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif -#ifdef SQLITE_CHECK_PAGES +#if SQLITE_CHECK_PAGES "CHECK_PAGES", #endif -#ifdef SQLITE_COVERAGE_TEST +#if SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif -#ifdef SQLITE_DEBUG +#if SQLITE_DEBUG "DEBUG", #endif -#ifdef SQLITE_DEFAULT_LOCKING_MODE +#if SQLITE_DEFAULT_LOCKING_MODE "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif #if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc) "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), #endif -#ifdef SQLITE_DISABLE_DIRSYNC +#if SQLITE_DISABLE_DIRSYNC "DISABLE_DIRSYNC", #endif -#ifdef SQLITE_DISABLE_LFS +#if SQLITE_DISABLE_LFS "DISABLE_LFS", #endif -#ifdef SQLITE_ENABLE_ATOMIC_WRITE +#if SQLITE_ENABLE_API_ARMOR + "ENABLE_API_ARMOR", +#endif +#if SQLITE_ENABLE_ATOMIC_WRITE "ENABLE_ATOMIC_WRITE", #endif -#ifdef SQLITE_ENABLE_CEROD +#if SQLITE_ENABLE_CEROD "ENABLE_CEROD", #endif -#ifdef SQLITE_ENABLE_COLUMN_METADATA +#if SQLITE_ENABLE_COLUMN_METADATA "ENABLE_COLUMN_METADATA", #endif -#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT +#if SQLITE_ENABLE_EXPENSIVE_ASSERT "ENABLE_EXPENSIVE_ASSERT", #endif -#ifdef SQLITE_ENABLE_FTS1 +#if SQLITE_ENABLE_FTS1 "ENABLE_FTS1", #endif -#ifdef SQLITE_ENABLE_FTS2 +#if SQLITE_ENABLE_FTS2 "ENABLE_FTS2", #endif -#ifdef SQLITE_ENABLE_FTS3 +#if SQLITE_ENABLE_FTS3 "ENABLE_FTS3", #endif -#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS +#if SQLITE_ENABLE_FTS3_PARENTHESIS "ENABLE_FTS3_PARENTHESIS", #endif -#ifdef SQLITE_ENABLE_FTS4 +#if SQLITE_ENABLE_FTS4 "ENABLE_FTS4", #endif -#ifdef SQLITE_ENABLE_ICU +#if SQLITE_ENABLE_ICU "ENABLE_ICU", #endif -#ifdef SQLITE_ENABLE_IOTRACE +#if SQLITE_ENABLE_IOTRACE "ENABLE_IOTRACE", #endif -#ifdef SQLITE_ENABLE_LOAD_EXTENSION +#if SQLITE_ENABLE_LOAD_EXTENSION "ENABLE_LOAD_EXTENSION", #endif -#ifdef SQLITE_ENABLE_LOCKING_STYLE +#if SQLITE_ENABLE_LOCKING_STYLE "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), #endif -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT +#if SQLITE_ENABLE_MEMORY_MANAGEMENT "ENABLE_MEMORY_MANAGEMENT", #endif -#ifdef SQLITE_ENABLE_MEMSYS3 +#if SQLITE_ENABLE_MEMSYS3 "ENABLE_MEMSYS3", #endif -#ifdef SQLITE_ENABLE_MEMSYS5 +#if SQLITE_ENABLE_MEMSYS5 "ENABLE_MEMSYS5", #endif -#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK +#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK "ENABLE_OVERSIZE_CELL_CHECK", #endif -#ifdef SQLITE_ENABLE_RTREE +#if SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif #if defined(SQLITE_ENABLE_STAT4) @@ -122,31 +125,31 @@ static const char * const azCompileOpt[] = { #elif defined(SQLITE_ENABLE_STAT3) "ENABLE_STAT3", #endif -#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY +#if SQLITE_ENABLE_UNLOCK_NOTIFY "ENABLE_UNLOCK_NOTIFY", #endif -#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT +#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT "ENABLE_UPDATE_DELETE_LIMIT", #endif -#ifdef SQLITE_HAS_CODEC +#if SQLITE_HAS_CODEC "HAS_CODEC", #endif -#ifdef SQLITE_HAVE_ISNAN +#if HAVE_ISNAN || SQLITE_HAVE_ISNAN "HAVE_ISNAN", #endif -#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX +#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX "HOMEGROWN_RECURSIVE_MUTEX", #endif -#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS +#if SQLITE_IGNORE_AFP_LOCK_ERRORS "IGNORE_AFP_LOCK_ERRORS", #endif -#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS +#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS "IGNORE_FLOCK_LOCK_ERRORS", #endif #ifdef SQLITE_INT64_TYPE "INT64_TYPE", #endif -#ifdef SQLITE_LOCK_TRACE +#if SQLITE_LOCK_TRACE "LOCK_TRACE", #endif #if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc) @@ -155,223 +158,226 @@ static const char * const azCompileOpt[] = { #ifdef SQLITE_MAX_SCHEMA_RETRY "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), #endif -#ifdef SQLITE_MEMDEBUG +#if SQLITE_MEMDEBUG "MEMDEBUG", #endif -#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT +#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT "MIXED_ENDIAN_64BIT_FLOAT", #endif -#ifdef SQLITE_NO_SYNC +#if SQLITE_NO_SYNC "NO_SYNC", #endif -#ifdef SQLITE_OMIT_ALTERTABLE +#if SQLITE_OMIT_ALTERTABLE "OMIT_ALTERTABLE", #endif -#ifdef SQLITE_OMIT_ANALYZE +#if SQLITE_OMIT_ANALYZE "OMIT_ANALYZE", #endif -#ifdef SQLITE_OMIT_ATTACH +#if SQLITE_OMIT_ATTACH "OMIT_ATTACH", #endif -#ifdef SQLITE_OMIT_AUTHORIZATION +#if SQLITE_OMIT_AUTHORIZATION "OMIT_AUTHORIZATION", #endif -#ifdef SQLITE_OMIT_AUTOINCREMENT +#if SQLITE_OMIT_AUTOINCREMENT "OMIT_AUTOINCREMENT", #endif -#ifdef SQLITE_OMIT_AUTOINIT +#if SQLITE_OMIT_AUTOINIT "OMIT_AUTOINIT", #endif -#ifdef SQLITE_OMIT_AUTOMATIC_INDEX +#if SQLITE_OMIT_AUTOMATIC_INDEX "OMIT_AUTOMATIC_INDEX", #endif -#ifdef SQLITE_OMIT_AUTORESET +#if SQLITE_OMIT_AUTORESET "OMIT_AUTORESET", #endif -#ifdef SQLITE_OMIT_AUTOVACUUM +#if SQLITE_OMIT_AUTOVACUUM "OMIT_AUTOVACUUM", #endif -#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION +#if SQLITE_OMIT_BETWEEN_OPTIMIZATION "OMIT_BETWEEN_OPTIMIZATION", #endif -#ifdef SQLITE_OMIT_BLOB_LITERAL +#if SQLITE_OMIT_BLOB_LITERAL "OMIT_BLOB_LITERAL", #endif -#ifdef SQLITE_OMIT_BTREECOUNT +#if SQLITE_OMIT_BTREECOUNT "OMIT_BTREECOUNT", #endif -#ifdef SQLITE_OMIT_BUILTIN_TEST +#if SQLITE_OMIT_BUILTIN_TEST "OMIT_BUILTIN_TEST", #endif -#ifdef SQLITE_OMIT_CAST +#if SQLITE_OMIT_CAST "OMIT_CAST", #endif -#ifdef SQLITE_OMIT_CHECK +#if SQLITE_OMIT_CHECK "OMIT_CHECK", #endif -#ifdef SQLITE_OMIT_COMPLETE +#if SQLITE_OMIT_COMPLETE "OMIT_COMPLETE", #endif -#ifdef SQLITE_OMIT_COMPOUND_SELECT +#if SQLITE_OMIT_COMPOUND_SELECT "OMIT_COMPOUND_SELECT", #endif -#ifdef SQLITE_OMIT_CTE +#if SQLITE_OMIT_CTE "OMIT_CTE", #endif -#ifdef SQLITE_OMIT_DATETIME_FUNCS +#if SQLITE_OMIT_DATETIME_FUNCS "OMIT_DATETIME_FUNCS", #endif -#ifdef SQLITE_OMIT_DECLTYPE +#if SQLITE_OMIT_DECLTYPE "OMIT_DECLTYPE", #endif -#ifdef SQLITE_OMIT_DEPRECATED +#if SQLITE_OMIT_DEPRECATED "OMIT_DEPRECATED", #endif -#ifdef SQLITE_OMIT_DISKIO +#if SQLITE_OMIT_DISKIO "OMIT_DISKIO", #endif -#ifdef SQLITE_OMIT_EXPLAIN +#if SQLITE_OMIT_EXPLAIN "OMIT_EXPLAIN", #endif -#ifdef SQLITE_OMIT_FLAG_PRAGMAS +#if SQLITE_OMIT_FLAG_PRAGMAS "OMIT_FLAG_PRAGMAS", #endif -#ifdef SQLITE_OMIT_FLOATING_POINT +#if SQLITE_OMIT_FLOATING_POINT "OMIT_FLOATING_POINT", #endif -#ifdef SQLITE_OMIT_FOREIGN_KEY +#if SQLITE_OMIT_FOREIGN_KEY "OMIT_FOREIGN_KEY", #endif -#ifdef SQLITE_OMIT_GET_TABLE +#if SQLITE_OMIT_GET_TABLE "OMIT_GET_TABLE", #endif -#ifdef SQLITE_OMIT_INCRBLOB +#if SQLITE_OMIT_INCRBLOB "OMIT_INCRBLOB", #endif -#ifdef SQLITE_OMIT_INTEGRITY_CHECK +#if SQLITE_OMIT_INTEGRITY_CHECK "OMIT_INTEGRITY_CHECK", #endif -#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION +#if SQLITE_OMIT_LIKE_OPTIMIZATION "OMIT_LIKE_OPTIMIZATION", #endif -#ifdef SQLITE_OMIT_LOAD_EXTENSION +#if SQLITE_OMIT_LOAD_EXTENSION "OMIT_LOAD_EXTENSION", #endif -#ifdef SQLITE_OMIT_LOCALTIME +#if SQLITE_OMIT_LOCALTIME "OMIT_LOCALTIME", #endif -#ifdef SQLITE_OMIT_LOOKASIDE +#if SQLITE_OMIT_LOOKASIDE "OMIT_LOOKASIDE", #endif -#ifdef SQLITE_OMIT_MEMORYDB +#if SQLITE_OMIT_MEMORYDB "OMIT_MEMORYDB", #endif -#ifdef SQLITE_OMIT_OR_OPTIMIZATION +#if SQLITE_OMIT_OR_OPTIMIZATION "OMIT_OR_OPTIMIZATION", #endif -#ifdef SQLITE_OMIT_PAGER_PRAGMAS +#if SQLITE_OMIT_PAGER_PRAGMAS "OMIT_PAGER_PRAGMAS", #endif -#ifdef SQLITE_OMIT_PRAGMA +#if SQLITE_OMIT_PRAGMA "OMIT_PRAGMA", #endif -#ifdef SQLITE_OMIT_PROGRESS_CALLBACK +#if SQLITE_OMIT_PROGRESS_CALLBACK "OMIT_PROGRESS_CALLBACK", #endif -#ifdef SQLITE_OMIT_QUICKBALANCE +#if SQLITE_OMIT_QUICKBALANCE "OMIT_QUICKBALANCE", #endif -#ifdef SQLITE_OMIT_REINDEX +#if SQLITE_OMIT_REINDEX "OMIT_REINDEX", #endif -#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS +#if SQLITE_OMIT_SCHEMA_PRAGMAS "OMIT_SCHEMA_PRAGMAS", #endif -#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS +#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS "OMIT_SCHEMA_VERSION_PRAGMAS", #endif -#ifdef SQLITE_OMIT_SHARED_CACHE +#if SQLITE_OMIT_SHARED_CACHE "OMIT_SHARED_CACHE", #endif -#ifdef SQLITE_OMIT_SUBQUERY +#if SQLITE_OMIT_SUBQUERY "OMIT_SUBQUERY", #endif -#ifdef SQLITE_OMIT_TCL_VARIABLE +#if SQLITE_OMIT_TCL_VARIABLE "OMIT_TCL_VARIABLE", #endif -#ifdef SQLITE_OMIT_TEMPDB +#if SQLITE_OMIT_TEMPDB "OMIT_TEMPDB", #endif -#ifdef SQLITE_OMIT_TRACE +#if SQLITE_OMIT_TRACE "OMIT_TRACE", #endif -#ifdef SQLITE_OMIT_TRIGGER +#if SQLITE_OMIT_TRIGGER "OMIT_TRIGGER", #endif -#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION +#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION "OMIT_TRUNCATE_OPTIMIZATION", #endif -#ifdef SQLITE_OMIT_UTF16 +#if SQLITE_OMIT_UTF16 "OMIT_UTF16", #endif -#ifdef SQLITE_OMIT_VACUUM +#if SQLITE_OMIT_VACUUM "OMIT_VACUUM", #endif -#ifdef SQLITE_OMIT_VIEW +#if SQLITE_OMIT_VIEW "OMIT_VIEW", #endif -#ifdef SQLITE_OMIT_VIRTUALTABLE +#if SQLITE_OMIT_VIRTUALTABLE "OMIT_VIRTUALTABLE", #endif -#ifdef SQLITE_OMIT_WAL +#if SQLITE_OMIT_WAL "OMIT_WAL", #endif -#ifdef SQLITE_OMIT_WSD +#if SQLITE_OMIT_WSD "OMIT_WSD", #endif -#ifdef SQLITE_OMIT_XFER_OPT +#if SQLITE_OMIT_XFER_OPT "OMIT_XFER_OPT", #endif -#ifdef SQLITE_PERFORMANCE_TRACE +#if SQLITE_PERFORMANCE_TRACE "PERFORMANCE_TRACE", #endif -#ifdef SQLITE_PROXY_DEBUG +#if SQLITE_PROXY_DEBUG "PROXY_DEBUG", #endif -#ifdef SQLITE_RTREE_INT_ONLY +#if SQLITE_RTREE_INT_ONLY "RTREE_INT_ONLY", #endif -#ifdef SQLITE_SECURE_DELETE +#if SQLITE_SECURE_DELETE "SECURE_DELETE", #endif -#ifdef SQLITE_SMALL_STACK +#if SQLITE_SMALL_STACK "SMALL_STACK", #endif -#ifdef SQLITE_SOUNDEX +#if SQLITE_SOUNDEX "SOUNDEX", #endif -#ifdef SQLITE_SYSTEM_MALLOC +#if SQLITE_SYSTEM_MALLOC "SYSTEM_MALLOC", #endif -#ifdef SQLITE_TCL +#if SQLITE_TCL "TCL", #endif #if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc) "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), #endif -#ifdef SQLITE_TEST +#if SQLITE_TEST "TEST", #endif #if defined(SQLITE_THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), #endif -#ifdef SQLITE_USE_ALLOCA +#if SQLITE_USE_ALLOCA "USE_ALLOCA", #endif -#ifdef SQLITE_WIN32_MALLOC +#if SQLITE_USER_AUTHENTICATION + "USER_AUTHENTICATION", +#endif +#if SQLITE_WIN32_MALLOC "WIN32_MALLOC", #endif -#ifdef SQLITE_ZERO_MALLOC +#if SQLITE_ZERO_MALLOC "ZERO_MALLOC" #endif }; @@ -385,6 +391,13 @@ static const char * const azCompileOpt[] = { */ int sqlite3_compileoption_used(const char *zOptName){ int i, n; + +#if SQLITE_ENABLE_API_ARMOR + if( zOptName==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; n = sqlite3Strlen30(zOptName); @@ -392,7 +405,7 @@ int sqlite3_compileoption_used(const char *zOptName){ ** linear search is adequate. No need for a binary search. */ for(i=0; i0 sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); @@ -451,7 +451,7 @@ static int osLocaltime(time_t *t, struct tm *pTm){ #ifndef SQLITE_OMIT_BUILTIN_TEST if( sqlite3GlobalConfig.bLocaltimeFault ) return 1; #endif -#if defined(HAVE_LOCALTIME_R) && HAVE_LOCALTIME_R +#if HAVE_LOCALTIME_R rc = localtime_r(t, pTm)==0; #else rc = localtime_s(pTm, t); @@ -875,7 +875,7 @@ static void dateFunc( ** %f ** fractional seconds SS.SSS ** %H hour 00-24 ** %j day of year 000-366 -** %J ** Julian day number +** %J ** julian day number ** %m month 01-12 ** %M minute 00-59 ** %s seconds since 1970-01-01 @@ -895,8 +895,10 @@ static void strftimeFunc( size_t i,j; char *z; sqlite3 *db; - const char *zFmt = (const char*)sqlite3_value_text(argv[0]); + const char *zFmt; char zBuf[100]; + if( argc==0 ) return; + zFmt = (const char*)sqlite3_value_text(argv[0]); if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; db = sqlite3_context_db_handle(context); for(i=0, n=1; zFmt[i]; i++, n++){ @@ -1090,7 +1092,7 @@ static void currentTimeFunc( iT = sqlite3StmtCurrentTime(context); if( iT<=0 ) return; t = iT/1000 - 10000*(sqlite3_int64)21086676; -#ifdef HAVE_GMTIME_R +#if HAVE_GMTIME_R pTm = gmtime_r(&t, &sNow); #else sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); diff --git a/src/delete.c b/src/delete.c index c74d8ea..011fb80 100644 --- a/src/delete.c +++ b/src/delete.c @@ -90,7 +90,7 @@ void sqlite3MaterializeView( Parse *pParse, /* Parsing context */ Table *pView, /* View definition */ Expr *pWhere, /* Optional WHERE clause to be added */ - int iCur /* Cursor number for ephemerial table */ + int iCur /* Cursor number for ephemeral table */ ){ SelectDest dest; Select *pSel; @@ -226,8 +226,8 @@ void sqlite3DeleteFrom( WhereInfo *pWInfo; /* Information about the WHERE clause */ Index *pIdx; /* For looping over indices of the table */ int iTabCur; /* Cursor number for the table */ - int iDataCur; /* VDBE cursor for the canonical data source */ - int iIdxCur; /* Cursor number of the first index */ + int iDataCur = 0; /* VDBE cursor for the canonical data source */ + int iIdxCur = 0; /* Cursor number of the first index */ int nIdx; /* Number of indices */ sqlite3 *db; /* Main database structure */ AuthContext sContext; /* Authorization context */ @@ -248,7 +248,7 @@ void sqlite3DeleteFrom( int addrBypass = 0; /* Address of jump over the delete logic */ int addrLoop = 0; /* Top of the delete loop */ int addrDelete = 0; /* Jump directly to the delete logic */ - int addrEphOpen = 0; /* Instruction to open the Ephermeral table */ + int addrEphOpen = 0; /* Instruction to open the Ephemeral table */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ @@ -328,7 +328,7 @@ void sqlite3DeleteFrom( sqlite3BeginWriteOperation(pParse, 1, iDb); /* If we are trying to delete from a view, realize that view into - ** a ephemeral table. + ** an ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( isView ){ @@ -382,7 +382,7 @@ void sqlite3DeleteFrom( iRowSet = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); }else{ - /* For a WITHOUT ROWID table, create an ephermeral table used to + /* For a WITHOUT ROWID table, create an ephemeral table used to ** hold all primary keys for rows to be deleted. */ pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); @@ -466,10 +466,11 @@ void sqlite3DeleteFrom( ** triggers. */ if( !isView ){ + testcase( IsVirtual(pTab) ); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen, &iDataCur, &iIdxCur); - assert( pPk || iDataCur==iTabCur ); - assert( pPk || iIdxCur==iDataCur+1 ); + assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur ); + assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 ); } /* Set up a loop over the rowids/primary-keys that were found in the @@ -477,9 +478,10 @@ void sqlite3DeleteFrom( */ if( okOnePass ){ /* Just one row. Hence the top-of-loop is a no-op */ - assert( nKey==nPk ); /* OP_Found will use an unpacked key */ + assert( nKey==nPk ); /* OP_Found will use an unpacked key */ + assert( !IsVirtual(pTab) ); if( aToOpen[iDataCur-iTabCur] ){ - assert( pPk!=0 ); + assert( pPk!=0 || pTab->pSelect!=0 ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); VdbeCoverage(v); } @@ -555,7 +557,7 @@ delete_from_cleanup: return; } /* Make sure "isView" and other macros defined above are undefined. Otherwise -** thely may interfere with compilation of other functions in this file +** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView diff --git a/src/expr.c b/src/expr.c index 0d2292e..32adedf 100644 --- a/src/expr.c +++ b/src/expr.c @@ -22,7 +22,7 @@ ** affinity of that column is returned. Otherwise, 0x00 is returned, ** indicating no affinity for the expression. ** -** i.e. the WHERE clause expresssions in the following statements all +** i.e. the WHERE clause expressions in the following statements all ** have an affinity: ** ** CREATE TABLE t1(a); @@ -501,7 +501,7 @@ void sqlite3ExprAttachSubtrees( } /* -** Allocate a Expr node which joins as many as two subtrees. +** Allocate an Expr node which joins as many as two subtrees. ** ** One or both of the subtrees can be NULL. Return a pointer to the new ** Expr node. Or, if an OOM error occurs, set pParse->db->mallocFailed, @@ -515,7 +515,7 @@ Expr *sqlite3PExpr( const Token *pToken /* Argument token */ ){ Expr *p; - if( op==TK_AND && pLeft && pRight ){ + if( op==TK_AND && pLeft && pRight && pParse->nErr==0 ){ /* Take advantage of short-circuit false optimization for AND */ p = sqlite3ExprAnd(pParse->db, pLeft, pRight); }else{ @@ -611,7 +611,7 @@ Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){ ** ** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number ** as the previous instance of the same wildcard. Or if this is the first -** instance of the wildcard, the next sequenial variable number is +** instance of the wildcard, the next sequential variable number is ** assigned. */ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ @@ -746,7 +746,7 @@ static int exprStructSize(Expr *p){ ** During expression analysis, extra information is computed and moved into ** later parts of teh Expr object and that extra information might get chopped ** off if the expression is reduced. Note also that it does not work to -** make a EXPRDUP_REDUCE copy of a reduced expression. It is only legal +** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal ** to reduce a pristine expression tree from the parser. The implementation ** of dupedExprStructSize() contain multiple assert() statements that attempt ** to enforce this constraint. @@ -815,7 +815,7 @@ static int dupedExprSize(Expr *p, int flags){ ** is not NULL then *pzBuffer is assumed to point to a buffer large enough ** to store the copy of expression p, the copies of p->u.zToken ** (if applicable), and the copies of the p->pLeft and p->pRight expressions, -** if any. Before returning, *pzBuffer is set to the first byte passed the +** if any. Before returning, *pzBuffer is set to the first byte past the ** portion of the buffer copied into by this function. */ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){ @@ -1069,6 +1069,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = p->nSelectRow; pNew->pWith = withDup(db, p->pWith); + sqlite3SelectSetName(pNew, p->zSelName); return pNew; } #else @@ -1209,37 +1210,51 @@ void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ } /* -** These routines are Walker callbacks. Walker.u.pi is a pointer -** to an integer. These routines are checking an expression to see -** if it is a constant. Set *Walker.u.pi to 0 if the expression is -** not constant. +** These routines are Walker callbacks used to check expressions to +** see if they are "constant" for some definition of constant. The +** Walker.eCode value determines the type of "constant" we are looking +** for. ** ** These callback routines are used to implement the following: ** -** sqlite3ExprIsConstant() -** sqlite3ExprIsConstantNotJoin() -** sqlite3ExprIsConstantOrFunction() +** sqlite3ExprIsConstant() pWalker->eCode==1 +** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2 +** sqlite3ExprRefOneTableOnly() pWalker->eCode==3 +** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5 ** +** In all cases, the callbacks set Walker.eCode=0 and abort if the expression +** is found to not be a constant. +** +** The sqlite3ExprIsConstantOrFunction() is used for evaluating expressions +** in a CREATE TABLE statement. The Walker.eCode value is 5 when parsing +** an existing schema and 4 when processing a new statement. A bound +** parameter raises an error for new statements, but is silently converted +** to NULL for existing schemas. This allows sqlite_master tables that +** contain a bound parameter because they were generated by older versions +** of SQLite to be parsed by newer versions of SQLite without raising a +** malformed schema error. */ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ - /* If pWalker->u.i is 3 then any term of the expression that comes from - ** the ON or USING clauses of a join disqualifies the expression + /* If pWalker->eCode is 2 then any term of the expression that comes from + ** the ON or USING clauses of a left join disqualifies the expression ** from being considered constant. */ - if( pWalker->u.i==3 && ExprHasProperty(pExpr, EP_FromJoin) ){ - pWalker->u.i = 0; + if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){ + pWalker->eCode = 0; return WRC_Abort; } switch( pExpr->op ){ /* Consider functions to be constant if all their arguments are constant - ** and either pWalker->u.i==2 or the function as the SQLITE_FUNC_CONST - ** flag. */ + ** and either pWalker->eCode==4 or 5 or the function has the + ** SQLITE_FUNC_CONST flag. */ case TK_FUNCTION: - if( pWalker->u.i==2 || ExprHasProperty(pExpr,EP_Constant) ){ + if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_Constant) ){ return WRC_Continue; + }else{ + pWalker->eCode = 0; + return WRC_Abort; } - /* Fall through */ case TK_ID: case TK_COLUMN: case TK_AGG_FUNCTION: @@ -1248,8 +1263,25 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); testcase( pExpr->op==TK_AGG_COLUMN ); - pWalker->u.i = 0; - return WRC_Abort; + if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){ + return WRC_Continue; + }else{ + pWalker->eCode = 0; + return WRC_Abort; + } + case TK_VARIABLE: + if( pWalker->eCode==5 ){ + /* Silently convert bound parameters that appear inside of CREATE + ** statements into a NULL when parsing the CREATE statement text out + ** of the sqlite_master table */ + pExpr->op = TK_NULL; + }else if( pWalker->eCode==4 ){ + /* A bound parameter in a CREATE statement that originates from + ** sqlite3_prepare() causes an error */ + pWalker->eCode = 0; + return WRC_Abort; + } + /* Fall through */ default: testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */ testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */ @@ -1258,21 +1290,22 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ } static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){ UNUSED_PARAMETER(NotUsed); - pWalker->u.i = 0; + pWalker->eCode = 0; return WRC_Abort; } -static int exprIsConst(Expr *p, int initFlag){ +static int exprIsConst(Expr *p, int initFlag, int iCur){ Walker w; memset(&w, 0, sizeof(w)); - w.u.i = initFlag; + w.eCode = initFlag; w.xExprCallback = exprNodeIsConstant; w.xSelectCallback = selectNodeIsConstant; + w.u.iCur = iCur; sqlite3WalkExpr(&w, p); - return w.u.i; + return w.eCode; } /* -** Walk an expression tree. Return 1 if the expression is constant +** Walk an expression tree. Return non-zero if the expression is constant ** and 0 if it involves variables or function calls. ** ** For the purposes of this function, a double-quoted string (ex: "abc") @@ -1280,21 +1313,31 @@ static int exprIsConst(Expr *p, int initFlag){ ** a constant. */ int sqlite3ExprIsConstant(Expr *p){ - return exprIsConst(p, 1); + return exprIsConst(p, 1, 0); } /* -** Walk an expression tree. Return 1 if the expression is constant +** Walk an expression tree. Return non-zero if the expression is constant ** that does no originate from the ON or USING clauses of a join. ** Return 0 if it involves variables or function calls or terms from ** an ON or USING clause. */ int sqlite3ExprIsConstantNotJoin(Expr *p){ - return exprIsConst(p, 3); + return exprIsConst(p, 2, 0); } /* -** Walk an expression tree. Return 1 if the expression is constant +** Walk an expression tree. Return non-zero if the expression constant +** for any single row of the table with cursor iCur. In other words, the +** expression must not refer to any non-deterministic function nor any +** table other than iCur. +*/ +int sqlite3ExprIsTableConstant(Expr *p, int iCur){ + return exprIsConst(p, 3, iCur); +} + +/* +** Walk an expression tree. Return non-zero if the expression is constant ** or a function call with constant arguments. Return and 0 if there ** are any variables. ** @@ -1302,8 +1345,9 @@ int sqlite3ExprIsConstantNotJoin(Expr *p){ ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. */ -int sqlite3ExprIsConstantOrFunction(Expr *p){ - return exprIsConst(p, 2); +int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ + assert( isInit==0 || isInit==1 ); + return exprIsConst(p, 4+isInit, 0); } /* @@ -1370,7 +1414,8 @@ int sqlite3ExprCanBeNull(const Expr *p){ return 0; case TK_COLUMN: assert( p->pTab!=0 ); - return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0; + return ExprHasProperty(p, EP_CanBeNull) || + (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0); default: return 1; } @@ -1541,7 +1586,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){ ** ** If the RHS of the IN operator is a list or a more complex subquery, then ** an ephemeral table might need to be generated from the RHS and then -** pX->iTable made to point to the ephermeral table instead of an +** pX->iTable made to point to the ephemeral table instead of an ** existing table. ** ** The inFlags parameter must contain exactly one of the bits @@ -1671,7 +1716,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){ ** and IN_INDEX_NOOP is an allowed reply ** and the RHS of the IN operator is a list, not a subquery ** and the RHS is not contant or has two or fewer terms, - ** then it is not worth creating an ephermeral table to evaluate + ** then it is not worth creating an ephemeral table to evaluate ** the IN operator so return IN_INDEX_NOOP. */ if( eType==0 @@ -1813,7 +1858,6 @@ int sqlite3CodeSubselect( assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); pSelect->iLimit = 0; testcase( pSelect->selFlags & SF_Distinct ); - pSelect->selFlags &= ~SF_Distinct; testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ if( sqlite3Select(pParse, pSelect, &dest) ){ sqlite3KeyInfoUnref(pKeyInfo); @@ -1912,6 +1956,7 @@ int sqlite3CodeSubselect( sqlite3SelectDestInit(&dest, 0, ++pParse->nMem); if( pExpr->op==TK_SELECT ){ dest.eDest = SRT_Mem; + dest.iSdst = dest.iSDParm; sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iSDParm); VdbeComment((v, "Init subquery result")); }else{ @@ -2431,16 +2476,9 @@ void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){ ** over to iTo..iTo+nReg-1. Keep the column cache up-to-date. */ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ - int i; - struct yColCache *p; assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo ); sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); - for(i=0, p=pParse->aColCache; iiReg; - if( x>=iFrom && xiReg += iTo-iFrom; - } - } + sqlite3ExprCacheRemove(pParse, iFrom, nReg); } #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) @@ -2595,26 +2633,13 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ - int aff, to_op; inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); - assert( !ExprHasProperty(pExpr, EP_IntValue) ); - aff = sqlite3AffinityType(pExpr->u.zToken, 0); - to_op = aff - SQLITE_AFF_TEXT + OP_ToText; - assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT ); - assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE ); - assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC ); - assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER ); - assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL ); - testcase( to_op==OP_ToText ); - testcase( to_op==OP_ToBlob ); - testcase( to_op==OP_ToNumeric ); - testcase( to_op==OP_ToInt ); - testcase( to_op==OP_ToReal ); if( inReg!=target ){ sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); inReg = target; } - sqlite3VdbeAddOp1(v, to_op, inReg); + sqlite3VdbeAddOp2(v, OP_Cast, target, + sqlite3AffinityType(pExpr->u.zToken, 0)); testcase( usedAsColumnCache(pParse, inReg, inReg) ); sqlite3ExprCacheAffinityChange(pParse, inReg, 1); break; @@ -2770,7 +2795,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ } /* Attempt a direct implementation of the built-in COALESCE() and - ** IFNULL() functions. This avoids unnecessary evalation of + ** IFNULL() functions. This avoids unnecessary evaluation of ** arguments past the first non-NULL argument. */ if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){ @@ -2979,7 +3004,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ #ifndef SQLITE_OMIT_FLOATING_POINT /* If the column has REAL affinity, it may currently be stored as an - ** integer. Use OP_RealAffinity to make sure it is really real. */ + ** integer. Use OP_RealAffinity to make sure it is really real. + ** + ** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to + ** floating point when extracting it from the record. */ if( pExpr->iColumn>=0 && pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL ){ @@ -3209,7 +3237,7 @@ void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ } /* -** Generate code that evalutes the given expression and puts the result +** Generate code that evaluates the given expression and puts the result ** in register target. ** ** Also make a copy of the expression results into another "cache" register @@ -3232,90 +3260,86 @@ void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ exprToRegister(pExpr, iMem); } -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) +#ifdef SQLITE_DEBUG /* ** Generate a human-readable explanation of an expression tree. */ -void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ - int op; /* The opcode being coded */ +void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ const char *zBinOp = 0; /* Binary operator */ const char *zUniOp = 0; /* Unary operator */ + pView = sqlite3TreeViewPush(pView, moreToFollow); if( pExpr==0 ){ - op = TK_NULL; - }else{ - op = pExpr->op; + sqlite3TreeViewLine(pView, "nil"); + sqlite3TreeViewPop(pView); + return; } - switch( op ){ + switch( pExpr->op ){ case TK_AGG_COLUMN: { - sqlite3ExplainPrintf(pOut, "AGG{%d:%d}", + sqlite3TreeViewLine(pView, "AGG{%d:%d}", pExpr->iTable, pExpr->iColumn); break; } case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ - sqlite3ExplainPrintf(pOut, "COLUMN(%d)", pExpr->iColumn); + sqlite3TreeViewLine(pView, "COLUMN(%d)", pExpr->iColumn); }else{ - sqlite3ExplainPrintf(pOut, "{%d:%d}", + sqlite3TreeViewLine(pView, "{%d:%d}", pExpr->iTable, pExpr->iColumn); } break; } case TK_INTEGER: { if( pExpr->flags & EP_IntValue ){ - sqlite3ExplainPrintf(pOut, "%d", pExpr->u.iValue); + sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); }else{ - sqlite3ExplainPrintf(pOut, "%s", pExpr->u.zToken); + sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); } break; } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { - sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken); + sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_STRING: { - sqlite3ExplainPrintf(pOut,"%Q", pExpr->u.zToken); + sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); break; } case TK_NULL: { - sqlite3ExplainPrintf(pOut,"NULL"); + sqlite3TreeViewLine(pView,"NULL"); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { - sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken); + sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_VARIABLE: { - sqlite3ExplainPrintf(pOut,"VARIABLE(%s,%d)", - pExpr->u.zToken, pExpr->iColumn); + sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", + pExpr->u.zToken, pExpr->iColumn); break; } case TK_REGISTER: { - sqlite3ExplainPrintf(pOut,"REGISTER(%d)", pExpr->iTable); + sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); break; } case TK_AS: { - sqlite3ExplainExpr(pOut, pExpr->pLeft); + sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } + case TK_ID: { + sqlite3TreeViewLine(pView,"ID %Q", pExpr->u.zToken); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ - const char *zAff = "unk"; - switch( sqlite3AffinityType(pExpr->u.zToken, 0) ){ - case SQLITE_AFF_TEXT: zAff = "TEXT"; break; - case SQLITE_AFF_NONE: zAff = "NONE"; break; - case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break; - case SQLITE_AFF_INTEGER: zAff = "INTEGER"; break; - case SQLITE_AFF_REAL: zAff = "REAL"; break; - } - sqlite3ExplainPrintf(pOut, "CAST-%s(", zAff); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut, ")"); + sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } #endif /* SQLITE_OMIT_CAST */ @@ -3339,6 +3363,7 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ case TK_LSHIFT: zBinOp = "LSHIFT"; break; case TK_RSHIFT: zBinOp = "RSHIFT"; break; case TK_CONCAT: zBinOp = "CONCAT"; break; + case TK_DOT: zBinOp = "DOT"; break; case TK_UMINUS: zUniOp = "UMINUS"; break; case TK_UPLUS: zUniOp = "UPLUS"; break; @@ -3348,8 +3373,8 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ case TK_NOTNULL: zUniOp = "NOTNULL"; break; case TK_COLLATE: { - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut,".COLLATE(%s)",pExpr->u.zToken); + sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } @@ -3361,41 +3386,36 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ }else{ pFarg = pExpr->x.pList; } - if( op==TK_AGG_FUNCTION ){ - sqlite3ExplainPrintf(pOut, "AGG_FUNCTION%d:%s(", + if( pExpr->op==TK_AGG_FUNCTION ){ + sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q", pExpr->op2, pExpr->u.zToken); }else{ - sqlite3ExplainPrintf(pOut, "FUNCTION:%s(", pExpr->u.zToken); + sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken); } if( pFarg ){ - sqlite3ExplainExprList(pOut, pFarg); + sqlite3TreeViewExprList(pView, pFarg, 0, 0); } - sqlite3ExplainPrintf(pOut, ")"); break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { - sqlite3ExplainPrintf(pOut, "EXISTS("); - sqlite3ExplainSelect(pOut, pExpr->x.pSelect); - sqlite3ExplainPrintf(pOut,")"); + sqlite3TreeViewLine(pView, "EXISTS-expr"); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_SELECT: { - sqlite3ExplainPrintf(pOut, "("); - sqlite3ExplainSelect(pOut, pExpr->x.pSelect); - sqlite3ExplainPrintf(pOut, ")"); + sqlite3TreeViewLine(pView, "SELECT-expr"); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_IN: { - sqlite3ExplainPrintf(pOut, "IN("); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut, ","); + sqlite3TreeViewLine(pView, "IN"); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - sqlite3ExplainSelect(pOut, pExpr->x.pSelect); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); }else{ - sqlite3ExplainExprList(pOut, pExpr->x.pList); + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); } - sqlite3ExplainPrintf(pOut, ")"); break; } #endif /* SQLITE_OMIT_SUBQUERY */ @@ -3415,13 +3435,10 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ Expr *pX = pExpr->pLeft; Expr *pY = pExpr->x.pList->a[0].pExpr; Expr *pZ = pExpr->x.pList->a[1].pExpr; - sqlite3ExplainPrintf(pOut, "BETWEEN("); - sqlite3ExplainExpr(pOut, pX); - sqlite3ExplainPrintf(pOut, ","); - sqlite3ExplainExpr(pOut, pY); - sqlite3ExplainPrintf(pOut, ","); - sqlite3ExplainExpr(pOut, pZ); - sqlite3ExplainPrintf(pOut, ")"); + sqlite3TreeViewLine(pView, "BETWEEN"); + sqlite3TreeViewExpr(pView, pX, 1); + sqlite3TreeViewExpr(pView, pY, 1); + sqlite3TreeViewExpr(pView, pZ, 0); break; } case TK_TRIGGER: { @@ -3432,15 +3449,14 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ ** is set to the column of the pseudo-table to read, or to -1 to ** read the rowid field. */ - sqlite3ExplainPrintf(pOut, "%s(%d)", + sqlite3TreeViewLine(pView, "%s(%d)", pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); break; } case TK_CASE: { - sqlite3ExplainPrintf(pOut, "CASE("); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut, ","); - sqlite3ExplainExprList(pOut, pExpr->x.pList); + sqlite3TreeViewLine(pView, "CASE"); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); break; } #ifndef SQLITE_OMIT_TRIGGER @@ -3452,55 +3468,57 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } - sqlite3ExplainPrintf(pOut, "RAISE-%s(%s)", zType, pExpr->u.zToken); + sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } #endif + default: { + sqlite3TreeViewLine(pView, "op=%d", pExpr->op); + break; + } } if( zBinOp ){ - sqlite3ExplainPrintf(pOut,"%s(", zBinOp); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut,","); - sqlite3ExplainExpr(pOut, pExpr->pRight); - sqlite3ExplainPrintf(pOut,")"); + sqlite3TreeViewLine(pView, "%s", zBinOp); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + sqlite3TreeViewExpr(pView, pExpr->pRight, 0); }else if( zUniOp ){ - sqlite3ExplainPrintf(pOut,"%s(", zUniOp); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut,")"); + sqlite3TreeViewLine(pView, "%s", zUniOp); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); } + sqlite3TreeViewPop(pView); } -#endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */ +#endif /* SQLITE_DEBUG */ -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) +#ifdef SQLITE_DEBUG /* ** Generate a human-readable explanation of an expression list. */ -void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){ +void sqlite3TreeViewExprList( + TreeView *pView, + const ExprList *pList, + u8 moreToFollow, + const char *zLabel +){ int i; - if( pList==0 || pList->nExpr==0 ){ - sqlite3ExplainPrintf(pOut, "(empty-list)"); - return; - }else if( pList->nExpr==1 ){ - sqlite3ExplainExpr(pOut, pList->a[0].pExpr); + pView = sqlite3TreeViewPush(pView, moreToFollow); + if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; + if( pList==0 ){ + sqlite3TreeViewLine(pView, "%s (empty)", zLabel); }else{ - sqlite3ExplainPush(pOut); + sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; inExpr; i++){ - sqlite3ExplainPrintf(pOut, "item[%d] = ", i); - sqlite3ExplainPush(pOut); - sqlite3ExplainExpr(pOut, pList->a[i].pExpr); - sqlite3ExplainPop(pOut); - if( pList->a[i].zName ){ + sqlite3TreeViewExpr(pView, pList->a[i].pExpr, inExpr-1); +#if 0 + if( pList->a[i].zName ){ sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName); } if( pList->a[i].bSpanIsTab ){ sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan); } - if( inExpr-1 ){ - sqlite3ExplainNL(pOut); - } +#endif } - sqlite3ExplainPop(pOut); } + sqlite3TreeViewPop(pView); } #endif /* SQLITE_DEBUG */ @@ -3564,7 +3582,7 @@ int sqlite3ExprCodeExprList( ** x>=y AND x<=z ** ** Code it as such, taking care to do the common subexpression -** elementation of x. +** elimination of x. */ static void exprCodeBetween( Parse *pParse, /* Parsing and code generating context */ @@ -4051,10 +4069,11 @@ static int exprSrcCount(Walker *pWalker, Expr *pExpr){ int i; struct SrcCount *p = pWalker->u.pSrcCount; SrcList *pSrc = p->pSrc; - for(i=0; inSrc; i++){ + int nSrc = pSrc ? pSrc->nSrc : 0; + for(i=0; iiTable==pSrc->a[i].iCursor ) break; } - if( inSrc ){ + if( inThis++; }else{ p->nOther++; @@ -4301,7 +4320,7 @@ int sqlite3GetTempReg(Parse *pParse){ ** purpose. ** ** If a register is currently being used by the column cache, then -** the dallocation is deferred until the column cache line that uses +** the deallocation is deferred until the column cache line that uses ** the register becomes stale. */ void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ diff --git a/src/fkey.c b/src/fkey.c index 50c10da..fa148ba 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -173,7 +173,7 @@ ** ** 4) No parent key columns were provided explicitly as part of the ** foreign key definition, and the PRIMARY KEY of the parent table -** consists of a a different number of columns to the child key in +** consists of a different number of columns to the child key in ** the child table. ** ** then non-zero is returned, and a "foreign key mismatch" error loaded @@ -437,7 +437,7 @@ static void fkLookupParent( OE_Abort, 0, P4_STATIC, P5_ConstraintFK); }else{ if( nIncr>0 && pFKey->isDeferred==0 ){ - sqlite3ParseToplevel(pParse)->mayAbort = 1; + sqlite3MayAbort(pParse); } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); } @@ -509,6 +509,10 @@ static Expr *exprTableColumn( ** code for an SQL UPDATE operation, this function may be called twice - ** once to "delete" the old row and once to "insert" the new row. ** +** Parameter nIncr is passed -1 when inserting a row (as this may decrease +** the number of FK violations in the db) or +1 when deleting one (as this +** may increase the number of FK constraint problems). +** ** The code generated by this function scans through the rows in the child ** table that correspond to the parent table row being deleted or inserted. ** For each child row found, one of the following actions is taken: @@ -625,13 +629,9 @@ static void fkScanChildren( sqlite3ResolveExprNames(&sNameContext, pWhere); /* Create VDBE to loop through the entries in pSrc that match the WHERE - ** clause. If the constraint is not deferred, throw an exception for - ** each row found. Otherwise, for deferred constraints, increment the - ** deferred constraint counter by nIncr for each row selected. */ + ** clause. For each row found, increment either the deferred or immediate + ** foreign key constraint counter. */ pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); - if( nIncr>0 && pFKey->isDeferred==0 ){ - sqlite3ParseToplevel(pParse)->mayAbort = 1; - } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); if( pWInfo ){ sqlite3WhereEnd(pWInfo); @@ -659,8 +659,7 @@ static void fkScanChildren( ** table). */ FKey *sqlite3FkReferences(Table *pTab){ - int nName = sqlite3Strlen30(pTab->zName); - return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName, nName); + return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName); } /* @@ -811,6 +810,24 @@ static int fkParentIsModified( return 0; } +/* +** Return true if the parser passed as the first argument is being +** used to code a trigger that is really a "SET NULL" action belonging +** to trigger pFKey. +*/ +static int isSetNullAction(Parse *pParse, FKey *pFKey){ + Parse *pTop = sqlite3ParseToplevel(pParse); + if( pTop->pTriggerPrg ){ + Trigger *p = pTop->pTriggerPrg->pTrigger; + if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull) + || (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull) + ){ + return 1; + } + } + return 0; +} + /* ** This function is called when inserting, deleting or updating a row of ** table pTab to generate VDBE code to perform foreign key constraint @@ -863,7 +880,7 @@ void sqlite3FkCheck( int *aiCol; int iCol; int i; - int isIgnore = 0; + int bIgnore = 0; if( aChange && sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0 @@ -922,7 +939,7 @@ void sqlite3FkCheck( int rcauth; char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName; rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb); - isIgnore = (rcauth==SQLITE_IGNORE); + bIgnore = (rcauth==SQLITE_IGNORE); } #endif } @@ -937,12 +954,18 @@ void sqlite3FkCheck( /* A row is being removed from the child table. Search for the parent. ** If the parent does not exist, removing the child row resolves an ** outstanding foreign key constraint violation. */ - fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1,isIgnore); + fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore); } - if( regNew!=0 ){ + if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){ /* A row is being added to the child table. If a parent row cannot - ** be found, adding the child row has violated the FK constraint. */ - fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1,isIgnore); + ** be found, adding the child row has violated the FK constraint. + ** + ** If this operation is being performed as part of a trigger program + ** that is actually a "SET NULL" action belonging to this very + ** foreign key, then omit this scan altogether. As all child key + ** values are guaranteed to be NULL, it is not possible for adding + ** this row to cause an FK violation. */ + fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1, bIgnore); } sqlite3DbFree(db, aiFree); @@ -963,8 +986,8 @@ void sqlite3FkCheck( && !pParse->pToplevel && !pParse->isMultiWrite ){ assert( regOld==0 && regNew!=0 ); - /* Inserting a single row into a parent table cannot cause an immediate - ** foreign key violation. So do nothing in this case. */ + /* Inserting a single row into a parent table cannot cause (or fix) + ** an immediate foreign key violation. So do nothing in this case. */ continue; } @@ -988,13 +1011,28 @@ void sqlite3FkCheck( fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1); } if( regOld!=0 ){ - /* If there is a RESTRICT action configured for the current operation - ** on the parent table of this FK, then throw an exception - ** immediately if the FK constraint is violated, even if this is a - ** deferred trigger. That's what RESTRICT means. To defer checking - ** the constraint, the FK should specify NO ACTION (represented - ** using OE_None). NO ACTION is the default. */ + int eAction = pFKey->aAction[aChange!=0]; fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1); + /* If this is a deferred FK constraint, or a CASCADE or SET NULL + ** action applies, then any foreign key violations caused by + ** removing the parent key will be rectified by the action trigger. + ** So do not set the "may-abort" flag in this case. + ** + ** Note 1: If the FK is declared "ON UPDATE CASCADE", then the + ** may-abort flag will eventually be set on this statement anyway + ** (when this function is called as part of processing the UPDATE + ** within the action trigger). + ** + ** Note 2: At first glance it may seem like SQLite could simply omit + ** all OP_FkCounter related scans when either CASCADE or SET NULL + ** applies. The trouble starts if the CASCADE or SET NULL action + ** trigger causes other triggers or action rules attached to the + ** child table to fire. In these cases the fk constraint counters + ** might be set incorrectly if any OP_FkCounter related scans are + ** omitted. */ + if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){ + sqlite3MayAbort(pParse); + } } pItem->zName = 0; sqlite3SrcListDelete(db, pSrc); @@ -1338,7 +1376,7 @@ void sqlite3FkDelete(sqlite3 *db, Table *pTab){ }else{ void *p = (void *)pFKey->pNextTo; const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo); - sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, sqlite3Strlen30(z), p); + sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p); } if( pFKey->pNextTo ){ pFKey->pNextTo->pPrevTo = pFKey->pPrevTo; diff --git a/src/func.c b/src/func.c index dbc8375..a057993 100644 --- a/src/func.c +++ b/src/func.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file contains the C-language implementions for many of the SQL +** This file contains the C-language implementations for many of the SQL ** functions of SQLite. (Some function, and in particular the date and ** time functions, are implemented separately.) */ @@ -22,7 +22,10 @@ ** Return the collating function associated with a function. */ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ - return context->pColl; + VdbeOp *pOp = &context->pVdbe->aOp[context->iOp-1]; + assert( pOp->opcode==OP_CollSeq ); + assert( pOp->p4type==P4_COLLSEQ ); + return pOp->p4.pColl; } /* @@ -154,8 +157,8 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ default: { /* Because sqlite3_value_double() returns 0.0 if the argument is not ** something that can be converted into a number, we have: - ** IMP: R-57326-31541 Abs(X) return 0.0 if X is a string or blob that - ** cannot be converted to a numeric value. + ** IMP: R-01992-00519 Abs(X) returns 0.0 if X is a string or blob + ** that cannot be converted to a numeric value. */ double rVal = sqlite3_value_double(argv[0]); if( rVal<0 ) rVal = -rVal; @@ -325,13 +328,14 @@ static void substrFunc( for(z2=z; *z2 && p2; p2--){ SQLITE_SKIP_UTF8(z2); } - sqlite3_result_text(context, (char*)z, (int)(z2-z), SQLITE_TRANSIENT); + sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT, + SQLITE_UTF8); }else{ if( p1+p2>len ){ p2 = len-p1; if( p2<0 ) p2 = 0; } - sqlite3_result_blob(context, (char*)&z[p1], (int)p2, SQLITE_TRANSIENT); + sqlite3_result_blob64(context, (char*)&z[p1], (u64)p2, SQLITE_TRANSIENT); } } @@ -390,7 +394,7 @@ static void *contextMalloc(sqlite3_context *context, i64 nByte){ sqlite3_result_error_toobig(context); z = 0; }else{ - z = sqlite3Malloc((int)nByte); + z = sqlite3Malloc(nByte); if( !z ){ sqlite3_result_error_nomem(context); } @@ -566,10 +570,12 @@ struct compareInfo { ** whereas only characters less than 0x80 do in ASCII. */ #if defined(SQLITE_EBCDIC) -# define sqlite3Utf8Read(A) (*((*A)++)) -# define GlobUpperToLower(A) A = sqlite3UpperToLower[A] +# define sqlite3Utf8Read(A) (*((*A)++)) +# define GlobUpperToLower(A) A = sqlite3UpperToLower[A] +# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A] #else -# define GlobUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; } +# define GlobUpperToLower(A) if( A<=0x7f ){ A = sqlite3UpperToLower[A]; } +# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A] #endif static const struct compareInfo globInfo = { '*', '?', '[', 0 }; @@ -582,7 +588,7 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 }; /* ** Compare two UTF-8 strings for equality where the first string can -** potentially be a "glob" expression. Return true (1) if they +** potentially be a "glob" or "like" expression. Return true (1) if they ** are the same and false (0) if they are different. ** ** Globbing rules: @@ -602,11 +608,18 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 }; ** "[a-z]" matches any single lower-case letter. To match a '-', make ** it the last character in the list. ** +** Like matching rules: +** +** '%' Matches any sequence of zero or more characters +** +*** '_' Matches any one character +** +** Ec Where E is the "esc" character and c is any other +** character, including '%', '_', and esc, match exactly c. +** +** The comments through this routine usually assume glob matching. +** ** This routine is usually quick, but can be N**2 in the worst case. -** -** Hints: to match '*' or '?', put them in "[]". Like this: -** -** abc[*]xyz Matches "abc*xyz" only */ static int patternCompare( const u8 *zPattern, /* The glob pattern */ @@ -614,17 +627,25 @@ static int patternCompare( const struct compareInfo *pInfo, /* Information about how to do the compare */ u32 esc /* The escape character */ ){ - u32 c, c2; - int invert; - int seen; - u8 matchOne = pInfo->matchOne; - u8 matchAll = pInfo->matchAll; - u8 matchSet = pInfo->matchSet; - u8 noCase = pInfo->noCase; - int prevEscape = 0; /* True if the previous character was 'escape' */ + u32 c, c2; /* Next pattern and input string chars */ + u32 matchOne = pInfo->matchOne; /* "?" or "_" */ + u32 matchAll = pInfo->matchAll; /* "*" or "%" */ + u32 matchOther; /* "[" or the escape character */ + u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */ + const u8 *zEscaped = 0; /* One past the last escaped input char */ + + /* The GLOB operator does not have an ESCAPE clause. And LIKE does not + ** have the matchSet operator. So we either have to look for one or + ** the other, never both. Hence the single variable matchOther is used + ** to store the one we have to look for. + */ + matchOther = esc ? esc : pInfo->matchSet; while( (c = sqlite3Utf8Read(&zPattern))!=0 ){ - if( c==matchAll && !prevEscape ){ + if( c==matchAll ){ /* Match "*" */ + /* Skip over multiple "*" characters in the pattern. If there + ** are also "?" characters, skip those as well, but consume a + ** single character of the input string for each "?" skipped */ while( (c=sqlite3Utf8Read(&zPattern)) == matchAll || c == matchOne ){ if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){ @@ -632,86 +653,98 @@ static int patternCompare( } } if( c==0 ){ - return 1; - }else if( c==esc ){ - c = sqlite3Utf8Read(&zPattern); - if( c==0 ){ - return 0; - } - }else if( c==matchSet ){ - assert( esc==0 ); /* This is GLOB, not LIKE */ - assert( matchSet<0x80 ); /* '[' is a single-byte character */ - while( *zString && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){ - SQLITE_SKIP_UTF8(zString); - } - return *zString!=0; - } - while( (c2 = sqlite3Utf8Read(&zString))!=0 ){ - if( noCase ){ - GlobUpperToLower(c2); - GlobUpperToLower(c); - while( c2 != 0 && c2 != c ){ - c2 = sqlite3Utf8Read(&zString); - GlobUpperToLower(c2); - } + return 1; /* "*" at the end of the pattern matches */ + }else if( c==matchOther ){ + if( esc ){ + c = sqlite3Utf8Read(&zPattern); + if( c==0 ) return 0; }else{ - while( c2 != 0 && c2 != c ){ - c2 = sqlite3Utf8Read(&zString); + /* "[...]" immediately follows the "*". We have to do a slow + ** recursive search in this case, but it is an unusual case. */ + assert( matchOther<0x80 ); /* '[' is a single-byte character */ + while( *zString + && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){ + SQLITE_SKIP_UTF8(zString); } + return *zString!=0; + } + } + + /* At this point variable c contains the first character of the + ** pattern string past the "*". Search in the input string for the + ** first matching character and recursively contine the match from + ** that point. + ** + ** For a case-insensitive search, set variable cx to be the same as + ** c but in the other case and search the input string for either + ** c or cx. + */ + if( c<=0x80 ){ + u32 cx; + if( noCase ){ + cx = sqlite3Toupper(c); + c = sqlite3Tolower(c); + }else{ + cx = c; + } + while( (c2 = *(zString++))!=0 ){ + if( c2!=c && c2!=cx ) continue; + if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; + } + }else{ + while( (c2 = sqlite3Utf8Read(&zString))!=0 ){ + if( c2!=c ) continue; + if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; } - if( c2==0 ) return 0; - if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; } return 0; - }else if( c==matchOne && !prevEscape ){ - if( sqlite3Utf8Read(&zString)==0 ){ - return 0; - } - }else if( c==matchSet ){ - u32 prior_c = 0; - assert( esc==0 ); /* This only occurs for GLOB, not LIKE */ - seen = 0; - invert = 0; - c = sqlite3Utf8Read(&zString); - if( c==0 ) return 0; - c2 = sqlite3Utf8Read(&zPattern); - if( c2=='^' ){ - invert = 1; - c2 = sqlite3Utf8Read(&zPattern); - } - if( c2==']' ){ - if( c==']' ) seen = 1; - c2 = sqlite3Utf8Read(&zPattern); - } - while( c2 && c2!=']' ){ - if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ - c2 = sqlite3Utf8Read(&zPattern); - if( c>=prior_c && c<=c2 ) seen = 1; - prior_c = 0; - }else{ - if( c==c2 ){ - seen = 1; - } - prior_c = c2; - } - c2 = sqlite3Utf8Read(&zPattern); - } - if( c2==0 || (seen ^ invert)==0 ){ - return 0; - } - }else if( esc==c && !prevEscape ){ - prevEscape = 1; - }else{ - c2 = sqlite3Utf8Read(&zString); - if( noCase ){ - GlobUpperToLower(c); - GlobUpperToLower(c2); - } - if( c!=c2 ){ - return 0; - } - prevEscape = 0; } + if( c==matchOther ){ + if( esc ){ + c = sqlite3Utf8Read(&zPattern); + if( c==0 ) return 0; + zEscaped = zPattern; + }else{ + u32 prior_c = 0; + int seen = 0; + int invert = 0; + c = sqlite3Utf8Read(&zString); + if( c==0 ) return 0; + c2 = sqlite3Utf8Read(&zPattern); + if( c2=='^' ){ + invert = 1; + c2 = sqlite3Utf8Read(&zPattern); + } + if( c2==']' ){ + if( c==']' ) seen = 1; + c2 = sqlite3Utf8Read(&zPattern); + } + while( c2 && c2!=']' ){ + if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ + c2 = sqlite3Utf8Read(&zPattern); + if( c>=prior_c && c<=c2 ) seen = 1; + prior_c = 0; + }else{ + if( c==c2 ){ + seen = 1; + } + prior_c = c2; + } + c2 = sqlite3Utf8Read(&zPattern); + } + if( c2==0 || (seen ^ invert)==0 ){ + return 0; + } + continue; + } + } + c2 = sqlite3Utf8Read(&zString); + if( c==c2 ) continue; + if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){ + continue; + } + if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue; + return 0; } return *zString==0; } @@ -1041,7 +1074,7 @@ static void charFunc( *zOut++ = 0x80 + (u8)(c & 0x3F); } \ } - sqlite3_result_text(context, (char*)z, (int)(zOut-z), sqlite3_free); + sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8); } /* @@ -1491,6 +1524,7 @@ static void minmaxStep( sqlite3SkipAccumulatorLoad(context); } }else{ + pBest->db = sqlite3_context_db_handle(context); sqlite3VdbeMemCopy(pBest, pArg); } } @@ -1638,7 +1672,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ } /* -** All all of the FuncDef structures in the aBuiltinFunc[] array above +** All of the FuncDef structures in the aBuiltinFunc[] array above ** to the global function hash table. This occurs at start-time (as ** a consequence of calling sqlite3_initialize()). ** @@ -1662,10 +1696,12 @@ void sqlite3RegisterGlobalFunctions(void){ FUNCTION(trim, 2, 3, 0, trimFunc ), FUNCTION(min, -1, 0, 1, minmaxFunc ), FUNCTION(min, 0, 0, 1, 0 ), - AGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize ), + AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize, + SQLITE_FUNC_MINMAX ), FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, 0, 1, 1, 0 ), - AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ), + AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize, + SQLITE_FUNC_MINMAX ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), FUNCTION(instr, 2, 0, 0, instrFunc ), @@ -1695,6 +1731,9 @@ void sqlite3RegisterGlobalFunctions(void){ FUNCTION(sqlite_version, 0, 0, 0, versionFunc ), FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), +#if SQLITE_USER_AUTHENTICATION + FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ), +#endif #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), @@ -1715,8 +1754,8 @@ void sqlite3RegisterGlobalFunctions(void){ AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ), AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ), - /* AGGREGATE(count, 0, 0, 0, countStep, countFinalize ), */ - {0,SQLITE_UTF8|SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0}, + AGGREGATE2(count, 0, 0, 0, countStep, countFinalize, + SQLITE_FUNC_COUNT ), AGGREGATE(count, 1, 0, 0, countStep, countFinalize ), AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize), AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), diff --git a/src/global.c b/src/global.c index 2c14b58..c7043bb 100644 --- a/src/global.c +++ b/src/global.c @@ -10,7 +10,7 @@ ** ************************************************************************* ** -** This file contains definitions of global variables and contants. +** This file contains definitions of global variables and constants. */ #include "sqliteInt.h" @@ -129,14 +129,36 @@ const unsigned char sqlite3CtypeMap[256] = { }; #endif +/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards +** compatibility for legacy applications, the URI filename capability is +** disabled by default. +** +** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled +** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options. +** +** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally +** disabled. The default value may be changed by compiling with the +** SQLITE_USE_URI symbol defined. +*/ #ifndef SQLITE_USE_URI # define SQLITE_USE_URI 0 #endif +/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the +** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if +** that compile-time option is omitted. +*/ #ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 #endif +/* The minimum PMA size is set to this value multiplied by the database +** page size in bytes. +*/ +#ifndef SQLITE_SORTER_PMASZ +# define SQLITE_SORTER_PMASZ 250 +#endif + /* ** The following singleton contains the global configuration for ** the SQLite library. @@ -167,6 +189,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0, /* nPage */ 0, /* mxParserStack */ 0, /* sharedCacheEnabled */ + SQLITE_SORTER_PMASZ, /* szPma */ /* All the rest should always be initialized to zero */ 0, /* isInit */ 0, /* inProgress */ @@ -222,8 +245,8 @@ const Token sqlite3IntTokens[] = { ** ** IMPORTANT: Changing the pending byte to any value other than ** 0x40000000 results in an incompatible database file format! -** Changing the pending byte during operating results in undefined -** and dileterious behavior. +** Changing the pending byte during operation will result in undefined +** and incorrect behavior. */ #ifndef SQLITE_OMIT_WSD int sqlite3PendingByte = 0x40000000; diff --git a/src/hash.c b/src/hash.c index f9901fe..b5886e0 100644 --- a/src/hash.c +++ b/src/hash.c @@ -52,12 +52,11 @@ void sqlite3HashClear(Hash *pH){ /* ** The hashing function. */ -static unsigned int strHash(const char *z, int nKey){ +static unsigned int strHash(const char *z){ unsigned int h = 0; - assert( nKey>=0 ); - while( nKey > 0 ){ - h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++]; - nKey--; + unsigned char c; + while( (c = (unsigned char)*z++)!=0 ){ + h = (h<<3) ^ h ^ sqlite3UpperToLower[c]; } return h; } @@ -129,7 +128,7 @@ static int rehash(Hash *pH, unsigned int new_size){ pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht); memset(new_ht, 0, new_size*sizeof(struct _ht)); for(elem=pH->first, pH->first=0; elem; elem = next_elem){ - unsigned int h = strHash(elem->pKey, elem->nKey) % new_size; + unsigned int h = strHash(elem->pKey) % new_size; next_elem = elem->next; insertElement(pH, &new_ht[h], elem); } @@ -137,28 +136,33 @@ static int rehash(Hash *pH, unsigned int new_size){ } /* This function (for internal use only) locates an element in an -** hash table that matches the given key. The hash for this key has -** already been computed and is passed as the 4th parameter. +** hash table that matches the given key. The hash for this key is +** also computed and returned in the *pH parameter. */ -static HashElem *findElementGivenHash( +static HashElem *findElementWithHash( const Hash *pH, /* The pH to be searched */ const char *pKey, /* The key we are searching for */ - int nKey, /* Bytes in key (not counting zero terminator) */ - unsigned int h /* The hash for this key. */ + unsigned int *pHash /* Write the hash value here */ ){ HashElem *elem; /* Used to loop thru the element list */ int count; /* Number of elements left to test */ + unsigned int h; /* The computed hash */ if( pH->ht ){ - struct _ht *pEntry = &pH->ht[h]; + struct _ht *pEntry; + h = strHash(pKey) % pH->htsize; + pEntry = &pH->ht[h]; elem = pEntry->chain; count = pEntry->count; }else{ + h = 0; elem = pH->first; count = pH->count; } - while( count-- && ALWAYS(elem) ){ - if( elem->nKey==nKey && sqlite3StrNICmp(elem->pKey,pKey,nKey)==0 ){ + *pHash = h; + while( count-- ){ + assert( elem!=0 ); + if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ return elem; } elem = elem->next; @@ -201,26 +205,20 @@ static void removeElementGivenHash( } /* Attempt to locate an element of the hash table pH with a key -** that matches pKey,nKey. Return the data for this element if it is +** that matches pKey. Return the data for this element if it is ** found, or NULL if there is no match. */ -void *sqlite3HashFind(const Hash *pH, const char *pKey, int nKey){ +void *sqlite3HashFind(const Hash *pH, const char *pKey){ HashElem *elem; /* The element that matches key */ unsigned int h; /* A hash on key */ assert( pH!=0 ); assert( pKey!=0 ); - assert( nKey>=0 ); - if( pH->ht ){ - h = strHash(pKey, nKey) % pH->htsize; - }else{ - h = 0; - } - elem = findElementGivenHash(pH, pKey, nKey, h); + elem = findElementWithHash(pH, pKey, &h); return elem ? elem->data : 0; } -/* Insert an element into the hash table pH. The key is pKey,nKey +/* Insert an element into the hash table pH. The key is pKey ** and the data is "data". ** ** If no element exists with a matching key, then a new @@ -234,20 +232,14 @@ void *sqlite3HashFind(const Hash *pH, const char *pKey, int nKey){ ** If the "data" parameter to this function is NULL, then the ** element corresponding to "key" is removed from the hash table. */ -void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, void *data){ +void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ unsigned int h; /* the hash of the key modulo hash table size */ HashElem *elem; /* Used to loop thru the element list */ HashElem *new_elem; /* New element added to the pH */ assert( pH!=0 ); assert( pKey!=0 ); - assert( nKey>=0 ); - if( pH->htsize ){ - h = strHash(pKey, nKey) % pH->htsize; - }else{ - h = 0; - } - elem = findElementGivenHash(pH,pKey,nKey,h); + elem = findElementWithHash(pH,pKey,&h); if( elem ){ void *old_data = elem->data; if( data==0 ){ @@ -255,7 +247,6 @@ void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, void *data){ }else{ elem->data = data; elem->pKey = pKey; - assert(nKey==elem->nKey); } return old_data; } @@ -263,19 +254,14 @@ void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, void *data){ new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) ); if( new_elem==0 ) return data; new_elem->pKey = pKey; - new_elem->nKey = nKey; new_elem->data = data; pH->count++; if( pH->count>=10 && pH->count > 2*pH->htsize ){ if( rehash(pH, pH->count*2) ){ assert( pH->htsize>0 ); - h = strHash(pKey, nKey) % pH->htsize; + h = strHash(pKey) % pH->htsize; } } - if( pH->ht ){ - insertElement(pH, &pH->ht[h], new_elem); - }else{ - insertElement(pH, 0, new_elem); - } + insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem); return 0; } diff --git a/src/hash.h b/src/hash.h index 82b7c58..6dfa4e0 100644 --- a/src/hash.h +++ b/src/hash.h @@ -59,15 +59,15 @@ struct Hash { struct HashElem { HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ - const char *pKey; int nKey; /* Key associated with this element */ + const char *pKey; /* Key associated with this element */ }; /* ** Access routines. To delete, insert a NULL pointer. */ void sqlite3HashInit(Hash*); -void *sqlite3HashInsert(Hash*, const char *pKey, int nKey, void *pData); -void *sqlite3HashFind(const Hash*, const char *pKey, int nKey); +void *sqlite3HashInsert(Hash*, const char *pKey, void *pData); +void *sqlite3HashFind(const Hash*, const char *pKey); void sqlite3HashClear(Hash*); /* diff --git a/src/insert.c b/src/insert.c index 5964b91..a5c3f3e 100644 --- a/src/insert.c +++ b/src/insert.c @@ -56,13 +56,13 @@ void sqlite3OpenTable( ** ** Character Column affinity ** ------------------------------ -** 'a' TEXT -** 'b' NONE -** 'c' NUMERIC -** 'd' INTEGER -** 'e' REAL +** 'A' NONE +** 'B' TEXT +** 'C' NUMERIC +** 'D' INTEGER +** 'F' REAL ** -** An extra 'd' is appended to the end of the string to cover the +** An extra 'D' is appended to the end of the string to cover the ** rowid that appears as the last column in every index. ** ** Memory for the buffer containing the column index affinity string @@ -111,11 +111,11 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ ** ** Character Column affinity ** ------------------------------ -** 'a' TEXT -** 'b' NONE -** 'c' NUMERIC -** 'd' INTEGER -** 'e' REAL +** 'A' NONE +** 'B' TEXT +** 'C' NUMERIC +** 'D' INTEGER +** 'E' REAL */ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ int i; @@ -410,7 +410,7 @@ static int xferOptimization( ** The 4th template is used if the insert statement takes its ** values from a SELECT but the data is being inserted into a table ** that is also read as part of the SELECT. In the third form, -** we have to use a intermediate table to store the results of +** we have to use an intermediate table to store the results of ** the select. The template is like this: ** ** X <- A @@ -575,7 +575,7 @@ void sqlite3Insert( regAutoinc = autoIncBegin(pParse, iDb, pTab); /* Allocate registers for holding the rowid of the new row, - ** the content of the new row, and the assemblied row record. + ** the content of the new row, and the assembled row record. */ regRowid = regIns = pParse->nMem+1; pParse->nMem += pTab->nCol + 1; @@ -1027,7 +1027,7 @@ insert_cleanup: } /* Make sure "isView" and other macros defined above are undefined. Otherwise -** thely may interfere with compilation of other functions in this file +** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView @@ -1143,7 +1143,7 @@ void sqlite3GenerateConstraintChecks( int ix; /* Index loop counter */ int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ - int j1; /* Addresss of jump instruction */ + int j1; /* Address of jump instruction */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ int ipkTop = 0; /* Top of the rowid change constraint check */ @@ -1547,7 +1547,7 @@ void sqlite3CompleteInsertion( Index *pIdx; /* An index being inserted or updated */ u8 pik_flags; /* flag values passed to the btree insert */ int regData; /* Content registers (after the rowid) */ - int regRec; /* Register holding assemblied record for the table */ + int regRec; /* Register holding assembled record for the table */ int i; /* Loop counter */ u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */ @@ -1612,6 +1612,9 @@ void sqlite3CompleteInsertion( ** For a WITHOUT ROWID table, *piDataCur will be somewhere in the range ** of *piIdxCurs, depending on where the PRIMARY KEY index appears on the ** pTab->pIndex list. +** +** If pTab is a virtual table, then this routine is a no-op and the +** *piDataCur and *piIdxCur values are left uninitialized. */ int sqlite3OpenTableAndIndices( Parse *pParse, /* Parsing context */ @@ -1630,9 +1633,9 @@ int sqlite3OpenTableAndIndices( assert( op==OP_OpenRead || op==OP_OpenWrite ); if( IsVirtual(pTab) ){ - assert( aToOpen==0 ); - *piDataCur = 0; - *piIdxCur = 1; + /* This routine is a no-op for virtual tables. Leave the output + ** variables *piDataCur and *piIdxCur uninitialized so that valgrind + ** can detect if they are used by mistake in the caller. */ return 0; } iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); @@ -1669,7 +1672,7 @@ int sqlite3OpenTableAndIndices( ** The following global variable is incremented whenever the ** transfer optimization is used. This is used for testing ** purposes only - to make sure the transfer optimization really -** is happening when it is suppose to. +** is happening when it is supposed to. */ int sqlite3_xferopt_count; #endif /* SQLITE_TEST */ @@ -1736,7 +1739,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ ** INSERT INTO tab1 SELECT * FROM tab2; ** ** The xfer optimization transfers raw records from tab2 over to tab1. -** Columns are not decoded and reassemblied, which greatly improves +** Columns are not decoded and reassembled, which greatly improves ** performance. Raw index records are transferred in the same way. ** ** The xfer optimization is only attempted if tab1 and tab2 are compatible. diff --git a/src/legacy.c b/src/legacy.c index 1913f0b..a10006e 100644 --- a/src/legacy.c +++ b/src/legacy.c @@ -44,7 +44,7 @@ int sqlite3_exec( if( zSql==0 ) zSql = ""; sqlite3_mutex_enter(db->mutex); - sqlite3Error(db, SQLITE_OK, 0); + sqlite3Error(db, SQLITE_OK); while( rc==SQLITE_OK && zSql[0] ){ int nCol; char **azVals = 0; @@ -102,7 +102,7 @@ int sqlite3_exec( rc = SQLITE_ABORT; sqlite3VdbeFinalize((Vdbe *)pStmt); pStmt = 0; - sqlite3Error(db, SQLITE_ABORT, 0); + sqlite3Error(db, SQLITE_ABORT); goto exec_out; } } @@ -125,14 +125,14 @@ exec_out: sqlite3DbFree(db, azCols); rc = sqlite3ApiExit(db, rc); - if( rc!=SQLITE_OK && ALWAYS(rc==sqlite3_errcode(db)) && pzErrMsg ){ + if( rc!=SQLITE_OK && pzErrMsg ){ int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db)); *pzErrMsg = sqlite3Malloc(nErrMsg); if( *pzErrMsg ){ memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg); }else{ rc = SQLITE_NOMEM; - sqlite3Error(db, SQLITE_NOMEM, 0); + sqlite3Error(db, SQLITE_NOMEM); } }else if( pzErrMsg ){ *pzErrMsg = 0; diff --git a/src/lempar.c b/src/lempar.c index 2afaa6c..ba0837c 100644 --- a/src/lempar.c +++ b/src/lempar.c @@ -271,9 +271,9 @@ static void yyGrowStack(yyParser *p){ ** A pointer to a parser. This pointer is used in subsequent calls ** to Parse and ParseFree. */ -void *ParseAlloc(void *(*mallocProc)(size_t)){ +void *ParseAlloc(void *(*mallocProc)(u64)){ yyParser *pParser; - pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); + pParser = (yyParser*)(*mallocProc)( (u64)sizeof(yyParser) ); if( pParser ){ pParser->yyidx = -1; #ifdef YYTRACKMAXSTACKDEPTH diff --git a/src/loadext.c b/src/loadext.c index 828e865..7b39ff1 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -34,7 +34,6 @@ # define sqlite3_column_table_name16 0 # define sqlite3_column_origin_name 0 # define sqlite3_column_origin_name16 0 -# define sqlite3_table_column_metadata 0 #endif #ifdef SQLITE_OMIT_AUTHORIZATION @@ -390,7 +389,20 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_uri_int64, sqlite3_uri_parameter, sqlite3_vsnprintf, - sqlite3_wal_checkpoint_v2 + sqlite3_wal_checkpoint_v2, + /* Version 3.8.7 and later */ + sqlite3_auto_extension, + sqlite3_bind_blob64, + sqlite3_bind_text64, + sqlite3_cancel_auto_extension, + sqlite3_load_extension, + sqlite3_malloc64, + sqlite3_msize, + sqlite3_realloc64, + sqlite3_reset_auto_extension, + sqlite3_result_blob64, + sqlite3_result_text64, + sqlite3_strglob }; /* @@ -749,7 +761,7 @@ void sqlite3AutoLoadExtensions(sqlite3 *db){ sqlite3_mutex_leave(mutex); zErrmsg = 0; if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){ - sqlite3Error(db, rc, + sqlite3ErrorWithMsg(db, rc, "automatic extension loading failed: %s", zErrmsg); go = 0; } diff --git a/src/main.c b/src/main.c index cea7282..5aa37fa 100644 --- a/src/main.c +++ b/src/main.c @@ -62,7 +62,7 @@ int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } ** I/O active are written using this function. These messages ** are intended for debugging activity only. */ -void (*sqlite3IoTrace)(const char*, ...) = 0; +/* not-private */ void (*sqlite3IoTrace)(const char*, ...) = 0; #endif /* @@ -271,6 +271,13 @@ int sqlite3_initialize(void){ ** when this routine is invoked, then this routine is a harmless no-op. */ int sqlite3_shutdown(void){ +#ifdef SQLITE_OMIT_WSD + int rc = sqlite3_wsd_init(4096, 24); + if( rc!=SQLITE_OK ){ + return rc; + } +#endif + if( sqlite3GlobalConfig.isInit ){ #ifdef SQLITE_EXTRA_SHUTDOWN void SQLITE_EXTRA_SHUTDOWN(void); @@ -329,15 +336,17 @@ int sqlite3_config(int op, ...){ switch( op ){ /* Mutex configuration options are only available in a threadsafe - ** compile. + ** compile. */ -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */ case SQLITE_CONFIG_SINGLETHREAD: { /* Disable all mutexing */ sqlite3GlobalConfig.bCoreMutex = 0; sqlite3GlobalConfig.bFullMutex = 0; break; } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */ case SQLITE_CONFIG_MULTITHREAD: { /* Disable mutexing of database connections */ /* Enable mutexing of core data structures */ @@ -345,17 +354,23 @@ int sqlite3_config(int op, ...){ sqlite3GlobalConfig.bFullMutex = 0; break; } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */ case SQLITE_CONFIG_SERIALIZED: { /* Enable all mutexing */ sqlite3GlobalConfig.bCoreMutex = 1; sqlite3GlobalConfig.bFullMutex = 1; break; } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */ case SQLITE_CONFIG_MUTEX: { /* Specify an alternative mutex implementation */ sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*); break; } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */ case SQLITE_CONFIG_GETMUTEX: { /* Retrieve the current mutex implementation */ *va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex; @@ -363,37 +378,61 @@ int sqlite3_config(int op, ...){ } #endif - case SQLITE_CONFIG_MALLOC: { - /* Specify an alternative malloc implementation */ + /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a + ** single argument which is a pointer to an instance of the + ** sqlite3_mem_methods structure. The argument specifies alternative + ** low-level memory allocation routines to be used in place of the memory + ** allocation routines built into SQLite. */ sqlite3GlobalConfig.m = *va_arg(ap, sqlite3_mem_methods*); break; } case SQLITE_CONFIG_GETMALLOC: { - /* Retrieve the current malloc() implementation */ + /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC option takes a + ** single argument which is a pointer to an instance of the + ** sqlite3_mem_methods structure. The sqlite3_mem_methods structure is + ** filled with the currently defined memory allocation routines. */ if( sqlite3GlobalConfig.m.xMalloc==0 ) sqlite3MemSetDefault(); *va_arg(ap, sqlite3_mem_methods*) = sqlite3GlobalConfig.m; break; } case SQLITE_CONFIG_MEMSTATUS: { - /* Enable or disable the malloc status collection */ + /* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes + ** single argument of type int, interpreted as a boolean, which enables + ** or disables the collection of memory allocation statistics. */ sqlite3GlobalConfig.bMemstat = va_arg(ap, int); break; } case SQLITE_CONFIG_SCRATCH: { - /* Designate a buffer for scratch memory space */ + /* EVIDENCE-OF: R-08404-60887 There are three arguments to + ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from + ** which the scratch allocations will be drawn, the size of each scratch + ** allocation (sz), and the maximum number of scratch allocations (N). */ sqlite3GlobalConfig.pScratch = va_arg(ap, void*); sqlite3GlobalConfig.szScratch = va_arg(ap, int); sqlite3GlobalConfig.nScratch = va_arg(ap, int); break; } case SQLITE_CONFIG_PAGECACHE: { - /* Designate a buffer for page cache memory space */ + /* EVIDENCE-OF: R-31408-40510 There are three arguments to + ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory, the size + ** of each page buffer (sz), and the number of pages (N). */ sqlite3GlobalConfig.pPage = va_arg(ap, void*); sqlite3GlobalConfig.szPage = va_arg(ap, int); sqlite3GlobalConfig.nPage = va_arg(ap, int); break; } + case SQLITE_CONFIG_PCACHE_HDRSZ: { + /* EVIDENCE-OF: R-39100-27317 The SQLITE_CONFIG_PCACHE_HDRSZ option takes + ** a single parameter which is a pointer to an integer and writes into + ** that integer the number of extra bytes per page required for each page + ** in SQLITE_CONFIG_PAGECACHE. */ + *va_arg(ap, int*) = + sqlite3HeaderSizeBtree() + + sqlite3HeaderSizePcache() + + sqlite3HeaderSizePcache1(); + break; + } case SQLITE_CONFIG_PCACHE: { /* no-op */ @@ -406,11 +445,18 @@ int sqlite3_config(int op, ...){ } case SQLITE_CONFIG_PCACHE2: { - /* Specify an alternative page cache implementation */ + /* EVIDENCE-OF: R-63325-48378 The SQLITE_CONFIG_PCACHE2 option takes a + ** single argument which is a pointer to an sqlite3_pcache_methods2 + ** object. This object specifies the interface to a custom page cache + ** implementation. */ sqlite3GlobalConfig.pcache2 = *va_arg(ap, sqlite3_pcache_methods2*); break; } case SQLITE_CONFIG_GETPCACHE2: { + /* EVIDENCE-OF: R-22035-46182 The SQLITE_CONFIG_GETPCACHE2 option takes a + ** single argument which is a pointer to an sqlite3_pcache_methods2 + ** object. SQLite copies of the current page cache implementation into + ** that object. */ if( sqlite3GlobalConfig.pcache2.xInit==0 ){ sqlite3PCacheSetDefault(); } @@ -418,9 +464,14 @@ int sqlite3_config(int op, ...){ break; } +/* EVIDENCE-OF: R-06626-12911 The SQLITE_CONFIG_HEAP option is only +** available if SQLite is compiled with either SQLITE_ENABLE_MEMSYS3 or +** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) case SQLITE_CONFIG_HEAP: { - /* Designate a buffer for heap memory space */ + /* EVIDENCE-OF: R-19854-42126 There are three arguments to + ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the + ** number of bytes in the memory buffer, and the minimum allocation size. */ sqlite3GlobalConfig.pHeap = va_arg(ap, void*); sqlite3GlobalConfig.nHeap = va_arg(ap, int); sqlite3GlobalConfig.mnReq = va_arg(ap, int); @@ -433,17 +484,19 @@ int sqlite3_config(int op, ...){ } if( sqlite3GlobalConfig.pHeap==0 ){ - /* If the heap pointer is NULL, then restore the malloc implementation - ** back to NULL pointers too. This will cause the malloc to go - ** back to its default implementation when sqlite3_initialize() is - ** run. + /* EVIDENCE-OF: R-49920-60189 If the first pointer (the memory pointer) + ** is NULL, then SQLite reverts to using its default memory allocator + ** (the system malloc() implementation), undoing any prior invocation of + ** SQLITE_CONFIG_MALLOC. + ** + ** Setting sqlite3GlobalConfig.m to all zeros will cause malloc to + ** revert to its default implementation when sqlite3_initialize() is run */ memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m)); }else{ - /* The heap pointer is not NULL, then install one of the - ** mem5.c/mem3.c methods. The enclosing #if guarantees at - ** least one of these methods is currently enabled. - */ + /* EVIDENCE-OF: R-61006-08918 If the memory pointer is not NULL then the + ** alternative memory allocator is engaged to handle all of SQLites + ** memory allocation needs. */ #ifdef SQLITE_ENABLE_MEMSYS3 sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3(); #endif @@ -476,12 +529,25 @@ int sqlite3_config(int op, ...){ break; } + /* EVIDENCE-OF: R-55548-33817 The compile-time setting for URI filenames + ** can be changed at start-time using the + ** sqlite3_config(SQLITE_CONFIG_URI,1) or + ** sqlite3_config(SQLITE_CONFIG_URI,0) configuration calls. + */ case SQLITE_CONFIG_URI: { + /* EVIDENCE-OF: R-25451-61125 The SQLITE_CONFIG_URI option takes a single + ** argument of type int. If non-zero, then URI handling is globally + ** enabled. If the parameter is zero, then URI handling is globally + ** disabled. */ sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); break; } case SQLITE_CONFIG_COVERING_INDEX_SCAN: { + /* EVIDENCE-OF: R-36592-02772 The SQLITE_CONFIG_COVERING_INDEX_SCAN + ** option takes a single integer argument which is interpreted as a + ** boolean in order to enable or disable the use of covering indices for + ** full table scans in the query optimizer. */ sqlite3GlobalConfig.bUseCis = va_arg(ap, int); break; } @@ -496,25 +562,43 @@ int sqlite3_config(int op, ...){ #endif case SQLITE_CONFIG_MMAP_SIZE: { + /* EVIDENCE-OF: R-58063-38258 SQLITE_CONFIG_MMAP_SIZE takes two 64-bit + ** integer (sqlite3_int64) values that are the default mmap size limit + ** (the default setting for PRAGMA mmap_size) and the maximum allowed + ** mmap size limit. */ sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64); sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64); - if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ - mxMmap = SQLITE_MAX_MMAP_SIZE; - } - sqlite3GlobalConfig.mxMmap = mxMmap; + /* EVIDENCE-OF: R-53367-43190 If either argument to this option is + ** negative, then that argument is changed to its compile-time default. + ** + ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be + ** silently truncated if necessary so that it does not exceed the + ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE + ** compile-time option. + */ + if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ) mxMmap = SQLITE_MAX_MMAP_SIZE; if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; if( szMmap>mxMmap) szMmap = mxMmap; + sqlite3GlobalConfig.mxMmap = mxMmap; sqlite3GlobalConfig.szMmap = szMmap; break; } -#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) +#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) /* IMP: R-04780-55815 */ case SQLITE_CONFIG_WIN32_HEAPSIZE: { + /* EVIDENCE-OF: R-34926-03360 SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit + ** unsigned integer value that specifies the maximum size of the created + ** heap. */ sqlite3GlobalConfig.nHeap = va_arg(ap, int); break; } #endif + case SQLITE_CONFIG_PMASZ: { + sqlite3GlobalConfig.szPma = va_arg(ap, unsigned int); + break; + } + default: { rc = SQLITE_ERROR; break; @@ -593,6 +677,12 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ ** Return the mutex associated with a database connection. */ sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif return db->mutex; } @@ -602,6 +692,10 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){ */ int sqlite3_db_release_memory(sqlite3 *db){ int i; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); for(i=0; inDb; i++){ @@ -691,13 +785,20 @@ static int binCollFunc( ){ int rc, n; n = nKey1lastRowid; } @@ -739,6 +846,12 @@ sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){ ** Return the number of changes in the most recent call to sqlite3_exec(). */ int sqlite3_changes(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif return db->nChange; } @@ -746,6 +859,12 @@ int sqlite3_changes(sqlite3 *db){ ** Return the number of changes since the database handle was opened. */ int sqlite3_total_changes(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif return db->nTotalChange; } @@ -852,7 +971,7 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){ ** SQLITE_BUSY if the connection can not be closed immediately. */ if( !forceZombie && connectionIsBusy(db) ){ - sqlite3Error(db, SQLITE_BUSY, "unable to close due to unfinalized " + sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to close due to unfinalized " "statements or unfinished backups"); sqlite3_mutex_leave(db->mutex); return SQLITE_BUSY; @@ -982,9 +1101,13 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ sqlite3HashClear(&db->aModule); #endif - sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */ + sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ sqlite3ValueFree(db->pErr); sqlite3CloseExtensions(db); +#if SQLITE_USER_AUTHENTICATION + sqlite3_free(db->auth.zAuthUser); + sqlite3_free(db->auth.zAuthPW); +#endif db->magic = SQLITE_MAGIC_ERROR; @@ -1007,13 +1130,15 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ /* ** Rollback all database files. If tripCode is not SQLITE_OK, then -** any open cursors are invalidated ("tripped" - as in "tripping a circuit +** any write cursors are invalidated ("tripped" - as in "tripping a circuit ** breaker") and made to return tripCode if there are any further -** attempts to use that cursor. +** attempts to use that cursor. Read cursors remain open and valid +** but are "saved" in case the table pages are moved around. */ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ int i; int inTrans = 0; + int schemaChange; assert( sqlite3_mutex_held(db->mutex) ); sqlite3BeginBenignMalloc(); @@ -1024,6 +1149,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ ** the database rollback and schema reset, which can cause false ** corruption reports in some cases. */ sqlite3BtreeEnterAll(db); + schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0; for(i=0; inDb; i++){ Btree *p = db->aDb[i].pBt; @@ -1031,7 +1157,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ if( sqlite3BtreeIsInTrans(p) ){ inTrans = 1; } - sqlite3BtreeRollback(p, tripCode); + sqlite3BtreeRollback(p, tripCode, !schemaChange); } } sqlite3VtabRollback(db); @@ -1224,7 +1350,7 @@ static int sqliteDefaultBusyCallback( void *ptr, /* Database connection */ int count /* Number of times table has been busy */ ){ -#if SQLITE_OS_WIN || (defined(HAVE_USLEEP) && HAVE_USLEEP) +#if SQLITE_OS_WIN || HAVE_USLEEP static const u8 delays[] = { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 }; static const u8 totals[] = @@ -1287,6 +1413,9 @@ int sqlite3_busy_handler( int (*xBusy)(void*,int), void *pArg ){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE; +#endif sqlite3_mutex_enter(db->mutex); db->busyHandler.xFunc = xBusy; db->busyHandler.pArg = pArg; @@ -1308,6 +1437,12 @@ void sqlite3_progress_handler( int (*xProgress)(void*), void *pArg ){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return; + } +#endif sqlite3_mutex_enter(db->mutex); if( nOps>0 ){ db->xProgress = xProgress; @@ -1328,6 +1463,9 @@ void sqlite3_progress_handler( ** specified number of milliseconds before returning 0. */ int sqlite3_busy_timeout(sqlite3 *db, int ms){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif if( ms>0 ){ sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db); db->busyTimeout = ms; @@ -1341,6 +1479,12 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){ ** Cause any pending operation to stop at its earliest opportunity. */ void sqlite3_interrupt(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return; + } +#endif db->u1.isInterrupted = 1; } @@ -1415,7 +1559,7 @@ int sqlite3CreateFunc( p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0); if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){ if( db->nVdbeActive ){ - sqlite3Error(db, SQLITE_BUSY, + sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify user-function due to active statements"); assert( !db->mallocFailed ); return SQLITE_BUSY; @@ -1478,6 +1622,12 @@ int sqlite3_create_function_v2( ){ int rc = SQLITE_ERROR; FuncDestructor *pArg = 0; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif sqlite3_mutex_enter(db->mutex); if( xDestroy ){ pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor)); @@ -1514,6 +1664,10 @@ int sqlite3_create_function16( ){ int rc; char *zFunc8; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE); @@ -1545,6 +1699,12 @@ int sqlite3_overload_function( ){ int nName = sqlite3Strlen30(zName); int rc = SQLITE_OK; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){ + return SQLITE_MISUSE_BKPT; + } +#endif sqlite3_mutex_enter(db->mutex); if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){ rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8, @@ -1566,6 +1726,13 @@ int sqlite3_overload_function( */ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){ void *pOld; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif sqlite3_mutex_enter(db->mutex); pOld = db->pTraceArg; db->xTrace = xTrace; @@ -1587,6 +1754,13 @@ void *sqlite3_profile( void *pArg ){ void *pOld; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif sqlite3_mutex_enter(db->mutex); pOld = db->pProfileArg; db->xProfile = xProfile; @@ -1607,6 +1781,13 @@ void *sqlite3_commit_hook( void *pArg /* Argument to the function */ ){ void *pOld; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif sqlite3_mutex_enter(db->mutex); pOld = db->pCommitArg; db->xCommitCallback = xCallback; @@ -1625,6 +1806,13 @@ void *sqlite3_update_hook( void *pArg /* Argument to the function */ ){ void *pRet; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif sqlite3_mutex_enter(db->mutex); pRet = db->pUpdateArg; db->xUpdateCallback = xCallback; @@ -1643,6 +1831,13 @@ void *sqlite3_rollback_hook( void *pArg /* Argument to the function */ ){ void *pRet; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif sqlite3_mutex_enter(db->mutex); pRet = db->pRollbackArg; db->xRollbackCallback = xCallback; @@ -1689,6 +1884,9 @@ int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){ UNUSED_PARAMETER(db); UNUSED_PARAMETER(nFrame); #else +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif if( nFrame>0 ){ sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame)); }else{ @@ -1709,6 +1907,12 @@ void *sqlite3_wal_hook( ){ #ifndef SQLITE_OMIT_WAL void *pRet; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif sqlite3_mutex_enter(db->mutex); pRet = db->pWalArg; db->xWalCallback = xCallback; @@ -1736,14 +1940,21 @@ int sqlite3_wal_checkpoint_v2( int rc; /* Return code */ int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + /* Initialize the output variables to -1 in case an error occurs. */ if( pnLog ) *pnLog = -1; if( pnCkpt ) *pnCkpt = -1; - assert( SQLITE_CHECKPOINT_FULL>SQLITE_CHECKPOINT_PASSIVE ); - assert( SQLITE_CHECKPOINT_FULLSQLITE_CHECKPOINT_RESTART ){ + assert( SQLITE_CHECKPOINT_PASSIVE==0 ); + assert( SQLITE_CHECKPOINT_FULL==1 ); + assert( SQLITE_CHECKPOINT_RESTART==2 ); + assert( SQLITE_CHECKPOINT_TRUNCATE==3 ); + if( eModeSQLITE_CHECKPOINT_TRUNCATE ){ + /* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint + ** mode: */ return SQLITE_MISUSE; } @@ -1753,10 +1964,11 @@ int sqlite3_wal_checkpoint_v2( } if( iDb<0 ){ rc = SQLITE_ERROR; - sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb); + sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb); }else{ + db->busyHandler.nBusy = 0; rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt); - sqlite3Error(db, rc, 0); + sqlite3Error(db, rc); } rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); @@ -1771,7 +1983,9 @@ int sqlite3_wal_checkpoint_v2( ** checkpointed. */ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ - return sqlite3_wal_checkpoint_v2(db, zDb, SQLITE_CHECKPOINT_PASSIVE, 0, 0); + /* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to + ** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */ + return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0); } #ifndef SQLITE_OMIT_WAL @@ -1911,7 +2125,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){ }else{ z = sqlite3_value_text16(db->pErr); if( z==0 ){ - sqlite3Error(db, db->errCode, sqlite3ErrStr(db->errCode)); + sqlite3ErrorWithMsg(db, db->errCode, sqlite3ErrStr(db->errCode)); z = sqlite3_value_text16(db->pErr); } /* A malloc() may have failed within the call to sqlite3_value_text16() @@ -1958,32 +2172,6 @@ const char *sqlite3_errstr(int rc){ return sqlite3ErrStr(rc); } -/* -** Invalidate all cached KeyInfo objects for database connection "db" -*/ -static void invalidateCachedKeyInfo(sqlite3 *db){ - Db *pDb; /* A single database */ - int iDb; /* The database index number */ - HashElem *k; /* For looping over tables in pDb */ - Table *pTab; /* A table in the database */ - Index *pIdx; /* Each index */ - - for(iDb=0, pDb=db->aDb; iDbnDb; iDb++, pDb++){ - if( pDb->pBt==0 ) continue; - sqlite3BtreeEnter(pDb->pBt); - for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ - pTab = (Table*)sqliteHashData(k); - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->pKeyInfo && pIdx->pKeyInfo->db==db ){ - sqlite3KeyInfoUnref(pIdx->pKeyInfo); - pIdx->pKeyInfo = 0; - } - } - } - sqlite3BtreeLeave(pDb->pBt); - } -} - /* ** Create a new collating function for database "db". The name is zName ** and the encoding is enc. @@ -1998,7 +2186,6 @@ static int createCollation( ){ CollSeq *pColl; int enc2; - int nName = sqlite3Strlen30(zName); assert( sqlite3_mutex_held(db->mutex) ); @@ -2023,12 +2210,11 @@ static int createCollation( pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0); if( pColl && pColl->xCmp ){ if( db->nVdbeActive ){ - sqlite3Error(db, SQLITE_BUSY, + sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify collation sequence due to active statements"); return SQLITE_BUSY; } sqlite3ExpirePreparedStatements(db); - invalidateCachedKeyInfo(db); /* If collation sequence pColl was created directly by a call to ** sqlite3_create_collation, and not generated by synthCollSeq(), @@ -2037,7 +2223,7 @@ static int createCollation( ** to be called. */ if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){ - CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName, nName); + CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName); int j; for(j=0; j<3; j++){ CollSeq *p = &aColl[j]; @@ -2057,7 +2243,7 @@ static int createCollation( pColl->pUser = pCtx; pColl->xDel = xDel; pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED)); - sqlite3Error(db, SQLITE_OK, 0); + sqlite3Error(db, SQLITE_OK); return SQLITE_OK; } @@ -2079,6 +2265,7 @@ static const int aHardLimit[] = { SQLITE_MAX_LIKE_PATTERN_LENGTH, SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ SQLITE_MAX_TRIGGER_DEPTH, + SQLITE_MAX_WORKER_THREADS, }; /* @@ -2114,6 +2301,9 @@ static const int aHardLimit[] = { #if SQLITE_MAX_TRIGGER_DEPTH<1 # error SQLITE_MAX_TRIGGER_DEPTH must be at least 1 #endif +#if SQLITE_MAX_WORKER_THREADS<0 || SQLITE_MAX_WORKER_THREADS>50 +# error SQLITE_MAX_WORKER_THREADS must be between 0 and 50 +#endif /* @@ -2129,6 +2319,12 @@ static const int aHardLimit[] = { int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ int oldLimit; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return -1; + } +#endif /* EVIDENCE-OF: R-30189-54097 For each limit category SQLITE_LIMIT_NAME ** there is a hard upper bound set at compile-time by a C preprocessor @@ -2147,7 +2343,8 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ SQLITE_MAX_LIKE_PATTERN_LENGTH ); assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER); assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH ); - assert( SQLITE_LIMIT_TRIGGER_DEPTH==(SQLITE_N_LIMIT-1) ); + assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS ); + assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-1) ); if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ @@ -2204,8 +2401,9 @@ int sqlite3ParseUri( assert( *pzErrMsg==0 ); - if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) - && nUri>=5 && memcmp(zUri, "file:", 5)==0 + if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */ + || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */ + && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */ ){ char *zOpt; int eState; /* Parser state when parsing URI */ @@ -2413,6 +2611,9 @@ static int openDatabase( char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */ char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */ +#ifdef SQLITE_ENABLE_API_ARMOR + if( ppDb==0 ) return SQLITE_MISUSE_BKPT; +#endif *ppDb = 0; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); @@ -2435,7 +2636,9 @@ static int openDatabase( testcase( (1<<(flags&7))==0x02 ); /* READONLY */ testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ - if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE_BKPT; + if( ((1<<(flags&7)) & 0x46)==0 ){ + return SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */ + } if( sqlite3GlobalConfig.bCoreMutex==0 ){ isThreadsafe = 0; @@ -2494,10 +2697,12 @@ static int openDatabase( assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); + db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS; db->autoCommit = 1; db->nextAutovac = -1; db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; + db->nMaxSorterMmap = 0x7FFFFFFF; db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill #if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX | SQLITE_AutoIndex @@ -2513,6 +2718,9 @@ static int openDatabase( #endif #if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS | SQLITE_ForeignKeys +#endif +#if defined(SQLITE_REVERSE_UNORDERED_SELECTS) + | SQLITE_ReverseOrder #endif ; sqlite3HashInit(&db->aCollSeq); @@ -2523,26 +2731,30 @@ static int openDatabase( /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary ** conversions. The only error that can occur here is a malloc() failure. + ** + ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating + ** functions: */ createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0); createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0); createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0); + createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0); if( db->mallocFailed ){ goto opendb_out; } + /* EVIDENCE-OF: R-08308-17224 The default collating function for all + ** strings is BINARY. + */ db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0); assert( db->pDfltColl!=0 ); - /* Also add a UTF-8 case-insensitive collation sequence. */ - createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); - /* Parse the filename/URI argument. */ db->openFlags = flags; rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; - sqlite3Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg); + sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg); sqlite3_free(zErrMsg); goto opendb_out; } @@ -2554,13 +2766,15 @@ static int openDatabase( if( rc==SQLITE_IOERR_NOMEM ){ rc = SQLITE_NOMEM; } - sqlite3Error(db, rc, 0); + sqlite3Error(db, rc); goto opendb_out; } + sqlite3BtreeEnter(db->aDb[0].pBt); db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); + if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db); + sqlite3BtreeLeave(db->aDb[0].pBt); db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); - /* The default safety_level for the main database is 'full'; for the temp ** database it is 'NONE'. This matches the pager layer defaults. */ @@ -2578,7 +2792,7 @@ static int openDatabase( ** database schema yet. This is delayed until the first time the database ** is accessed. */ - sqlite3Error(db, SQLITE_OK, 0); + sqlite3Error(db, SQLITE_OK); sqlite3RegisterBuiltinFunctions(db); /* Load automatic extensions - extensions that have been registered @@ -2635,7 +2849,7 @@ static int openDatabase( SQLITE_DEFAULT_LOCKING_MODE); #endif - if( rc ) sqlite3Error(db, rc, 0); + if( rc ) sqlite3Error(db, rc); /* Enable the lookaside-malloc subsystem */ setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside, @@ -2699,13 +2913,15 @@ int sqlite3_open16( sqlite3_value *pVal; int rc; - assert( zFilename ); - assert( ppDb ); +#ifdef SQLITE_ENABLE_API_ARMOR + if( ppDb==0 ) return SQLITE_MISUSE_BKPT; +#endif *ppDb = 0; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ) return rc; #endif + if( zFilename==0 ) zFilename = "\000\000"; pVal = sqlite3ValueNew(0); sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC); zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8); @@ -2714,7 +2930,7 @@ int sqlite3_open16( SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); assert( *ppDb || rc==SQLITE_NOMEM ); if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){ - ENC(*ppDb) = SQLITE_UTF16NATIVE; + SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE; } }else{ rc = SQLITE_NOMEM; @@ -2735,13 +2951,7 @@ int sqlite3_create_collation( void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ - int rc; - sqlite3_mutex_enter(db->mutex); - assert( !db->mallocFailed ); - rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, 0); - rc = sqlite3ApiExit(db, rc); - sqlite3_mutex_leave(db->mutex); - return rc; + return sqlite3_create_collation_v2(db, zName, enc, pCtx, xCompare, 0); } /* @@ -2756,6 +2966,10 @@ int sqlite3_create_collation_v2( void(*xDel)(void*) ){ int rc; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xDel); @@ -2777,6 +2991,10 @@ int sqlite3_create_collation16( ){ int rc = SQLITE_OK; char *zName8; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE); @@ -2799,6 +3017,9 @@ int sqlite3_collation_needed( void *pCollNeededArg, void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*) ){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); db->xCollNeeded = xCollNeeded; db->xCollNeeded16 = 0; @@ -2817,6 +3038,9 @@ int sqlite3_collation_needed16( void *pCollNeededArg, void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*) ){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); db->xCollNeeded = 0; db->xCollNeeded16 = xCollNeeded16; @@ -2843,13 +3067,19 @@ int sqlite3_global_recover(void){ ** by the next COMMIT or ROLLBACK. */ int sqlite3_get_autocommit(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif return db->autoCommit; } /* -** The following routines are subtitutes for constants SQLITE_CORRUPT, +** The following routines are substitutes for constants SQLITE_CORRUPT, ** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_IOERR and possibly other error -** constants. They server two purposes: +** constants. They serve two purposes: ** ** 1. Serve as a convenient place to set a breakpoint in a debugger ** to detect when version error conditions occurs. @@ -2896,7 +3126,6 @@ void sqlite3_thread_cleanup(void){ ** Return meta information about a specific column of a database table. ** See comment in sqlite3.h (sqlite.h.in) for details. */ -#ifdef SQLITE_ENABLE_COLUMN_METADATA int sqlite3_table_column_metadata( sqlite3 *db, /* Connection handle */ const char *zDbName, /* Database name or NULL */ @@ -2912,7 +3141,7 @@ int sqlite3_table_column_metadata( char *zErrMsg = 0; Table *pTab = 0; Column *pCol = 0; - int iCol; + int iCol = 0; char const *zDataType = 0; char const *zCollSeq = 0; @@ -2936,11 +3165,8 @@ int sqlite3_table_column_metadata( } /* Find the column for which info is requested */ - if( sqlite3IsRowid(zColumnName) ){ - iCol = pTab->iPKey; - if( iCol>=0 ){ - pCol = &pTab->aCol[iCol]; - } + if( zColumnName==0 ){ + /* Query for existance of table only */ }else{ for(iCol=0; iColnCol; iCol++){ pCol = &pTab->aCol[iCol]; @@ -2949,8 +3175,13 @@ int sqlite3_table_column_metadata( } } if( iCol==pTab->nCol ){ - pTab = 0; - goto error_out; + if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){ + iCol = pTab->iPKey; + pCol = iCol>=0 ? &pTab->aCol[iCol] : 0; + }else{ + pTab = 0; + goto error_out; + } } } @@ -2997,13 +3228,12 @@ error_out: zColumnName); rc = SQLITE_ERROR; } - sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg); + sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg); sqlite3DbFree(db, zErrMsg); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } -#endif /* ** Sleep for a little while. Return the amount of time slept. @@ -3025,6 +3255,9 @@ int sqlite3_sleep(int ms){ ** Enable or disable the extended result codes. */ int sqlite3_extended_result_codes(sqlite3 *db, int onoff){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); db->errMask = onoff ? 0xffffffff : 0xff; sqlite3_mutex_leave(db->mutex); @@ -3038,6 +3271,9 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){ int rc = SQLITE_ERROR; Btree *pBtree; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); pBtree = sqlite3DbNameToBtree(db, zDbName); if( pBtree ){ @@ -3163,7 +3399,7 @@ int sqlite3_test_control(int op, ...){ ** IMPORTANT: Changing the PENDING byte from 0x40000000 results in ** an incompatible database file format. Changing the PENDING byte ** while any database connection is open results in undefined and - ** dileterious behavior. + ** deleterious behavior. */ case SQLITE_TESTCTRL_PENDING_BYTE: { rc = PENDING_BYTE; @@ -3318,22 +3554,6 @@ int sqlite3_test_control(int op, ...){ break; } -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) - /* sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, - ** sqlite3_stmt*,const char**); - ** - ** If compiled with SQLITE_ENABLE_TREE_EXPLAIN, each sqlite3_stmt holds - ** a string that describes the optimized parse tree. This test-control - ** returns a pointer to that string. - */ - case SQLITE_TESTCTRL_EXPLAIN_STMT: { - sqlite3_stmt *pStmt = va_arg(ap, sqlite3_stmt*); - const char **pzRet = va_arg(ap, const char**); - *pzRet = sqlite3VdbeExplanation((Vdbe*)pStmt); - break; - } -#endif - /* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int); ** ** Set or clear a flag that indicates that the database file is always well- @@ -3362,6 +3582,13 @@ int sqlite3_test_control(int op, ...){ break; } + /* sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, nMax); */ + case SQLITE_TESTCTRL_SORTER_MMAP: { + sqlite3 *db = va_arg(ap, sqlite3*); + db->nMaxSorterMmap = va_arg(ap, int); + break; + } + /* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT); ** ** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if @@ -3371,7 +3598,6 @@ int sqlite3_test_control(int op, ...){ if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; break; } - } va_end(ap); #endif /* SQLITE_OMIT_BUILTIN_TEST */ @@ -3390,7 +3616,7 @@ int sqlite3_test_control(int op, ...){ ** returns a NULL pointer. */ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ - if( zFilename==0 ) return 0; + if( zFilename==0 || zParam==0 ) return 0; zFilename += sqlite3Strlen30(zFilename) + 1; while( zFilename[0] ){ int x = strcmp(zFilename, zParam); @@ -3446,7 +3672,14 @@ Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ ** connection. */ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){ - Btree *pBt = sqlite3DbNameToBtree(db, zDbName); + Btree *pBt; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + pBt = sqlite3DbNameToBtree(db, zDbName); return pBt ? sqlite3BtreeGetFilename(pBt) : 0; } @@ -3455,6 +3688,13 @@ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){ ** no such database exists. */ int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){ - Btree *pBt = sqlite3DbNameToBtree(db, zDbName); + Btree *pBt; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return -1; + } +#endif + pBt = sqlite3DbNameToBtree(db, zDbName); return pBt ? sqlite3BtreeIsReadonly(pBt) : -1; } diff --git a/src/malloc.c b/src/malloc.c index 9c11d07..4960f91 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -294,11 +294,9 @@ static int mallocWithAlarm(int n, void **pp){ ** Allocate memory. This routine is like sqlite3_malloc() except that it ** assumes the memory subsystem has already been initialized. */ -void *sqlite3Malloc(int n){ +void *sqlite3Malloc(u64 n){ void *p; - if( n<=0 /* IMP: R-65312-04917 */ - || n>=0x7fffff00 - ){ + if( n==0 || n>=0x7fffff00 ){ /* A memory allocation of a number of bytes which is near the maximum ** signed integer value might cause an integer overflow inside of the ** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving @@ -307,12 +305,12 @@ void *sqlite3Malloc(int n){ p = 0; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); - mallocWithAlarm(n, &p); + mallocWithAlarm((int)n, &p); sqlite3_mutex_leave(mem0.mutex); }else{ - p = sqlite3GlobalConfig.m.xMalloc(n); + p = sqlite3GlobalConfig.m.xMalloc((int)n); } - assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-04675-44850 */ + assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-11148-40995 */ return p; } @@ -322,6 +320,12 @@ void *sqlite3Malloc(int n){ ** allocation. */ void *sqlite3_malloc(int n){ +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return n<=0 ? 0 : sqlite3Malloc(n); +} +void *sqlite3_malloc64(sqlite3_uint64 n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif @@ -352,22 +356,20 @@ void *sqlite3ScratchMalloc(int n){ assert( n>0 ); sqlite3_mutex_enter(mem0.mutex); + sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n); if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){ p = mem0.pScratchFree; mem0.pScratchFree = mem0.pScratchFree->pNext; mem0.nScratchFree--; sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1); - sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n); sqlite3_mutex_leave(mem0.mutex); }else{ - if( sqlite3GlobalConfig.bMemstat ){ - sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n); - n = mallocWithAlarm(n, &p); - if( p ) sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n); + sqlite3_mutex_leave(mem0.mutex); + p = sqlite3Malloc(n); + if( sqlite3GlobalConfig.bMemstat && p ){ + sqlite3_mutex_enter(mem0.mutex); + sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p)); sqlite3_mutex_leave(mem0.mutex); - }else{ - sqlite3_mutex_leave(mem0.mutex); - p = sqlite3GlobalConfig.m.xMalloc(n); } sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH); } @@ -375,11 +377,12 @@ void *sqlite3ScratchMalloc(int n){ #if SQLITE_THREADSAFE==0 && !defined(NDEBUG) - /* Verify that no more than two scratch allocations per thread - ** are outstanding at one time. (This is only checked in the - ** single-threaded case since checking in the multi-threaded case - ** would be much more complicated.) */ - assert( scratchAllocOut<=1 ); + /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch + ** buffers per thread. + ** + ** This can only be checked in single-threaded mode. + */ + assert( scratchAllocOut==0 ); if( p ) scratchAllocOut++; #endif @@ -445,29 +448,37 @@ static int isLookaside(sqlite3 *db, void *p){ */ int sqlite3MallocSize(void *p){ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); - assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) ); return sqlite3GlobalConfig.m.xSize(p); } int sqlite3DbMallocSize(sqlite3 *db, void *p){ - assert( db!=0 ); - assert( sqlite3_mutex_held(db->mutex) ); - if( isLookaside(db, p) ){ - return db->lookaside.sz; + if( db==0 ){ + assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); + assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); + return sqlite3MallocSize(p); }else{ - assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) ); - assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) ); - assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); - return sqlite3GlobalConfig.m.xSize(p); + assert( sqlite3_mutex_held(db->mutex) ); + if( isLookaside(db, p) ){ + return db->lookaside.sz; + }else{ + assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + return sqlite3GlobalConfig.m.xSize(p); + } } } +sqlite3_uint64 sqlite3_msize(void *p){ + assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); + assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); + return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p); +} /* ** Free memory previously obtained from sqlite3Malloc(). */ void sqlite3_free(void *p){ if( p==0 ) return; /* IMP: R-49053-54554 */ - assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); + assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p)); @@ -479,6 +490,14 @@ void sqlite3_free(void *p){ } } +/* +** Add the size of memory allocation "p" to the count in +** *db->pnBytesFreed. +*/ +static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){ + *db->pnBytesFreed += sqlite3DbMallocSize(db,p); +} + /* ** Free memory that might be associated with a particular database ** connection. @@ -488,7 +507,7 @@ void sqlite3DbFree(sqlite3 *db, void *p){ if( p==0 ) return; if( db ){ if( db->pnBytesFreed ){ - *db->pnBytesFreed += sqlite3DbMallocSize(db, p); + measureAllocationSize(db, p); return; } if( isLookaside(db, p) ){ @@ -503,8 +522,8 @@ void sqlite3DbFree(sqlite3 *db, void *p){ return; } } - assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) ); - assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) ); + assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); @@ -513,14 +532,16 @@ void sqlite3DbFree(sqlite3 *db, void *p){ /* ** Change the size of an existing memory allocation */ -void *sqlite3Realloc(void *pOld, int nBytes){ +void *sqlite3Realloc(void *pOld, u64 nBytes){ int nOld, nNew, nDiff; void *pNew; + assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); + assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) ); if( pOld==0 ){ - return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */ + return sqlite3Malloc(nBytes); /* IMP: R-04300-56712 */ } - if( nBytes<=0 ){ - sqlite3_free(pOld); /* IMP: R-31593-10574 */ + if( nBytes==0 ){ + sqlite3_free(pOld); /* IMP: R-26507-47431 */ return 0; } if( nBytes>=0x7fffff00 ){ @@ -531,22 +552,20 @@ void *sqlite3Realloc(void *pOld, int nBytes){ /* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second ** argument to xRealloc is always a value returned by a prior call to ** xRoundup. */ - nNew = sqlite3GlobalConfig.m.xRoundup(nBytes); + nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes); if( nOld==nNew ){ pNew = pOld; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes); + sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); nDiff = nNew - nOld; if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= mem0.alarmThreshold-nDiff ){ sqlite3MallocAlarm(nDiff); } - assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); - assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) ); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); if( pNew==0 && mem0.alarmCallback ){ - sqlite3MallocAlarm(nBytes); + sqlite3MallocAlarm((int)nBytes); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } if( pNew ){ @@ -557,7 +576,7 @@ void *sqlite3Realloc(void *pOld, int nBytes){ }else{ pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } - assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-04675-44850 */ + assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-11148-40995 */ return pNew; } @@ -566,6 +585,13 @@ void *sqlite3Realloc(void *pOld, int nBytes){ ** subsystem is initialized prior to invoking sqliteRealloc. */ void *sqlite3_realloc(void *pOld, int n){ +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + if( n<0 ) n = 0; /* IMP: R-26507-47431 */ + return sqlite3Realloc(pOld, n); +} +void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif @@ -576,10 +602,10 @@ void *sqlite3_realloc(void *pOld, int n){ /* ** Allocate and zero memory. */ -void *sqlite3MallocZero(int n){ +void *sqlite3MallocZero(u64 n){ void *p = sqlite3Malloc(n); if( p ){ - memset(p, 0, n); + memset(p, 0, (size_t)n); } return p; } @@ -588,10 +614,10 @@ void *sqlite3MallocZero(int n){ ** Allocate and zero memory. If the allocation fails, make ** the mallocFailed flag in the connection pointer. */ -void *sqlite3DbMallocZero(sqlite3 *db, int n){ +void *sqlite3DbMallocZero(sqlite3 *db, u64 n){ void *p = sqlite3DbMallocRaw(db, n); if( p ){ - memset(p, 0, n); + memset(p, 0, (size_t)n); } return p; } @@ -614,7 +640,7 @@ void *sqlite3DbMallocZero(sqlite3 *db, int n){ ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed ** that all prior mallocs (ex: "a") worked too. */ -void *sqlite3DbMallocRaw(sqlite3 *db, int n){ +void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){ void *p; assert( db==0 || sqlite3_mutex_held(db->mutex) ); assert( db==0 || db->pnBytesFreed==0 ); @@ -649,8 +675,8 @@ void *sqlite3DbMallocRaw(sqlite3 *db, int n){ if( !p && db ){ db->mallocFailed = 1; } - sqlite3MemdebugSetType(p, MEMTYPE_DB | - ((db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); + sqlite3MemdebugSetType(p, + (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP); return p; } @@ -658,7 +684,7 @@ void *sqlite3DbMallocRaw(sqlite3 *db, int n){ ** Resize the block of memory pointed to by p to n bytes. If the ** resize fails, set the mallocFailed flag in the connection object. */ -void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){ +void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){ void *pNew = 0; assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); @@ -676,15 +702,14 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){ sqlite3DbFree(db, p); } }else{ - assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) ); - assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) ); + assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); - pNew = sqlite3_realloc(p, n); + pNew = sqlite3_realloc64(p, n); if( !pNew ){ - sqlite3MemdebugSetType(p, MEMTYPE_DB|MEMTYPE_HEAP); db->mallocFailed = 1; } - sqlite3MemdebugSetType(pNew, MEMTYPE_DB | + sqlite3MemdebugSetType(pNew, (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); } } @@ -695,7 +720,7 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){ ** Attempt to reallocate p. If the reallocation fails, then free p ** and set the mallocFailed flag in the database connection. */ -void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){ +void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){ void *pNew; pNew = sqlite3DbRealloc(db, p, n); if( !pNew ){ @@ -725,7 +750,7 @@ char *sqlite3DbStrDup(sqlite3 *db, const char *z){ } return zNew; } -char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){ +char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ char *zNew; if( z==0 ){ return 0; @@ -733,7 +758,7 @@ char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){ assert( (n&0x7fffffff)==n ); zNew = sqlite3DbMallocRaw(db, n+1); if( zNew ){ - memcpy(zNew, z, n); + memcpy(zNew, z, (size_t)n); zNew[n] = 0; } return zNew; @@ -755,6 +780,14 @@ void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat, ...){ *pz = z; } +/* +** Take actions at the end of an API call to indicate an OOM error +*/ +static SQLITE_NOINLINE int apiOomError(sqlite3 *db){ + db->mallocFailed = 0; + sqlite3Error(db, SQLITE_NOMEM); + return SQLITE_NOMEM; +} /* ** This function must be called before exiting any API function (i.e. @@ -775,10 +808,9 @@ int sqlite3ApiExit(sqlite3* db, int rc){ ** is unsafe, as is the call to sqlite3Error(). */ assert( !db || sqlite3_mutex_held(db->mutex) ); - if( db && (db->mallocFailed || rc==SQLITE_IOERR_NOMEM) ){ - sqlite3Error(db, SQLITE_NOMEM, 0); - db->mallocFailed = 0; - rc = SQLITE_NOMEM; + if( db==0 ) return rc & 0xff; + if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ + return apiOomError(db); } - return rc & (db ? db->errMask : 0xff); + return rc & db->errMask; } diff --git a/src/mem1.c b/src/mem1.c index 6dbf105..ec9a4e3 100644 --- a/src/mem1.c +++ b/src/mem1.c @@ -79,9 +79,9 @@ static malloc_zone_t* _sqliteZone_; ** The malloc.h header file is needed for malloc_usable_size() function ** on some systems (e.g. Linux). */ -#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLOC_USABLE_SIZE) -# define SQLITE_USE_MALLOC_H -# define SQLITE_USE_MALLOC_USABLE_SIZE +#if HAVE_MALLOC_H && HAVE_MALLOC_USABLE_SIZE +# define SQLITE_USE_MALLOC_H 1 +# define SQLITE_USE_MALLOC_USABLE_SIZE 1 /* ** The MSVCRT has malloc_usable_size(), but it is called _msize(). The ** use of _msize() is automatic, but can be disabled by compiling with @@ -188,7 +188,7 @@ static int sqlite3MemSize(void *pPrior){ ** ** For this low-level interface, we know that pPrior!=0. Cases where ** pPrior==0 while have been intercepted by higher-level routine and -** redirected to xMalloc. Similarly, we know that nByte>0 becauses +** redirected to xMalloc. Similarly, we know that nByte>0 because ** cases where nByte<=0 will have been intercepted by higher-level ** routines and redirected to xFree. */ diff --git a/src/mem2.c b/src/mem2.c index 99ea425..51ea297 100644 --- a/src/mem2.c +++ b/src/mem2.c @@ -394,7 +394,7 @@ void sqlite3MemdebugSetType(void *p, u8 eType){ ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** -** assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) ); +** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); */ int sqlite3MemdebugHasType(void *p, u8 eType){ int rc = 1; @@ -416,7 +416,7 @@ int sqlite3MemdebugHasType(void *p, u8 eType){ ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** -** assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) ); +** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); */ int sqlite3MemdebugNoType(void *p, u8 eType){ int rc = 1; diff --git a/src/mem5.c b/src/mem5.c index 67615bb..1479ddd 100644 --- a/src/mem5.c +++ b/src/mem5.c @@ -28,7 +28,7 @@ ** 1. All memory allocations sizes are rounded up to a power of 2. ** ** 2. If two adjacent free blocks are the halves of a larger block, -** then the two blocks are coalesed into the single larger block. +** then the two blocks are coalesced into the single larger block. ** ** 3. New memory is allocated from the first available free block. ** diff --git a/src/memjournal.c b/src/memjournal.c index 65ed378..6452cec 100644 --- a/src/memjournal.c +++ b/src/memjournal.c @@ -26,7 +26,7 @@ typedef struct FileChunk FileChunk; ** ** The size chosen is a little less than a power of two. That way, ** the FileChunk object will have a size that almost exactly fills -** a power-of-two allocation. This mimimizes wasted space in power-of-two +** a power-of-two allocation. This minimizes wasted space in power-of-two ** memory allocators. */ #define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*))) diff --git a/src/msvc.h b/src/msvc.h new file mode 100644 index 0000000..4508e69 --- /dev/null +++ b/src/msvc.h @@ -0,0 +1,35 @@ +/* +** 2015 January 12 +** +** 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 contains code that is specific to MSVC. +*/ +#ifndef _MSVC_H_ +#define _MSVC_H_ + +#if defined(_MSC_VER) +#pragma warning(disable : 4054) +#pragma warning(disable : 4055) +#pragma warning(disable : 4100) +#pragma warning(disable : 4127) +#pragma warning(disable : 4152) +#pragma warning(disable : 4189) +#pragma warning(disable : 4206) +#pragma warning(disable : 4210) +#pragma warning(disable : 4232) +#pragma warning(disable : 4244) +#pragma warning(disable : 4305) +#pragma warning(disable : 4306) +#pragma warning(disable : 4702) +#pragma warning(disable : 4706) +#endif /* defined(_MSC_VER) */ + +#endif /* _MSVC_H_ */ diff --git a/src/mutex.c b/src/mutex.c index bad5a7c..2b45036 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -82,6 +82,7 @@ int sqlite3MutexEnd(void){ sqlite3_mutex *sqlite3_mutex_alloc(int id){ #ifndef SQLITE_OMIT_AUTOINIT if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0; + if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0; #endif return sqlite3GlobalConfig.mutex.xMutexAlloc(id); } diff --git a/src/mutex.h b/src/mutex.h index 0978812..03eb1fa 100644 --- a/src/mutex.h +++ b/src/mutex.h @@ -25,7 +25,7 @@ ** Figure out what version of the code to use. The choices are ** ** SQLITE_MUTEX_OMIT No mutex logic. Not even stubs. The -** mutexes implemention cannot be overridden +** mutexes implementation cannot be overridden ** at start-time. ** ** SQLITE_MUTEX_NOOP For single-threaded applications. No diff --git a/src/mutex_unix.c b/src/mutex_unix.c index c866314..c936914 100644 --- a/src/mutex_unix.c +++ b/src/mutex_unix.c @@ -175,8 +175,12 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ break; } default: { - assert( iType-2 >= 0 ); - assert( iType-2 < ArraySize(staticMutexes) ); +#ifdef SQLITE_ENABLE_API_ARMOR + if( iType-2<0 || iType-2>=ArraySize(staticMutexes) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif p = &staticMutexes[iType-2]; #if SQLITE_MUTEX_NREF p->id = iType; diff --git a/src/mutex_w32.c b/src/mutex_w32.c index 218342d..a799c86 100644 --- a/src/mutex_w32.c +++ b/src/mutex_w32.c @@ -99,7 +99,7 @@ static int winMutex_isNt = -1; /* <0 means "need to query" */ ** of the sqlite3_initialize() and sqlite3_shutdown() processing, the ** "interlocked" magic used here is probably not strictly necessary. */ -static LONG volatile winMutex_lock = 0; +static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0; int sqlite3_win32_is_nt(void); /* os_win.c */ void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ @@ -209,6 +209,12 @@ static sqlite3_mutex *winMutexAlloc(int iType){ break; } default: { +#ifdef SQLITE_ENABLE_API_ARMOR + if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif assert( iType-2 >= 0 ); assert( iType-2 < ArraySize(winMutex_staticMutexes) ); assert( winMutex_isInit==1 ); diff --git a/src/notify.c b/src/notify.c index fcab5bf..8137226 100644 --- a/src/notify.c +++ b/src/notify.c @@ -184,7 +184,7 @@ int sqlite3_unlock_notify( leaveMutex(); assert( !db->mallocFailed ); - sqlite3Error(db, rc, (rc?"database is deadlocked":0)); + sqlite3ErrorWithMsg(db, rc, (rc?"database is deadlocked":0)); sqlite3_mutex_leave(db->mutex); return rc; } diff --git a/src/os.c b/src/os.c index b6c28a1..2a2cf13 100644 --- a/src/os.c +++ b/src/os.c @@ -361,6 +361,10 @@ int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ int rc = sqlite3_initialize(); if( rc ) return rc; #endif +#ifdef SQLITE_ENABLE_API_ARMOR + if( pVfs==0 ) return SQLITE_MISUSE_BKPT; +#endif + MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); diff --git a/src/os.h b/src/os.h index 3920a62..2c1b86f 100644 --- a/src/os.h +++ b/src/os.h @@ -120,7 +120,7 @@ ** shared locks begins at SHARED_FIRST. ** ** The same locking strategy and -** byte ranges are used for Unix. This leaves open the possiblity of having +** byte ranges are used for Unix. This leaves open the possibility of having ** clients on win95, winNT, and unix all talking to the same shared file ** and all locking correctly. To do so would require that samba (or whatever ** tool is being used for file sharing) implements locks correctly between diff --git a/src/os_unix.c b/src/os_unix.c index b1a0bed..ddd6a80 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -299,6 +299,14 @@ static int randomnessPid = 0; # endif #endif +/* +** Explicitly call the 64-bit version of lseek() on Android. Otherwise, lseek() +** is the 32-bit version, even if _FILE_OFFSET_BITS=64 is defined. +*/ +#ifdef __ANDROID__ +# define lseek lseek64 +#endif + /* ** Different Unix systems declare open() in different ways. Same use ** open(const char*,int,mode_t). Others use open(const char*,int,...). @@ -631,7 +639,7 @@ static int unixMutexHeld(void) { #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) /* ** Helper function for printing out trace information from debugging -** binaries. This returns the string represetation of the supplied +** binaries. This returns the string representation of the supplied ** integer lock-type. */ static const char *azFileLock(int eFileLock){ @@ -708,9 +716,22 @@ static int lockTrace(int fd, int op, struct flock *p){ /* ** Retry ftruncate() calls that fail due to EINTR +** +** All calls to ftruncate() within this file should be made through this wrapper. +** On the Android platform, bypassing the logic below could lead to a corrupt +** database. */ static int robust_ftruncate(int h, sqlite3_int64 sz){ int rc; +#ifdef __ANDROID__ + /* On Android, ftruncate() always uses 32-bit offsets, even if + ** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to + ** truncate a file to any size larger than 2GiB. Silently ignore any + ** such attempts. */ + if( sz>(sqlite3_int64)0x7FFFFFFF ){ + rc = SQLITE_OK; + }else +#endif do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR ); return rc; } @@ -3098,7 +3119,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){ ** NB: If you define USE_PREAD or USE_PREAD64, then it might also ** be necessary to define _XOPEN_SOURCE to be 500. This varies from ** one system to another. Since SQLite does not define USE_PREAD -** any any form by default, we will not attempt to define _XOPEN_SOURCE. +** in any form by default, we will not attempt to define _XOPEN_SOURCE. ** See tickets #2741 and #2681. ** ** To avoid stomping the errno value on a failed read the lastErrno value @@ -3365,9 +3386,9 @@ int sqlite3_fullsync_count = 0; ** We do not trust systems to provide a working fdatasync(). Some do. ** Others do no. To be safe, we will stick with the (slightly slower) ** fsync(). If you know that your system does support fdatasync() correctly, -** then simply compile with -Dfdatasync=fdatasync +** then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC */ -#if !defined(fdatasync) +#if !defined(fdatasync) && !HAVE_FDATASYNC # define fdatasync fsync #endif @@ -3595,7 +3616,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } - rc = robust_ftruncate(pFile->h, (off_t)nByte); + rc = robust_ftruncate(pFile->h, nByte); if( rc ){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); @@ -3688,24 +3709,28 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ }while( err==EINTR ); if( err ) return SQLITE_IOERR_WRITE; #else - /* If the OS does not have posix_fallocate(), fake it. First use - ** ftruncate() to set the file size, then write a single byte to - ** the last byte in each block within the extended region. This - ** is the same technique used by glibc to implement posix_fallocate() - ** on systems that do not have a real fallocate() system call. + /* If the OS does not have posix_fallocate(), fake it. Write a + ** single byte to the last byte in each block that falls entirely + ** within the extended region. Then, if required, a single byte + ** at offset (nSize-1), to set the size of the file correctly. + ** This is a similar technique to that used by glibc on systems + ** that do not have a real fallocate() call. */ int nBlk = buf.st_blksize; /* File-system block size */ + int nWrite = 0; /* Number of bytes written by seekAndWrite */ i64 iWrite; /* Next offset to write to */ - if( robust_ftruncate(pFile->h, nSize) ){ - pFile->lastErrno = errno; - return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); - } iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1; - while( iWrite=buf.st_size ); + assert( (iWrite/nBlk)==((buf.st_size+nBlk-1)/nBlk) ); + assert( ((iWrite+1)%nBlk)==0 ); + for(/*no-op*/; iWritectrlFlags is set. ** ** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. @@ -3937,7 +3962,7 @@ static int unixSectorSize(sqlite3_file *id){ ** Return the device characteristics for the file. ** ** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default. -** However, that choice is contraversial since technically the underlying +** However, that choice is controversial since technically the underlying ** file system does not always provide powersafe overwrites. (In other ** words, after a power-loss event, parts of the file that were never ** written might end up being altered.) However, non-PSOW behavior is very, @@ -4909,7 +4934,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){ ** looks at the filesystem type and tries to guess the best locking ** strategy from that. ** -** For finder-funtion F, two objects are created: +** For finder-function F, two objects are created: ** ** (1) The real finder-function named "FImpt()". ** @@ -4930,7 +4955,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){ ** * An I/O method finder function called FINDER that returns a pointer ** to the METHOD object in the previous bullet. */ -#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK) \ +#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK, SHMMAP) \ static const sqlite3_io_methods METHOD = { \ VERSION, /* iVersion */ \ CLOSE, /* xClose */ \ @@ -4945,7 +4970,7 @@ static const sqlite3_io_methods METHOD = { \ unixFileControl, /* xFileControl */ \ unixSectorSize, /* xSectorSize */ \ unixDeviceCharacteristics, /* xDeviceCapabilities */ \ - unixShmMap, /* xShmMap */ \ + SHMMAP, /* xShmMap */ \ unixShmLock, /* xShmLock */ \ unixShmBarrier, /* xShmBarrier */ \ unixShmUnmap, /* xShmUnmap */ \ @@ -4971,16 +4996,18 @@ IOMETHODS( unixClose, /* xClose method */ unixLock, /* xLock method */ unixUnlock, /* xUnlock method */ - unixCheckReservedLock /* xCheckReservedLock method */ + unixCheckReservedLock, /* xCheckReservedLock method */ + unixShmMap /* xShmMap method */ ) IOMETHODS( nolockIoFinder, /* Finder function name */ nolockIoMethods, /* sqlite3_io_methods object name */ - 1, /* shared memory is disabled */ + 3, /* shared memory is disabled */ nolockClose, /* xClose method */ nolockLock, /* xLock method */ nolockUnlock, /* xUnlock method */ - nolockCheckReservedLock /* xCheckReservedLock method */ + nolockCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) IOMETHODS( dotlockIoFinder, /* Finder function name */ @@ -4989,7 +5016,8 @@ IOMETHODS( dotlockClose, /* xClose method */ dotlockLock, /* xLock method */ dotlockUnlock, /* xUnlock method */ - dotlockCheckReservedLock /* xCheckReservedLock method */ + dotlockCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS @@ -5000,7 +5028,8 @@ IOMETHODS( flockClose, /* xClose method */ flockLock, /* xLock method */ flockUnlock, /* xUnlock method */ - flockCheckReservedLock /* xCheckReservedLock method */ + flockCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #endif @@ -5012,7 +5041,8 @@ IOMETHODS( semClose, /* xClose method */ semLock, /* xLock method */ semUnlock, /* xUnlock method */ - semCheckReservedLock /* xCheckReservedLock method */ + semCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #endif @@ -5024,7 +5054,8 @@ IOMETHODS( afpClose, /* xClose method */ afpLock, /* xLock method */ afpUnlock, /* xUnlock method */ - afpCheckReservedLock /* xCheckReservedLock method */ + afpCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #endif @@ -5049,7 +5080,8 @@ IOMETHODS( proxyClose, /* xClose method */ proxyLock, /* xLock method */ proxyUnlock, /* xUnlock method */ - proxyCheckReservedLock /* xCheckReservedLock method */ + proxyCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #endif @@ -5062,7 +5094,8 @@ IOMETHODS( unixClose, /* xClose method */ unixLock, /* xLock method */ nfsUnlock, /* xUnlock method */ - unixCheckReservedLock /* xCheckReservedLock method */ + unixCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ ) #endif @@ -5171,7 +5204,7 @@ static const sqlite3_io_methods #endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */ /* -** An abstract type for a pointer to a IO method finder function: +** An abstract type for a pointer to an IO method finder function: */ typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); @@ -5485,7 +5518,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ ** descriptor on the same path, fail, and return an error to SQLite. ** ** Even if a subsequent open() call does succeed, the consequences of - ** not searching for a resusable file descriptor are not dire. */ + ** not searching for a reusable file descriptor are not dire. */ if( 0==osStat(zPath, &sStat) ){ unixInodeInfo *pInode; @@ -5516,7 +5549,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ ** written to *pMode. If an IO error occurs, an SQLite error code is ** returned and the value of *pMode is not modified. ** -** In most cases cases, this routine sets *pMode to 0, which will become +** In most cases, this routine sets *pMode to 0, which will become ** an indication to robust_open() to create the file using ** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask. ** But if the file being opened is a WAL or regular journal file, then @@ -5885,7 +5918,7 @@ static int unixDelete( if( osUnlink(zPath)==(-1) ){ if( errno==ENOENT #if OS_VXWORKS - || errno==0x380003 + || osAccess(zPath,0)!=0 #endif ){ rc = SQLITE_IOERR_DELETE_NOENT; @@ -6308,7 +6341,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** proxy path against the values stored in the conch. The conch file is ** stored in the same directory as the database file and the file name ** is patterned after the database file name as ".-conch". -** If the conch file does not exist, or it's contents do not match the +** If the conch file does not exist, or its contents do not match the ** host ID and/or proxy path, then the lock is escalated to an exclusive ** lock and the conch file contents is updated with the host ID and proxy ** path and the lock is downgraded to a shared lock again. If the conch @@ -6360,7 +6393,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will ** force proxy locking to be used for every database file opened, and 0 ** will force automatic proxy locking to be disabled for all database -** files (explicity calling the SQLITE_SET_LOCKPROXYFILE pragma or +** files (explicitly calling the SQLITE_SET_LOCKPROXYFILE pragma or ** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING). */ diff --git a/src/os_win.c b/src/os_win.c index f479de3..e2f9aec 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -34,6 +34,11 @@ with SQLITE_OMIT_WAL." #endif +#if !SQLITE_OS_WINNT && SQLITE_MAX_MMAP_SIZE>0 +# error "Memory mapped files require support from the Windows NT kernel,\ + compile with SQLITE_MAX_MMAP_SIZE=0." +#endif + /* ** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions ** based on the sub-platform)? @@ -163,10 +168,11 @@ /* ** Do we need to manually define the Win32 file mapping APIs for use with WAL -** mode (e.g. these APIs are available in the Windows CE SDK; however, they -** are not present in the header file)? +** mode or memory mapped files (e.g. these APIs are available in the Windows +** CE SDK; however, they are not present in the header file)? */ -#if SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) +#if SQLITE_WIN32_FILEMAPPING_API && \ + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) /* ** Two of the file mapping APIs are different under WinRT. Figure out which ** set we need. @@ -194,7 +200,7 @@ WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T); ** This file mapping API is common to both Win32 and WinRT. */ WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); -#endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */ +#endif /* SQLITE_WIN32_FILEMAPPING_API */ /* ** Some Microsoft compilers lack this definition. @@ -410,9 +416,9 @@ const sqlite3_mem_methods *sqlite3MemGetWin32(void); ** can manually set this value to 1 to emulate Win98 behavior. */ #ifdef SQLITE_TEST -LONG volatile sqlite3_os_type = 0; +LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; #else -static LONG volatile sqlite3_os_type = 0; +static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; #endif #ifndef SYSCALL @@ -487,7 +493,7 @@ static struct win_syscall { LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent) #if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \ - !defined(SQLITE_OMIT_WAL)) + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 }, #else { "CreateFileMappingA", (SYSCALL)0, 0 }, @@ -497,7 +503,7 @@ static struct win_syscall { DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent) #if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ - !defined(SQLITE_OMIT_WAL)) + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 }, #else { "CreateFileMappingW", (SYSCALL)0, 0 }, @@ -837,7 +843,8 @@ static struct win_syscall { LPOVERLAPPED))aSyscall[48].pCurrent) #endif -#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)) +#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \ + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 }, #else { "MapViewOfFile", (SYSCALL)0, 0 }, @@ -907,7 +914,7 @@ static struct win_syscall { #define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ LPOVERLAPPED))aSyscall[58].pCurrent) -#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) +#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 }, #else { "UnmapViewOfFile", (SYSCALL)0, 0 }, @@ -943,7 +950,7 @@ static struct win_syscall { #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ DWORD))aSyscall[63].pCurrent) -#if SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, #else { "WaitForSingleObjectEx", (SYSCALL)0, 0 }, @@ -970,7 +977,7 @@ static struct win_syscall { #define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \ FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent) -#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL) +#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, #else { "MapViewOfFileFromApp", (SYSCALL)0, 0 }, @@ -1034,7 +1041,7 @@ static struct win_syscall { #define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent) -#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL) +#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 }, #else { "CreateFileMappingFromApp", (SYSCALL)0, 0 }, @@ -1055,8 +1062,8 @@ static struct win_syscall { #else { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, -#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG volatile*, \ - LONG,LONG))aSyscall[76].pCurrent) +#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \ + SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent) #endif /* defined(InterlockedCompareExchange) */ }; /* End of the overrideable system calls */ @@ -1196,8 +1203,8 @@ int sqlite3_win32_reset_heap(){ int rc; MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */ MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */ - MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) - MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); ) + MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); ) + MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); ) sqlite3_mutex_enter(pMaster); sqlite3_mutex_enter(pMem); winMemAssertMagic(); @@ -1290,6 +1297,16 @@ void sqlite3_win32_sleep(DWORD milliseconds){ #endif } +#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ + SQLITE_THREADSAFE>0 +DWORD sqlite3Win32Wait(HANDLE hObject){ + DWORD rc; + while( (rc = osWaitForSingleObjectEx(hObject, INFINITE, + TRUE))==WAIT_IO_COMPLETION ){} + return rc; +} +#endif + /* ** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, ** or WinCE. Return false (zero) for Win95, Win98, or WinME. @@ -1317,27 +1334,36 @@ void sqlite3_win32_sleep(DWORD milliseconds){ ** based on the NT kernel. */ int sqlite3_win32_is_nt(void){ -#if defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX +#if SQLITE_OS_WINRT + /* + ** NOTE: The WinRT sub-platform is always assumed to be based on the NT + ** kernel. + */ + return 1; +#elif defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ - defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8 - OSVERSIONINFOW sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - osGetVersionExW(&sInfo); - osInterlockedCompareExchange(&sqlite3_os_type, - (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); -#elif defined(SQLITE_WIN32_HAS_ANSI) +#if defined(SQLITE_WIN32_HAS_ANSI) OSVERSIONINFOA sInfo; sInfo.dwOSVersionInfoSize = sizeof(sInfo); osGetVersionExA(&sInfo); osInterlockedCompareExchange(&sqlite3_os_type, (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); +#elif defined(SQLITE_WIN32_HAS_WIDE) + OSVERSIONINFOW sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + osGetVersionExW(&sInfo); + osInterlockedCompareExchange(&sqlite3_os_type, + (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); #endif } return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; #elif SQLITE_TEST return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; #else + /* + ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are + ** deprecated are always assumed to be based on the NT kernel. + */ return 1; #endif } @@ -2453,7 +2479,7 @@ static int winRead( int amt, /* Number of bytes to read */ sqlite3_int64 offset /* Begin reading at this offset */ ){ -#if !SQLITE_OS_WINCE +#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) OVERLAPPED overlapped; /* The offset for ReadFile. */ #endif winFile *pFile = (winFile*)id; /* file handle */ @@ -2485,7 +2511,7 @@ static int winRead( } #endif -#if SQLITE_OS_WINCE +#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) if( winSeekFile(pFile, offset) ){ OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h)); return SQLITE_FULL; @@ -2557,13 +2583,13 @@ static int winWrite( } #endif -#if SQLITE_OS_WINCE +#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) rc = winSeekFile(pFile, offset); if( rc==0 ){ #else { #endif -#if !SQLITE_OS_WINCE +#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) OVERLAPPED overlapped; /* The offset for WriteFile. */ #endif u8 *aRem = (u8 *)pBuf; /* Data yet to be written */ @@ -2571,14 +2597,14 @@ static int winWrite( DWORD nWrite; /* Bytes written by each WriteFile() call */ DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */ -#if !SQLITE_OS_WINCE +#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) memset(&overlapped, 0, sizeof(OVERLAPPED)); overlapped.Offset = (LONG)(offset & 0xffffffff); overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); #endif while( nRem>0 ){ -#if SQLITE_OS_WINCE +#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){ #else if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){ @@ -2591,7 +2617,7 @@ static int winWrite( lastErrno = osGetLastError(); break; } -#if !SQLITE_OS_WINCE +#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) offset += nWrite; overlapped.Offset = (LONG)(offset & 0xffffffff); overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); @@ -3114,7 +3140,7 @@ static int winUnlock(sqlite3_file *id, int locktype){ } /* -** If *pArg is inititially negative then this is a query. Set *pArg to +** If *pArg is initially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. ** ** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. @@ -4128,7 +4154,7 @@ static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){ }else{ /* FIXME: If Windows truly always prevents truncating or deleting a ** file while a mapping is held, then the following winUnmapfile() call - ** is unnecessary can can be omitted - potentially improving + ** is unnecessary can be omitted - potentially improving ** performance. */ winUnmapfile(pFd); } diff --git a/src/os_win.h b/src/os_win.h index d662cd4..5174ac7 100644 --- a/src/os_win.h +++ b/src/os_win.h @@ -64,4 +64,14 @@ # define SQLITE_OS_WINRT 0 #endif +/* +** For WinCE, some API function parameters do not appear to be declared as +** volatile. +*/ +#if SQLITE_OS_WINCE +# define SQLITE_WIN32_VOLATILE +#else +# define SQLITE_WIN32_VOLATILE volatile +#endif + #endif /* _OS_WIN_H_ */ diff --git a/src/pager.c b/src/pager.c index a77dcec..2230174 100644 --- a/src/pager.c +++ b/src/pager.c @@ -76,12 +76,12 @@ ** Definition: Two databases (or the same database at two points it time) ** are said to be "logically equivalent" if they give the same answer to ** all queries. Note in particular the content of freelist leaf -** pages can be changed arbitarily without effecting the logical equivalence +** pages can be changed arbitrarily without affecting the logical equivalence ** of the database. ** ** (7) At any time, if any subset, including the empty set and the total set, ** of the unsynced changes to a rollback journal are removed and the -** journal is rolled back, the resulting database file will be logical +** journal is rolled back, the resulting database file will be logically ** equivalent to the database file at the beginning of the transaction. ** ** (8) When a transaction is rolled back, the xTruncate method of the VFS @@ -378,7 +378,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** ** The exception is when the database file is unlocked as the pager moves ** from ERROR to OPEN state. At this point there may be a hot-journal file -** in the file-system that needs to be rolled back (as part of a OPEN->SHARED +** in the file-system that needs to be rolled back (as part of an OPEN->SHARED ** transition, by the same pager or any other). If the call to xUnlock() ** fails at this point and the pager is left holding an EXCLUSIVE lock, this ** can confuse the call to xCheckReservedLock() call made later as part @@ -461,7 +461,7 @@ struct PagerSavepoint { #define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */ /* -** A open page cache is an instance of struct Pager. A description of +** An open page cache is an instance of struct Pager. A description of ** some of the more important member variables follows: ** ** eState @@ -633,7 +633,7 @@ struct Pager { /************************************************************************** ** The following block contains those class members that change during - ** routine opertion. Class members not in this block are either fixed + ** routine operation. Class members not in this block are either fixed ** when the pager is first created or else only change when there is a ** significant mode change (such as changing the page_size, locking_mode, ** or the journal_mode). From another view, these class members describe @@ -646,6 +646,8 @@ struct Pager { u8 setMaster; /* True if a m-j name has been written to jrnl */ u8 doNotSpill; /* Do not spill the cache when non-zero */ u8 subjInMemory; /* True to use in-memory sub-journals */ + u8 bUseFetch; /* True to use xFetch() */ + u8 hasBeenUsed; /* True if any content previously read from this pager*/ Pgno dbSize; /* Number of pages in the database */ Pgno dbOrigSize; /* dbSize before the current transaction */ Pgno dbFileSize; /* Number of pages in the database file */ @@ -663,9 +665,9 @@ struct Pager { sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */ PagerSavepoint *aSavepoint; /* Array of active savepoints */ int nSavepoint; /* Number of elements in aSavepoint[] */ + u32 iDataVersion; /* Changes whenever database content changes */ char dbFileVers[16]; /* Changes whenever database file changes */ - u8 bUseFetch; /* True to use xFetch() */ int nMmapOut; /* Number of mmap pages currently outstanding */ sqlite3_int64 szMmap; /* Desired maximum mmap size */ PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */ @@ -1677,29 +1679,23 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ return rc; } -/* -** Find a page in the hash table given its page number. Return -** a pointer to the page or NULL if the requested page is not -** already in memory. -*/ -static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ - PgHdr *p = 0; /* Return value */ - - /* It is not possible for a call to PcacheFetch() with createFlag==0 to - ** fail, since no attempt to allocate dynamic memory will be made. - */ - (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &p); - return p; -} - /* ** Discard the entire contents of the in-memory page-cache. */ static void pager_reset(Pager *pPager){ + pPager->iDataVersion++; sqlite3BackupRestart(pPager->pBackup); sqlite3PcacheClear(pPager->pPCache); } +/* +** Return the pPager->iDataVersion value +*/ +u32 sqlite3PagerDataVersion(Pager *pPager){ + assert( pPager->eState>PAGER_OPEN ); + return pPager->iDataVersion; +} + /* ** Free all structures in the Pager.aSavepoint[] array and set both ** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal @@ -1956,6 +1952,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ rc = SQLITE_OK; }else{ rc = sqlite3OsTruncate(pPager->jfd, 0); + if( rc==SQLITE_OK && pPager->fullSync ){ + /* Make sure the new file size is written into the inode right away. + ** Otherwise the journal might resurrect following a power loss and + ** cause the last transaction to roll back. See + ** https://bugzilla.mozilla.org/show_bug.cgi?id=1072773 + */ + rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); + } } pPager->journalOff = 0; }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST @@ -1984,7 +1988,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ #ifdef SQLITE_CHECK_PAGES sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash); if( pPager->dbSize==0 && sqlite3PcacheRefCount(pPager->pPCache)>0 ){ - PgHdr *p = pager_lookup(pPager, 1); + PgHdr *p = sqlite3PagerLookup(pPager, 1); if( p ){ p->pageHash = 0; sqlite3PagerUnrefNotNull(p); @@ -2263,7 +2267,7 @@ static int pager_playback_one_page( if( pagerUseWal(pPager) ){ pPg = 0; }else{ - pPg = pager_lookup(pPager, pgno); + pPg = sqlite3PagerLookup(pPager, pgno); } assert( pPg || !MEMDB ); assert( pPager->eState!=PAGER_OPEN || pPg==0 ); @@ -2443,7 +2447,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){ rc = sqlite3OsFileSize(pMaster, &nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; nMasterPtr = pVfs->mxPathname+1; - zMasterJournal = sqlite3Malloc((int)nMasterJournal + nMasterPtr + 1); + zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1); if( !zMasterJournal ){ rc = SQLITE_NOMEM; goto delmaster_out; @@ -2512,7 +2516,7 @@ delmaster_out: ** If the file on disk is currently larger than nPage pages, then use the VFS ** xTruncate() method to truncate it. ** -** Or, it might might be the case that the file on disk is smaller than +** Or, it might be the case that the file on disk is smaller than ** nPage pages. Some operating system implementations can get confused if ** you try to truncate a file to some size that is larger than it ** currently is, so detect this case and write a single zero byte to @@ -2571,7 +2575,7 @@ int sqlite3SectorSize(sqlite3_file *pFile){ /* ** Set the value of the Pager.sectorSize variable for the given ** pager based on the value returned by the xSectorSize method -** of the open database file. The sector size will be used used +** of the open database file. The sector size will be used ** to determine the size and alignment of journal header and ** master journal pointers within created journal files. ** @@ -2906,7 +2910,7 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){ ** ** For an encrypted database, the situation is more complex: bytes ** 24..39 of the database are white noise. But the probability of - ** white noising equaling 16 bytes of 0xff is vanishingly small so + ** white noise equaling 16 bytes of 0xff is vanishingly small so ** we should still be ok. */ memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers)); @@ -3633,11 +3637,15 @@ int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){ if( rc==SQLITE_OK ){ pager_reset(pPager); - pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); - pPager->pageSize = pageSize; + rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); + } + if( rc==SQLITE_OK ){ sqlite3PageFree(pPager->pTmpSpace); pPager->pTmpSpace = pNew; - sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); + pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); + pPager->pageSize = pageSize; + }else{ + sqlite3PageFree(pNew); } } @@ -3771,7 +3779,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){ int rc; /* Return code */ /* Check that this is either a no-op (because the requested lock is - ** already held, or one of the transistions that the busy-handler + ** already held), or one of the transitions that the busy-handler ** may be invoked during, according to the comment above ** sqlite3PagerSetBusyhandler(). */ @@ -3890,7 +3898,7 @@ static int pagerAcquireMapPage( PgHdr **ppPage /* OUT: Acquired page object */ ){ PgHdr *p; /* Memory mapped page to return */ - + if( pPager->pMmapFreelist ){ *ppPage = p = pPager->pMmapFreelist; pPager->pMmapFreelist = p->pDirty; @@ -4399,8 +4407,8 @@ static int pagerStress(void *p, PgHdr *pPg){ ** a rollback or by user request, respectively. ** ** Spilling is also prohibited when in an error state since that could - ** lead to database corruption. In the current implementaton it - ** is impossible for sqlite3PcacheFetch() to be called with createFlag==1 + ** lead to database corruption. In the current implementation it + ** is impossible for sqlite3PcacheFetch() to be called with createFlag==3 ** while in the error state, hence it is impossible for this routine to ** be called in the error state. Nevertheless, we include a NEVER() ** test for the error state as a safeguard against future changes. @@ -4736,22 +4744,23 @@ act_like_temp_file: testcase( rc!=SQLITE_OK ); } - /* If an error occurred in either of the blocks above, free the - ** Pager structure and close the file. + /* Initialize the PCache object. */ + if( rc==SQLITE_OK ){ + assert( nExtra<1000 ); + nExtra = ROUND8(nExtra); + rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, + !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); + } + + /* If an error occurred above, free the Pager structure and close the file. */ if( rc!=SQLITE_OK ){ - assert( !pPager->pTmpSpace ); sqlite3OsClose(pPager->fd); + sqlite3PageFree(pPager->pTmpSpace); sqlite3_free(pPager); return rc; } - /* Initialize the PCache object. */ - assert( nExtra<1000 ); - nExtra = ROUND8(nExtra); - sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, - !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); - PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename)); IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename)) @@ -4938,7 +4947,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ *pExists = (first!=0); }else if( rc==SQLITE_CANTOPEN ){ /* If we cannot open the rollback journal file in order to see if - ** its has a zero header, that might be due to an I/O error, or + ** it has a zero header, that might be due to an I/O error, or ** it might be due to the race condition described above and in ** ticket #3883. Either way, assume that the journal is hot. ** This might be a false positive. But if it is, then the @@ -5120,16 +5129,12 @@ int sqlite3PagerSharedLock(Pager *pPager){ ); } - if( !pPager->tempFile && ( - pPager->pBackup - || sqlite3PcachePagecount(pPager->pPCache)>0 - || USEFETCH(pPager) - )){ - /* The shared-lock has just been acquired on the database file - ** and there are already pages in the cache (from a previous - ** read or write transaction). Check to see if the database - ** has been modified. If the database has changed, flush the - ** cache. + if( !pPager->tempFile && pPager->hasBeenUsed ){ + /* The shared-lock has just been acquired then check to + ** see if the database has been modified. If the database has changed, + ** flush the cache. The pPager->hasBeenUsed flag prevents this from + ** occurring on the very first access to a file, in order to save a + ** single unnecessary sqlite3OsRead() call at the start-up. ** ** Database changes is detected by looking at 15 bytes beginning ** at offset 24 into the file. The first 4 of these 16 bytes are @@ -5294,13 +5299,13 @@ int sqlite3PagerAcquire( if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } + pPager->hasBeenUsed = 1; /* If the pager is in the error state, return an error immediately. ** Otherwise, request the page from the PCache layer. */ if( pPager->errCode!=SQLITE_OK ){ rc = pPager->errCode; }else{ - if( bMmapOk && pagerUseWal(pPager) ){ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); if( rc!=SQLITE_OK ) goto pager_acquire_err; @@ -5315,7 +5320,7 @@ int sqlite3PagerAcquire( if( rc==SQLITE_OK && pData ){ if( pPager->eState>PAGER_READER ){ - (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg); + pPg = sqlite3PagerLookup(pPager, pgno); } if( pPg==0 ){ rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg); @@ -5333,7 +5338,16 @@ int sqlite3PagerAcquire( } } - rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage); + { + sqlite3_pcache_page *pBase; + pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); + if( pBase==0 ){ + rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase); + if( rc!=SQLITE_OK ) goto pager_acquire_err; + } + pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase); + if( pPg==0 ) rc = SQLITE_NOMEM; + } } if( rc!=SQLITE_OK ){ @@ -5430,13 +5444,13 @@ pager_acquire_err: ** has ever happened. */ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ - PgHdr *pPg = 0; + sqlite3_pcache_page *pPage; assert( pPager!=0 ); assert( pgno!=0 ); assert( pPager->pPCache!=0 ); - assert( pPager->eState>=PAGER_READER && pPager->eState!=PAGER_ERROR ); - sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg); - return pPg; + pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0); + assert( pPage==0 || pPager->hasBeenUsed ); + return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage); } /* @@ -5772,6 +5786,97 @@ static int pager_write(PgHdr *pPg){ return rc; } +/* +** This is a variant of sqlite3PagerWrite() that runs when the sector size +** is larger than the page size. SQLite makes the (reasonable) assumption that +** all bytes of a sector are written together by hardware. Hence, all bytes of +** a sector need to be journalled in case of a power loss in the middle of +** a write. +** +** Usually, the sector size is less than or equal to the page size, in which +** case pages can be individually written. This routine only runs in the exceptional +** case where the page size is smaller than the sector size. +*/ +static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){ + int rc = SQLITE_OK; /* Return code */ + Pgno nPageCount; /* Total number of pages in database file */ + Pgno pg1; /* First page of the sector pPg is located on. */ + int nPage = 0; /* Number of pages starting at pg1 to journal */ + int ii; /* Loop counter */ + int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */ + Pager *pPager = pPg->pPager; /* The pager that owns pPg */ + Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); + + /* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow + ** a journal header to be written between the pages journaled by + ** this function. + */ + assert( !MEMDB ); + assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 ); + pPager->doNotSpill |= SPILLFLAG_NOSYNC; + + /* This trick assumes that both the page-size and sector-size are + ** an integer power of 2. It sets variable pg1 to the identifier + ** of the first page of the sector pPg is located on. + */ + pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1; + + nPageCount = pPager->dbSize; + if( pPg->pgno>nPageCount ){ + nPage = (pPg->pgno - pg1)+1; + }else if( (pg1+nPagePerSector-1)>nPageCount ){ + nPage = nPageCount+1-pg1; + }else{ + nPage = nPagePerSector; + } + assert(nPage>0); + assert(pg1<=pPg->pgno); + assert((pg1+nPage)>pPg->pgno); + + for(ii=0; iipgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ + if( pg!=PAGER_MJ_PGNO(pPager) ){ + rc = sqlite3PagerGet(pPager, pg, &pPage); + if( rc==SQLITE_OK ){ + rc = pager_write(pPage); + if( pPage->flags&PGHDR_NEED_SYNC ){ + needSync = 1; + } + sqlite3PagerUnrefNotNull(pPage); + } + } + }else if( (pPage = sqlite3PagerLookup(pPager, pg))!=0 ){ + if( pPage->flags&PGHDR_NEED_SYNC ){ + needSync = 1; + } + sqlite3PagerUnrefNotNull(pPage); + } + } + + /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages + ** starting at pg1, then it needs to be set for all of them. Because + ** writing to any of these nPage pages may damage the others, the + ** journal file must contain sync()ed copies of all of them + ** before any of them can be written out to the database file. + */ + if( rc==SQLITE_OK && needSync ){ + assert( !MEMDB ); + for(ii=0; iiflags |= PGHDR_NEED_SYNC; + sqlite3PagerUnrefNotNull(pPage); + } + } + } + + assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 ); + pPager->doNotSpill &= ~SPILLFLAG_NOSYNC; + return rc; +} + /* ** Mark a data page as writeable. This routine must be called before ** making changes to a page. The caller must check the return value @@ -5786,96 +5891,16 @@ static int pager_write(PgHdr *pPg){ ** If an error occurs, SQLITE_NOMEM or an IO error code is returned ** as appropriate. Otherwise, SQLITE_OK. */ -int sqlite3PagerWrite(DbPage *pDbPage){ - int rc = SQLITE_OK; - - PgHdr *pPg = pDbPage; - Pager *pPager = pPg->pPager; - +int sqlite3PagerWrite(PgHdr *pPg){ assert( (pPg->flags & PGHDR_MMAP)==0 ); - assert( pPager->eState>=PAGER_WRITER_LOCKED ); - assert( pPager->eState!=PAGER_ERROR ); - assert( assert_pager_state(pPager) ); - - if( pPager->sectorSize > (u32)pPager->pageSize ){ - Pgno nPageCount; /* Total number of pages in database file */ - Pgno pg1; /* First page of the sector pPg is located on. */ - int nPage = 0; /* Number of pages starting at pg1 to journal */ - int ii; /* Loop counter */ - int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */ - Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); - - /* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow - ** a journal header to be written between the pages journaled by - ** this function. - */ - assert( !MEMDB ); - assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 ); - pPager->doNotSpill |= SPILLFLAG_NOSYNC; - - /* This trick assumes that both the page-size and sector-size are - ** an integer power of 2. It sets variable pg1 to the identifier - ** of the first page of the sector pPg is located on. - */ - pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1; - - nPageCount = pPager->dbSize; - if( pPg->pgno>nPageCount ){ - nPage = (pPg->pgno - pg1)+1; - }else if( (pg1+nPagePerSector-1)>nPageCount ){ - nPage = nPageCount+1-pg1; - }else{ - nPage = nPagePerSector; - } - assert(nPage>0); - assert(pg1<=pPg->pgno); - assert((pg1+nPage)>pPg->pgno); - - for(ii=0; iipgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ - if( pg!=PAGER_MJ_PGNO(pPager) ){ - rc = sqlite3PagerGet(pPager, pg, &pPage); - if( rc==SQLITE_OK ){ - rc = pager_write(pPage); - if( pPage->flags&PGHDR_NEED_SYNC ){ - needSync = 1; - } - sqlite3PagerUnrefNotNull(pPage); - } - } - }else if( (pPage = pager_lookup(pPager, pg))!=0 ){ - if( pPage->flags&PGHDR_NEED_SYNC ){ - needSync = 1; - } - sqlite3PagerUnrefNotNull(pPage); - } - } - - /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages - ** starting at pg1, then it needs to be set for all of them. Because - ** writing to any of these nPage pages may damage the others, the - ** journal file must contain sync()ed copies of all of them - ** before any of them can be written out to the database file. - */ - if( rc==SQLITE_OK && needSync ){ - assert( !MEMDB ); - for(ii=0; iiflags |= PGHDR_NEED_SYNC; - sqlite3PagerUnrefNotNull(pPage); - } - } - } - - assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 ); - pPager->doNotSpill &= ~SPILLFLAG_NOSYNC; + assert( pPg->pPager->eState>=PAGER_WRITER_LOCKED ); + assert( pPg->pPager->eState!=PAGER_ERROR ); + assert( assert_pager_state(pPg->pPager) ); + if( pPg->pPager->sectorSize > (u32)pPg->pPager->pageSize ){ + return pagerWriteLargeSector(pPg); }else{ - rc = pager_write(pDbPage); + return pager_write(pPg); } - return rc; } /* @@ -6291,6 +6316,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){ } PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); + pPager->iDataVersion++; rc = pager_end_transaction(pPager, pPager->setMaster, 1); return pager_error(pPager, rc); } @@ -6771,7 +6797,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ ** for the page moved there. */ pPg->flags &= ~PGHDR_NEED_SYNC; - pPgOld = pager_lookup(pPager, pgno); + pPgOld = sqlite3PagerLookup(pPager, pgno); assert( !pPgOld || pPgOld->nRef==1 ); if( pPgOld ){ pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); @@ -6831,6 +6857,18 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ } #endif +/* +** The page handle passed as the first argument refers to a dirty page +** with a page number other than iNew. This function changes the page's +** page number to iNew and sets the value of the PgHdr.flags field to +** the value passed as the third parameter. +*/ +void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){ + assert( pPg->pgno!=iNew ); + pPg->flags = flags; + sqlite3PcacheMove(pPg, iNew); +} + /* ** Return a pointer to the data for the specified page. */ @@ -7047,7 +7085,8 @@ int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){ int rc = SQLITE_OK; if( pPager->pWal ){ rc = sqlite3WalCheckpoint(pPager->pWal, eMode, - pPager->xBusyHandler, pPager->pBusyHandlerArg, + (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), + pPager->pBusyHandlerArg, pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, pnLog, pnCkpt ); @@ -7224,9 +7263,10 @@ int sqlite3PagerCloseWal(Pager *pPager){ ** is empty, return 0. */ int sqlite3PagerWalFramesize(Pager *pPager){ - assert( pPager->eState==PAGER_READER ); + assert( pPager->eState>=PAGER_READER ); return sqlite3WalFramesize(pPager->pWal); } #endif + #endif /* SQLITE_OMIT_DISKIO */ diff --git a/src/pager.h b/src/pager.h index c9ca855..e07fa88 100644 --- a/src/pager.h +++ b/src/pager.h @@ -172,6 +172,7 @@ int sqlite3PagerSharedLock(Pager *pPager); /* Functions used to query pager state and configuration. */ u8 sqlite3PagerIsreadonly(Pager*); +u32 sqlite3PagerDataVersion(Pager*); int sqlite3PagerRefcount(Pager*); int sqlite3PagerMemUsed(Pager*); const char *sqlite3PagerFilename(Pager*, int); @@ -188,6 +189,8 @@ int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ void sqlite3PagerTruncateImage(Pager*,Pgno); +void sqlite3PagerRekey(DbPage*, Pgno, u16); + #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) void *sqlite3PagerCodec(DbPage *); #endif diff --git a/src/parse.y b/src/parse.y index dbc129c..544888a 100644 --- a/src/parse.y +++ b/src/parse.y @@ -399,9 +399,6 @@ cmd ::= DROP VIEW ifexists(E) fullname(X). { cmd ::= select(X). { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; sqlite3Select(pParse, X, &dest); - sqlite3ExplainBegin(pParse->pVdbe); - sqlite3ExplainSelect(pParse->pVdbe, X); - sqlite3ExplainFinish(pParse->pVdbe); sqlite3SelectDelete(pParse->db, X); } @@ -418,13 +415,19 @@ select(A) ::= with(W) selectnowith(X). { int cnt = 0, mxSelect; p->pWith = W; if( p->pPrior ){ + u16 allValues = SF_Values; pNext = 0; for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){ pLoop->pNext = pNext; pLoop->selFlags |= SF_Compound; + allValues &= pLoop->selFlags; } - mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT]; - if( mxSelect && cnt>mxSelect ){ + if( allValues ){ + p->selFlags |= SF_AllValues; + }else if( + (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 + && cnt>mxSelect + ){ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); } } @@ -459,9 +462,33 @@ multiselect_op(A) ::= UNION(OP). {A = @OP;} multiselect_op(A) ::= UNION ALL. {A = TK_ALL;} multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;} %endif SQLITE_OMIT_COMPOUND_SELECT -oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) +oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y) groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). { A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset); +#if SELECTTRACE_ENABLED + /* Populate the Select.zSelName[] string that is used to help with + ** query planner debugging, to differentiate between multiple Select + ** objects in a complex query. + ** + ** If the SELECT keyword is immediately followed by a C-style comment + ** then extract the first few alphanumeric characters from within that + ** comment to be the zSelName value. Otherwise, the label is #N where + ** is an integer that is incremented with each SELECT statement seen. + */ + if( A!=0 ){ + const char *z = S.z+6; + int i; + sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "#%d", + ++pParse->nSelect); + while( z[0]==' ' ) z++; + if( z[0]=='/' && z[1]=='*' ){ + z += 2; + while( z[0]==' ' ) z++; + for(i=0; sqlite3Isalnum(z[i]); i++){} + sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "%.*s", i, z); + } + } +#endif /* SELECTRACE_ENABLED */ } oneselect(A) ::= values(X). {A = X;} @@ -940,7 +967,7 @@ expr(A) ::= expr(X) NOT NULL(E). {spanUnaryPostfix(&A,pParse,TK_NOTNULL,&X,&E);} ** unary TK_ISNULL or TK_NOTNULL expression. */ static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ sqlite3 *db = pParse->db; - if( db->mallocFailed==0 && pY->op==TK_NULL ){ + if( pY && pA && pY->op==TK_NULL ){ pA->op = (u8)op; sqlite3ExprDelete(db, pA->pRight); pA->pRight = 0; diff --git a/src/pcache.c b/src/pcache.c index e18bf93..467e2b3 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -31,102 +31,73 @@ struct PCache { PgHdr *pPage1; /* Reference to page 1 */ }; -/* -** Some of the assert() macros in this code are too expensive to run -** even during normal debugging. Use them only rarely on long-running -** tests. Enable the expensive asserts using the -** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option. -*/ -#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT -# define expensive_assert(X) assert(X) -#else -# define expensive_assert(X) -#endif - /********************************** Linked List Management ********************/ -#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT) -/* -** Check that the pCache->pSynced variable is set correctly. If it -** is not, either fail an assert or return zero. Otherwise, return -** non-zero. This is only used in debugging builds, as follows: -** -** expensive_assert( pcacheCheckSynced(pCache) ); -*/ -static int pcacheCheckSynced(PCache *pCache){ - PgHdr *p; - for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pDirtyPrev){ - assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) ); - } - return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0); -} -#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */ +/* Allowed values for second argument to pcacheManageDirtyList() */ +#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */ +#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */ +#define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */ /* -** Remove page pPage from the list of dirty pages. +** Manage pPage's participation on the dirty list. Bits of the addRemove +** argument determines what operation to do. The 0x01 bit means first +** remove pPage from the dirty list. The 0x02 means add pPage back to +** the dirty list. Doing both moves pPage to the front of the dirty list. */ -static void pcacheRemoveFromDirtyList(PgHdr *pPage){ +static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ PCache *p = pPage->pCache; - assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); - assert( pPage->pDirtyPrev || pPage==p->pDirty ); - - /* Update the PCache1.pSynced variable if necessary. */ - if( p->pSynced==pPage ){ - PgHdr *pSynced = pPage->pDirtyPrev; - while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){ - pSynced = pSynced->pDirtyPrev; + if( addRemove & PCACHE_DIRTYLIST_REMOVE ){ + assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); + assert( pPage->pDirtyPrev || pPage==p->pDirty ); + + /* Update the PCache1.pSynced variable if necessary. */ + if( p->pSynced==pPage ){ + PgHdr *pSynced = pPage->pDirtyPrev; + while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){ + pSynced = pSynced->pDirtyPrev; + } + p->pSynced = pSynced; } - p->pSynced = pSynced; + + if( pPage->pDirtyNext ){ + pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev; + }else{ + assert( pPage==p->pDirtyTail ); + p->pDirtyTail = pPage->pDirtyPrev; + } + if( pPage->pDirtyPrev ){ + pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; + }else{ + assert( pPage==p->pDirty ); + p->pDirty = pPage->pDirtyNext; + if( p->pDirty==0 && p->bPurgeable ){ + assert( p->eCreate==1 ); + p->eCreate = 2; + } + } + pPage->pDirtyNext = 0; + pPage->pDirtyPrev = 0; } - - if( pPage->pDirtyNext ){ - pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev; - }else{ - assert( pPage==p->pDirtyTail ); - p->pDirtyTail = pPage->pDirtyPrev; - } - if( pPage->pDirtyPrev ){ - pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; - }else{ - assert( pPage==p->pDirty ); - p->pDirty = pPage->pDirtyNext; - if( p->pDirty==0 && p->bPurgeable ){ - assert( p->eCreate==1 ); - p->eCreate = 2; + if( addRemove & PCACHE_DIRTYLIST_ADD ){ + assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage ); + + pPage->pDirtyNext = p->pDirty; + if( pPage->pDirtyNext ){ + assert( pPage->pDirtyNext->pDirtyPrev==0 ); + pPage->pDirtyNext->pDirtyPrev = pPage; + }else{ + p->pDirtyTail = pPage; + if( p->bPurgeable ){ + assert( p->eCreate==2 ); + p->eCreate = 1; + } + } + p->pDirty = pPage; + if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){ + p->pSynced = pPage; } } - pPage->pDirtyNext = 0; - pPage->pDirtyPrev = 0; - - expensive_assert( pcacheCheckSynced(p) ); -} - -/* -** Add page pPage to the head of the dirty list (PCache1.pDirty is set to -** pPage). -*/ -static void pcacheAddToDirtyList(PgHdr *pPage){ - PCache *p = pPage->pCache; - - assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage ); - - pPage->pDirtyNext = p->pDirty; - if( pPage->pDirtyNext ){ - assert( pPage->pDirtyNext->pDirtyPrev==0 ); - pPage->pDirtyNext->pDirtyPrev = pPage; - }else if( p->bPurgeable ){ - assert( p->eCreate==2 ); - p->eCreate = 1; - } - p->pDirty = pPage; - if( !p->pDirtyTail ){ - p->pDirtyTail = pPage; - } - if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){ - p->pSynced = pPage; - } - expensive_assert( pcacheCheckSynced(p) ); } /* @@ -134,12 +105,22 @@ static void pcacheAddToDirtyList(PgHdr *pPage){ ** being used for an in-memory database, this function is a no-op. */ static void pcacheUnpin(PgHdr *p){ - PCache *pCache = p->pCache; - if( pCache->bPurgeable ){ + if( p->pCache->bPurgeable ){ if( p->pgno==1 ){ - pCache->pPage1 = 0; + p->pCache->pPage1 = 0; } - sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 0); + sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); + } +} + +/* +** Compute the number of pages of cache requested. +*/ +static int numberOfCachePages(PCache *p){ + if( p->szCache>=0 ){ + return p->szCache; + }else{ + return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); } } @@ -175,7 +156,7 @@ int sqlite3PcacheSize(void){ return sizeof(PCache); } ** The caller discovers how much space needs to be allocated by ** calling sqlite3PcacheSize(). */ -void sqlite3PcacheOpen( +int sqlite3PcacheOpen( int szPage, /* Size of every page */ int szExtra, /* Extra space associated with each page */ int bPurgeable, /* True if pages are on backing store */ @@ -184,76 +165,76 @@ void sqlite3PcacheOpen( PCache *p /* Preallocated space for the PCache */ ){ memset(p, 0, sizeof(PCache)); - p->szPage = szPage; + p->szPage = 1; p->szExtra = szExtra; p->bPurgeable = bPurgeable; p->eCreate = 2; p->xStress = xStress; p->pStress = pStress; p->szCache = 100; + return sqlite3PcacheSetPageSize(p, szPage); } /* ** Change the page size for PCache object. The caller must ensure that there ** are no outstanding page references when this function is called. */ -void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ +int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ assert( pCache->nRef==0 && pCache->pDirty==0 ); - if( pCache->pCache ){ - sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); - pCache->pCache = 0; + if( pCache->szPage ){ + sqlite3_pcache *pNew; + pNew = sqlite3GlobalConfig.pcache2.xCreate( + szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)), + pCache->bPurgeable + ); + if( pNew==0 ) return SQLITE_NOMEM; + sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache)); + if( pCache->pCache ){ + sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); + } + pCache->pCache = pNew; pCache->pPage1 = 0; + pCache->szPage = szPage; } - pCache->szPage = szPage; -} - -/* -** Compute the number of pages of cache requested. -*/ -static int numberOfCachePages(PCache *p){ - if( p->szCache>=0 ){ - return p->szCache; - }else{ - return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); - } + return SQLITE_OK; } /* ** Try to obtain a page from the cache. +** +** This routine returns a pointer to an sqlite3_pcache_page object if +** such an object is already in cache, or if a new one is created. +** This routine returns a NULL pointer if the object was not in cache +** and could not be created. +** +** The createFlags should be 0 to check for existing pages and should +** be 3 (not 1, but 3) to try to create a new page. +** +** If the createFlag is 0, then NULL is always returned if the page +** is not already in the cache. If createFlag is 1, then a new page +** is created only if that can be done without spilling dirty pages +** and without exceeding the cache size limit. +** +** The caller needs to invoke sqlite3PcacheFetchFinish() to properly +** initialize the sqlite3_pcache_page object and convert it into a +** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish() +** routines are split this way for performance reasons. When separated +** they can both (usually) operate without having to push values to +** the stack on entry and pop them back off on exit, which saves a +** lot of pushing and popping. */ -int sqlite3PcacheFetch( +sqlite3_pcache_page *sqlite3PcacheFetch( PCache *pCache, /* Obtain the page from this cache */ Pgno pgno, /* Page number to obtain */ - int createFlag, /* If true, create page if it does not exist already */ - PgHdr **ppPage /* Write the page here */ + int createFlag /* If true, create page if it does not exist already */ ){ - sqlite3_pcache_page *pPage; - PgHdr *pPgHdr = 0; int eCreate; assert( pCache!=0 ); - assert( createFlag==1 || createFlag==0 ); + assert( pCache->pCache!=0 ); + assert( createFlag==3 || createFlag==0 ); assert( pgno>0 ); - /* If the pluggable cache (sqlite3_pcache*) has not been allocated, - ** allocate it now. - */ - if( !pCache->pCache ){ - sqlite3_pcache *p; - if( !createFlag ){ - *ppPage = 0; - return SQLITE_OK; - } - p = sqlite3GlobalConfig.pcache2.xCreate( - pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable - ); - if( !p ){ - return SQLITE_NOMEM; - } - sqlite3GlobalConfig.pcache2.xCachesize(p, numberOfCachePages(pCache)); - pCache->pCache = p; - } - /* eCreate defines what to do if the page does not exist. ** 0 Do not allocate a new page. (createFlag==0) ** 1 Allocate a new page if doing so is inexpensive. @@ -261,89 +242,135 @@ int sqlite3PcacheFetch( ** 2 Allocate a new page even it doing so is difficult. ** (createFlag==1 AND !(bPurgeable AND pDirty) */ - eCreate = createFlag==0 ? 0 : pCache->eCreate; - assert( (createFlag*(1+(!pCache->bPurgeable||!pCache->pDirty)))==eCreate ); - pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); - if( !pPage && eCreate==1 ){ - PgHdr *pPg; + eCreate = createFlag & pCache->eCreate; + assert( eCreate==0 || eCreate==1 || eCreate==2 ); + assert( createFlag==0 || pCache->eCreate==eCreate ); + assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); + return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); +} - /* Find a dirty page to write-out and recycle. First try to find a - ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC - ** cleared), but if that is not possible settle for any other - ** unreferenced dirty page. - */ - expensive_assert( pcacheCheckSynced(pCache) ); - for(pPg=pCache->pSynced; - pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); - pPg=pPg->pDirtyPrev - ); - pCache->pSynced = pPg; - if( !pPg ){ - for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); - } - if( pPg ){ - int rc; +/* +** If the sqlite3PcacheFetch() routine is unable to allocate a new +** page because new clean pages are available for reuse and the cache +** size limit has been reached, then this routine can be invoked to +** try harder to allocate a page. This routine might invoke the stress +** callback to spill dirty pages to the journal. It will then try to +** allocate the new page and will only fail to allocate a new page on +** an OOM error. +** +** This routine should be invoked only after sqlite3PcacheFetch() fails. +*/ +int sqlite3PcacheFetchStress( + PCache *pCache, /* Obtain the page from this cache */ + Pgno pgno, /* Page number to obtain */ + sqlite3_pcache_page **ppPage /* Write result here */ +){ + PgHdr *pPg; + if( pCache->eCreate==2 ) return 0; + + + /* Find a dirty page to write-out and recycle. First try to find a + ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC + ** cleared), but if that is not possible settle for any other + ** unreferenced dirty page. + */ + for(pPg=pCache->pSynced; + pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); + pPg=pPg->pDirtyPrev + ); + pCache->pSynced = pPg; + if( !pPg ){ + for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); + } + if( pPg ){ + int rc; #ifdef SQLITE_LOG_CACHE_SPILL - sqlite3_log(SQLITE_FULL, - "spill page %d making room for %d - cache used: %d/%d", - pPg->pgno, pgno, - sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), - numberOfCachePages(pCache)); + sqlite3_log(SQLITE_FULL, + "spill page %d making room for %d - cache used: %d/%d", + pPg->pgno, pgno, + sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), + numberOfCachePages(pCache)); #endif - rc = pCache->xStress(pCache->pStress, pPg); - if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ - return rc; - } - } - - pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); - } - - if( pPage ){ - pPgHdr = (PgHdr *)pPage->pExtra; - - if( !pPgHdr->pPage ){ - memset(pPgHdr, 0, sizeof(PgHdr)); - pPgHdr->pPage = pPage; - pPgHdr->pData = pPage->pBuf; - pPgHdr->pExtra = (void *)&pPgHdr[1]; - memset(pPgHdr->pExtra, 0, pCache->szExtra); - pPgHdr->pCache = pCache; - pPgHdr->pgno = pgno; - } - assert( pPgHdr->pCache==pCache ); - assert( pPgHdr->pgno==pgno ); - assert( pPgHdr->pData==pPage->pBuf ); - assert( pPgHdr->pExtra==(void *)&pPgHdr[1] ); - - if( 0==pPgHdr->nRef ){ - pCache->nRef++; - } - pPgHdr->nRef++; - if( pgno==1 ){ - pCache->pPage1 = pPgHdr; + rc = pCache->xStress(pCache->pStress, pPg); + if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ + return rc; } } - *ppPage = pPgHdr; - return (pPgHdr==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK; + *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); + return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK; +} + +/* +** This is a helper routine for sqlite3PcacheFetchFinish() +** +** In the uncommon case where the page being fetched has not been +** initialized, this routine is invoked to do the initialization. +** This routine is broken out into a separate function since it +** requires extra stack manipulation that can be avoided in the common +** case. +*/ +static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit( + PCache *pCache, /* Obtain the page from this cache */ + Pgno pgno, /* Page number obtained */ + sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */ +){ + PgHdr *pPgHdr; + assert( pPage!=0 ); + pPgHdr = (PgHdr*)pPage->pExtra; + assert( pPgHdr->pPage==0 ); + memset(pPgHdr, 0, sizeof(PgHdr)); + pPgHdr->pPage = pPage; + pPgHdr->pData = pPage->pBuf; + pPgHdr->pExtra = (void *)&pPgHdr[1]; + memset(pPgHdr->pExtra, 0, pCache->szExtra); + pPgHdr->pCache = pCache; + pPgHdr->pgno = pgno; + return sqlite3PcacheFetchFinish(pCache,pgno,pPage); +} + +/* +** This routine converts the sqlite3_pcache_page object returned by +** sqlite3PcacheFetch() into an initialized PgHdr object. This routine +** must be called after sqlite3PcacheFetch() in order to get a usable +** result. +*/ +PgHdr *sqlite3PcacheFetchFinish( + PCache *pCache, /* Obtain the page from this cache */ + Pgno pgno, /* Page number obtained */ + sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */ +){ + PgHdr *pPgHdr; + + if( pPage==0 ) return 0; + pPgHdr = (PgHdr *)pPage->pExtra; + + if( !pPgHdr->pPage ){ + return pcacheFetchFinishWithInit(pCache, pgno, pPage); + } + if( 0==pPgHdr->nRef ){ + pCache->nRef++; + } + pPgHdr->nRef++; + if( pgno==1 ){ + pCache->pPage1 = pPgHdr; + } + return pPgHdr; } /* ** Decrement the reference count on a page. If the page is clean and the -** reference count drops to 0, then it is made elible for recycling. +** reference count drops to 0, then it is made eligible for recycling. */ -void sqlite3PcacheRelease(PgHdr *p){ +void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ assert( p->nRef>0 ); p->nRef--; if( p->nRef==0 ){ - PCache *pCache = p->pCache; - pCache->nRef--; + p->pCache->nRef--; if( (p->flags&PGHDR_DIRTY)==0 ){ pcacheUnpin(p); - }else{ + }else if( p->pDirtyPrev!=0 ){ /* Move the page to the head of the dirty list. */ - pcacheRemoveFromDirtyList(p); - pcacheAddToDirtyList(p); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } } @@ -362,17 +389,15 @@ void sqlite3PcacheRef(PgHdr *p){ ** page pointed to by p is invalid. */ void sqlite3PcacheDrop(PgHdr *p){ - PCache *pCache; assert( p->nRef==1 ); if( p->flags&PGHDR_DIRTY ){ - pcacheRemoveFromDirtyList(p); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); } - pCache = p->pCache; - pCache->nRef--; + p->pCache->nRef--; if( p->pgno==1 ){ - pCache->pPage1 = 0; + p->pCache->pPage1 = 0; } - sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 1); + sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1); } /* @@ -384,7 +409,7 @@ void sqlite3PcacheMakeDirty(PgHdr *p){ assert( p->nRef>0 ); if( 0==(p->flags & PGHDR_DIRTY) ){ p->flags |= PGHDR_DIRTY; - pcacheAddToDirtyList( p); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD); } } @@ -394,7 +419,7 @@ void sqlite3PcacheMakeDirty(PgHdr *p){ */ void sqlite3PcacheMakeClean(PgHdr *p){ if( (p->flags & PGHDR_DIRTY) ){ - pcacheRemoveFromDirtyList(p); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC); if( p->nRef==0 ){ pcacheUnpin(p); @@ -433,8 +458,7 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno); p->pgno = newPgno; if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ - pcacheRemoveFromDirtyList(p); - pcacheAddToDirtyList(p); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } @@ -475,9 +499,8 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ ** Close a cache. */ void sqlite3PcacheClose(PCache *pCache){ - if( pCache->pCache ){ - sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); - } + assert( pCache->pCache!=0 ); + sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); } /* @@ -586,11 +609,8 @@ int sqlite3PcachePageRefcount(PgHdr *p){ ** Return the total number of pages in the cache. */ int sqlite3PcachePagecount(PCache *pCache){ - int nPage = 0; - if( pCache->pCache ){ - nPage = sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache); - } - return nPage; + assert( pCache->pCache!=0 ); + return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache); } #ifdef SQLITE_TEST @@ -606,22 +626,27 @@ int sqlite3PcacheGetCachesize(PCache *pCache){ ** Set the suggested cache-size value. */ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ + assert( pCache->pCache!=0 ); pCache->szCache = mxPage; - if( pCache->pCache ){ - sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache, - numberOfCachePages(pCache)); - } + sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache, + numberOfCachePages(pCache)); } /* ** Free up as much memory as possible from the page cache. */ void sqlite3PcacheShrink(PCache *pCache){ - if( pCache->pCache ){ - sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache); - } + assert( pCache->pCache!=0 ); + sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache); } +/* +** Return the size of the header added by this middleware layer +** in the page-cache hierarchy. +*/ +int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); } + + #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* ** For all dirty pages currently in the cache, invoke the specified diff --git a/src/pcache.h b/src/pcache.h index f4d4ad7..9ed62a8 100644 --- a/src/pcache.h +++ b/src/pcache.h @@ -68,7 +68,7 @@ void sqlite3PCacheBufferSetup(void *, int sz, int n); ** Under memory stress, invoke xStress to try to make pages clean. ** Only clean and unpinned pages can be reclaimed. */ -void sqlite3PcacheOpen( +int sqlite3PcacheOpen( int szPage, /* Size of every page */ int szExtra, /* Extra space associated with each page */ int bPurgeable, /* True if pages are on backing store */ @@ -78,7 +78,7 @@ void sqlite3PcacheOpen( ); /* Modify the page-size after the cache has been created. */ -void sqlite3PcacheSetPageSize(PCache *, int); +int sqlite3PcacheSetPageSize(PCache *, int); /* Return the size in bytes of a PCache object. Used to preallocate ** storage space. @@ -88,7 +88,9 @@ int sqlite3PcacheSize(void); /* One release per successful fetch. Page is pinned until released. ** Reference counted. */ -int sqlite3PcacheFetch(PCache*, Pgno, int createFlag, PgHdr**); +sqlite3_pcache_page *sqlite3PcacheFetch(PCache*, Pgno, int createFlag); +int sqlite3PcacheFetchStress(PCache*, Pgno, sqlite3_pcache_page**); +PgHdr *sqlite3PcacheFetchFinish(PCache*, Pgno, sqlite3_pcache_page *pPage); void sqlite3PcacheRelease(PgHdr*); void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache */ @@ -158,4 +160,8 @@ void sqlite3PcacheStats(int*,int*,int*,int*); void sqlite3PCacheSetDefault(void); +/* Return the header size */ +int sqlite3HeaderSizePcache(void); +int sqlite3HeaderSizePcache1(void); + #endif /* _PCACHE_H_ */ diff --git a/src/pcache1.c b/src/pcache1.c index 1644b06..f5f7893 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -13,7 +13,7 @@ ** This file implements the default page cache implementation (the ** sqlite3_pcache interface). It also contains part of the implementation ** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features. -** If the default page cache implementation is overriden, then neither of +** If the default page cache implementation is overridden, then neither of ** these two features are available. */ @@ -25,7 +25,7 @@ typedef struct PgFreeslot PgFreeslot; typedef struct PGroup PGroup; /* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set -** of one or more PCaches that are able to recycle each others unpinned +** of one or more PCaches that are able to recycle each other's unpinned ** pages when they are under memory pressure. A PGroup is an instance of ** the following object. ** @@ -296,7 +296,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){ pPg = 0; } #else - pPg = pcache1Alloc(sizeof(PgHdr1) + pCache->szPage + pCache->szExtra); + pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra); p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage]; #endif pcache1EnterMutex(pCache->pGroup); @@ -383,7 +383,7 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){ ** ** The PCache mutex must be held when this function is called. */ -static int pcache1ResizeHash(PCache1 *p){ +static void pcache1ResizeHash(PCache1 *p){ PgHdr1 **apNew; unsigned int nNew; unsigned int i; @@ -415,8 +415,6 @@ static int pcache1ResizeHash(PCache1 *p){ p->apHash = apNew; p->nHash = nNew; } - - return (p->apHash ? SQLITE_OK : SQLITE_NOMEM); } /* @@ -551,6 +549,9 @@ static void pcache1Shutdown(void *NotUsed){ memset(&pcache1, 0, sizeof(pcache1)); } +/* forward declaration */ +static void pcache1Destroy(sqlite3_pcache *p); + /* ** Implementation of the sqlite3_pcache.xCreate method. ** @@ -595,12 +596,17 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ pCache->szPage = szPage; pCache->szExtra = szExtra; pCache->bPurgeable = (bPurgeable ? 1 : 0); + pcache1EnterMutex(pGroup); + pcache1ResizeHash(pCache); if( bPurgeable ){ pCache->nMin = 10; - pcache1EnterMutex(pGroup); pGroup->nMinPage += pCache->nMin; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; - pcache1LeaveMutex(pGroup); + } + pcache1LeaveMutex(pGroup); + if( pCache->nHash==0 ){ + pcache1Destroy((sqlite3_pcache*)pCache); + pCache = 0; } } return (sqlite3_pcache *)pCache; @@ -656,6 +662,95 @@ static int pcache1Pagecount(sqlite3_pcache *p){ return n; } + +/* +** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described +** in the header of the pcache1Fetch() procedure. +** +** This steps are broken out into a separate procedure because they are +** usually not needed, and by avoiding the stack initialization required +** for these steps, the main pcache1Fetch() procedure can run faster. +*/ +static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( + PCache1 *pCache, + unsigned int iKey, + int createFlag +){ + unsigned int nPinned; + PGroup *pGroup = pCache->pGroup; + PgHdr1 *pPage = 0; + + /* Step 3: Abort if createFlag is 1 but the cache is nearly full */ + assert( pCache->nPage >= pCache->nRecyclable ); + nPinned = pCache->nPage - pCache->nRecyclable; + assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage ); + assert( pCache->n90pct == pCache->nMax*9/10 ); + if( createFlag==1 && ( + nPinned>=pGroup->mxPinned + || nPinned>=pCache->n90pct + || (pcache1UnderMemoryPressure(pCache) && pCache->nRecyclablenPage>=pCache->nHash ) pcache1ResizeHash(pCache); + assert( pCache->nHash>0 && pCache->apHash ); + + /* Step 4. Try to recycle a page. */ + if( pCache->bPurgeable && pGroup->pLruTail && ( + (pCache->nPage+1>=pCache->nMax) + || pGroup->nCurrentPage>=pGroup->nMaxPage + || pcache1UnderMemoryPressure(pCache) + )){ + PCache1 *pOther; + pPage = pGroup->pLruTail; + assert( pPage->isPinned==0 ); + pcache1RemoveFromHash(pPage); + pcache1PinPage(pPage); + pOther = pPage->pCache; + + /* We want to verify that szPage and szExtra are the same for pOther + ** and pCache. Assert that we can verify this by comparing sums. */ + assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 ); + assert( pCache->szExtra<512 ); + assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 ); + assert( pOther->szExtra<512 ); + + if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){ + pcache1FreePage(pPage); + pPage = 0; + }else{ + pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable); + } + } + + /* Step 5. If a usable page buffer has still not been found, + ** attempt to allocate a new one. + */ + if( !pPage ){ + if( createFlag==1 ) sqlite3BeginBenignMalloc(); + pPage = pcache1AllocPage(pCache); + if( createFlag==1 ) sqlite3EndBenignMalloc(); + } + + if( pPage ){ + unsigned int h = iKey % pCache->nHash; + pCache->nPage++; + pPage->iKey = iKey; + pPage->pNext = pCache->apHash[h]; + pPage->pCache = pCache; + pPage->pLruPrev = 0; + pPage->pLruNext = 0; + pPage->isPinned = 1; + *(void **)pPage->page.pExtra = 0; + pCache->apHash[h] = pPage; + if( iKey>pCache->iMaxKey ){ + pCache->iMaxKey = iKey; + } + } + return pPage; +} + /* ** Implementation of the sqlite3_pcache.xFetch method. ** @@ -715,9 +810,7 @@ static sqlite3_pcache_page *pcache1Fetch( unsigned int iKey, int createFlag ){ - unsigned int nPinned; PCache1 *pCache = (PCache1 *)p; - PGroup *pGroup; PgHdr1 *pPage = 0; assert( offsetof(PgHdr1,page)==0 ); @@ -725,107 +818,22 @@ static sqlite3_pcache_page *pcache1Fetch( assert( pCache->bPurgeable || pCache->nMin==0 ); assert( pCache->bPurgeable==0 || pCache->nMin==10 ); assert( pCache->nMin==0 || pCache->bPurgeable ); - pcache1EnterMutex(pGroup = pCache->pGroup); + assert( pCache->nHash>0 ); + pcache1EnterMutex(pCache->pGroup); /* Step 1: Search the hash table for an existing entry. */ - if( pCache->nHash>0 ){ - unsigned int h = iKey % pCache->nHash; - for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext); - } + pPage = pCache->apHash[iKey % pCache->nHash]; + while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; } /* Step 2: Abort if no existing page is found and createFlag is 0 */ if( pPage ){ if( !pPage->isPinned ) pcache1PinPage(pPage); - goto fetch_out; + }else if( createFlag ){ + /* Steps 3, 4, and 5 implemented by this subroutine */ + pPage = pcache1FetchStage2(pCache, iKey, createFlag); } - if( createFlag==0 ){ - goto fetch_out; - } - - /* The pGroup local variable will normally be initialized by the - ** pcache1EnterMutex() macro above. But if SQLITE_MUTEX_OMIT is defined, - ** then pcache1EnterMutex() is a no-op, so we have to initialize the - ** local variable here. Delaying the initialization of pGroup is an - ** optimization: The common case is to exit the module before reaching - ** this point. - */ -#ifdef SQLITE_MUTEX_OMIT - pGroup = pCache->pGroup; -#endif - - /* Step 3: Abort if createFlag is 1 but the cache is nearly full */ - assert( pCache->nPage >= pCache->nRecyclable ); - nPinned = pCache->nPage - pCache->nRecyclable; - assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage ); - assert( pCache->n90pct == pCache->nMax*9/10 ); - if( createFlag==1 && ( - nPinned>=pGroup->mxPinned - || nPinned>=pCache->n90pct - || pcache1UnderMemoryPressure(pCache) - )){ - goto fetch_out; - } - - if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){ - goto fetch_out; - } - assert( pCache->nHash>0 && pCache->apHash ); - - /* Step 4. Try to recycle a page. */ - if( pCache->bPurgeable && pGroup->pLruTail && ( - (pCache->nPage+1>=pCache->nMax) - || pGroup->nCurrentPage>=pGroup->nMaxPage - || pcache1UnderMemoryPressure(pCache) - )){ - PCache1 *pOther; - pPage = pGroup->pLruTail; - assert( pPage->isPinned==0 ); - pcache1RemoveFromHash(pPage); - pcache1PinPage(pPage); - pOther = pPage->pCache; - - /* We want to verify that szPage and szExtra are the same for pOther - ** and pCache. Assert that we can verify this by comparing sums. */ - assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 ); - assert( pCache->szExtra<512 ); - assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 ); - assert( pOther->szExtra<512 ); - - if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){ - pcache1FreePage(pPage); - pPage = 0; - }else{ - pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable); - } - } - - /* Step 5. If a usable page buffer has still not been found, - ** attempt to allocate a new one. - */ - if( !pPage ){ - if( createFlag==1 ) sqlite3BeginBenignMalloc(); - pPage = pcache1AllocPage(pCache); - if( createFlag==1 ) sqlite3EndBenignMalloc(); - } - - if( pPage ){ - unsigned int h = iKey % pCache->nHash; - pCache->nPage++; - pPage->iKey = iKey; - pPage->pNext = pCache->apHash[h]; - pPage->pCache = pCache; - pPage->pLruPrev = 0; - pPage->pLruNext = 0; - pPage->isPinned = 1; - *(void **)pPage->page.pExtra = 0; - pCache->apHash[h] = pPage; - } - -fetch_out: - if( pPage && iKey>pCache->iMaxKey ){ - pCache->iMaxKey = iKey; - } - pcache1LeaveMutex(pGroup); + assert( pPage==0 || pCache->iMaxKey>=iKey ); + pcache1LeaveMutex(pCache->pGroup); return (sqlite3_pcache_page*)pPage; } @@ -973,6 +981,11 @@ void sqlite3PCacheSetDefault(void){ sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods); } +/* +** Return the size of the header on each page of this PCACHE implementation. +*/ +int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); } + #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* ** This function is called to free superfluous dynamically allocated memory diff --git a/src/pragma.c b/src/pragma.c index 9ed5e13..34830e3 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -61,15 +61,17 @@ #define PragTyp_TABLE_INFO 30 #define PragTyp_TEMP_STORE 31 #define PragTyp_TEMP_STORE_DIRECTORY 32 -#define PragTyp_WAL_AUTOCHECKPOINT 33 -#define PragTyp_WAL_CHECKPOINT 34 -#define PragTyp_ACTIVATE_EXTENSIONS 35 -#define PragTyp_HEXKEY 36 -#define PragTyp_KEY 37 -#define PragTyp_REKEY 38 -#define PragTyp_LOCK_STATUS 39 -#define PragTyp_PARSER_TRACE 40 +#define PragTyp_THREADS 33 +#define PragTyp_WAL_AUTOCHECKPOINT 34 +#define PragTyp_WAL_CHECKPOINT 35 +#define PragTyp_ACTIVATE_EXTENSIONS 36 +#define PragTyp_HEXKEY 37 +#define PragTyp_KEY 38 +#define PragTyp_REKEY 39 +#define PragTyp_LOCK_STATUS 40 +#define PragTyp_PARSER_TRACE 41 #define PragFlag_NeedSchema 0x01 +#define PragFlag_ReadOnly 0x02 static const struct sPragmaNames { const char *const zName; /* Name of pragma */ u8 ePragTyp; /* PragTyp_XXX value */ @@ -86,7 +88,7 @@ static const struct sPragmaNames { { /* zName: */ "application_id", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlag: */ 0, - /* iArg: */ 0 }, + /* iArg: */ BTREE_APPLICATION_ID }, #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) { /* zName: */ "auto_vacuum", @@ -152,6 +154,12 @@ static const struct sPragmaNames { /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + { /* zName: */ "data_version", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlag: */ PragFlag_ReadOnly, + /* iArg: */ BTREE_DATA_VERSION }, +#endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) { /* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, @@ -207,8 +215,8 @@ static const struct sPragmaNames { #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) { /* zName: */ "freelist_count", /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + /* ePragFlag: */ PragFlag_ReadOnly, + /* iArg: */ BTREE_FREE_PAGE_COUNT }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) { /* zName: */ "full_column_names", @@ -360,7 +368,7 @@ static const struct sPragmaNames { { /* zName: */ "schema_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlag: */ 0, - /* iArg: */ 0 }, + /* iArg: */ BTREE_SCHEMA_VERSION }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) { /* zName: */ "secure_delete", @@ -418,11 +426,15 @@ static const struct sPragmaNames { /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif + { /* zName: */ "threads", + /* ePragTyp: */ PragTyp_THREADS, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) { /* zName: */ "user_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlag: */ 0, - /* iArg: */ 0 }, + /* iArg: */ BTREE_USER_VERSION }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if defined(SQLITE_DEBUG) @@ -465,7 +477,7 @@ static const struct sPragmaNames { /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, #endif }; -/* Number of pragmas: 56 on by default, 69 total. */ +/* Number of pragmas: 58 on by default, 71 total. */ /* End of the automatically generated pragma table. ***************************************************************************/ @@ -715,7 +727,7 @@ void sqlite3Pragma( Token *pId; /* Pointer to token */ char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */ int iDb; /* Database index for */ - int lwr, upr, mid; /* Binary search bounds */ + int lwr, upr, mid = 0; /* Binary search bounds */ int rc; /* return value form SQLITE_FCNTL_PRAGMA */ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* The specific database being pragmaed */ @@ -1392,6 +1404,12 @@ void sqlite3Pragma( ** in auto-commit mode. */ mask &= ~(SQLITE_ForeignKeys); } +#if SQLITE_USER_AUTHENTICATION + if( db->auth.authLevel==UAUTH_User ){ + /* Do not allow non-admin users to modify the schema arbitrarily */ + mask &= ~(SQLITE_WriteSchema); + } +#endif if( sqlite3GetBoolean(zRight, 0) ){ db->flags |= mask; @@ -2069,7 +2087,8 @@ void sqlite3Pragma( ){ for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ - ENC(pParse->db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE; + SCHEMA_ENC(db) = ENC(db) = + pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE; break; } } @@ -2114,24 +2133,9 @@ void sqlite3Pragma( ** applications for any purpose. */ case PragTyp_HEADER_VALUE: { - int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */ + int iCookie = aPragmaNames[mid].iArg; /* Which cookie to read or write */ sqlite3VdbeUsesBtree(v, iDb); - switch( zLeft[0] ){ - case 'a': case 'A': - iCookie = BTREE_APPLICATION_ID; - break; - case 'f': case 'F': - iCookie = BTREE_FREE_PAGE_COUNT; - break; - case 's': case 'S': - iCookie = BTREE_SCHEMA_VERSION; - break; - default: - iCookie = BTREE_USER_VERSION; - break; - } - - if( zRight && iCookie!=BTREE_FREE_PAGE_COUNT ){ + if( zRight && (aPragmaNames[mid].mPragFlag & PragFlag_ReadOnly)==0 ){ /* Write the specified cookie value */ static const VdbeOpList setCookie[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ @@ -2184,7 +2188,7 @@ void sqlite3Pragma( #ifndef SQLITE_OMIT_WAL /* - ** PRAGMA [database.]wal_checkpoint = passive|full|restart + ** PRAGMA [database.]wal_checkpoint = passive|full|restart|truncate ** ** Checkpoint the database. */ @@ -2196,6 +2200,8 @@ void sqlite3Pragma( eMode = SQLITE_CHECKPOINT_FULL; }else if( sqlite3StrICmp(zRight, "restart")==0 ){ eMode = SQLITE_CHECKPOINT_RESTART; + }else if( sqlite3StrICmp(zRight, "truncate")==0 ){ + eMode = SQLITE_CHECKPOINT_TRUNCATE; } } sqlite3VdbeSetNumCols(v, 3); @@ -2273,6 +2279,26 @@ void sqlite3Pragma( break; } + /* + ** PRAGMA threads + ** PRAGMA threads = N + ** + ** Configure the maximum number of worker threads. Return the new + ** maximum, which might be less than requested. + */ + case PragTyp_THREADS: { + sqlite3_int64 N; + if( zRight + && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK + && N>=0 + ){ + sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff)); + } + returnSingleInt(pParse, "threads", + sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1)); + break; + } + #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Report the current state of file logs for all databases diff --git a/src/prepare.c b/src/prepare.c index c7ba53a..97be900 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -328,7 +328,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ db->aDb[iDb].zName, zMasterName); #ifndef SQLITE_OMIT_AUTHORIZATION { - int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); + sqlite3_xauth xAuth; xAuth = db->xAuth; db->xAuth = 0; #endif @@ -394,8 +394,11 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ int commit_internal = !(db->flags&SQLITE_InternChanges); assert( sqlite3_mutex_held(db->mutex) ); + assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) ); + assert( db->init.busy==0 ); rc = SQLITE_OK; db->init.busy = 1; + ENC(db) = SCHEMA_ENC(db); for(i=0; rc==SQLITE_OK && inDb; i++){ if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; rc = sqlite3InitOne(db, i, pzErrMsg); @@ -409,8 +412,8 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ ** schema may contain references to objects in other databases. */ #ifndef SQLITE_OMIT_TEMPDB - if( rc==SQLITE_OK && ALWAYS(db->nDb>1) - && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ + assert( db->nDb>1 ); + if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, 1, pzErrMsg); if( rc ){ sqlite3ResetOneSchema(db, 1); @@ -593,7 +596,7 @@ static int sqlite3Prepare( rc = sqlite3BtreeSchemaLocked(pBt); if( rc ){ const char *zDb = db->aDb[i].zName; - sqlite3Error(db, rc, "database schema is locked: %s", zDb); + sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); testcase( db->flags & SQLITE_ReadUncommitted ); goto end_prepare; } @@ -610,7 +613,7 @@ static int sqlite3Prepare( testcase( nBytes==mxLen ); testcase( nBytes==mxLen+1 ); if( nBytes>mxLen ){ - sqlite3Error(db, SQLITE_TOOBIG, "statement too long"); + sqlite3ErrorWithMsg(db, SQLITE_TOOBIG, "statement too long"); rc = sqlite3ApiExit(db, SQLITE_TOOBIG); goto end_prepare; } @@ -677,10 +680,10 @@ static int sqlite3Prepare( } if( zErrMsg ){ - sqlite3Error(db, rc, "%s", zErrMsg); + sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg); sqlite3DbFree(db, zErrMsg); }else{ - sqlite3Error(db, rc, 0); + sqlite3Error(db, rc); } /* Delete any TriggerPrg structures allocated while parsing this statement. */ @@ -708,9 +711,12 @@ static int sqlite3LockAndPrepare( const char **pzTail /* OUT: End of parsed string */ ){ int rc; - assert( ppStmt!=0 ); + +#ifdef SQLITE_ENABLE_API_ARMOR + if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; +#endif *ppStmt = 0; - if( !sqlite3SafetyCheckOk(db) ){ + if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); @@ -817,9 +823,11 @@ static int sqlite3Prepare16( const char *zTail8 = 0; int rc = SQLITE_OK; - assert( ppStmt ); +#ifdef SQLITE_ENABLE_API_ARMOR + if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; +#endif *ppStmt = 0; - if( !sqlite3SafetyCheckOk(db) ){ + if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ return SQLITE_MISUSE_BKPT; } if( nBytes>=0 ){ diff --git a/src/printf.c b/src/printf.c index 3791080..428c959 100644 --- a/src/printf.c +++ b/src/printf.c @@ -201,7 +201,7 @@ void sqlite3VXPrintf( const et_info *infop; /* Pointer to the appropriate info structure */ char *zOut; /* Rendering buffer */ int nOut; /* Size of the rendering buffer */ - char *zExtra; /* Malloced memory used by some conversion */ + char *zExtra = 0; /* Malloced memory used by some conversion */ #ifndef SQLITE_OMIT_FLOATING_POINT int exp, e2; /* exponent of real numbers */ int nsd; /* Number of significant digits returned */ @@ -212,6 +212,13 @@ void sqlite3VXPrintf( PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */ char buf[etBUFSIZE]; /* Conversion buffer */ +#ifdef SQLITE_ENABLE_API_ARMOR + if( ap==0 ){ + (void)SQLITE_MISUSE_BKPT; + sqlite3StrAccumReset(pAccum); + return; + } +#endif bufpt = 0; if( bFlags ){ if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){ @@ -224,9 +231,13 @@ void sqlite3VXPrintf( for(; (c=(*fmt))!=0; ++fmt){ if( c!='%' ){ bufpt = (char *)fmt; - while( (c=(*++fmt))!='%' && c!=0 ){}; +#if HAVE_STRCHRNUL + fmt = strchrnul(fmt, '%'); +#else + do{ fmt++; }while( *fmt && *fmt != '%' ); +#endif sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt)); - if( c==0 ) break; + if( *fmt==0 ) break; } if( (c=(*++fmt))==0 ){ sqlite3StrAccumAppend(pAccum, "%", 1); @@ -314,7 +325,6 @@ void sqlite3VXPrintf( break; } } - zExtra = 0; /* ** At this point, variables are initialized as follows: @@ -605,13 +615,16 @@ void sqlite3VXPrintf( }else{ c = va_arg(ap,int); } - buf[0] = (char)c; - if( precision>=0 ){ - for(idx=1; idx1 ){ + width -= precision-1; + if( width>1 && !flag_leftjustify ){ + sqlite3AppendChar(pAccum, width-1, ' '); + width = 0; + } + sqlite3AppendChar(pAccum, precision-1, c); } + length = 1; + buf[0] = c; bufpt = buf; break; case etSTRING: @@ -712,11 +725,14 @@ void sqlite3VXPrintf( ** the output. */ width -= length; - if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width); + if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); sqlite3StrAccumAppend(pAccum, bufpt, length); - if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width); + if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); - if( zExtra ) sqlite3_free(zExtra); + if( zExtra ){ + sqlite3_free(zExtra); + zExtra = 0; + } }/* End for loop over the format string */ } /* End of function */ @@ -743,6 +759,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ char *zOld = (p->zText==p->zBase ? 0 : p->zText); i64 szNew = p->nChar; szNew += N + 1; + if( szNew+p->nChar<=p->mxAlloc ){ + /* Force exponential buffer size growth as long as it does not overflow, + ** to avoid having to call this routine too often */ + szNew += p->nChar; + } if( szNew > p->mxAlloc ){ sqlite3StrAccumReset(p); setStrAccumError(p, STRACCUM_TOOBIG); @@ -759,6 +780,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ assert( p->zText!=0 || p->nChar==0 ); if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); p->zText = zNew; + p->nAlloc = sqlite3DbMallocSize(p->db, zNew); }else{ sqlite3StrAccumReset(p); setStrAccumError(p, STRACCUM_NOMEM); @@ -769,11 +791,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ } /* -** Append N space characters to the given string buffer. +** Append N copies of character c to the given string buffer. */ -void sqlite3AppendSpace(StrAccum *p, int N){ +void sqlite3AppendChar(StrAccum *p, int N, char c){ if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return; - while( (N--)>0 ) p->zText[p->nChar++] = ' '; + while( (N--)>0 ) p->zText[p->nChar++] = c; } /* @@ -784,7 +806,7 @@ void sqlite3AppendSpace(StrAccum *p, int N){ ** work (enlarging the buffer) using tail recursion, so that the ** sqlite3StrAccumAppend() routine can use fast calling semantics. */ -static void enlargeAndAppend(StrAccum *p, const char *z, int N){ +static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ N = sqlite3StrAccumEnlarge(p, N); if( N>0 ){ memcpy(&p->zText[p->nChar], z, N); @@ -803,11 +825,11 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ assert( p->accError==0 || p->nAlloc==0 ); if( p->nChar+N >= p->nAlloc ){ enlargeAndAppend(p,z,N); - return; + }else{ + assert( p->zText ); + p->nChar += N; + memcpy(&p->zText[p->nChar-N], z, N); } - assert( p->zText ); - memcpy(&p->zText[p->nChar], z, N); - p->nChar += N; } /* @@ -904,7 +926,7 @@ char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){ /* ** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting -** the string and before returnning. This routine is intended to be used +** the string and before returning. This routine is intended to be used ** to modify an existing string. For example: ** ** x = sqlite3MPrintf(db, x, "prefix %s suffix", x); @@ -928,6 +950,13 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){ char *z; char zBase[SQLITE_PRINT_BUF_SIZE]; StrAccum acc; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( zFormat==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif @@ -970,6 +999,13 @@ char *sqlite3_mprintf(const char *zFormat, ...){ char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){ StrAccum acc; if( n<=0 ) return zBuf; +#ifdef SQLITE_ENABLE_API_ARMOR + if( zBuf==0 || zFormat==0 ) { + (void)SQLITE_MISUSE_BKPT; + if( zBuf && n>0 ) zBuf[0] = 0; + return zBuf; + } +#endif sqlite3StrAccumInit(&acc, zBuf, n, 0); acc.useMalloc = 0; sqlite3VXPrintf(&acc, 0, zFormat, ap); @@ -1037,6 +1073,69 @@ void sqlite3DebugPrintf(const char *zFormat, ...){ } #endif +#ifdef SQLITE_DEBUG +/************************************************************************* +** Routines for implementing the "TreeView" display of hierarchical +** data structures for debugging. +** +** The main entry points (coded elsewhere) are: +** sqlite3TreeViewExpr(0, pExpr, 0); +** sqlite3TreeViewExprList(0, pList, 0, 0); +** sqlite3TreeViewSelect(0, pSelect, 0); +** Insert calls to those routines while debugging in order to display +** a diagram of Expr, ExprList, and Select objects. +** +*/ +/* Add a new subitem to the tree. The moreToFollow flag indicates that this +** is not the last item in the tree. */ +TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ + if( p==0 ){ + p = sqlite3_malloc( sizeof(*p) ); + if( p==0 ) return 0; + memset(p, 0, sizeof(*p)); + }else{ + p->iLevel++; + } + assert( moreToFollow==0 || moreToFollow==1 ); + if( p->iLevelbLine) ) p->bLine[p->iLevel] = moreToFollow; + return p; +} +/* Finished with one layer of the tree */ +void sqlite3TreeViewPop(TreeView *p){ + if( p==0 ) return; + p->iLevel--; + if( p->iLevel<0 ) sqlite3_free(p); +} +/* Generate a single line of output for the tree, with a prefix that contains +** all the appropriate tree lines */ +void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ + va_list ap; + int i; + StrAccum acc; + char zBuf[500]; + sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0); + acc.useMalloc = 0; + if( p ){ + for(i=0; iiLevel && ibLine)-1; i++){ + sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4); + } + sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); + } + va_start(ap, zFormat); + sqlite3VXPrintf(&acc, 0, zFormat, ap); + va_end(ap); + if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1); + sqlite3StrAccumFinish(&acc); + fprintf(stdout,"%s", zBuf); + fflush(stdout); +} +/* Shorthand for starting a new tree item that consists of a single label */ +void sqlite3TreeViewItem(TreeView *p, const char *zLabel, u8 moreToFollow){ + p = sqlite3TreeViewPush(p, moreToFollow); + sqlite3TreeViewLine(p, "%s", zLabel); +} +#endif /* SQLITE_DEBUG */ + /* ** variable-argument wrapper around sqlite3VXPrintf(). */ diff --git a/src/random.c b/src/random.c index b825665..179d01b 100644 --- a/src/random.c +++ b/src/random.c @@ -48,11 +48,19 @@ void sqlite3_randomness(int N, void *pBuf){ #endif #if SQLITE_THREADSAFE - sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); - sqlite3_mutex_enter(mutex); + sqlite3_mutex *mutex; #endif - if( N<=0 ){ +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return; +#endif + +#if SQLITE_THREADSAFE + mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); +#endif + + sqlite3_mutex_enter(mutex); + if( N<=0 || pBuf==0 ){ wsdPrng.isInit = 0; sqlite3_mutex_leave(mutex); return; diff --git a/src/resolve.c b/src/resolve.c index 935d311..d4bd548 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -28,7 +28,7 @@ ** is a helper function - a callback for the tree walker. */ static int incrAggDepth(Walker *pWalker, Expr *pExpr){ - if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.i; + if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n; return WRC_Continue; } static void incrAggFunctionDepth(Expr *pExpr, int N){ @@ -36,7 +36,7 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){ Walker w; memset(&w, 0, sizeof(w)); w.xExprCallback = incrAggDepth; - w.u.i = N; + w.u.n = N; sqlite3WalkExpr(&w, pExpr); } } @@ -320,6 +320,10 @@ static int lookupName( if( pMatch ){ pExpr->iTable = pMatch->iCursor; pExpr->pTab = pMatch->pTab; + assert( (pMatch->jointype & JT_RIGHT)==0 ); /* RIGHT JOIN not (yet) supported */ + if( (pMatch->jointype & JT_LEFT)!=0 ){ + ExprSetProperty(pExpr, EP_CanBeNull); + } pSchema = pExpr->pTab->pSchema; } } /* if( pSrcList ) */ @@ -584,7 +588,7 @@ static int exprProbability(Expr *p){ sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8); assert( r>=0.0 ); if( r>1.0 ) return -1; - return (int)(r*1000.0); + return (int)(r*134217728.0); } /* @@ -716,12 +720,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent to ** likelihood(X,0.9375). */ /* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */ - pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938; + pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120; } } - } #ifndef SQLITE_OMIT_AUTHORIZATION - if( pDef ){ auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0); if( auth!=SQLITE_OK ){ if( auth==SQLITE_DENY ){ @@ -732,9 +734,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pExpr->op = TK_NULL; return WRC_Prune; } +#endif if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant); } -#endif if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); pNC->nErr++; @@ -757,7 +759,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pExpr->op2++; pNC2 = pNC2->pNext; } - if( pNC2 ) pNC2->ncFlags |= NC_HasAgg; + assert( pDef!=0 ); + if( pNC2 ){ + assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); + testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); + pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); + + } pNC->ncFlags |= NC_AllowAgg; } /* FIX ME: Compute pExpr->affinity based on the expected return @@ -1118,7 +1126,7 @@ static int resolveOrderGroupBy( } /* -** Resolve names in the SELECT statement p and all of its descendents. +** Resolve names in the SELECT statement p and all of its descendants. */ static int resolveSelectStep(Walker *pWalker, Select *p){ NameContext *pOuterNC; /* Context that contains this SELECT */ @@ -1222,7 +1230,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ assert( (p->selFlags & SF_Aggregate)==0 ); pGroupBy = p->pGroupBy; if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ - p->selFlags |= SF_Aggregate; + assert( NC_MinMaxAgg==SF_MinMaxAgg ); + p->selFlags |= SF_Aggregate | (sNC.ncFlags&NC_MinMaxAgg); }else{ sNC.ncFlags &= ~NC_AllowAgg; } @@ -1350,7 +1359,7 @@ int sqlite3ResolveExprNames( NameContext *pNC, /* Namespace to resolve expressions in. */ Expr *pExpr /* The expression to be analyzed. */ ){ - u8 savedHasAgg; + u16 savedHasAgg; Walker w; if( pExpr==0 ) return 0; @@ -1363,8 +1372,8 @@ int sqlite3ResolveExprNames( pParse->nHeight += pExpr->nHeight; } #endif - savedHasAgg = pNC->ncFlags & NC_HasAgg; - pNC->ncFlags &= ~NC_HasAgg; + savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg); + pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg); memset(&w, 0, sizeof(w)); w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; @@ -1379,9 +1388,8 @@ int sqlite3ResolveExprNames( } if( pNC->ncFlags & NC_HasAgg ){ ExprSetProperty(pExpr, EP_Agg); - }else if( savedHasAgg ){ - pNC->ncFlags |= NC_HasAgg; } + pNC->ncFlags |= savedHasAgg; return ExprHasProperty(pExpr, EP_Error); } diff --git a/src/rowset.c b/src/rowset.c index ba2e056..ff55938 100644 --- a/src/rowset.c +++ b/src/rowset.c @@ -50,7 +50,7 @@ ** No INSERTs may occurs after a SMALLEST. An assertion will fail if ** that is attempted. ** -** The cost of an INSERT is roughly constant. (Sometime new memory +** The cost of an INSERT is roughly constant. (Sometimes new memory ** has to be allocated on an INSERT.) The cost of a TEST with a new ** batch number is O(NlogN) where N is the number of elements in the RowSet. ** The cost of a TEST using the same batch number is O(logN). The cost @@ -443,8 +443,8 @@ int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ ** Check to see if element iRowid was inserted into the rowset as ** part of any insert batch prior to iBatch. Return 1 or 0. ** -** If this is the first test of a new batch and if there exist entires -** on pRowSet->pEntry, then sort those entires into the forest at +** If this is the first test of a new batch and if there exist entries +** on pRowSet->pEntry, then sort those entries into the forest at ** pRowSet->pForest so that they can be tested. */ int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){ diff --git a/src/select.c b/src/select.c index 932874d..39a0550 100644 --- a/src/select.c +++ b/src/select.c @@ -14,6 +14,20 @@ */ #include "sqliteInt.h" +/* +** Trace output macros +*/ +#if SELECTTRACE_ENABLED +/***/ int sqlite3SelectTrace = 0; +# define SELECTTRACE(K,P,S,X) \ + if(sqlite3SelectTrace&(K)) \ + sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",(S)->zSelName,(S)),\ + sqlite3DebugPrintf X +#else +# define SELECTTRACE(K,P,S,X) +#endif + + /* ** An instance of the following object is used to record information about ** how to process the DISTINCT keyword, to simplify passing that information @@ -44,20 +58,25 @@ struct SortCtx { #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* -** Delete all the content of a Select structure but do not deallocate -** the select structure itself. +** Delete all the content of a Select structure. Deallocate the structure +** itself only if bFree is true. */ -static void clearSelect(sqlite3 *db, Select *p){ - sqlite3ExprListDelete(db, p->pEList); - sqlite3SrcListDelete(db, p->pSrc); - sqlite3ExprDelete(db, p->pWhere); - sqlite3ExprListDelete(db, p->pGroupBy); - sqlite3ExprDelete(db, p->pHaving); - sqlite3ExprListDelete(db, p->pOrderBy); - sqlite3SelectDelete(db, p->pPrior); - sqlite3ExprDelete(db, p->pLimit); - sqlite3ExprDelete(db, p->pOffset); - sqlite3WithDelete(db, p->pWith); +static void clearSelect(sqlite3 *db, Select *p, int bFree){ + while( p ){ + Select *pPrior = p->pPrior; + sqlite3ExprListDelete(db, p->pEList); + sqlite3SrcListDelete(db, p->pSrc); + sqlite3ExprDelete(db, p->pWhere); + sqlite3ExprListDelete(db, p->pGroupBy); + sqlite3ExprDelete(db, p->pHaving); + sqlite3ExprListDelete(db, p->pOrderBy); + sqlite3ExprDelete(db, p->pLimit); + sqlite3ExprDelete(db, p->pOffset); + sqlite3WithDelete(db, p->pWith); + if( bFree ) sqlite3DbFree(db, p); + p = pPrior; + bFree = 1; + } } /* @@ -116,8 +135,7 @@ Select *sqlite3SelectNew( pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; if( db->mallocFailed ) { - clearSelect(db, pNew); - if( pNew!=&standin ) sqlite3DbFree(db, pNew); + clearSelect(db, pNew, pNew!=&standin); pNew = 0; }else{ assert( pNew->pSrc!=0 || pParse->nErr>0 ); @@ -126,14 +144,23 @@ Select *sqlite3SelectNew( return pNew; } +#if SELECTTRACE_ENABLED +/* +** Set the name of a Select object +*/ +void sqlite3SelectSetName(Select *p, const char *zName){ + if( p && zName ){ + sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName); + } +} +#endif + + /* ** Delete the given Select structure and all of its substructures. */ void sqlite3SelectDelete(sqlite3 *db, Select *p){ - if( p ){ - clearSelect(db, p); - sqlite3DbFree(db, p); - } + clearSelect(db, p, 1); } /* @@ -455,28 +482,43 @@ static KeyInfo *keyInfoFromExprList( ); /* -** Insert code into "v" that will push the record in register regData -** into the sorter. +** Generate code that will push the record in registers regData +** through regData+nData-1 onto the sorter. */ static void pushOntoSorter( Parse *pParse, /* Parser context */ SortCtx *pSort, /* Information about the ORDER BY clause */ Select *pSelect, /* The whole SELECT statement */ - int regData /* Register holding data to be sorted */ + int regData, /* First register holding data to be sorted */ + int nData, /* Number of elements in the data array */ + int nPrefixReg /* No. of reg prior to regData available for use */ ){ - Vdbe *v = pParse->pVdbe; - int nExpr = pSort->pOrderBy->nExpr; - int regRecord = ++pParse->nMem; - int regBase = pParse->nMem+1; - int nOBSat = pSort->nOBSat; - int op; + Vdbe *v = pParse->pVdbe; /* Stmt under construction */ + int bSeq = ((pSort->sortFlags & SORTFLAG_UseSorter)==0); + int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */ + int nBase = nExpr + bSeq + nData; /* Fields in sorter record */ + int regBase; /* Regs for sorter record */ + int regRecord = ++pParse->nMem; /* Assembled sorter record */ + int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */ + int op; /* Opcode to add sorter record to sorter */ - pParse->nMem += nExpr+2; /* nExpr+2 registers allocated at regBase */ - sqlite3ExprCacheClear(pParse); - sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0); - sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); - sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat,regRecord); + assert( bSeq==0 || bSeq==1 ); + if( nPrefixReg ){ + assert( nPrefixReg==nExpr+bSeq ); + regBase = regData - nExpr - bSeq; + }else{ + regBase = pParse->nMem + 1; + pParse->nMem += nBase; + } + sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, SQLITE_ECEL_DUP); + if( bSeq ){ + sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); + } + if( nPrefixReg==0 ){ + sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData); + } + + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord); if( nOBSat>0 ){ int regPrevKey; /* The first nOBSat columns of the previous row */ int addrFirst; /* Address of the OP_IfNot opcode */ @@ -487,16 +529,23 @@ static void pushOntoSorter( regPrevKey = pParse->nMem+1; pParse->nMem += pSort->nOBSat; - nKey = nExpr - pSort->nOBSat + 1; - addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); VdbeCoverage(v); + nKey = nExpr - pSort->nOBSat + bSeq; + if( bSeq ){ + addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); + }else{ + addrFirst = sqlite3VdbeAddOp1(v, OP_SequenceTest, pSort->iECursor); + } + VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat); pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); if( pParse->db->mallocFailed ) return; - pOp->p2 = nKey + 1; + pOp->p2 = nKey + nData; pKI = pOp->p4.pKeyInfo; memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */ sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); - pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1); + testcase( pKI->nXField>2 ); + pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, + pKI->nXField-1); addrJmp = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); pSort->labelBkOut = sqlite3VdbeMakeLabel(v); @@ -504,7 +553,7 @@ static void pushOntoSorter( sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor); sqlite3VdbeJumpHere(v, addrFirst); - sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat); + sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat); sqlite3VdbeJumpHere(v, addrJmp); } if( pSort->sortFlags & SORTFLAG_UseSorter ){ @@ -626,6 +675,7 @@ static void selectInnerLoop( int eDest = pDest->eDest; /* How to dispose of results */ int iParm = pDest->iSDParm; /* First argument to disposal method */ int nResultCol; /* Number of result columns */ + int nPrefixReg = 0; /* Number of extra registers before regResult */ assert( v ); assert( pEList!=0 ); @@ -641,6 +691,11 @@ static void selectInnerLoop( nResultCol = pEList->nExpr; if( pDest->iSdst==0 ){ + if( pSort ){ + nPrefixReg = pSort->pOrderBy->nExpr; + if( !(pSort->sortFlags & SORTFLAG_UseSorter) ) nPrefixReg++; + pParse->nMem += nPrefixReg; + } pDest->iSdst = pParse->nMem+1; pParse->nMem += nResultCol; }else if( pDest->iSdst+nResultCol > pParse->nMem ){ @@ -757,10 +812,10 @@ static void selectInnerLoop( case SRT_DistFifo: case SRT_Table: case SRT_EphemTab: { - int r1 = sqlite3GetTempReg(pParse); + int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1); testcase( eDest==SRT_Table ); testcase( eDest==SRT_EphemTab ); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg); #ifndef SQLITE_OMIT_CTE if( eDest==SRT_DistFifo ){ /* If the destination is DistFifo, then cursor (iParm+1) is open @@ -775,7 +830,7 @@ static void selectInnerLoop( } #endif if( pSort ){ - pushOntoSorter(pParse, pSort, p, r1); + pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, 1, nPrefixReg); }else{ int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); @@ -783,7 +838,7 @@ static void selectInnerLoop( sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3ReleaseTempReg(pParse, r2); } - sqlite3ReleaseTempReg(pParse, r1); + sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1); break; } @@ -801,7 +856,7 @@ static void selectInnerLoop( ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ - pushOntoSorter(pParse, pSort, p, regResult); + pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg); }else{ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1); @@ -827,9 +882,9 @@ static void selectInnerLoop( case SRT_Mem: { assert( nResultCol==1 ); if( pSort ){ - pushOntoSorter(pParse, pSort, p, regResult); + pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg); }else{ - sqlite3ExprCodeMove(pParse, regResult, iParm, 1); + assert( regResult==iParm ); /* The LIMIT clause will jump out of the loop for us */ } break; @@ -841,10 +896,7 @@ static void selectInnerLoop( testcase( eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); if( pSort ){ - int r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); - pushOntoSorter(pParse, pSort, p, r1); - sqlite3ReleaseTempReg(pParse, r1); + pushOntoSorter(pParse, pSort, p, regResult, nResultCol, nPrefixReg); }else if( eDest==SRT_Coroutine ){ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); }else{ @@ -987,7 +1039,7 @@ int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; } ** then the KeyInfo structure is appropriate for initializing a virtual ** index to implement a DISTINCT test. ** -** Space to hold the KeyInfo structure is obtain from malloc. The calling +** Space to hold the KeyInfo structure is obtained from malloc. The calling ** function is responsible for seeing that this structure is eventually ** freed. */ @@ -1004,7 +1056,7 @@ static KeyInfo *keyInfoFromExprList( int i; nExpr = pList->nExpr; - pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1); + pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1); if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); for(i=iStart, pItem=pList->a+iStart; ipOrderBy; int eDest = pDest->eDest; int iParm = pDest->iSDParm; int regRow; int regRowid; int nKey; + int iSortTab; /* Sorter cursor to read from */ + int nSortData; /* Trailing values to read from sorter */ + int i; + int bSeq; /* True if sorter record includes seq. no. */ +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + struct ExprList_item *aOutEx = p->pEList->a; +#endif if( pSort->labelBkOut ){ sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak); sqlite3VdbeResolveLabel(v, pSort->labelBkOut); - addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); } iTab = pSort->iECursor; - regRow = sqlite3GetTempReg(pParse); if( eDest==SRT_Output || eDest==SRT_Coroutine ){ - pseudoTab = pParse->nTab++; - sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn); regRowid = 0; + regRow = pDest->iSdst; + nSortData = nColumn; }else{ regRowid = sqlite3GetTempReg(pParse); + regRow = sqlite3GetTempReg(pParse); + nSortData = 1; } nKey = pOrderBy->nExpr - pSort->nOBSat; if( pSort->sortFlags & SORTFLAG_UseSorter ){ int regSortOut = ++pParse->nMem; - int ptab2 = pParse->nTab++; - sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, nKey+2); + iSortTab = pParse->nTab++; + if( pSort->labelBkOut ){ + addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); + } + sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData); if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); - sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut); - sqlite3VdbeAddOp3(v, OP_Column, ptab2, nKey+1, regRow); - sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); + sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab); + bSeq = 0; }else{ - if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); - sqlite3VdbeAddOp3(v, OP_Column, iTab, nKey+1, regRow); + iSortTab = iTab; + bSeq = 1; + } + for(i=0; iiSdst+i ); - sqlite3VdbeAddOp3(v, OP_Column, pseudoTab, i, pDest->iSdst+i); - if( i==0 ){ - sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); - } - } if( eDest==SRT_Output ){ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn); sqlite3ExprCacheAffinityChange(pParse, pDest->iSdst, nColumn); @@ -1212,9 +1268,10 @@ static void generateSortTail( break; } } - sqlite3ReleaseTempReg(pParse, regRow); - sqlite3ReleaseTempReg(pParse, regRowid); - + if( regRowid ){ + sqlite3ReleaseTempReg(pParse, regRow); + sqlite3ReleaseTempReg(pParse, regRowid); + } /* The bottom of the loop */ sqlite3VdbeResolveLabel(v, addrContinue); @@ -1509,7 +1566,7 @@ static void generateColumnNames( } /* -** Given a an expression list (which is really the list of expressions +** Given an expression list (which is really the list of expressions ** that form the result set of a SELECT statement) compute appropriate ** column names for a table that would hold the expression list. ** @@ -1582,7 +1639,7 @@ static int selectColumnsFromExprList( } /* Make sure the column name is unique. If the name is not unique, - ** append a integer to the name so that it becomes unique. + ** append an integer to the name so that it becomes unique. */ nName = sqlite3Strlen30(zName); for(j=cnt=0; jselFlags & SF_Values ){ + sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms"); + }else{ + sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s" + " do not have the same number of result columns", selectOpName(p->op)); + } +} + +/* +** Handle the special case of a compound-select that originates from a +** VALUES clause. By handling this as a special case, we avoid deep +** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT +** on a VALUES clause. +** +** Because the Select object originates from a VALUES clause: +** (1) It has no LIMIT or OFFSET +** (2) All terms are UNION ALL +** (3) There is no ORDER BY clause +*/ +static int multiSelectValues( + Parse *pParse, /* Parsing context */ + Select *p, /* The right-most of SELECTs to be coded */ + SelectDest *pDest /* What to do with query results */ +){ + Select *pPrior; + int nExpr = p->pEList->nExpr; + int nRow = 1; + int rc = 0; + assert( p->pNext==0 ); + assert( p->selFlags & SF_AllValues ); + do{ + assert( p->selFlags & SF_Values ); + assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); + assert( p->pLimit==0 ); + assert( p->pOffset==0 ); + if( p->pEList->nExpr!=nExpr ){ + selectWrongNumTermsError(pParse, p); + return 1; + } + if( p->pPrior==0 ) break; + assert( p->pPrior->pNext==p ); + p = p->pPrior; + nRow++; + }while(1); + while( p ){ + pPrior = p->pPrior; + p->pPrior = 0; + rc = sqlite3Select(pParse, p, pDest); + p->pPrior = pPrior; + if( rc ) break; + p->nSelectRow = nRow; + p = p->pNext; + } + return rc; +} /* ** This routine is called to process a compound query form from @@ -2102,17 +2219,19 @@ static int multiSelect( dest.eDest = SRT_Table; } + /* Special handling for a compound-select that originates as a VALUES clause. + */ + if( p->selFlags & SF_AllValues ){ + rc = multiSelectValues(pParse, p, &dest); + goto multi_select_end; + } + /* Make sure all SELECTs in the statement have the same number of elements ** in their result sets. */ assert( p->pEList && pPrior->pEList ); if( p->pEList->nExpr!=pPrior->pEList->nExpr ){ - if( p->selFlags & SF_Values ){ - sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms"); - }else{ - sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s" - " do not have the same number of result columns", selectOpName(p->op)); - } + selectWrongNumTermsError(pParse, p); rc = 1; goto multi_select_end; } @@ -3066,7 +3185,7 @@ static void substSelect( ** ** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5 ** -** The code generated for this simpification gives the same result +** The code generated for this simplification gives the same result ** but only has to scan the data once. And because indices might ** exist on the table t1, a complete scan of the data might be ** avoided. @@ -3099,8 +3218,10 @@ static void substSelect( ** (9) The subquery does not use LIMIT or the outer query does not use ** aggregates. ** -** (10) The subquery does not use aggregates or the outer query does not -** use LIMIT. +** (**) Restriction (10) was removed from the code on 2005-02-05 but we +** accidently carried the comment forward until 2014-09-15. Original +** text: "The subquery does not use aggregates or the outer query does not +** use LIMIT." ** ** (11) The subquery and the outer query do not both have ORDER BY clauses. ** @@ -3163,6 +3284,11 @@ static void substSelect( ** parent to a compound query confuses the code that handles ** recursive queries in multiSelect(). ** +** (24) The subquery is not an aggregate that uses the built-in min() or +** or max() functions. (Without this restriction, a query like: +** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily +** return the value X for which Y was maximal.) +** ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query @@ -3210,7 +3336,7 @@ static int flattenSubquery( pSubSrc = pSub->pSrc; assert( pSubSrc ); /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, - ** not arbitrary expresssions, we allowed some combining of LIMIT and OFFSET + ** not arbitrary expressions, we allowed some combining of LIMIT and OFFSET ** because they could be computed at compile-time. But when LIMIT and OFFSET ** became arbitrary expressions, we were forced to add restrictions (13) ** and (14). */ @@ -3235,8 +3361,14 @@ static int flattenSubquery( if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){ return 0; /* Restriction (21) */ } - if( pSub->selFlags & SF_Recursive ) return 0; /* Restriction (22) */ - if( (p->selFlags & SF_Recursive) && pSub->pPrior ) return 0; /* (23) */ + testcase( pSub->selFlags & SF_Recursive ); + testcase( pSub->selFlags & SF_MinMaxAgg ); + if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){ + return 0; /* Restrictions (22) and (24) */ + } + if( (p->selFlags & SF_Recursive) && pSub->pPrior ){ + return 0; /* Restriction (23) */ + } /* OBSOLETE COMMENT 1: ** Restriction 3: If the subquery is a join, make sure the subquery is @@ -3310,6 +3442,8 @@ static int flattenSubquery( } /***** If we reach this point, flattening is permitted. *****/ + SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n", + pSub->zSelName, pSub, iFrom)); /* Authorize the subquery */ pParse->zAuthContext = pSubitem->zName; @@ -3362,6 +3496,7 @@ static int flattenSubquery( p->pLimit = 0; p->pOffset = 0; pNew = sqlite3SelectDup(db, p, 0); + sqlite3SelectSetName(pNew, pSub->zSelName); p->pOffset = pOffset; p->pLimit = pLimit; p->pOrderBy = pOrderBy; @@ -3374,6 +3509,9 @@ static int flattenSubquery( if( pPrior ) pPrior->pNext = pNew; pNew->pNext = p; p->pPrior = pNew; + SELECTTRACE(2,pParse,p, + ("compound-subquery flattener creates %s.%p as peer\n", + pNew->zSelName, pNew)); } if( db->mallocFailed ) return 1; } @@ -3503,8 +3641,23 @@ static int flattenSubquery( pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList); } if( pSub->pOrderBy ){ + /* At this point, any non-zero iOrderByCol values indicate that the + ** ORDER BY column expression is identical to the iOrderByCol'th + ** expression returned by SELECT statement pSub. Since these values + ** do not necessarily correspond to columns in SELECT statement pParent, + ** zero them before transfering the ORDER BY clause. + ** + ** Not doing this may cause an error if a subsequent call to this + ** function attempts to flatten a compound sub-query into pParent + ** (the only way this can happen is if the compound sub-query is + ** currently part of pSub->pSrc). See ticket [d11a6e908f]. */ + ExprList *pOrderBy = pSub->pOrderBy; + for(i=0; inExpr; i++){ + pOrderBy->a[i].u.x.iOrderByCol = 0; + } assert( pParent->pOrderBy==0 ); - pParent->pOrderBy = pSub->pOrderBy; + assert( pSub->pPrior==0 ); + pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; }else if( pParent->pOrderBy ){ substExprList(db, pParent->pOrderBy, iParent, pSub->pEList); @@ -3550,6 +3703,13 @@ static int flattenSubquery( */ sqlite3SelectDelete(db, pSub1); +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x100 ){ + sqlite3DebugPrintf("After flattening:\n"); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + return 1; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ @@ -3596,7 +3756,7 @@ static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){ /* ** The select statement passed as the first argument is an aggregate query. -** The second argment is the associated aggregate-info object. This +** The second argument is the associated aggregate-info object. This ** function tests if the SELECT is of the form: ** ** SELECT count(*) FROM @@ -3926,10 +4086,10 @@ static void selectPopWith(Walker *pWalker, Select *p){ ** fill pTabList->a[].pSelect with a copy of the SELECT statement ** that implements the view. A copy is made of the view's SELECT ** statement so that we can freely modify or delete that statement -** without worrying about messing up the presistent representation +** without worrying about messing up the persistent representation ** of the view. ** -** (3) Add terms to the WHERE clause to accomodate the NATURAL keyword +** (3) Add terms to the WHERE clause to accommodate the NATURAL keyword ** on joins and the ON and USING clause of joins. ** ** (4) Scan the list of columns in the result set (pEList) looking @@ -3957,7 +4117,9 @@ static int selectExpander(Walker *pWalker, Select *p){ } pTabList = p->pSrc; pEList = p->pEList; - sqlite3WithPush(pParse, findRightmost(p)->pWith, 0); + if( pWalker->xSelectCallback2==selectPopWith ){ + sqlite3WithPush(pParse, findRightmost(p)->pWith, 0); + } /* Make sure cursor numbers have been assigned to all entries in ** the FROM clause of the SELECT statement. @@ -4020,6 +4182,7 @@ static int selectExpander(Walker *pWalker, Select *p){ if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); + sqlite3SelectSetName(pFrom->pSelect, pTab->zName); sqlite3WalkSelect(pWalker, pFrom->pSelect); } #endif @@ -4247,7 +4410,9 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; - w.xSelectCallback2 = selectPopWith; + if( (pSelect->selFlags & SF_AllValues)==0 ){ + w.xSelectCallback2 = selectPopWith; + } sqlite3WalkSelect(&w, pSelect); } @@ -4554,6 +4719,13 @@ int sqlite3Select( } if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; memset(&sAggInfo, 0, sizeof(sAggInfo)); +#if SELECTTRACE_ENABLED + pParse->nSelectIndent++; + SELECTTRACE(1,pParse,p, ("begin processing:\n")); + if( sqlite3SelectTrace & 0x100 ){ + sqlite3TreeViewSelect(0, p, 0); + } +#endif assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); @@ -4710,6 +4882,10 @@ int sqlite3Select( if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); explainSetInteger(pParse->iSelectId, iRestoreSelectId); +#if SELECTTRACE_ENABLED + SELECTTRACE(1,pParse,p,("end compound-select processing\n")); + pParse->nSelectIndent--; +#endif return rc; } #endif @@ -4722,7 +4898,7 @@ int sqlite3Select( ** ** is transformed to: ** - ** SELECT xyz FROM ... GROUP BY xyz + ** SELECT xyz FROM ... GROUP BY xyz ORDER BY xyz ** ** The second form is preferred as a single index (or temp-table) may be ** used for both the ORDER BY and DISTINCT processing. As originally @@ -4735,7 +4911,6 @@ int sqlite3Select( p->selFlags &= ~SF_Distinct; p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); pGroupBy = p->pGroupBy; - sSort.pOrderBy = 0; /* Notice that even thought SF_Distinct has been cleared from p->selFlags, ** the sDistinct.isTnct is still set. Hence, isTnct represents the ** original setting of the SF_Distinct flag, not the current setting */ @@ -4751,12 +4926,13 @@ int sqlite3Select( */ if( sSort.pOrderBy ){ KeyInfo *pKeyInfo; - pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0); + pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr); sSort.iECursor = pParse->nTab++; sSort.addrSortIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, - sSort.iECursor, sSort.pOrderBy->nExpr+2, 0, - (char*)pKeyInfo, P4_KEYINFO); + sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0, + (char*)pKeyInfo, P4_KEYINFO + ); }else{ sSort.addrSortIndex = -1; } @@ -4887,7 +5063,7 @@ int sqlite3Select( sNC.pSrcList = pTabList; sNC.pAggInfo = &sAggInfo; sAggInfo.mnReg = pParse->nMem+1; - sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0; + sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0; sAggInfo.pGroupBy = pGroupBy; sqlite3ExprAnalyzeAggList(&sNC, pEList); sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy); @@ -4924,7 +5100,7 @@ int sqlite3Select( ** will be converted into a Noop. */ sAggInfo.sortingIdx = pParse->nTab++; - pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0); + pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn); addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, sAggInfo.sortingIdx, sAggInfo.nSortingColumn, 0, (char*)pKeyInfo, P4_KEYINFO); @@ -4980,8 +5156,8 @@ int sqlite3Select( groupBySort = 1; nGroupBy = pGroupBy->nExpr; - nCol = nGroupBy + 1; - j = nGroupBy+1; + nCol = nGroupBy; + j = nGroupBy; for(i=0; i=j ){ nCol++; @@ -4991,8 +5167,7 @@ int sqlite3Select( regBase = sqlite3GetTempRange(pParse, nCol); sqlite3ExprCacheClear(pParse); sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0); - sqlite3VdbeAddOp2(v, OP_Sequence, sAggInfo.sortingIdx,regBase+nGroupBy); - j = nGroupBy+1; + j = nGroupBy; for(i=0; iiSorterColumn>=j ){ @@ -5045,12 +5220,11 @@ int sqlite3Select( addrTopOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3ExprCacheClear(pParse); if( groupBySort ){ - sqlite3VdbeAddOp2(v, OP_SorterData, sAggInfo.sortingIdx, sortOut); + sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, sortOut,sortPTab); } for(j=0; jnExpr; j++){ if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j); - if( j==0 ) sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); }else{ sAggInfo.directMode = 1; sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j); @@ -5309,100 +5483,103 @@ select_end: sqlite3DbFree(db, sAggInfo.aCol); sqlite3DbFree(db, sAggInfo.aFunc); +#if SELECTTRACE_ENABLED + SELECTTRACE(1,pParse,p,("end processing\n")); + pParse->nSelectIndent--; +#endif return rc; } -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) +#ifdef SQLITE_DEBUG /* ** Generate a human-readable description of a the Select object. */ -static void explainOneSelect(Vdbe *pVdbe, Select *p){ - sqlite3ExplainPrintf(pVdbe, "SELECT "); - if( p->selFlags & (SF_Distinct|SF_Aggregate) ){ - if( p->selFlags & SF_Distinct ){ - sqlite3ExplainPrintf(pVdbe, "DISTINCT "); - } - if( p->selFlags & SF_Aggregate ){ - sqlite3ExplainPrintf(pVdbe, "agg_flag "); - } - sqlite3ExplainNL(pVdbe); - sqlite3ExplainPrintf(pVdbe, " "); - } - sqlite3ExplainExprList(pVdbe, p->pEList); - sqlite3ExplainNL(pVdbe); +void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ + int n = 0; + pView = sqlite3TreeViewPush(pView, moreToFollow); + sqlite3TreeViewLine(pView, "SELECT%s%s", + ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), + ((p->selFlags & SF_Aggregate) ? " agg_flag" : "") + ); + if( p->pSrc && p->pSrc->nSrc ) n++; + if( p->pWhere ) n++; + if( p->pGroupBy ) n++; + if( p->pHaving ) n++; + if( p->pOrderBy ) n++; + if( p->pLimit ) n++; + if( p->pOffset ) n++; + if( p->pPrior ) n++; + sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set"); if( p->pSrc && p->pSrc->nSrc ){ int i; - sqlite3ExplainPrintf(pVdbe, "FROM "); - sqlite3ExplainPush(pVdbe); + pView = sqlite3TreeViewPush(pView, (n--)>0); + sqlite3TreeViewLine(pView, "FROM"); for(i=0; ipSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; - sqlite3ExplainPrintf(pVdbe, "{%d,*} = ", pItem->iCursor); - if( pItem->pSelect ){ - sqlite3ExplainSelect(pVdbe, pItem->pSelect); - if( pItem->pTab ){ - sqlite3ExplainPrintf(pVdbe, " (tabname=%s)", pItem->pTab->zName); - } + StrAccum x; + char zLine[100]; + sqlite3StrAccumInit(&x, zLine, sizeof(zLine), 0); + sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor); + if( pItem->zDatabase ){ + sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName); }else if( pItem->zName ){ - sqlite3ExplainPrintf(pVdbe, "%s", pItem->zName); + sqlite3XPrintf(&x, 0, " %s", pItem->zName); + } + if( pItem->pTab ){ + sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName); } if( pItem->zAlias ){ - sqlite3ExplainPrintf(pVdbe, " (AS %s)", pItem->zAlias); + sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias); } if( pItem->jointype & JT_LEFT ){ - sqlite3ExplainPrintf(pVdbe, " LEFT-JOIN"); + sqlite3XPrintf(&x, 0, " LEFT-JOIN"); } - sqlite3ExplainNL(pVdbe); + sqlite3StrAccumFinish(&x); + sqlite3TreeViewItem(pView, zLine, ipSrc->nSrc-1); + if( pItem->pSelect ){ + sqlite3TreeViewSelect(pView, pItem->pSelect, 0); + } + sqlite3TreeViewPop(pView); } - sqlite3ExplainPop(pVdbe); + sqlite3TreeViewPop(pView); } if( p->pWhere ){ - sqlite3ExplainPrintf(pVdbe, "WHERE "); - sqlite3ExplainExpr(pVdbe, p->pWhere); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "WHERE", (n--)>0); + sqlite3TreeViewExpr(pView, p->pWhere, 0); + sqlite3TreeViewPop(pView); } if( p->pGroupBy ){ - sqlite3ExplainPrintf(pVdbe, "GROUPBY "); - sqlite3ExplainExprList(pVdbe, p->pGroupBy); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY"); } if( p->pHaving ){ - sqlite3ExplainPrintf(pVdbe, "HAVING "); - sqlite3ExplainExpr(pVdbe, p->pHaving); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "HAVING", (n--)>0); + sqlite3TreeViewExpr(pView, p->pHaving, 0); + sqlite3TreeViewPop(pView); } if( p->pOrderBy ){ - sqlite3ExplainPrintf(pVdbe, "ORDERBY "); - sqlite3ExplainExprList(pVdbe, p->pOrderBy); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); } if( p->pLimit ){ - sqlite3ExplainPrintf(pVdbe, "LIMIT "); - sqlite3ExplainExpr(pVdbe, p->pLimit); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); + sqlite3TreeViewExpr(pView, p->pLimit, 0); + sqlite3TreeViewPop(pView); } if( p->pOffset ){ - sqlite3ExplainPrintf(pVdbe, "OFFSET "); - sqlite3ExplainExpr(pVdbe, p->pOffset); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); + sqlite3TreeViewExpr(pView, p->pOffset, 0); + sqlite3TreeViewPop(pView); } + if( p->pPrior ){ + const char *zOp = "UNION"; + switch( p->op ){ + case TK_ALL: zOp = "UNION ALL"; break; + case TK_INTERSECT: zOp = "INTERSECT"; break; + case TK_EXCEPT: zOp = "EXCEPT"; break; + } + sqlite3TreeViewItem(pView, zOp, (n--)>0); + sqlite3TreeViewSelect(pView, p->pPrior, 0); + sqlite3TreeViewPop(pView); + } + sqlite3TreeViewPop(pView); } -void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){ - if( p==0 ){ - sqlite3ExplainPrintf(pVdbe, "(null-select)"); - return; - } - sqlite3ExplainPush(pVdbe); - while( p ){ - explainOneSelect(pVdbe, p); - p = p->pNext; - if( p==0 ) break; - sqlite3ExplainNL(pVdbe); - sqlite3ExplainPrintf(pVdbe, "%s\n", selectOpName(p->op)); - } - sqlite3ExplainPrintf(pVdbe, "END"); - sqlite3ExplainPop(pVdbe); -} - -/* End of the structure debug printing code -*****************************************************************************/ -#endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */ +#endif /* SQLITE_DEBUG */ diff --git a/src/shell.c b/src/shell.c index a74dcdb..02c27f4 100644 --- a/src/shell.c +++ b/src/shell.c @@ -17,6 +17,13 @@ #define _CRT_SECURE_NO_WARNINGS #endif +/* +** If requested, include the SQLite compiler options file for MSVC. +*/ +#if defined(INCLUDE_MSVC_H) +#include "msvc.h" +#endif + /* ** Enable large-file support for fopen() and friends on unix. */ @@ -33,6 +40,9 @@ #include #include #include "sqlite3.h" +#if SQLITE_USER_AUTHENTICATION +# include "sqlite3userauth.h" +#endif #include #include @@ -45,23 +55,42 @@ # include #endif -#if defined(HAVE_READLINE) && HAVE_READLINE!=0 +#if HAVE_READLINE # include # include -#else -# undef HAVE_READLINE #endif -#if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE) -# define HAVE_READLINE 1 + +#if HAVE_EDITLINE # include #endif -#if !defined(HAVE_READLINE) -# define add_history(X) -# define read_history(X) -# define write_history(X) -# define stifle_history(X) + +#if HAVE_EDITLINE || HAVE_READLINE + +# define shell_add_history(X) add_history(X) +# define shell_read_history(X) read_history(X) +# define shell_write_history(X) write_history(X) +# define shell_stifle_history(X) stifle_history(X) +# define shell_readline(X) readline(X) + +#elif HAVE_LINENOISE + +# include "linenoise.h" +# define shell_add_history(X) linenoiseHistoryAdd(X) +# define shell_read_history(X) linenoiseHistoryLoad(X) +# define shell_write_history(X) linenoiseHistorySave(X) +# define shell_stifle_history(X) linenoiseHistorySetMaxLen(X) +# define shell_readline(X) linenoise(X) + +#else + +# define shell_read_history(X) +# define shell_write_history(X) +# define shell_stifle_history(X) + +# define SHELL_USE_LOCAL_GETLINE 1 #endif + #if defined(_WIN32) || defined(WIN32) # include # include @@ -169,7 +198,8 @@ static HANDLE hProcess; static FILETIME ftKernelBegin; static FILETIME ftUserBegin; static sqlite3_int64 ftWallBegin; -typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); +typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, + LPFILETIME, LPFILETIME); static GETPROCTIMES getProcessTimesAddr = NULL; /* @@ -180,15 +210,16 @@ static int hasTimer(void){ if( getProcessTimesAddr ){ return 1; } else { - /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions. - ** See if the version we are running on has it, and if it does, save off - ** a pointer to it and the current process handle. + /* GetProcessTimes() isn't supported in WIN95 and some other Windows + ** versions. See if the version we are running on has it, and if it + ** does, save off a pointer to it and the current process handle. */ hProcess = GetCurrentProcess(); if( hProcess ){ HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); if( NULL != hinstLib ){ - getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); + getProcessTimesAddr = + (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); if( NULL != getProcessTimesAddr ){ return 1; } @@ -205,7 +236,8 @@ static int hasTimer(void){ static void beginTimer(void){ if( enableTimer && getProcessTimesAddr ){ FILETIME ftCreation, ftExit; - getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin); + getProcessTimesAddr(hProcess,&ftCreation,&ftExit, + &ftKernelBegin,&ftUserBegin); ftWallBegin = timeOfDay(); } } @@ -224,7 +256,7 @@ static void endTimer(void){ if( enableTimer && getProcessTimesAddr){ FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; sqlite3_int64 ftWallEnd = timeOfDay(); - getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd); + getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd); printf("Run Time: real %.3f user %f sys %f\n", (ftWallEnd - ftWallBegin)*0.001, timeDiff(&ftUserBegin, &ftUserEnd), @@ -419,36 +451,42 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ zResult = local_getline(zPrior, in); }else{ zPrompt = isContinuation ? continuePrompt : mainPrompt; -#if defined(HAVE_READLINE) - free(zPrior); - zResult = readline(zPrompt); - if( zResult && *zResult ) add_history(zResult); -#else +#if SHELL_USE_LOCAL_GETLINE printf("%s", zPrompt); fflush(stdout); zResult = local_getline(zPrior, stdin); +#else + free(zPrior); + zResult = shell_readline(zPrompt); + if( zResult && *zResult ) shell_add_history(zResult); #endif } return zResult; } -struct previous_mode_data { - int valid; /* Is there legit data in here? */ - int mode; - int showHeader; - int colWidth[100]; +/* +** Shell output mode information from before ".explain on", +** saved so that it can be restored by ".explain off" +*/ +typedef struct SavedModeInfo SavedModeInfo; +struct SavedModeInfo { + int valid; /* Is there legit data in here? */ + int mode; /* Mode prior to ".explain on" */ + int showHeader; /* The ".header" setting prior to ".explain on" */ + int colWidth[100]; /* Column widths prior to ".explain on" */ }; /* -** An pointer to an instance of this structure is passed from -** the main program to the callback. This is used to communicate -** state and mode information. +** State information about the database connection is contained in an +** instance of the following structure. */ -struct callback_data { +typedef struct ShellState ShellState; +struct ShellState { sqlite3 *db; /* The database */ int echoOn; /* True to echo input commands */ int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ int statsOn; /* True to display memory stats before each finalize */ + int scanstatsOn; /* True to display scan stats before each finalize */ int outCount; /* Revert to stdout when reaching zero */ int cnt; /* Number of records displayed so far */ FILE *out; /* Write results here */ @@ -457,16 +495,15 @@ struct callback_data { int mode; /* An output mode setting */ int writableSchema; /* True if PRAGMA writable_schema=ON */ int showHeader; /* True to show column names in List or Column mode */ + unsigned shellFlgs; /* Various flags */ char *zDestTable; /* Name of destination table when MODE_Insert */ - char separator[20]; /* Separator character for MODE_List */ - char newline[20]; /* Record separator in MODE_Csv */ + char colSeparator[20]; /* Column separator character for several modes */ + char rowSeparator[20]; /* Row separator character for MODE_Ascii */ int colWidth[100]; /* Requested width of each column when in column mode*/ int actualWidth[100]; /* Actual width of each column */ - char nullvalue[20]; /* The text to print when a NULL comes back from + char nullValue[20]; /* The text to print when a NULL comes back from ** the database */ - struct previous_mode_data explainPrev; - /* Holds the mode information just before - ** .explain ON */ + SavedModeInfo normalMode;/* Holds the mode just before .explain ON */ char outfile[FILENAME_MAX]; /* Filename for *out */ const char *zDbFilename; /* name of the database file */ char *zFreeOnClose; /* Filename to free when closing */ @@ -478,6 +515,13 @@ struct callback_data { int iIndent; /* Index of current op in aiIndent[] */ }; +/* +** These are the allowed shellFlgs values +*/ +#define SHFLG_Scratch 0x00001 /* The --scratch option is used */ +#define SHFLG_Pagecache 0x00002 /* The --pagecache option is used */ +#define SHFLG_Lookaside 0x00004 /* Lookaside memory is used */ + /* ** These are the allowed modes. */ @@ -490,6 +534,7 @@ struct callback_data { #define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */ #define MODE_Csv 7 /* Quote strings, numbers are plain */ #define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */ +#define MODE_Ascii 9 /* Use ASCII unit and record separators (0x1F/0x1E) */ static const char *modeDescr[] = { "line", @@ -501,8 +546,22 @@ static const char *modeDescr[] = { "tcl", "csv", "explain", + "ascii", }; +/* +** These are the column/row/line separators used by the various +** import/export modes. +*/ +#define SEP_Column "|" +#define SEP_Row "\n" +#define SEP_Tab "\t" +#define SEP_Space " " +#define SEP_Comma "," +#define SEP_CrLf "\r\n" +#define SEP_Unit "\x1F" +#define SEP_Record "\x1E" + /* ** Number of elements in an array */ @@ -522,7 +581,7 @@ static int strlen30(const char *z){ ** A callback for the sqlite3_log() interface. */ static void shellLog(void *pArg, int iErrCode, const char *zMsg){ - struct callback_data *p = (struct callback_data*)pArg; + ShellState *p = (ShellState*)pArg; if( p->pLog==0 ) return; fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg); fflush(p->pLog); @@ -659,22 +718,22 @@ static const char needCsvQuote[] = { }; /* -** Output a single term of CSV. Actually, p->separator is used for -** the separator, which may or may not be a comma. p->nullvalue is +** Output a single term of CSV. Actually, p->colSeparator is used for +** the separator, which may or may not be a comma. p->nullValue is ** the null value. Strings are quoted if necessary. The separator ** is only issued if bSep is true. */ -static void output_csv(struct callback_data *p, const char *z, int bSep){ +static void output_csv(ShellState *p, const char *z, int bSep){ FILE *out = p->out; if( z==0 ){ - fprintf(out,"%s",p->nullvalue); + fprintf(out,"%s",p->nullValue); }else{ int i; - int nSep = strlen30(p->separator); + int nSep = strlen30(p->colSeparator); for(i=0; z[i]; i++){ if( needCsvQuote[((unsigned char*)z)[i]] - || (z[i]==p->separator[0] && - (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){ + || (z[i]==p->colSeparator[0] && + (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){ i = 0; break; } @@ -691,7 +750,7 @@ static void output_csv(struct callback_data *p, const char *z, int bSep){ } } if( bSep ){ - fprintf(p->out, "%s", p->separator); + fprintf(p->out, "%s", p->colSeparator); } } @@ -711,9 +770,15 @@ static void interrupt_handler(int NotUsed){ ** This is the callback routine that the shell ** invokes for each row of a query result. */ -static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){ +static int shell_callback( + void *pArg, + int nArg, /* Number of result columns */ + char **azArg, /* Text of each result column */ + char **azCol, /* Column names */ + int *aiType /* Column types */ +){ int i; - struct callback_data *p = (struct callback_data*)pArg; + ShellState *p = (ShellState*)pArg; switch( p->mode ){ case MODE_Line: { @@ -723,10 +788,10 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int int len = strlen30(azCol[i] ? azCol[i] : ""); if( len>w ) w = len; } - if( p->cnt++>0 ) fprintf(p->out,"\n"); + if( p->cnt++>0 ) fprintf(p->out, "%s", p->rowSeparator); for(i=0; iout,"%*s = %s\n", w, azCol[i], - azArg[i] ? azArg[i] : p->nullvalue); + fprintf(p->out,"%*s = %s%s", w, azCol[i], + azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator); } break; } @@ -743,7 +808,7 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int if( w==0 ){ w = strlen30(azCol[i] ? azCol[i] : ""); if( w<10 ) w = 10; - n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue); + n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullValue); if( wactualWidth) ){ @@ -751,9 +816,11 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int } if( p->showHeader ){ if( w<0 ){ - fprintf(p->out,"%*.*s%s",-w,-w,azCol[i], i==nArg-1 ? "\n": " "); + fprintf(p->out,"%*.*s%s",-w,-w,azCol[i], + i==nArg-1 ? p->rowSeparator : " "); }else{ - fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " "); + fprintf(p->out,"%-*.*s%s",w,w,azCol[i], + i==nArg-1 ? p->rowSeparator : " "); } } } @@ -768,7 +835,7 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int } fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------" "----------------------------------------------------------", - i==nArg-1 ? "\n": " "); + i==nArg-1 ? p->rowSeparator : " "); } } } @@ -791,10 +858,12 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int } if( w<0 ){ fprintf(p->out,"%*.*s%s",-w,-w, - azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); + azArg[i] ? azArg[i] : p->nullValue, + i==nArg-1 ? p->rowSeparator : " "); }else{ fprintf(p->out,"%-*.*s%s",w,w, - azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); + azArg[i] ? azArg[i] : p->nullValue, + i==nArg-1 ? p->rowSeparator : " "); } } break; @@ -803,20 +872,21 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int case MODE_List: { if( p->cnt++==0 && p->showHeader ){ for(i=0; iout,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator); + fprintf(p->out,"%s%s",azCol[i], + i==nArg-1 ? p->rowSeparator : p->colSeparator); } } if( azArg==0 ) break; for(i=0; inullvalue; + if( z==0 ) z = p->nullValue; fprintf(p->out, "%s", z); if( iout, "%s", p->separator); + fprintf(p->out, "%s", p->colSeparator); }else if( p->mode==MODE_Semi ){ - fprintf(p->out, ";\n"); + fprintf(p->out, ";%s", p->rowSeparator); }else{ - fprintf(p->out, "\n"); + fprintf(p->out, "%s", p->rowSeparator); } } break; @@ -835,7 +905,7 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int fprintf(p->out,""); for(i=0; iout,"\n"); } fprintf(p->out,"\n"); @@ -845,16 +915,16 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int if( p->cnt++==0 && p->showHeader ){ for(i=0; iout,azCol[i] ? azCol[i] : ""); - if(iout, "%s", p->separator); + if(iout, "%s", p->colSeparator); } - fprintf(p->out,"\n"); + fprintf(p->out, "%s", p->rowSeparator); } if( azArg==0 ) break; for(i=0; iout, azArg[i] ? azArg[i] : p->nullvalue); - if(iout, "%s", p->separator); + output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue); + if(iout, "%s", p->colSeparator); } - fprintf(p->out,"\n"); + fprintf(p->out, "%s", p->rowSeparator); break; } case MODE_Csv: { @@ -866,13 +936,13 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int for(i=0; iout,"%s",p->newline); + fprintf(p->out, "%s", p->rowSeparator); } - if( azArg>0 ){ + if( nArg>0 ){ for(i=0; iout,"%s",p->newline); + fprintf(p->out, "%s", p->rowSeparator); } #if defined(WIN32) || defined(_WIN32) fflush(p->out); @@ -909,6 +979,22 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int fprintf(p->out,");\n"); break; } + case MODE_Ascii: { + if( p->cnt++==0 && p->showHeader ){ + for(i=0; i0 ) fprintf(p->out, "%s", p->colSeparator); + fprintf(p->out,"%s",azCol[i] ? azCol[i] : ""); + } + fprintf(p->out, "%s", p->rowSeparator); + } + if( azArg==0 ) break; + for(i=0; i0 ) fprintf(p->out, "%s", p->colSeparator); + fprintf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue); + } + fprintf(p->out, "%s", p->rowSeparator); + break; + } } return 0; } @@ -923,11 +1009,11 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ } /* -** Set the destination table field of the callback_data structure to +** Set the destination table field of the ShellState structure to ** the name of the table given. Escape any quote characters in the ** table name. */ -static void set_table_name(struct callback_data *p, const char *zName){ +static void set_table_name(ShellState *p, const char *zName){ int i, n; int needQuote; char *z; @@ -1017,7 +1103,7 @@ static char *appendText(char *zIn, char const *zAppend, char quote){ ** won't consume the semicolon terminator. */ static int run_table_dump_query( - struct callback_data *p, /* Query context */ + ShellState *p, /* Query context */ const char *zSelect, /* SELECT statement to extract content */ const char *zFirstRow /* Print before first row, if not NULL */ ){ @@ -1080,7 +1166,7 @@ static char *save_err_msg( */ static int display_stats( sqlite3 *db, /* Database to query */ - struct callback_data *pArg, /* Pointer to struct callback_data */ + ShellState *pArg, /* Pointer to ShellState */ int bReset /* True to reset the stats */ ){ int iCur; @@ -1090,57 +1176,77 @@ static int display_stats( iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Memory Used: %d (max %d) bytes\n", iCur, iHiwtr); + fprintf(pArg->out, + "Memory Used: %d (max %d) bytes\n", + iCur, iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr); -/* -** Not currently used by the CLI. -** iHiwtr = iCur = -1; -** sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset); -** fprintf(pArg->out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr); -*/ + fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", + iCur, iHiwtr); + if( pArg->shellFlgs & SHFLG_Pagecache ){ + iHiwtr = iCur = -1; + sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset); + fprintf(pArg->out, + "Number of Pcache Pages Used: %d (max %d) pages\n", + iCur, iHiwtr); + } iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); -/* -** Not currently used by the CLI. -** iHiwtr = iCur = -1; -** sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset); -** fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr); -*/ + fprintf(pArg->out, + "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", + iCur, iHiwtr); + if( pArg->shellFlgs & SHFLG_Scratch ){ + iHiwtr = iCur = -1; + sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset); + fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", + iCur, iHiwtr); + } iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); + fprintf(pArg->out, + "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", + iCur, iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Largest Allocation: %d bytes\n", iHiwtr); + fprintf(pArg->out, "Largest Allocation: %d bytes\n", + iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n", iHiwtr); + fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n", + iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n", iHiwtr); + fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n", + iHiwtr); #ifdef YYTRACKMAXSTACKDEPTH iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", iCur, iHiwtr); + fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", + iCur, iHiwtr); #endif } if( pArg && pArg->out && db ){ - iHiwtr = iCur = -1; - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Successful lookaside attempts: %d\n", iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Lookaside failures due to size: %d\n", iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Lookaside failures due to OOM: %d\n", iHiwtr); + if( pArg->shellFlgs & SHFLG_Lookaside ){ + iHiwtr = iCur = -1; + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, + &iCur, &iHiwtr, bReset); + fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", + iCur, iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, + &iCur, &iHiwtr, bReset); + fprintf(pArg->out, "Successful lookaside attempts: %d\n", iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, + &iCur, &iHiwtr, bReset); + fprintf(pArg->out, "Lookaside failures due to size: %d\n", iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, + &iCur, &iHiwtr, bReset); + fprintf(pArg->out, "Lookaside failures due to OOM: %d\n", iHiwtr); + } iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1; + fprintf(pArg->out, "Pager Heap Usage: %d bytes\n",iCur); + iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); fprintf(pArg->out, "Page cache hits: %d\n", iCur); iHiwtr = iCur = -1; @@ -1151,18 +1257,19 @@ static int display_stats( fprintf(pArg->out, "Page cache writes: %d\n", iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur); + fprintf(pArg->out, "Schema Heap Usage: %d bytes\n",iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur); + fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n",iCur); } if( pArg && pArg->out && db && pArg->pStmt ){ - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, + bReset); fprintf(pArg->out, "Fullscan Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); fprintf(pArg->out, "Sort Operations: %d\n", iCur); - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset); fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); fprintf(pArg->out, "Virtual Machine Steps: %d\n", iCur); @@ -1171,6 +1278,51 @@ static int display_stats( return 0; } +/* +** Display scan stats. +*/ +static void display_scanstats( + sqlite3 *db, /* Database to query */ + ShellState *pArg /* Pointer to ShellState */ +){ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + int i, k, n, mx; + fprintf(pArg->out, "-------- scanstats --------\n"); + mx = 0; + for(k=0; k<=mx; k++){ + double rEstLoop = 1.0; + for(i=n=0; 1; i++){ + sqlite3_stmt *p = pArg->pStmt; + sqlite3_int64 nLoop, nVisit; + double rEst; + int iSid; + const char *zExplain; + if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ + break; + } + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid); + if( iSid>mx ) mx = iSid; + if( iSid!=k ) continue; + if( n==0 ){ + rEstLoop = (double)nLoop; + if( k>0 ) fprintf(pArg->out, "-------- subquery %d -------\n", k); + } + n++; + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); + fprintf(pArg->out, "Loop %2d: %s\n", n, zExplain); + rEstLoop *= rEst; + fprintf(pArg->out, + " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", + nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst + ); + } + } + fprintf(pArg->out, "---------------------------\n"); +#endif +} + /* ** Parameter azArray points to a zero-terminated array of strings. zStr ** points to a single nul-terminated string. Return non-zero if zStr @@ -1187,7 +1339,7 @@ static int str_in_array(const char *zStr, const char **azArray){ /* ** If compiled statement pSql appears to be an EXPLAIN statement, allocate -** and populate the callback_data.aiIndent[] array with the number of +** and populate the ShellState.aiIndent[] array with the number of ** spaces each opcode should be indented before it is output. ** ** The indenting rules are: @@ -1203,7 +1355,7 @@ static int str_in_array(const char *zStr, const char **azArray){ ** then indent all opcodes between the earlier instruction ** and "Goto" by 2 spaces. */ -static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){ +static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){ const char *zSql; /* The text of the SQL statement */ const char *z; /* Used to check if this is an EXPLAIN */ int *abYield = 0; /* True if op is an OP_Yield */ @@ -1212,7 +1364,8 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){ const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", "NextIfOpen", "PrevIfOpen", 0 }; - const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", "Rewind", 0 }; + const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", + "Rewind", 0 }; const char *azGoto[] = { "Goto", 0 }; /* Try to figure out if this is really an EXPLAIN statement. If this @@ -1263,7 +1416,7 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){ /* ** Free the array allocated by explain_data_prepare(). */ -static void explain_data_delete(struct callback_data *p){ +static void explain_data_delete(ShellState *p){ sqlite3_free(p->aiIndent); p->aiIndent = 0; p->nIndent = 0; @@ -1280,12 +1433,12 @@ static void explain_data_delete(struct callback_data *p){ ** and callback data argument. */ static int shell_exec( - sqlite3 *db, /* An open database */ - const char *zSql, /* SQL to be evaluated */ + sqlite3 *db, /* An open database */ + const char *zSql, /* SQL to be evaluated */ int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */ - /* (not the same as sqlite3_exec) */ - struct callback_data *pArg, /* Pointer to struct callback_data */ - char **pzErrMsg /* Error msg written here */ + /* (not the same as sqlite3_exec) */ + ShellState *pArg, /* Pointer to ShellState */ + char **pzErrMsg /* Error msg written here */ ){ sqlite3_stmt *pStmt = NULL; /* Statement to execute. */ int rc = SQLITE_OK; /* Return Code */ @@ -1325,7 +1478,8 @@ static int shell_exec( /* Show the EXPLAIN QUERY PLAN if .eqp is on */ if( pArg && pArg->autoEQP ){ sqlite3_stmt *pExplain; - char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", sqlite3_sql(pStmt)); + char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", + sqlite3_sql(pStmt)); rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); if( rc==SQLITE_OK ){ while( sqlite3_step(pExplain)==SQLITE_ROW ){ @@ -1339,15 +1493,6 @@ static int shell_exec( sqlite3_free(zEQP); } - /* Output TESTCTRL_EXPLAIN text of requested */ - if( pArg && pArg->mode==MODE_Explain ){ - const char *zExplain = 0; - sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain); - if( zExplain && zExplain[0] ){ - fprintf(pArg->out, "%s", zExplain); - } - } - /* If the shell is currently in ".explain" mode, gather the extra ** data required to add indents to the output.*/ if( pArg && pArg->mode==MODE_Explain ){ @@ -1418,6 +1563,11 @@ static int shell_exec( display_stats(db, pArg, 0); } + /* print loop-counters if required */ + if( pArg && pArg->scanstatsOn ){ + display_scanstats(db, pArg); + } + /* Finalize the statement just executed. If this fails, save a ** copy of the error message. Otherwise, set zSql to point to the ** next statement to execute. */ @@ -1453,7 +1603,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){ const char *zType; const char *zSql; const char *zPrepStmt = 0; - struct callback_data *p = (struct callback_data *)pArg; + ShellState *p = (ShellState *)pArg; UNUSED_PARAMETER(azCol); if( nArg!=3 ) return 1; @@ -1549,7 +1699,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){ ** "ORDER BY rowid DESC" to the end. */ static int run_schema_dump_query( - struct callback_data *p, + ShellState *p, const char *zQuery ){ int rc; @@ -1610,12 +1760,13 @@ static char zHelp[] = #endif ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n" ".mode MODE ?TABLE? Set output mode where MODE is one of:\n" + " ascii Columns/rows delimited by 0x1F and 0x1E\n" " csv Comma-separated values\n" " column Left-aligned columns. (See .width)\n" " html HTML
    "); - output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue); + output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue); fprintf(p->out,"
    code\n" " insert SQL insert statements for TABLE\n" " line One value per line\n" - " list Values delimited by .separator string\n" + " list Values delimited by .separator strings\n" " tabs Tab-separated values\n" " tcl TCL list elements\n" ".nullvalue STRING Use STRING in place of NULL values\n" @@ -1628,11 +1779,12 @@ static char zHelp[] = ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" ".save FILE Write in-memory database into FILE\n" + ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n" ".schema ?TABLE? Show the CREATE statements\n" " If TABLE specified, only show tables matching\n" " LIKE pattern TABLE.\n" - ".separator STRING ?NL? Change separator used by output mode and .import\n" - " NL is the end-of-line mark for CSV\n" + ".separator COL ?ROW? Change the column separator and optionally the row\n" + " separator for both the output mode and .import\n" ".shell CMD ARGS... Run CMD ARGS... in a system shell\n" ".show Show the current values for various settings\n" ".stats on|off Turn stats on or off\n" @@ -1649,7 +1801,7 @@ static char zHelp[] = ; /* Forward reference */ -static int process_input(struct callback_data *p, FILE *in); +static int process_input(ShellState *p, FILE *in); /* ** Implementation of the "readfile(X)" SQL function. The entire content ** of the file named X is read and returned as a BLOB. NULL is returned @@ -1715,7 +1867,7 @@ static void writefileFunc( ** Make sure the database is open. If it is not, then open it. If ** the database fails to open, print an error message and exit. */ -static void open_db(struct callback_data *p, int keepAlive){ +static void open_db(ShellState *p, int keepAlive){ if( p->db==0 ){ sqlite3_initialize(); sqlite3_open(p->zDbFilename, &p->db); @@ -1896,7 +2048,11 @@ static FILE *output_file_open(const char *zFile){ */ static void sql_trace_callback(void *pArg, const char *z){ FILE *f = (FILE*)pArg; - if( f ) fprintf(f, "%s\n", z); + if( f ){ + int i = (int)strlen(z); + while( i>0 && z[i-1]==';' ){ i--; } + fprintf(f, "%.*s;\n", i, z); + } } /* @@ -1909,10 +2065,10 @@ static void test_breakpoint(void){ } /* -** An object used to read a CSV file +** An object used to read a CSV and other files for import. */ -typedef struct CSVReader CSVReader; -struct CSVReader { +typedef struct ImportCtx ImportCtx; +struct ImportCtx { const char *zFile; /* Name of the input file */ FILE *in; /* Read the CSV text from this input stream */ char *z; /* Accumulated text for a field */ @@ -1920,11 +2076,12 @@ struct CSVReader { int nAlloc; /* Space allocated for z[] */ int nLine; /* Current line number */ int cTerm; /* Character that terminated the most recent field */ - int cSeparator; /* The separator character. (Usually ",") */ + int cColSep; /* The column separator character. (Usually ",") */ + int cRowSep; /* The row separator character. (Usually "\n") */ }; /* Append a single byte to z[] */ -static void csv_append_char(CSVReader *p, int c){ +static void import_append_char(ImportCtx *p, int c){ if( p->n+1>=p->nAlloc ){ p->nAlloc += p->nAlloc + 100; p->z = sqlite3_realloc(p->z, p->nAlloc); @@ -1942,15 +2099,17 @@ static void csv_append_char(CSVReader *p, int c){ ** + Input comes from p->in. ** + Store results in p->z of length p->n. Space to hold p->z comes ** from sqlite3_malloc(). -** + Use p->cSep as the separator. The default is ",". +** + Use p->cSep as the column separator. The default is ",". +** + Use p->rSep as the row separator. The default is "\n". ** + Keep track of the line number in p->nLine. ** + Store the character that terminates the field in p->cTerm. Store ** EOF on end-of-file. ** + Report syntax errors on stderr */ -static char *csv_read_one_field(CSVReader *p){ - int c, pc, ppc; - int cSep = p->cSeparator; +static char *csv_read_one_field(ImportCtx *p){ + int c; + int cSep = p->cColSep; + int rSep = p->cRowSep; p->n = 0; c = fgetc(p->in); if( c==EOF || seenInterrupt ){ @@ -1958,12 +2117,13 @@ static char *csv_read_one_field(CSVReader *p){ return 0; } if( c=='"' ){ + int pc, ppc; int startLine = p->nLine; int cQuote = c; pc = ppc = 0; while( 1 ){ c = fgetc(p->in); - if( c=='\n' ) p->nLine++; + if( c==rSep ) p->nLine++; if( c==cQuote ){ if( pc==cQuote ){ pc = 0; @@ -1971,8 +2131,8 @@ static char *csv_read_one_field(CSVReader *p){ } } if( (c==cSep && pc==cQuote) - || (c=='\n' && pc==cQuote) - || (c=='\n' && pc=='\r' && ppc==cQuote) + || (c==rSep && pc==cQuote) + || (c==rSep && pc=='\r' && ppc==cQuote) || (c==EOF && pc==cQuote) ){ do{ p->n--; }while( p->z[p->n]!=cQuote ); @@ -1986,19 +2146,19 @@ static char *csv_read_one_field(CSVReader *p){ if( c==EOF ){ fprintf(stderr, "%s:%d: unterminated %c-quoted field\n", p->zFile, startLine, cQuote); - p->cTerm = EOF; + p->cTerm = c; break; } - csv_append_char(p, c); + import_append_char(p, c); ppc = pc; pc = c; } }else{ - while( c!=EOF && c!=cSep && c!='\n' ){ - csv_append_char(p, c); + while( c!=EOF && c!=cSep && c!=rSep ){ + import_append_char(p, c); c = fgetc(p->in); } - if( c=='\n' ){ + if( c==rSep ){ p->nLine++; if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--; } @@ -2008,13 +2168,47 @@ static char *csv_read_one_field(CSVReader *p){ return p->z; } +/* Read a single field of ASCII delimited text. +** +** + Input comes from p->in. +** + Store results in p->z of length p->n. Space to hold p->z comes +** from sqlite3_malloc(). +** + Use p->cSep as the column separator. The default is "\x1F". +** + Use p->rSep as the row separator. The default is "\x1E". +** + Keep track of the row number in p->nLine. +** + Store the character that terminates the field in p->cTerm. Store +** EOF on end-of-file. +** + Report syntax errors on stderr +*/ +static char *ascii_read_one_field(ImportCtx *p){ + int c; + int cSep = p->cColSep; + int rSep = p->cRowSep; + p->n = 0; + c = fgetc(p->in); + if( c==EOF || seenInterrupt ){ + p->cTerm = EOF; + return 0; + } + while( c!=EOF && c!=cSep && c!=rSep ){ + import_append_char(p, c); + c = fgetc(p->in); + } + if( c==rSep ){ + p->nLine++; + } + p->cTerm = c; + if( p->z ) p->z[p->n] = 0; + return p->z; +} + /* ** Try to transfer data for table zTable. If an error is seen while ** moving forward, try to go backwards. The backwards movement won't ** work for WITHOUT ROWID tables. */ static void tryToCloneData( - struct callback_data *p, + ShellState *p, sqlite3 *newDb, const char *zTable ){ @@ -2127,10 +2321,10 @@ end_data_xfer: ** sqlite_master table, try again moving backwards. */ static void tryToCloneSchema( - struct callback_data *p, + ShellState *p, sqlite3 *newDb, const char *zWhere, - void (*xForEach)(struct callback_data*,sqlite3*,const char*) + void (*xForEach)(ShellState*,sqlite3*,const char*) ){ sqlite3_stmt *pQuery = 0; char *zQuery = 0; @@ -2201,7 +2395,7 @@ end_schema_xfer: ** as possible out of the main database (which might be corrupt) and write it ** into zNewDb. */ -static void tryToClone(struct callback_data *p, const char *zNewDb){ +static void tryToClone(ShellState *p, const char *zNewDb){ int rc; sqlite3 *newDb = 0; if( access(zNewDb,0)==0 ){ @@ -2226,7 +2420,7 @@ static void tryToClone(struct callback_data *p, const char *zNewDb){ /* ** Change the output file back to stdout */ -static void output_reset(struct callback_data *p){ +static void output_reset(ShellState *p){ if( p->outfile[0]=='|' ){ pclose(p->out); }else{ @@ -2242,7 +2436,7 @@ static void output_reset(struct callback_data *p){ ** ** Return 1 on error, 2 to exit, and 0 otherwise. */ -static int do_meta_command(char *zLine, struct callback_data *p){ +static int do_meta_command(char *zLine, ShellState *p){ int i = 1; int nArg = 0; int n, c; @@ -2360,7 +2554,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ }else if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ - struct callback_data data; + ShellState data; char *zErrMsg = 0; open_db(p, 0); memcpy(&data, p, sizeof(data)); @@ -2458,11 +2652,11 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){ int val = nArg>=2 ? booleanValue(azArg[1]) : 1; if(val == 1) { - if(!p->explainPrev.valid) { - p->explainPrev.valid = 1; - p->explainPrev.mode = p->mode; - p->explainPrev.showHeader = p->showHeader; - memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth)); + if(!p->normalMode.valid) { + p->normalMode.valid = 1; + p->normalMode.mode = p->mode; + p->normalMode.showHeader = p->showHeader; + memcpy(p->normalMode.colWidth,p->colWidth,sizeof(p->colWidth)); } /* We could put this code under the !p->explainValid ** condition so that it does not execute if we are already in @@ -2482,16 +2676,16 @@ static int do_meta_command(char *zLine, struct callback_data *p){ p->colWidth[5] = 13; /* P4 */ p->colWidth[6] = 2; /* P5 */ p->colWidth[7] = 13; /* Comment */ - }else if (p->explainPrev.valid) { - p->explainPrev.valid = 0; - p->mode = p->explainPrev.mode; - p->showHeader = p->explainPrev.showHeader; - memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth)); + }else if (p->normalMode.valid) { + p->normalMode.valid = 0; + p->mode = p->normalMode.mode; + p->showHeader = p->normalMode.showHeader; + memcpy(p->colWidth,p->normalMode.colWidth,sizeof(p->colWidth)); } }else if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){ - struct callback_data data; + ShellState data; char *zErrMsg = 0; int doStats = 0; if( nArg!=1 ){ @@ -2508,7 +2702,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" " FROM sqlite_master UNION ALL" " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " - "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'" + "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' " "ORDER BY rowid", callback, &data, &zErrMsg ); @@ -2562,9 +2756,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){ int nByte; /* Number of bytes in an SQL string */ int i, j; /* Loop counters */ int needCommit; /* True to COMMIT or ROLLBACK at end */ - int nSep; /* Number of bytes in p->separator[] */ + int nSep; /* Number of bytes in p->colSeparator[] */ char *zSql; /* An SQL statement */ - CSVReader sCsv; /* Reader context */ + ImportCtx sCtx; /* Reader context */ + char *(*xRead)(ImportCtx*); /* Procedure to read one value */ int (*xCloser)(FILE*); /* Procedure to close th3 connection */ if( nArg!=3 ){ @@ -2574,55 +2769,79 @@ static int do_meta_command(char *zLine, struct callback_data *p){ zFile = azArg[1]; zTable = azArg[2]; seenInterrupt = 0; - memset(&sCsv, 0, sizeof(sCsv)); + memset(&sCtx, 0, sizeof(sCtx)); open_db(p, 0); - nSep = strlen30(p->separator); + nSep = strlen30(p->colSeparator); if( nSep==0 ){ - fprintf(stderr, "Error: non-null separator required for import\n"); + fprintf(stderr, "Error: non-null column separator required for import\n"); return 1; } if( nSep>1 ){ - fprintf(stderr, "Error: multi-character separators not allowed" + fprintf(stderr, "Error: multi-character column separators not allowed" " for import\n"); return 1; } - sCsv.zFile = zFile; - sCsv.nLine = 1; - if( sCsv.zFile[0]=='|' ){ - sCsv.in = popen(sCsv.zFile+1, "r"); - sCsv.zFile = ""; + nSep = strlen30(p->rowSeparator); + if( nSep==0 ){ + fprintf(stderr, "Error: non-null row separator required for import\n"); + return 1; + } + if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){ + /* When importing CSV (only), if the row separator is set to the + ** default output row separator, change it to the default input + ** row separator. This avoids having to maintain different input + ** and output row separators. */ + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); + nSep = strlen30(p->rowSeparator); + } + if( nSep>1 ){ + fprintf(stderr, "Error: multi-character row separators not allowed" + " for import\n"); + return 1; + } + sCtx.zFile = zFile; + sCtx.nLine = 1; + if( sCtx.zFile[0]=='|' ){ + sCtx.in = popen(sCtx.zFile+1, "r"); + sCtx.zFile = ""; xCloser = pclose; }else{ - sCsv.in = fopen(sCsv.zFile, "rb"); + sCtx.in = fopen(sCtx.zFile, "rb"); xCloser = fclose; } - if( sCsv.in==0 ){ + if( p->mode==MODE_Ascii ){ + xRead = ascii_read_one_field; + }else{ + xRead = csv_read_one_field; + } + if( sCtx.in==0 ){ fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); return 1; } - sCsv.cSeparator = p->separator[0]; + sCtx.cColSep = p->colSeparator[0]; + sCtx.cRowSep = p->rowSeparator[0]; zSql = sqlite3_mprintf("SELECT * FROM %s", zTable); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); - xCloser(sCsv.in); + xCloser(sCtx.in); return 1; } nByte = strlen30(zSql); rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - csv_append_char(&sCsv, 0); /* To ensure sCsv.z is allocated */ + import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */ if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){ char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable); char cSep = '('; - while( csv_read_one_field(&sCsv) ){ - zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCsv.z); + while( xRead(&sCtx) ){ + zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCtx.z); cSep = ','; - if( sCsv.cTerm!=sCsv.cSeparator ) break; + if( sCtx.cTerm!=sCtx.cColSep ) break; } if( cSep=='(' ){ sqlite3_free(zCreate); - sqlite3_free(sCsv.z); - xCloser(sCsv.in); - fprintf(stderr,"%s: empty file\n", sCsv.zFile); + sqlite3_free(sCtx.z); + xCloser(sCtx.in); + fprintf(stderr,"%s: empty file\n", sCtx.zFile); return 1; } zCreate = sqlite3_mprintf("%z\n)", zCreate); @@ -2631,8 +2850,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( rc ){ fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable, sqlite3_errmsg(db)); - sqlite3_free(sCsv.z); - xCloser(sCsv.in); + sqlite3_free(sCtx.z); + xCloser(sCtx.in); return 1; } rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); @@ -2641,7 +2860,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( rc ){ if (pStmt) sqlite3_finalize(pStmt); fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); - xCloser(sCsv.in); + xCloser(sCtx.in); return 1; } nCol = sqlite3_column_count(pStmt); @@ -2651,7 +2870,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 ); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); - xCloser(sCsv.in); + xCloser(sCtx.in); return 1; } sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable); @@ -2667,52 +2886,62 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( rc ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); if (pStmt) sqlite3_finalize(pStmt); - xCloser(sCsv.in); + xCloser(sCtx.in); return 1; } needCommit = sqlite3_get_autocommit(db); if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0); do{ - int startLine = sCsv.nLine; + int startLine = sCtx.nLine; for(i=0; imode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break; sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT); - if( i=nCol ){ sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); if( rc!=SQLITE_OK ){ - fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCsv.zFile, startLine, + fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine, sqlite3_errmsg(db)); } } - }while( sCsv.cTerm!=EOF ); + }while( sCtx.cTerm!=EOF ); - xCloser(sCsv.in); - sqlite3_free(sCsv.z); + xCloser(sCtx.in); + sqlite3_free(sCtx.z); sqlite3_finalize(pStmt); if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0); }else if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){ - struct callback_data data; + ShellState data; char *zErrMsg = 0; open_db(p, 0); memcpy(&data, p, sizeof(data)); @@ -2824,28 +3053,32 @@ static int do_meta_command(char *zLine, struct callback_data *p){ p->mode = MODE_Html; }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){ p->mode = MODE_Tcl; - sqlite3_snprintf(sizeof(p->separator), p->separator, " "); + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space); }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){ p->mode = MODE_Csv; - sqlite3_snprintf(sizeof(p->separator), p->separator, ","); - sqlite3_snprintf(sizeof(p->newline), p->newline, "\r\n"); + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){ p->mode = MODE_List; - sqlite3_snprintf(sizeof(p->separator), p->separator, "\t"); + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab); }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){ p->mode = MODE_Insert; set_table_name(p, nArg>=3 ? azArg[2] : "table"); + }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){ + p->mode = MODE_Ascii; + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit); + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record); }else { fprintf(stderr,"Error: mode should be one of: " - "column csv html insert line list tabs tcl\n"); + "ascii column csv html insert line list tabs tcl\n"); rc = 1; } }else if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){ if( nArg==2 ){ - sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue, - "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]); + sqlite3_snprintf(sizeof(p->nullValue), p->nullValue, + "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]); }else{ fprintf(stderr, "Usage: .nullvalue STRING\n"); rc = 1; @@ -3005,8 +3238,21 @@ static int do_meta_command(char *zLine, struct callback_data *p){ sqlite3_close(pSrc); }else + + if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ + if( nArg==2 ){ + p->scanstatsOn = booleanValue(azArg[1]); +#ifndef SQLITE_ENABLE_STMT_SCANSTATUS + fprintf(stderr, "Warning: .scanstats not available in this build.\n"); +#endif + }else{ + fprintf(stderr, "Usage: .scanstats on|off\n"); + rc = 1; + } + }else + if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ - struct callback_data data; + ShellState data; char *zErrMsg = 0; open_db(p, 0); memcpy(&data, p, sizeof(data)); @@ -3062,7 +3308,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" " FROM sqlite_master UNION ALL" " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " - "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'" + "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' " "ORDER BY rowid", callback, &data, &zErrMsg ); @@ -3083,6 +3329,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else + +#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) + if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){ + extern int sqlite3SelectTrace; + sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff; + }else +#endif + + #ifdef SQLITE_DEBUG /* Undocumented commands for internal testing. Subject to change ** without notice. */ @@ -3108,14 +3363,16 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){ if( nArg<2 || nArg>3 ){ - fprintf(stderr, "Usage: .separator SEPARATOR ?NEWLINE?\n"); + fprintf(stderr, "Usage: .separator COL ?ROW?\n"); rc = 1; } if( nArg>=2 ){ - sqlite3_snprintf(sizeof(p->separator), p->separator, azArg[1]); + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, + "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]); } if( nArg>=3 ){ - sqlite3_snprintf(sizeof(p->newline), p->newline, azArg[2]); + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, + "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]); } }else @@ -3146,23 +3403,24 @@ static int do_meta_command(char *zLine, struct callback_data *p){ rc = 1; goto meta_command_exit; } - fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off"); - fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off"); - fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off"); - fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off"); - fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]); - fprintf(p->out,"%9.9s: ", "nullvalue"); - output_c_string(p->out, p->nullvalue); + fprintf(p->out,"%12.12s: %s\n","echo", p->echoOn ? "on" : "off"); + fprintf(p->out,"%12.12s: %s\n","eqp", p->autoEQP ? "on" : "off"); + fprintf(p->out,"%9.9s: %s\n","explain", p->normalMode.valid ? "on" :"off"); + fprintf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off"); + fprintf(p->out,"%12.12s: %s\n","mode", modeDescr[p->mode]); + fprintf(p->out,"%12.12s: ", "nullvalue"); + output_c_string(p->out, p->nullValue); fprintf(p->out, "\n"); - fprintf(p->out,"%9.9s: %s\n","output", + fprintf(p->out,"%12.12s: %s\n","output", strlen30(p->outfile) ? p->outfile : "stdout"); - fprintf(p->out,"%9.9s: ", "separator"); - output_c_string(p->out, p->separator); - fprintf(p->out," "); - output_c_string(p->out, p->newline); + fprintf(p->out,"%12.12s: ", "colseparator"); + output_c_string(p->out, p->colSeparator); fprintf(p->out, "\n"); - fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off"); - fprintf(p->out,"%9.9s: ","width"); + fprintf(p->out,"%12.12s: ", "rowseparator"); + output_c_string(p->out, p->rowSeparator); + fprintf(p->out, "\n"); + fprintf(p->out,"%12.12s: %s\n","stats", p->statsOn ? "on" : "off"); + fprintf(p->out,"%12.12s: ","width"); for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) { fprintf(p->out,"%d ",p->colWidth[i]); } @@ -3253,7 +3511,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ for(i=0; iout, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : ""); + fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:""); } fprintf(p->out, "\n"); } @@ -3420,6 +3678,71 @@ static int do_meta_command(char *zLine, struct callback_data *p){ #endif }else +#if SQLITE_USER_AUTHENTICATION + if( c=='u' && strncmp(azArg[0], "user", n)==0 ){ + if( nArg<2 ){ + fprintf(stderr, "Usage: .user SUBCOMMAND ...\n"); + rc = 1; + goto meta_command_exit; + } + open_db(p, 0); + if( strcmp(azArg[1],"login")==0 ){ + if( nArg!=4 ){ + fprintf(stderr, "Usage: .user login USER PASSWORD\n"); + rc = 1; + goto meta_command_exit; + } + rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], + (int)strlen(azArg[3])); + if( rc ){ + fprintf(stderr, "Authentication failed for user %s\n", azArg[2]); + rc = 1; + } + }else if( strcmp(azArg[1],"add")==0 ){ + if( nArg!=5 ){ + fprintf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n"); + rc = 1; + goto meta_command_exit; + } + rc = sqlite3_user_add(p->db, azArg[2], + azArg[3], (int)strlen(azArg[3]), + booleanValue(azArg[4])); + if( rc ){ + fprintf(stderr, "User-Add failed: %d\n", rc); + rc = 1; + } + }else if( strcmp(azArg[1],"edit")==0 ){ + if( nArg!=5 ){ + fprintf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n"); + rc = 1; + goto meta_command_exit; + } + rc = sqlite3_user_change(p->db, azArg[2], + azArg[3], (int)strlen(azArg[3]), + booleanValue(azArg[4])); + if( rc ){ + fprintf(stderr, "User-Edit failed: %d\n", rc); + rc = 1; + } + }else if( strcmp(azArg[1],"delete")==0 ){ + if( nArg!=3 ){ + fprintf(stderr, "Usage: .user delete USER\n"); + rc = 1; + goto meta_command_exit; + } + rc = sqlite3_user_delete(p->db, azArg[2]); + if( rc ){ + fprintf(stderr, "User-Delete failed: %d\n", rc); + rc = 1; + } + }else{ + fprintf(stderr, "Usage: .user login|add|edit|delete ...\n"); + rc = 1; + goto meta_command_exit; + } + }else +#endif /* SQLITE_USER_AUTHENTICATION */ + if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/, sqlite3_libversion(), sqlite3_sourceid()); @@ -3540,7 +3863,7 @@ static int line_is_complete(char *zSql, int nSql){ ** ** Return the number of errors. */ -static int process_input(struct callback_data *p, FILE *in){ +static int process_input(ShellState *p, FILE *in){ char *zLine = 0; /* A single input line */ char *zSql = 0; /* Accumulated SQL text */ int nLine; /* Length of current line */ @@ -3642,6 +3965,7 @@ static int process_input(struct callback_data *p, FILE *in){ if( nSql ){ if( !_all_whitespace(zSql) ){ fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); + errCnt++; } free(zSql); } @@ -3657,7 +3981,8 @@ static char *find_home_dir(void){ static char *home_dir = NULL; if( home_dir ) return home_dir; -#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL) +#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \ + && !defined(__RTP__) && !defined(_WRS_KERNEL) { struct passwd *pwent; uid_t uid = getuid(); @@ -3719,7 +4044,7 @@ static char *find_home_dir(void){ ** Returns the number of errors. */ static int process_sqliterc( - struct callback_data *p, /* Configuration data */ + ShellState *p, /* Configuration data */ const char *sqliterc_override /* Name of config file. NULL to use default */ ){ char *home_dir = NULL; @@ -3756,6 +4081,7 @@ static int process_sqliterc( ** Show available command line options */ static const char zOptions[] = + " -ascii set output mode to 'ascii'\n" " -bail stop after hitting an error\n" " -batch force batch I/O\n" " -column set output mode to 'column'\n" @@ -3772,13 +4098,16 @@ static const char zOptions[] = " -interactive force interactive I/O\n" " -line set output mode to 'line'\n" " -list set output mode to 'list'\n" + " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" " -mmap N default mmap size set to N\n" #ifdef SQLITE_ENABLE_MULTIPLEX " -multiplex enable the multiplexor VFS\n" #endif - " -newline SEP set newline character(s) for CSV\n" + " -newline SEP set output row separator. Default: '\\n'\n" " -nullvalue TEXT set text string for NULL values. Default ''\n" - " -separator SEP set output field separator. Default: '|'\n" + " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" + " -scratch SIZE N use N slots of SZ bytes each for scratch memory\n" + " -separator SEP set output column separator. Default: '|'\n" " -stats print memory stats before each finalize\n" " -version show SQLite version\n" " -vfs NAME use NAME as the default VFS\n" @@ -3802,17 +4131,18 @@ static void usage(int showDetail){ /* ** Initialize the state information in data */ -static void main_init(struct callback_data *data) { +static void main_init(ShellState *data) { memset(data, 0, sizeof(*data)); data->mode = MODE_List; - memcpy(data->separator,"|", 2); - memcpy(data->newline,"\r\n", 3); + memcpy(data->colSeparator,SEP_Column, 2); + memcpy(data->rowSeparator,SEP_Row, 2); data->showHeader = 0; + data->shellFlgs = SHFLG_Lookaside; sqlite3_config(SQLITE_CONFIG_URI, 1); sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); + sqlite3_config(SQLITE_CONFIG_MULTITHREAD); sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); - sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); } /* @@ -3850,12 +4180,14 @@ static char *cmdline_option_value(int argc, char **argv, int i){ int main(int argc, char **argv){ char *zErrMsg = 0; - struct callback_data data; + ShellState data; const char *zInitFile = 0; - char *zFirstCmd = 0; int i; int rc = 0; int warnInmemoryDb = 0; + int readStdin = 1; + int nCmd = 0; + char **azCmd = 0; #if USE_SYSTEM_SQLITE+0!=1 if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){ @@ -3875,6 +4207,18 @@ int main(int argc, char **argv){ signal(SIGINT, interrupt_handler); #endif +#ifdef SQLITE_SHELL_DBNAME_PROC + { + /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name + ** of a C-function that will provide the name of the database file. Use + ** this compile-time option to embed this shell program in larger + ** applications. */ + extern void SQLITE_SHELL_DBNAME_PROC(const char**); + SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename); + warnInmemoryDb = 0; + } +#endif + /* Do an initial pass through the command-line argument to locate ** the name of the database file, the name of the initialization file, ** the size of the alternative malloc heap, @@ -3886,15 +4230,18 @@ int main(int argc, char **argv){ if( z[0]!='-' ){ if( data.zDbFilename==0 ){ data.zDbFilename = z; - continue; + }else{ + /* Excesss arguments are interpreted as SQL (or dot-commands) and + ** mean that nothing is read from stdin */ + readStdin = 0; + nCmd++; + azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd); + if( azCmd==0 ){ + fprintf(stderr, "out of memory\n"); + exit(1); + } + azCmd[nCmd-1] = z; } - if( zFirstCmd==0 ){ - zFirstCmd = z; - continue; - } - fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]); - fprintf(stderr,"Use -help for a list of options.\n"); - return 1; } if( z[1]=='-' ) z++; if( strcmp(z,"-separator")==0 @@ -3921,6 +4268,33 @@ int main(int argc, char **argv){ if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); #endif + }else if( strcmp(z,"-scratch")==0 ){ + int n, sz; + sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); + if( sz>400000 ) sz = 400000; + if( sz<2500 ) sz = 2500; + n = (int)integerValue(cmdline_option_value(argc,argv,++i)); + if( n>10 ) n = 10; + if( n<1 ) n = 1; + sqlite3_config(SQLITE_CONFIG_SCRATCH, malloc(n*sz+1), sz, n); + data.shellFlgs |= SHFLG_Scratch; + }else if( strcmp(z,"-pagecache")==0 ){ + int n, sz; + sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); + if( sz>70000 ) sz = 70000; + if( sz<800 ) sz = 800; + n = (int)integerValue(cmdline_option_value(argc,argv,++i)); + if( n<10 ) n = 10; + sqlite3_config(SQLITE_CONFIG_PAGECACHE, malloc(n*sz+1), sz, n); + data.shellFlgs |= SHFLG_Pagecache; + }else if( strcmp(z,"-lookaside")==0 ){ + int n, sz; + sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); + if( sz<0 ) sz = 0; + n = (int)integerValue(cmdline_option_value(argc,argv,++i)); + if( n<0 ) n = 0; + sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n); + if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside; #ifdef SQLITE_ENABLE_VFSTRACE }else if( strcmp(z,"-vfstrace")==0 ){ extern int vfstrace_register( @@ -3957,11 +4331,6 @@ int main(int argc, char **argv){ #else fprintf(stderr,"%s: Error: no database filename specified\n", Argv0); return 1; -#endif -#ifdef SQLITE_SHELL_DBNAME_PROC - { extern void SQLITE_SHELL_DBNAME_PROC(const char**); - SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename); - warnInmemoryDb = 0; } #endif } data.out = stdout; @@ -4005,15 +4374,21 @@ int main(int argc, char **argv){ data.mode = MODE_Column; }else if( strcmp(z,"-csv")==0 ){ data.mode = MODE_Csv; - memcpy(data.separator,",",2); + memcpy(data.colSeparator,",",2); + }else if( strcmp(z,"-ascii")==0 ){ + data.mode = MODE_Ascii; + sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, + SEP_Unit); + sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, + SEP_Record); }else if( strcmp(z,"-separator")==0 ){ - sqlite3_snprintf(sizeof(data.separator), data.separator, + sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, "%s",cmdline_option_value(argc,argv,++i)); }else if( strcmp(z,"-newline")==0 ){ - sqlite3_snprintf(sizeof(data.newline), data.newline, + sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, "%s",cmdline_option_value(argc,argv,++i)); }else if( strcmp(z,"-nullvalue")==0 ){ - sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue, + sqlite3_snprintf(sizeof(data.nullValue), data.nullValue, "%s",cmdline_option_value(argc,argv,++i)); }else if( strcmp(z,"-header")==0 ){ data.showHeader = 1; @@ -4025,6 +4400,8 @@ int main(int argc, char **argv){ data.autoEQP = 1; }else if( strcmp(z,"-stats")==0 ){ data.statsOn = 1; + }else if( strcmp(z,"-scanstats")==0 ){ + data.scanstatsOn = 1; }else if( strcmp(z,"-bail")==0 ){ bail_on_error = 1; }else if( strcmp(z,"-version")==0 ){ @@ -4036,6 +4413,12 @@ int main(int argc, char **argv){ stdin_is_interactive = 0; }else if( strcmp(z,"-heap")==0 ){ i++; + }else if( strcmp(z,"-scratch")==0 ){ + i+=2; + }else if( strcmp(z,"-pagecache")==0 ){ + i+=2; + }else if( strcmp(z,"-lookaside")==0 ){ + i+=2; }else if( strcmp(z,"-mmap")==0 ){ i++; }else if( strcmp(z,"-vfs")==0 ){ @@ -4051,6 +4434,10 @@ int main(int argc, char **argv){ }else if( strcmp(z,"-help")==0 ){ usage(1); }else if( strcmp(z,"-cmd")==0 ){ + /* Run commands that follow -cmd first and separately from commands + ** that simply appear on the command-line. This seems goofy. It would + ** be better if all commands ran in the order that they appear. But + ** we retain the goofy behavior for historical compatibility. */ if( i==argc-1 ) break; z = cmdline_option_value(argc,argv,++i); if( z[0]=='.' ){ @@ -4074,23 +4461,28 @@ int main(int argc, char **argv){ } } - if( zFirstCmd ){ - /* Run just the command that follows the database name + if( !readStdin ){ + /* Run all arguments that do not begin with '-' as if they were separate + ** command-line inputs, except for the argToSkip argument which contains + ** the database filename. */ - if( zFirstCmd[0]=='.' ){ - rc = do_meta_command(zFirstCmd, &data); - if( rc==2 ) rc = 0; - }else{ - open_db(&data, 0); - rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg); - if( zErrMsg!=0 ){ - fprintf(stderr,"Error: %s\n", zErrMsg); - return rc!=0 ? rc : 1; - }else if( rc!=0 ){ - fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd); - return rc; + for(i=0; i ** ** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as -** was given no the corresponding lock. +** was given on the corresponding lock. ** ** The xShmLock method can transition between unlocked and SHARED or ** between unlocked and EXCLUSIVE. It cannot transition between SHARED @@ -1498,26 +1499,28 @@ struct sqlite3_mem_methods { ** SQLITE_CONFIG_SERIALIZED configuration option. ** ** [[SQLITE_CONFIG_MALLOC]]
    SQLITE_CONFIG_MALLOC
    -**
    ^(This option takes a single argument which is a pointer to an -** instance of the [sqlite3_mem_methods] structure. The argument specifies +**
    ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is +** a pointer to an instance of the [sqlite3_mem_methods] structure. +** The argument specifies ** alternative low-level memory allocation routines to be used in place of ** the memory allocation routines built into SQLite.)^ ^SQLite makes ** its own private copy of the content of the [sqlite3_mem_methods] structure ** before the [sqlite3_config()] call returns.
    ** ** [[SQLITE_CONFIG_GETMALLOC]]
    SQLITE_CONFIG_GETMALLOC
    -**
    ^(This option takes a single argument which is a pointer to an -** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] +**
    ^(The SQLITE_CONFIG_GETMALLOC option takes a single argument which +** is a pointer to an instance of the [sqlite3_mem_methods] structure. +** The [sqlite3_mem_methods] ** structure is filled with the currently defined memory allocation routines.)^ ** This option can be used to overload the default memory allocation ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example.
    ** ** [[SQLITE_CONFIG_MEMSTATUS]]
    SQLITE_CONFIG_MEMSTATUS
    -**
    ^This option takes single argument of type int, interpreted as a -** boolean, which enables or disables the collection of memory allocation -** statistics. ^(When memory allocation statistics are disabled, the -** following SQLite interfaces become non-operational: +**
    ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, +** interpreted as a boolean, which enables or disables the collection of +** memory allocation statistics. ^(When memory allocation statistics are +** disabled, the following SQLite interfaces become non-operational: **
      **
    • [sqlite3_memory_used()] **
    • [sqlite3_memory_highwater()] @@ -1530,53 +1533,67 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_CONFIG_SCRATCH]]
    SQLITE_CONFIG_SCRATCH
    -**
    ^This option specifies a static memory buffer that SQLite can use for -** scratch memory. There are three arguments: A pointer an 8-byte +**
    ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer +** that SQLite can use for scratch memory. ^(There are three arguments +** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte ** aligned memory buffer from which the scratch allocations will be ** drawn, the size of each scratch allocation (sz), -** and the maximum number of scratch allocations (N). The sz -** argument must be a multiple of 16. +** and the maximum number of scratch allocations (N).)^ ** The first argument must be a pointer to an 8-byte aligned buffer ** of at least sz*N bytes of memory. -** ^SQLite will use no more than two scratch buffers per thread. So -** N should be set to twice the expected maximum number of threads. -** ^SQLite will never require a scratch buffer that is more than 6 -** times the database page size. ^If SQLite needs needs additional +** ^SQLite will not use more than one scratch buffers per thread. +** ^SQLite will never request a scratch buffer that is more than 6 +** times the database page size. +** ^If SQLite needs needs additional ** scratch memory beyond what is provided by this configuration option, then -** [sqlite3_malloc()] will be used to obtain the memory needed.
    +** [sqlite3_malloc()] will be used to obtain the memory needed.

    +** ^When the application provides any amount of scratch memory using +** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large +** [sqlite3_malloc|heap allocations]. +** This can help [Robson proof|prevent memory allocation failures] due to heap +** fragmentation in low-memory embedded systems. +** ** ** [[SQLITE_CONFIG_PAGECACHE]]

    SQLITE_CONFIG_PAGECACHE
    -**
    ^This option specifies a static memory buffer that SQLite can use for -** the database page cache with the default page cache implementation. +**
    ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer +** that SQLite can use for the database page cache with the default page +** cache implementation. ** This configuration should not be used if an application-define page -** cache implementation is loaded using the SQLITE_CONFIG_PCACHE2 option. -** There are three arguments to this option: A pointer to 8-byte aligned +** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2] +** configuration option. +** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to +** 8-byte aligned ** memory, the size of each page buffer (sz), and the number of pages (N). ** The sz argument should be the size of the largest database page -** (a power of two between 512 and 32768) plus a little extra for each -** page header. ^The page header size is 20 to 40 bytes depending on -** the host architecture. ^It is harmless, apart from the wasted memory, -** to make sz a little too large. The first -** argument should point to an allocation of at least sz*N bytes of memory. +** (a power of two between 512 and 65536) plus some extra bytes for each +** page header. ^The number of extra bytes needed by the page header +** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option +** to [sqlite3_config()]. +** ^It is harmless, apart from the wasted memory, +** for the sz parameter to be larger than necessary. The first +** argument should pointer to an 8-byte aligned block of memory that +** is at least sz*N bytes of memory, otherwise subsequent behavior is +** undefined. ** ^SQLite will use the memory provided by the first argument to satisfy its ** memory needs for the first N pages that it adds to cache. ^If additional ** page cache memory is needed beyond what is provided by this option, then -** SQLite goes to [sqlite3_malloc()] for the additional storage space. -** The pointer in the first argument must -** be aligned to an 8-byte boundary or subsequent behavior of SQLite -** will be undefined.
    +** SQLite goes to [sqlite3_malloc()] for the additional storage space. ** ** [[SQLITE_CONFIG_HEAP]]
    SQLITE_CONFIG_HEAP
    -**
    ^This option specifies a static memory buffer that SQLite will use -** for all of its dynamic memory allocation needs beyond those provided -** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. -** There are three arguments: An 8-byte aligned pointer to the memory, +**
    ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer +** that SQLite will use for all of its dynamic memory allocation needs +** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and +** [SQLITE_CONFIG_PAGECACHE]. +** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled +** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns +** [SQLITE_ERROR] if invoked otherwise. +** ^There are three arguments to SQLITE_CONFIG_HEAP: +** An 8-byte aligned pointer to the memory, ** the number of bytes in the memory buffer, and the minimum allocation size. ** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts ** to using its default memory allocator (the system malloc() implementation), ** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the -** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or -** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory +** memory pointer is not NULL then the alternative memory ** allocator is engaged to handle all of SQLites memory allocation needs. ** The first pointer (the memory pointer) must be aligned to an 8-byte ** boundary or subsequent behavior of SQLite will be undefined. @@ -1584,11 +1601,11 @@ struct sqlite3_mem_methods { ** for the minimum allocation size are 2**5 through 2**8.
    ** ** [[SQLITE_CONFIG_MUTEX]]
    SQLITE_CONFIG_MUTEX
    -**
    ^(This option takes a single argument which is a pointer to an -** instance of the [sqlite3_mutex_methods] structure. The argument specifies -** alternative low-level mutex routines to be used in place -** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the -** content of the [sqlite3_mutex_methods] structure before the call to +**
    ^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a +** pointer to an instance of the [sqlite3_mutex_methods] structure. +** The argument specifies alternative low-level mutex routines to be used +** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of +** the content of the [sqlite3_mutex_methods] structure before the call to ** [sqlite3_config()] returns. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** the entire mutexing subsystem is omitted from the build and hence calls to @@ -1596,8 +1613,8 @@ struct sqlite3_mem_methods { ** return [SQLITE_ERROR].
    ** ** [[SQLITE_CONFIG_GETMUTEX]]
    SQLITE_CONFIG_GETMUTEX
    -**
    ^(This option takes a single argument which is a pointer to an -** instance of the [sqlite3_mutex_methods] structure. The +**
    ^(The SQLITE_CONFIG_GETMUTEX option takes a single argument which +** is a pointer to an instance of the [sqlite3_mutex_methods] structure. The ** [sqlite3_mutex_methods] ** structure is filled with the currently defined mutex routines.)^ ** This option can be used to overload the default mutex allocation @@ -1609,25 +1626,25 @@ struct sqlite3_mem_methods { ** return [SQLITE_ERROR].
    ** ** [[SQLITE_CONFIG_LOOKASIDE]]
    SQLITE_CONFIG_LOOKASIDE
    -**
    ^(This option takes two arguments that determine the default -** memory allocation for the lookaside memory allocator on each -** [database connection]. The first argument is the +**
    ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine +** the default size of lookaside memory on each [database connection]. +** The first argument is the ** size of each lookaside buffer slot and the second is the number of -** slots allocated to each database connection.)^ ^(This option sets the -** default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] -** verb to [sqlite3_db_config()] can be used to change the lookaside +** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE +** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] +** option to [sqlite3_db_config()] can be used to change the lookaside ** configuration on individual connections.)^
    ** ** [[SQLITE_CONFIG_PCACHE2]]
    SQLITE_CONFIG_PCACHE2
    -**
    ^(This option takes a single argument which is a pointer to -** an [sqlite3_pcache_methods2] object. This object specifies the interface -** to a custom page cache implementation.)^ ^SQLite makes a copy of the -** object and uses it for page cache memory allocations.
    +**
    ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is +** a pointer to an [sqlite3_pcache_methods2] object. This object specifies +** the interface to a custom page cache implementation.)^ +** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.
    ** ** [[SQLITE_CONFIG_GETPCACHE2]]
    SQLITE_CONFIG_GETPCACHE2
    -**
    ^(This option takes a single argument which is a pointer to an -** [sqlite3_pcache_methods2] object. SQLite copies of the current -** page cache implementation into that object.)^
    +**
    ^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which +** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of +** the current page cache implementation into that object.)^
    ** ** [[SQLITE_CONFIG_LOG]]
    SQLITE_CONFIG_LOG
    **
    The SQLITE_CONFIG_LOG option is used to configure the SQLite @@ -1650,10 +1667,11 @@ struct sqlite3_mem_methods { ** function must be threadsafe.
    ** ** [[SQLITE_CONFIG_URI]]
    SQLITE_CONFIG_URI -**
    ^(This option takes a single argument of type int. If non-zero, then -** URI handling is globally enabled. If the parameter is zero, then URI handling -** is globally disabled.)^ ^If URI handling is globally enabled, all filenames -** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or +**
    ^(The SQLITE_CONFIG_URI option takes a single argument of type int. +** If non-zero, then URI handling is globally enabled. If the parameter is zero, +** then URI handling is globally disabled.)^ ^If URI handling is globally +** enabled, all filenames passed to [sqlite3_open()], [sqlite3_open_v2()], +** [sqlite3_open16()] or ** specified as part of [ATTACH] commands are interpreted as URIs, regardless ** of whether or not the [SQLITE_OPEN_URI] flag is set when the database ** connection is opened. ^If it is globally disabled, filenames are @@ -1663,9 +1681,10 @@ struct sqlite3_mem_methods { ** [SQLITE_USE_URI] symbol defined.)^ ** ** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]]
    SQLITE_CONFIG_COVERING_INDEX_SCAN -**
    ^This option takes a single integer argument which is interpreted as -** a boolean in order to enable or disable the use of covering indices for -** full table scans in the query optimizer. ^The default setting is determined +**
    ^The SQLITE_CONFIG_COVERING_INDEX_SCAN option takes a single integer +** argument which is interpreted as a boolean in order to enable or disable +** the use of covering indices for full table scans in the query optimizer. +** ^The default setting is determined ** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on" ** if that compile-time option is omitted. ** The ability to disable the use of covering indices for full table scans @@ -1705,19 +1724,39 @@ struct sqlite3_mem_methods { ** ^The default setting can be overridden by each database connection using ** either the [PRAGMA mmap_size] command, or by using the ** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size -** cannot be changed at run-time. Nor may the maximum allowed mmap size -** exceed the compile-time maximum mmap size set by the +** will be silently truncated if necessary so that it does not exceed the +** compile-time maximum mmap size set by the ** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^ ** ^If either argument to this option is negative, then that argument is ** changed to its compile-time default. ** ** [[SQLITE_CONFIG_WIN32_HEAPSIZE]] **
    SQLITE_CONFIG_WIN32_HEAPSIZE -**
    ^This option is only available if SQLite is compiled for Windows -** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined. -** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value +**
    ^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is +** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro +** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value ** that specifies the maximum size of the created heap. ** +** +** [[SQLITE_CONFIG_PCACHE_HDRSZ]] +**
    SQLITE_CONFIG_PCACHE_HDRSZ +**
    ^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which +** is a pointer to an integer and writes into that integer the number of extra +** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE]. +** The amount of extra space required can change depending on the compiler, +** target platform, and SQLite version. +** +** [[SQLITE_CONFIG_PMASZ]] +**
    SQLITE_CONFIG_PMASZ +**
    ^The SQLITE_CONFIG_PMASZ option takes a single parameter which +** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded +** sorter to that integer. The default minimum PMA Size is set by the +** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched +** to help with sort operations when multithreaded sorting +** is enabled (using the [PRAGMA threads] command) and the amount of content +** to be sorted exceeds the page size times the minimum of the +** [PRAGMA cache_size] setting and this value. +** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ @@ -1742,6 +1781,8 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ +#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ +#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ /* ** CAPI3REF: Database Connection Configuration Options @@ -1869,47 +1910,45 @@ sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); /* ** CAPI3REF: Count The Number Of Rows Modified ** -** ^This function returns the number of database rows that were changed -** or inserted or deleted by the most recently completed SQL statement -** on the [database connection] specified by the first parameter. -** ^(Only changes that are directly specified by the [INSERT], [UPDATE], -** or [DELETE] statement are counted. Auxiliary changes caused by -** triggers or [foreign key actions] are not counted.)^ Use the -** [sqlite3_total_changes()] function to find the total number of changes -** including changes caused by triggers and foreign key actions. +** ^This function returns the number of rows modified, inserted or +** deleted by the most recently completed INSERT, UPDATE or DELETE +** statement on the database connection specified by the only parameter. +** ^Executing any other type of SQL statement does not modify the value +** returned by this function. ** -** ^Changes to a view that are simulated by an [INSTEAD OF trigger] -** are not counted. Only real table changes are counted. +** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are +** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], +** [foreign key actions] or [REPLACE] constraint resolution are not counted. +** +** Changes to a view that are intercepted by +** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value +** returned by sqlite3_changes() immediately after an INSERT, UPDATE or +** DELETE statement run on a view is always zero. Only changes made to real +** tables are counted. ** -** ^(A "row change" is a change to a single row of a single table -** caused by an INSERT, DELETE, or UPDATE statement. Rows that -** are changed as side effects of [REPLACE] constraint resolution, -** rollback, ABORT processing, [DROP TABLE], or by any other -** mechanisms do not count as direct row changes.)^ -** -** A "trigger context" is a scope of execution that begins and -** ends with the script of a [CREATE TRIGGER | trigger]. -** Most SQL statements are -** evaluated outside of any trigger. This is the "top level" -** trigger context. If a trigger fires from the top level, a -** new trigger context is entered for the duration of that one -** trigger. Subtriggers create subcontexts for their duration. -** -** ^Calling [sqlite3_exec()] or [sqlite3_step()] recursively does -** not create a new trigger context. -** -** ^This function returns the number of direct row changes in the -** most recent INSERT, UPDATE, or DELETE statement within the same -** trigger context. -** -** ^Thus, when called from the top level, this function returns the -** number of changes in the most recent INSERT, UPDATE, or DELETE -** that also occurred at the top level. ^(Within the body of a trigger, -** the sqlite3_changes() interface can be called to find the number of -** changes in the most recently completed INSERT, UPDATE, or DELETE -** statement within the body of the same trigger. -** However, the number returned does not include changes -** caused by subtriggers since those have their own context.)^ +** Things are more complicated if the sqlite3_changes() function is +** executed while a trigger program is running. This may happen if the +** program uses the [changes() SQL function], or if some other callback +** function invokes sqlite3_changes() directly. Essentially: +** +**
      +**
    • ^(Before entering a trigger program the value returned by +** sqlite3_changes() function is saved. After the trigger program +** has finished, the original value is restored.)^ +** +**
    • ^(Within a trigger program each INSERT, UPDATE and DELETE +** statement sets the value returned by sqlite3_changes() +** upon completion as normal. Of course, this value will not include +** any changes performed by sub-triggers, as the sqlite3_changes() +** value will be saved and restored after each sub-trigger has run.)^ +**
    +** +** ^This means that if the changes() SQL function (or similar) is used +** by the first INSERT, UPDATE or DELETE statement within a trigger, it +** returns the value as set when the calling statement began executing. +** ^If it is used by the second or subsequent such statement within a trigger +** program, the value returned reflects the number of rows modified by the +** previous INSERT, UPDATE or DELETE statement within the same trigger. ** ** See also the [sqlite3_total_changes()] interface, the ** [count_changes pragma], and the [changes() SQL function]. @@ -1923,20 +1962,17 @@ int sqlite3_changes(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified ** -** ^This function returns the number of row changes caused by [INSERT], -** [UPDATE] or [DELETE] statements since the [database connection] was opened. -** ^(The count returned by sqlite3_total_changes() includes all changes -** from all [CREATE TRIGGER | trigger] contexts and changes made by -** [foreign key actions]. However, -** the count does not include changes used to implement [REPLACE] constraints, -** do rollbacks or ABORT processing, or [DROP TABLE] processing. The -** count does not include rows of views that fire an [INSTEAD OF trigger], -** though if the INSTEAD OF trigger makes changes of its own, those changes -** are counted.)^ -** ^The sqlite3_total_changes() function counts the changes as soon as -** the statement that makes them is completed (when the statement handle -** is passed to [sqlite3_reset()] or [sqlite3_finalize()]). -** +** ^This function returns the total number of rows inserted, modified or +** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed +** since the database connection was opened, including those executed as +** part of trigger programs. ^Executing any other type of SQL statement +** does not affect the value returned by sqlite3_total_changes(). +** +** ^Changes made as part of [foreign key actions] are included in the +** count, but those made as part of REPLACE constraint resolution are +** not. ^Changes to a view that are intercepted by INSTEAD OF triggers +** are not counted. +** ** See also the [sqlite3_changes()] interface, the ** [count_changes pragma], and the [total_changes() SQL function]. ** @@ -2023,6 +2059,7 @@ int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors +** KEYWORDS: {busy-handler callback} {busy handler} ** ** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X ** that might be invoked with argument P whenever @@ -2039,7 +2076,7 @@ int sqlite3_complete16(const void *sql); ** ^The first argument to the busy handler is a copy of the void* pointer which ** is the third argument to sqlite3_busy_handler(). ^The second argument to ** the busy handler callback is the number of times that the busy handler has -** been invoked for the same locking event. ^If the +** been invoked previously for the same locking event. ^If the ** busy callback returns 0, then no additional attempts are made to ** access the database and [SQLITE_BUSY] is returned ** to the application. @@ -2094,7 +2131,7 @@ int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); ** turns off all busy handlers. ** ** ^(There can only be a single busy handler for a particular -** [database connection] any any given moment. If another busy handler +** [database connection] at any given moment. If another busy handler ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ ** @@ -2298,6 +2335,10 @@ char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns ** a NULL pointer. ** +** ^The sqlite3_malloc64(N) routine works just like +** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead +** of a signed 32-bit integer. +** ** ^Calling sqlite3_free() with a pointer previously returned ** by sqlite3_malloc() or sqlite3_realloc() releases that memory so ** that it might be reused. ^The sqlite3_free() routine is @@ -2309,24 +2350,38 @@ char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** might result if sqlite3_free() is called with a non-NULL pointer that ** was not obtained from sqlite3_malloc() or sqlite3_realloc(). ** -** ^(The sqlite3_realloc() interface attempts to resize a -** prior memory allocation to be at least N bytes, where N is the -** second parameter. The memory allocation to be resized is the first -** parameter.)^ ^ If the first parameter to sqlite3_realloc() +** ^The sqlite3_realloc(X,N) interface attempts to resize a +** prior memory allocation X to be at least N bytes. +** ^If the X parameter to sqlite3_realloc(X,N) ** is a NULL pointer then its behavior is identical to calling -** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc(). -** ^If the second parameter to sqlite3_realloc() is zero or +** sqlite3_malloc(N). +** ^If the N parameter to sqlite3_realloc(X,N) is zero or ** negative then the behavior is exactly the same as calling -** sqlite3_free(P) where P is the first parameter to sqlite3_realloc(). -** ^sqlite3_realloc() returns a pointer to a memory allocation -** of at least N bytes in size or NULL if sufficient memory is unavailable. +** sqlite3_free(X). +** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation +** of at least N bytes in size or NULL if insufficient memory is available. ** ^If M is the size of the prior allocation, then min(N,M) bytes ** of the prior allocation are copied into the beginning of buffer returned -** by sqlite3_realloc() and the prior allocation is freed. -** ^If sqlite3_realloc() returns NULL, then the prior allocation -** is not freed. +** by sqlite3_realloc(X,N) and the prior allocation is freed. +** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the +** prior allocation is not freed. ** -** ^The memory returned by sqlite3_malloc() and sqlite3_realloc() +** ^The sqlite3_realloc64(X,N) interfaces works the same as +** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead +** of a 32-bit signed integer. +** +** ^If X is a memory allocation previously obtained from sqlite3_malloc(), +** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then +** sqlite3_msize(X) returns the size of that memory allocation in bytes. +** ^The value returned by sqlite3_msize(X) might be larger than the number +** of bytes requested when X was allocated. ^If X is a NULL pointer then +** sqlite3_msize(X) returns zero. If X points to something that is not +** the beginning of memory allocation, or if it points to a formerly +** valid memory allocation that has now been freed, then the behavior +** of sqlite3_msize(X) is undefined and possibly harmful. +** +** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(), +** sqlite3_malloc64(), and sqlite3_realloc64() ** is always aligned to at least an 8 byte boundary, or to a ** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time ** option is used. @@ -2354,8 +2409,11 @@ char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** [sqlite3_free()] or [sqlite3_realloc()]. */ void *sqlite3_malloc(int); +void *sqlite3_malloc64(sqlite3_uint64); void *sqlite3_realloc(void*, int); +void *sqlite3_realloc64(void*, sqlite3_uint64); void sqlite3_free(void*); +sqlite3_uint64 sqlite3_msize(void*); /* ** CAPI3REF: Memory Allocator Statistics @@ -2393,13 +2451,14 @@ sqlite3_int64 sqlite3_memory_highwater(int resetFlag); ** applications to access the same PRNG for other purposes. ** ** ^A call to this routine stores N bytes of randomness into buffer P. -** ^If N is less than one, then P can be a NULL pointer. +** ^The P parameter can be a NULL pointer. ** ** ^If this routine has not been previously called or if the previous -** call had N less than one, then the PRNG is seeded using randomness -** obtained from the xRandomness method of the default [sqlite3_vfs] object. -** ^If the previous call to this routine had an N of 1 or more then -** the pseudo-randomness is generated +** call had N less than one or a NULL pointer for P, then the PRNG is +** seeded using randomness obtained from the xRandomness method of +** the default [sqlite3_vfs] object. +** ^If the previous call to this routine had an N of 1 or more and a +** non-NULL P then the pseudo-randomness is generated ** internally and without recourse to the [sqlite3_vfs] xRandomness ** method. */ @@ -2642,9 +2701,9 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** an English language description of the error following a failure of any ** of the sqlite3_open() routines. ** -** ^The default encoding for the database will be UTF-8 if -** sqlite3_open() or sqlite3_open_v2() is called and -** UTF-16 in the native byte order if sqlite3_open16() is used. +** ^The default encoding will be UTF-8 for databases created using +** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases +** created using sqlite3_open16() will be UTF-16 in the native byte order. ** ** Whether or not an error occurs when it is opened, resources ** associated with the [database connection] handle should be released by @@ -2732,13 +2791,14 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** then it is interpreted as an absolute path. ^If the path does not begin ** with a '/' (meaning that the authority section is omitted from the URI) ** then the path is interpreted as a relative path. -** ^On windows, the first component of an absolute path -** is a drive specification (e.g. "C:"). +** ^(On windows, the first component of an absolute path +** is a drive specification (e.g. "C:").)^ ** ** [[core URI query parameters]] ** The query component of a URI may contain parameters that are interpreted ** either by SQLite itself, or by a [VFS | custom VFS implementation]. -** SQLite interprets the following three query parameters: +** SQLite and its built-in [VFSes] interpret the +** following query parameters: ** **
      **
    • vfs: ^The "vfs" parameter may be used to specify the name of @@ -2773,11 +2833,9 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** -**
    • psow: ^The psow parameter may be "true" (or "on" or "yes" or -** "1") or "false" (or "off" or "no" or "0") to indicate that the +**
    • psow: ^The psow parameter indicates whether or not the ** [powersafe overwrite] property does or does not apply to the -** storage media on which the database file resides. ^The psow query -** parameter only works for the built-in unix and Windows VFSes. +** storage media on which the database file resides. ** **
    • nolock: ^The nolock parameter is a boolean query parameter ** which if set disables file locking in rollback journal modes. This @@ -3073,6 +3131,10 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
      SQLITE_LIMIT_TRIGGER_DEPTH
      **
      The maximum depth of recursion for triggers.
      )^ +** +** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
      SQLITE_LIMIT_WORKER_THREADS
      +**
      The maximum number of auxiliary worker threads that a single +** [prepared statement] may start.
      )^ ** */ #define SQLITE_LIMIT_LENGTH 0 @@ -3086,6 +3148,7 @@ int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 +#define SQLITE_LIMIT_WORKER_THREADS 11 /* ** CAPI3REF: Compiling An SQL Statement @@ -3359,18 +3422,18 @@ typedef struct sqlite3_context sqlite3_context; ** If the fourth parameter to sqlite3_bind_blob() is negative, then ** the behavior is undefined. ** If a non-negative fourth parameter is provided to sqlite3_bind_text() -** or sqlite3_bind_text16() then that parameter must be the byte offset +** or sqlite3_bind_text16() or sqlite3_bind_text64() then +** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL ** terminated. If any NUL characters occur at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** -** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and -** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or +** ^The fifth argument to the BLOB and string binding interfaces +** is a destructor used to dispose of the BLOB or ** string after SQLite has finished with it. ^The destructor is called -** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(), -** sqlite3_bind_text(), or sqlite3_bind_text16() fails. +** to dispose of the BLOB or string even if the call to bind API fails. ** ^If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. @@ -3378,6 +3441,14 @@ typedef struct sqlite3_context sqlite3_context; ** SQLite makes its own private copy of the data immediately, before ** the sqlite3_bind_*() routine returns. ** +** ^The sixth argument to sqlite3_bind_text64() must be one of +** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] +** to specify the encoding of the text in the third parameter. If +** the sixth argument to sqlite3_bind_text64() is not one of the +** allowed values shown above, or if the text encoding is different +** from the encoding specified by the sixth parameter, then the behavior +** is undefined. +** ** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that ** is filled with zeroes. ^A zeroblob uses a fixed amount of memory ** (just an integer to hold its size) while it is being processed. @@ -3398,6 +3469,9 @@ typedef struct sqlite3_context sqlite3_context; ** ** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an ** [error code] if anything goes wrong. +** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB +** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or +** [SQLITE_MAX_LENGTH]. ** ^[SQLITE_RANGE] is returned if the parameter ** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails. ** @@ -3405,12 +3479,16 @@ typedef struct sqlite3_context sqlite3_context; ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. */ int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); +int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, + void(*)(void*)); int sqlite3_bind_double(sqlite3_stmt*, int, double); int sqlite3_bind_int(sqlite3_stmt*, int, int); int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); int sqlite3_bind_null(sqlite3_stmt*, int); -int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); +int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); +int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, + void(*)(void*), unsigned char encoding); int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); @@ -4102,9 +4180,9 @@ int sqlite3_create_function_v2( ** These constant define integer codes that represent the various ** text encodings supported by SQLite. */ -#define SQLITE_UTF8 1 -#define SQLITE_UTF16LE 2 -#define SQLITE_UTF16BE 3 +#define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ +#define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ +#define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */ #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* Deprecated */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ @@ -4159,7 +4237,7 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), ** object results in undefined behavior. ** ** ^These routines work just like the corresponding [column access functions] -** except that these routines take a single [protected sqlite3_value] object +** except that these routines take a single [protected sqlite3_value] object ** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. ** ** ^The sqlite3_value_text16() interface extracts a UTF-16 string @@ -4406,6 +4484,10 @@ typedef void (*sqlite3_destructor_type)(void*); ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. +** ^The sqlite3_result_text64() interface sets the return value of an +** application-defined function to be a text string in an encoding +** specified by the fifth (and last) parameter, which must be one +** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to the sqlite3_result_text* interfaces @@ -4449,6 +4531,8 @@ typedef void (*sqlite3_destructor_type)(void*); ** the [sqlite3_context] pointer, the results are undefined. */ void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); +void sqlite3_result_blob64(sqlite3_context*,const void*, + sqlite3_uint64,void(*)(void*)); void sqlite3_result_double(sqlite3_context*, double); void sqlite3_result_error(sqlite3_context*, const char*, int); void sqlite3_result_error16(sqlite3_context*, const void*, int); @@ -4459,6 +4543,8 @@ void sqlite3_result_int(sqlite3_context*, int); void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); void sqlite3_result_null(sqlite3_context*); void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); +void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, + void(*)(void*), unsigned char encoding); void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); @@ -5078,20 +5164,27 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); /* ** CAPI3REF: Extract Metadata About A Column Of A Table ** -** ^This routine returns metadata about a specific column of a specific -** database table accessible using the [database connection] handle -** passed as the first function argument. +** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns +** information about column C of table T in database D +** on [database connection] X.)^ ^The sqlite3_table_column_metadata() +** interface returns SQLITE_OK and fills in the non-NULL pointers in +** the final five arguments with appropriate values if the specified +** column exists. ^The sqlite3_table_column_metadata() interface returns +** SQLITE_ERROR and if the specified column does not exist. +** ^If the column-name parameter to sqlite3_table_column_metadata() is a +** NULL pointer, then this routine simply checks for the existance of the +** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it +** does not. ** ** ^The column is identified by the second, third and fourth parameters to -** this function. ^The second parameter is either the name of the database +** this function. ^(The second parameter is either the name of the database ** (i.e. "main", "temp", or an attached database) containing the specified -** table or NULL. ^If it is NULL, then all attached databases are searched +** table or NULL.)^ ^If it is NULL, then all attached databases are searched ** for the table using the same algorithm used by the database engine to ** resolve unqualified table references. ** ** ^The third and fourth parameters to this function are the table and column -** name of the desired column, respectively. Neither of these parameters -** may be NULL. +** name of the desired column, respectively. ** ** ^Metadata is returned by writing to the memory locations passed as the 5th ** and subsequent parameters to this function. ^Any of these arguments may be @@ -5110,16 +5203,17 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); ** )^ ** ** ^The memory pointed to by the character pointers returned for the -** declaration type and collation sequence is valid only until the next +** declaration type and collation sequence is valid until the next ** call to any SQLite API function. ** ** ^If the specified table is actually a view, an [error code] is returned. ** -** ^If the specified column is "rowid", "oid" or "_rowid_" and an +** ^If the specified column is "rowid", "oid" or "_rowid_" and the table +** is not a [WITHOUT ROWID] table and an ** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output ** parameters are set for the explicitly declared column. ^(If there is no -** explicitly declared [INTEGER PRIMARY KEY] column, then the output -** parameters are set as follows: +** [INTEGER PRIMARY KEY] column, then the outputs +** for the [rowid] are set as follows: ** **
       **     data type: "INTEGER"
      @@ -5129,13 +5223,9 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
       **     auto increment: 0
       ** 
      )^ ** -** ^(This function may load one or more schemas from database files. If an -** error occurs during this process, or if the requested table or column -** cannot be found, an [error code] is returned and an error message left -** in the [database connection] (to be retrieved using sqlite3_errmsg()).)^ -** -** ^This API is only available if the library was compiled with the -** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol defined. +** ^This function causes all database schemas to be read from disk and +** parsed, if that has not already been done, and returns an error if +** any errors are encountered while loading the schema. */ int sqlite3_table_column_metadata( sqlite3 *db, /* Connection handle */ @@ -5588,26 +5678,42 @@ typedef struct sqlite3_blob sqlite3_blob; ** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow; ** )^ ** +** ^(Parameter zDb is not the filename that contains the database, but +** rather the symbolic name of the database. For attached databases, this is +** the name that appears after the AS keyword in the [ATTACH] statement. +** For the main database file, the database name is "main". For TEMP +** tables, the database name is "temp".)^ +** ** ^If the flags parameter is non-zero, then the BLOB is opened for read -** and write access. ^If it is zero, the BLOB is opened for read access. -** ^It is not possible to open a column that is part of an index or primary -** key for writing. ^If [foreign key constraints] are enabled, it is -** not possible to open a column that is part of a [child key] for writing. +** and write access. ^If the flags parameter is zero, the BLOB is opened for +** read-only access. ** -** ^Note that the database name is not the filename that contains -** the database but rather the symbolic name of the database that -** appears after the AS keyword when the database is connected using [ATTACH]. -** ^For the main database file, the database name is "main". -** ^For TEMP tables, the database name is "temp". +** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored +** in *ppBlob. Otherwise an [error code] is returned and, unless the error +** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided +** the API is not misused, it is always safe to call [sqlite3_blob_close()] +** on *ppBlob after this function it returns. +** +** This function fails with SQLITE_ERROR if any of the following are true: +**
        +**
      • ^(Database zDb does not exist)^, +**
      • ^(Table zTable does not exist within database zDb)^, +**
      • ^(Table zTable is a WITHOUT ROWID table)^, +**
      • ^(Column zColumn does not exist)^, +**
      • ^(Row iRow is not present in the table)^, +**
      • ^(The specified column of row iRow contains a value that is not +** a TEXT or BLOB value)^, +**
      • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE +** constraint and the blob is being opened for read/write access)^, +**
      • ^([foreign key constraints | Foreign key constraints] are enabled, +** column zColumn is part of a [child key] definition and the blob is +** being opened for read/write access)^. +**
      +** +** ^Unless it returns SQLITE_MISUSE, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. ** -** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written -** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set -** to be a null pointer.)^ -** ^This function sets the [database connection] error code and message -** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related -** functions. ^Note that the *ppBlob variable is always initialized in a -** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob -** regardless of the success or failure of this routine. ** ** ^(If the row that a BLOB handle points to is modified by an ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects @@ -5625,13 +5731,9 @@ typedef struct sqlite3_blob sqlite3_blob; ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. ** -** ^The [sqlite3_blob_open()] interface will fail for a [WITHOUT ROWID] -** table. Incremental BLOB I/O is not possible on [WITHOUT ROWID] tables. -** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces -** and the built-in [zeroblob] SQL function can be used, if desired, -** to create an empty, zero-filled blob in which to read or write using -** this interface. +** and the built-in [zeroblob] SQL function may be used to create a +** zero-filled blob to read or write using the incremental-blob interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually ** be released by a call to [sqlite3_blob_close()]. @@ -5673,24 +5775,22 @@ SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); /* ** CAPI3REF: Close A BLOB Handle ** -** ^Closes an open [BLOB handle]. +** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed +** unconditionally. Even if this routine returns an error code, the +** handle is still closed.)^ ** -** ^Closing a BLOB shall cause the current transaction to commit -** if there are no other BLOBs, no pending prepared statements, and the -** database connection is in [autocommit mode]. -** ^If any writes were made to the BLOB, they might be held in cache -** until the close operation if they will fit. +** ^If the blob handle being closed was opened for read-write access, and if +** the database is in auto-commit mode and there are no other open read-write +** blob handles or active write statements, the current transaction is +** committed. ^If an error occurs while committing the transaction, an error +** code is returned and the transaction rolled back. ** -** ^(Closing the BLOB often forces the changes -** out to disk and so if any I/O errors occur, they will likely occur -** at the time when the BLOB is closed. Any errors that occur during -** closing are reported as a non-zero return value.)^ -** -** ^(The BLOB is closed unconditionally. Even if this routine returns -** an error code, the BLOB is still closed.)^ -** -** ^Calling this routine with a null pointer (such as would be returned -** by a failed call to [sqlite3_blob_open()]) is a harmless no-op. +** Calling this function with an argument that is not a NULL pointer or an +** open blob handle results in undefined behaviour. ^Calling this routine +** with a null pointer (such as would be returned by a failed call to +** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function +** is passed a valid open blob handle, the values returned by the +** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning. */ int sqlite3_blob_close(sqlite3_blob *); @@ -5740,21 +5840,27 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); /* ** CAPI3REF: Write Data Into A BLOB Incrementally ** -** ^This function is used to write data into an open [BLOB handle] from a -** caller-supplied buffer. ^N bytes of data are copied from the buffer Z -** into the open BLOB, starting at offset iOffset. +** ^(This function is used to write data into an open [BLOB handle] from a +** caller-supplied buffer. N bytes of data are copied from the buffer Z +** into the open BLOB, starting at offset iOffset.)^ +** +** ^(On success, sqlite3_blob_write() returns SQLITE_OK. +** Otherwise, an [error code] or an [extended error code] is returned.)^ +** ^Unless SQLITE_MISUSE is returned, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. ** ** ^If the [BLOB handle] passed as the first argument was not opened for ** writing (the flags parameter to [sqlite3_blob_open()] was zero), ** this function returns [SQLITE_READONLY]. ** -** ^This function may only modify the contents of the BLOB; it is +** This function may only modify the contents of the BLOB; it is ** not possible to increase the size of a BLOB using this API. ** ^If offset iOffset is less than N bytes from the end of the BLOB, -** [SQLITE_ERROR] is returned and no data is written. ^If N is -** less than zero [SQLITE_ERROR] is returned and no data is written. -** The size of the BLOB (and hence the maximum value of N+iOffset) -** can be determined using the [sqlite3_blob_bytes()] interface. +** [SQLITE_ERROR] is returned and no data is written. The size of the +** BLOB (and hence the maximum value of N+iOffset) can be determined +** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less +** than zero [SQLITE_ERROR] is returned and no data is written. ** ** ^An attempt to write to an expired [BLOB handle] fails with an ** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred @@ -5763,9 +5869,6 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); ** have been overwritten by the statement that expired the BLOB handle ** or by other independent statements. ** -** ^(On success, sqlite3_blob_write() returns SQLITE_OK. -** Otherwise, an [error code] or an [extended error code] is returned.)^ -** ** This routine only works on a [BLOB handle] which has been created ** by a prior successful call to [sqlite3_blob_open()] and which has not ** been closed by [sqlite3_blob_close()]. Passing any other pointer in @@ -5818,34 +5921,34 @@ int sqlite3_vfs_unregister(sqlite3_vfs*); ** ** The SQLite source code contains multiple implementations ** of these mutex routines. An appropriate implementation -** is selected automatically at compile-time. ^(The following +** is selected automatically at compile-time. The following ** implementations are available in the SQLite core: ** **
        **
      • SQLITE_MUTEX_PTHREADS **
      • SQLITE_MUTEX_W32 **
      • SQLITE_MUTEX_NOOP -**
      )^ +**
    ** -** ^The SQLITE_MUTEX_NOOP implementation is a set of routines +** The SQLITE_MUTEX_NOOP implementation is a set of routines ** that does no real locking and is appropriate for use in -** a single-threaded application. ^The SQLITE_MUTEX_PTHREADS and +** a single-threaded application. The SQLITE_MUTEX_PTHREADS and ** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix ** and Windows. ** -** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor +** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor ** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex ** implementation is included with the library. In this case the ** application must supply a custom mutex implementation using the ** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function ** before calling sqlite3_initialize() or any other public sqlite3_ -** function that calls sqlite3_initialize().)^ +** function that calls sqlite3_initialize(). ** ** ^The sqlite3_mutex_alloc() routine allocates a new -** mutex and returns a pointer to it. ^If it returns NULL -** that means that a mutex could not be allocated. ^SQLite -** will unwind its stack and return an error. ^(The argument -** to sqlite3_mutex_alloc() is one of these integer constants: +** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc() +** routine returns NULL if it is unable to allocate the requested +** mutex. The argument to sqlite3_mutex_alloc() must one of these +** integer constants: ** **
      **
    • SQLITE_MUTEX_FAST @@ -5858,7 +5961,8 @@ int sqlite3_vfs_unregister(sqlite3_vfs*); **
    • SQLITE_MUTEX_STATIC_PMEM **
    • SQLITE_MUTEX_STATIC_APP1 **
    • SQLITE_MUTEX_STATIC_APP2 -**
    )^ +**
  • SQLITE_MUTEX_STATIC_APP3 +** ** ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) ** cause sqlite3_mutex_alloc() to create @@ -5866,14 +5970,14 @@ int sqlite3_vfs_unregister(sqlite3_vfs*); ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does -** not want to. ^SQLite will only request a recursive mutex in -** cases where it really needs one. ^If a faster non-recursive mutex +** not want to. SQLite will only request a recursive mutex in +** cases where it really needs one. If a faster non-recursive mutex ** implementation is available on the host platform, the mutex subsystem ** might return such a mutex in response to SQLITE_MUTEX_FAST. ** ** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other ** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return -** a pointer to a static preexisting mutex. ^Six static mutexes are +** a pointer to a static preexisting mutex. ^Nine static mutexes are ** used by the current version of SQLite. Future versions of SQLite ** may add additional static mutexes. Static mutexes are for internal ** use by SQLite only. Applications that use SQLite mutexes should @@ -5882,16 +5986,13 @@ int sqlite3_vfs_unregister(sqlite3_vfs*); ** ** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() -** returns a different mutex on every call. ^But for the static +** returns a different mutex on every call. ^For the static ** mutex types, the same mutex is returned on every call that has ** the same type number. ** ** ^The sqlite3_mutex_free() routine deallocates a previously -** allocated dynamic mutex. ^SQLite is careful to deallocate every -** dynamic mutex that it allocates. The dynamic mutexes must not be in -** use when they are deallocated. Attempting to deallocate a static -** mutex results in undefined behavior. ^SQLite never deallocates -** a static mutex. +** allocated dynamic mutex. Attempting to deallocate a static +** mutex results in undefined behavior. ** ** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt ** to enter a mutex. ^If another thread is already within the mutex, @@ -5899,23 +6000,21 @@ int sqlite3_vfs_unregister(sqlite3_vfs*); ** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK] ** upon successful entry. ^(Mutexes created using ** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread. -** In such cases the, +** In such cases, the ** mutex must be exited an equal number of times before another thread -** can enter.)^ ^(If the same thread tries to enter any other -** kind of mutex more than once, the behavior is undefined. -** SQLite will never exhibit -** such behavior in its own use of mutexes.)^ +** can enter.)^ If the same thread tries to enter any mutex other +** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined. ** ** ^(Some systems (for example, Windows 95) do not support the operation ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() -** will always return SQLITE_BUSY. The SQLite core only ever uses -** sqlite3_mutex_try() as an optimization so this is acceptable behavior.)^ +** will always return SQLITE_BUSY. The SQLite core only ever uses +** sqlite3_mutex_try() as an optimization so this is acceptable +** behavior.)^ ** ** ^The sqlite3_mutex_leave() routine exits a mutex that was -** previously entered by the same thread. ^(The behavior +** previously entered by the same thread. The behavior ** is undefined if the mutex is not currently entered by the -** calling thread or is not currently allocated. SQLite will -** never do either.)^ +** calling thread or is not currently allocated. ** ** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or ** sqlite3_mutex_leave() is a NULL pointer, then all three routines @@ -5936,9 +6035,9 @@ void sqlite3_mutex_leave(sqlite3_mutex*); ** used to allocate and use mutexes. ** ** Usually, the default mutex implementations provided by SQLite are -** sufficient, however the user has the option of substituting a custom +** sufficient, however the application has the option of substituting a custom ** implementation for specialized deployments or systems for which SQLite -** does not provide a suitable implementation. In this case, the user +** does not provide a suitable implementation. In this case, the application ** creates and populates an instance of this structure to pass ** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option. ** Additionally, an instance of this structure can be used as an @@ -5979,13 +6078,13 @@ void sqlite3_mutex_leave(sqlite3_mutex*); ** (i.e. it is acceptable to provide an implementation that segfaults if ** it is passed a NULL pointer). ** -** The xMutexInit() method must be threadsafe. ^It must be harmless to +** The xMutexInit() method must be threadsafe. It must be harmless to ** invoke xMutexInit() multiple times within the same process and without ** intervening calls to xMutexEnd(). Second and subsequent calls to ** xMutexInit() must be no-ops. ** -** ^xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()] -** and its associates). ^Similarly, xMutexAlloc() must not use SQLite memory +** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()] +** and its associates). Similarly, xMutexAlloc() must not use SQLite memory ** allocation for a static mutex. ^However xMutexAlloc() may use SQLite ** memory allocation for a fast or recursive mutex. ** @@ -6011,29 +6110,29 @@ struct sqlite3_mutex_methods { ** CAPI3REF: Mutex Verification Routines ** ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines -** are intended for use inside assert() statements. ^The SQLite core +** are intended for use inside assert() statements. The SQLite core ** never uses these routines except inside an assert() and applications -** are advised to follow the lead of the core. ^The SQLite core only +** are advised to follow the lead of the core. The SQLite core only ** provides implementations for these routines when it is compiled -** with the SQLITE_DEBUG flag. ^External mutex implementations +** with the SQLITE_DEBUG flag. External mutex implementations ** are only required to provide these routines if SQLITE_DEBUG is ** defined and if NDEBUG is not defined. ** -** ^These routines should return true if the mutex in their argument +** These routines should return true if the mutex in their argument ** is held or not held, respectively, by the calling thread. ** -** ^The implementation is not required to provide versions of these +** The implementation is not required to provide versions of these ** routines that actually work. If the implementation does not provide working ** versions of these routines, it should at least provide stubs that always ** return true so that one does not get spurious assertion failures. ** -** ^If the argument to sqlite3_mutex_held() is a NULL pointer then +** If the argument to sqlite3_mutex_held() is a NULL pointer then ** the routine should return 1. This seems counter-intuitive since ** clearly the mutex cannot be held if it does not exist. But ** the reason the mutex does not exist is because the build is not ** using mutexes. And we do not want the assert() containing the ** call to sqlite3_mutex_held() to fail, so a non-zero return is -** the appropriate thing to do. ^The sqlite3_mutex_notheld() +** the appropriate thing to do. The sqlite3_mutex_notheld() ** interface should also return 1 when given a NULL pointer. */ #ifndef NDEBUG @@ -6155,12 +6254,13 @@ int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 -#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 +#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_ISINIT 23 -#define SQLITE_TESTCTRL_LAST 23 +#define SQLITE_TESTCTRL_SORTER_MMAP 24 +#define SQLITE_TESTCTRL_LAST 24 /* ** CAPI3REF: SQLite Runtime Status @@ -6351,12 +6451,12 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
    SQLITE_DBSTATUS_CACHE_USED
    -**
    This parameter returns the approximate number of of bytes of heap +**
    This parameter returns the approximate number of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
    SQLITE_DBSTATUS_SCHEMA_USED
    -**
    This parameter returns the approximate number of of bytes of heap +**
    This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the @@ -6365,7 +6465,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. ** ** [[SQLITE_DBSTATUS_STMT_USED]] ^(
    SQLITE_DBSTATUS_STMT_USED
    -**
    This parameter returns the approximate number of of bytes of heap +**
    This parameter returns the approximate number of bytes of heap ** and lookaside memory used by all prepared statements associated with ** the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. @@ -6765,6 +6865,10 @@ typedef struct sqlite3_backup sqlite3_backup; ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with ** an error. ** +** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if +** there is already a read or read-write transaction open on the +** destination database. +** ** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is ** returned and an error code and error message are stored in the ** destination [database connection] D. @@ -7088,12 +7192,10 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...); ** CAPI3REF: Write-Ahead Log Commit Hook ** ** ^The [sqlite3_wal_hook()] function is used to register a callback that -** will be invoked each time a database connection commits data to a -** [write-ahead log] (i.e. whenever a transaction is committed in -** [journal_mode | journal_mode=WAL mode]). +** is invoked each time data is committed to a database in wal mode. ** -** ^The callback is invoked by SQLite after the commit has taken place and -** the associated write-lock on the database released, so the implementation +** ^(The callback is invoked by SQLite after the commit has taken place and +** the associated write-lock on the database released)^, so the implementation ** may read, write or [checkpoint] the database as required. ** ** ^The first parameter passed to the callback function when it is invoked @@ -7158,97 +7260,114 @@ int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); /* ** CAPI3REF: Checkpoint a database ** -** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X -** on [database connection] D to be [checkpointed]. ^If X is NULL or an -** empty string, then a checkpoint is run on all databases of -** connection D. ^If the database connection D is not in -** [WAL | write-ahead log mode] then this interface is a harmless no-op. -** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a -** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint. -** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL -** or RESET checkpoint. +** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to +** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^ ** -** ^The [wal_checkpoint pragma] can be used to invoke this interface -** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the -** [wal_autocheckpoint pragma] can be used to cause this interface to be -** run whenever the WAL reaches a certain size threshold. +** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the +** [write-ahead log] for database X on [database connection] D to be +** transferred into the database file and for the write-ahead log to +** be reset. See the [checkpointing] documentation for addition +** information. ** -** See also: [sqlite3_wal_checkpoint_v2()] +** This interface used to be the only way to cause a checkpoint to +** occur. But then the newer and more powerful [sqlite3_wal_checkpoint_v2()] +** interface was added. This interface is retained for backwards +** compatibility and as a convenience for applications that need to manually +** start a callback but which do not need the full power (and corresponding +** complication) of [sqlite3_wal_checkpoint_v2()]. */ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Checkpoint a database ** -** Run a checkpoint operation on WAL database zDb attached to database -** handle db. The specific operation is determined by the value of the -** eMode parameter: +** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint +** operation on database X of [database connection] D in mode M. Status +** information is written back into integers pointed to by L and C.)^ +** ^(The M parameter must be a valid [checkpoint mode]:)^ ** **
    **
    SQLITE_CHECKPOINT_PASSIVE
    -** Checkpoint as many frames as possible without waiting for any database -** readers or writers to finish. Sync the db file if all frames in the log -** are checkpointed. This mode is the same as calling -** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback] -** is never invoked. +** ^Checkpoint as many frames as possible without waiting for any database +** readers or writers to finish, then sync the database file if all frames +** in the log were checkpointed. ^The [busy-handler callback] +** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode. +** ^On the other hand, passive mode might leave the checkpoint unfinished +** if there are concurrent readers or writers. ** **
    SQLITE_CHECKPOINT_FULL
    -** This mode blocks (it invokes the +** ^This mode blocks (it invokes the ** [sqlite3_busy_handler|busy-handler callback]) until there is no ** database writer and all readers are reading from the most recent database -** snapshot. It then checkpoints all frames in the log file and syncs the -** database file. This call blocks database writers while it is running, -** but not database readers. +** snapshot. ^It then checkpoints all frames in the log file and syncs the +** database file. ^This mode blocks new database writers while it is pending, +** but new database readers are allowed to continue unimpeded. ** **
    SQLITE_CHECKPOINT_RESTART
    -** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after -** checkpointing the log file it blocks (calls the -** [sqlite3_busy_handler|busy-handler callback]) -** until all readers are reading from the database file only. This ensures -** that the next client to write to the database file restarts the log file -** from the beginning. This call blocks database writers while it is running, -** but not database readers. +** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition +** that after checkpointing the log file it blocks (calls the +** [busy-handler callback]) +** until all readers are reading from the database file only. ^This ensures +** that the next writer will restart the log file from the beginning. +** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new +** database writer attempts while it is pending, but does not impede readers. +** +**
    SQLITE_CHECKPOINT_TRUNCATE
    +** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the +** addition that it also truncates the log file to zero bytes just prior +** to a successful return. **
    ** -** If pnLog is not NULL, then *pnLog is set to the total number of frames in -** the log file before returning. If pnCkpt is not NULL, then *pnCkpt is set to -** the total number of checkpointed frames (including any that were already -** checkpointed when this function is called). *pnLog and *pnCkpt may be -** populated even if sqlite3_wal_checkpoint_v2() returns other than SQLITE_OK. -** If no values are available because of an error, they are both set to -1 -** before returning to communicate this to the caller. +** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in +** the log file or to -1 if the checkpoint could not run because +** of an error or because the database is not in [WAL mode]. ^If pnCkpt is not +** NULL,then *pnCkpt is set to the total number of checkpointed frames in the +** log file (including any that were already checkpointed before the function +** was called) or to -1 if the checkpoint could not run due to an error or +** because the database is not in WAL mode. ^Note that upon successful +** completion of an SQLITE_CHECKPOINT_TRUNCATE, the log file will have been +** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero. ** -** All calls obtain an exclusive "checkpoint" lock on the database file. If +** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If ** any other process is running a checkpoint operation at the same time, the -** lock cannot be obtained and SQLITE_BUSY is returned. Even if there is a +** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a ** busy-handler configured, it will not be invoked in this case. ** -** The SQLITE_CHECKPOINT_FULL and RESTART modes also obtain the exclusive -** "writer" lock on the database file. If the writer lock cannot be obtained -** immediately, and a busy-handler is configured, it is invoked and the writer -** lock retried until either the busy-handler returns 0 or the lock is -** successfully obtained. The busy-handler is also invoked while waiting for -** database readers as described above. If the busy-handler returns 0 before +** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the +** exclusive "writer" lock on the database file. ^If the writer lock cannot be +** obtained immediately, and a busy-handler is configured, it is invoked and +** the writer lock retried until either the busy-handler returns 0 or the lock +** is successfully obtained. ^The busy-handler is also invoked while waiting for +** database readers as described above. ^If the busy-handler returns 0 before ** the writer lock is obtained or while waiting for database readers, the ** checkpoint operation proceeds from that point in the same way as ** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible -** without blocking any further. SQLITE_BUSY is returned in this case. +** without blocking any further. ^SQLITE_BUSY is returned in this case. ** -** If parameter zDb is NULL or points to a zero length string, then the -** specified operation is attempted on all WAL databases. In this case the -** values written to output parameters *pnLog and *pnCkpt are undefined. If +** ^If parameter zDb is NULL or points to a zero length string, then the +** specified operation is attempted on all WAL databases [attached] to +** [database connection] db. In this case the +** values written to output parameters *pnLog and *pnCkpt are undefined. ^If ** an SQLITE_BUSY error is encountered when processing one or more of the ** attached WAL databases, the operation is still attempted on any remaining -** attached databases and SQLITE_BUSY is returned to the caller. If any other +** attached databases and SQLITE_BUSY is returned at the end. ^If any other ** error occurs while processing an attached database, processing is abandoned -** and the error code returned to the caller immediately. If no error +** and the error code is returned to the caller immediately. ^If no error ** (SQLITE_BUSY or otherwise) is encountered while processing the attached ** databases, SQLITE_OK is returned. ** -** If database zDb is the name of an attached database that is not in WAL -** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. If +** ^If database zDb is the name of an attached database that is not in WAL +** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. ^If ** zDb is not NULL (or a zero length string) and is not the name of any ** attached database, SQLITE_ERROR is returned to the caller. +** +** ^Unless it returns SQLITE_MISUSE, +** the sqlite3_wal_checkpoint_v2() interface +** sets the error information that is queried by +** [sqlite3_errcode()] and [sqlite3_errmsg()]. +** +** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface +** from SQL. */ int sqlite3_wal_checkpoint_v2( sqlite3 *db, /* Database handle */ @@ -7259,16 +7378,18 @@ int sqlite3_wal_checkpoint_v2( ); /* -** CAPI3REF: Checkpoint operation parameters +** CAPI3REF: Checkpoint Mode Values +** KEYWORDS: {checkpoint mode} ** -** These constants can be used as the 3rd parameter to -** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()] -** documentation for additional information about the meaning and use of -** each of these values. +** These constants define all valid values for the "checkpoint mode" passed +** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface. +** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the +** meaning of each of these checkpoint modes. */ -#define SQLITE_CHECKPOINT_PASSIVE 0 -#define SQLITE_CHECKPOINT_FULL 1 -#define SQLITE_CHECKPOINT_RESTART 2 +#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ +#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ +#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */ +#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */ /* ** CAPI3REF: Virtual Table Interface Configuration @@ -7357,6 +7478,106 @@ int sqlite3_vtab_on_conflict(sqlite3 *); /* #define SQLITE_ABORT 4 // Also an error code */ #define SQLITE_REPLACE 5 +/* +** CAPI3REF: Prepared Statement Scan Status Opcodes +** KEYWORDS: {scanstatus options} +** +** The following constants can be used for the T parameter to the +** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a +** different metric for sqlite3_stmt_scanstatus() to return. +** +** When the value returned to V is a string, space to hold that string is +** managed by the prepared statement S and will be automatically freed when +** S is finalized. +** +**
    +** [[SQLITE_SCANSTAT_NLOOP]]
    SQLITE_SCANSTAT_NLOOP
    +**
    ^The [sqlite3_int64] variable pointed to by the T parameter will be +** set to the total number of times that the X-th loop has run.
    +** +** [[SQLITE_SCANSTAT_NVISIT]]
    SQLITE_SCANSTAT_NVISIT
    +**
    ^The [sqlite3_int64] variable pointed to by the T parameter will be set +** to the total number of rows examined by all iterations of the X-th loop.
    +** +** [[SQLITE_SCANSTAT_EST]]
    SQLITE_SCANSTAT_EST
    +**
    ^The "double" variable pointed to by the T parameter will be set to the +** query planner's estimate for the average number of rows output from each +** iteration of the X-th loop. If the query planner's estimates was accurate, +** then this value will approximate the quotient NVISIT/NLOOP and the +** product of this value for all prior loops with the same SELECTID will +** be the NLOOP value for the current loop. +** +** [[SQLITE_SCANSTAT_NAME]]
    SQLITE_SCANSTAT_NAME
    +**
    ^The "const char *" variable pointed to by the T parameter will be set +** to a zero-terminated UTF-8 string containing the name of the index or table +** used for the X-th loop. +** +** [[SQLITE_SCANSTAT_EXPLAIN]]
    SQLITE_SCANSTAT_EXPLAIN
    +**
    ^The "const char *" variable pointed to by the T parameter will be set +** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] +** description for the X-th loop. +** +** [[SQLITE_SCANSTAT_SELECTID]]
    SQLITE_SCANSTAT_SELECT
    +**
    ^The "int" variable pointed to by the T parameter will be set to the +** "select-id" for the X-th loop. The select-id identifies which query or +** subquery the loop is part of. The main query has a select-id of zero. +** The select-id is the same value as is output in the first column +** of an [EXPLAIN QUERY PLAN] query. +**
    +*/ +#define SQLITE_SCANSTAT_NLOOP 0 +#define SQLITE_SCANSTAT_NVISIT 1 +#define SQLITE_SCANSTAT_EST 2 +#define SQLITE_SCANSTAT_NAME 3 +#define SQLITE_SCANSTAT_EXPLAIN 4 +#define SQLITE_SCANSTAT_SELECTID 5 + +/* +** CAPI3REF: Prepared Statement Scan Status +** +** This interface returns information about the predicted and measured +** performance for pStmt. Advanced applications can use this +** interface to compare the predicted and the measured performance and +** issue warnings and/or rerun [ANALYZE] if discrepancies are found. +** +** Since this interface is expected to be rarely used, it is only +** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS] +** compile-time option. +** +** The "iScanStatusOp" parameter determines which status information to return. +** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior +** of this interface is undefined. +** ^The requested measurement is written into a variable pointed to by +** the "pOut" parameter. +** Parameter "idx" identifies the specific loop to retrieve statistics for. +** Loops are numbered starting from zero. ^If idx is out of range - less than +** zero or greater than or equal to the total number of loops used to implement +** the statement - a non-zero value is returned and the variable that pOut +** points to is unchanged. +** +** ^Statistics might not be available for all loops in all statements. ^In cases +** where there exist loops with no available statistics, this function behaves +** as if the loop did not exist - it returns non-zero and leave the variable +** that pOut points to unchanged. +** +** See also: [sqlite3_stmt_scanstatus_reset()] +*/ +SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( + sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ + int idx, /* Index of loop to report on */ + int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ + void *pOut /* Result written here */ +); + +/* +** CAPI3REF: Zero Scan-Status Counters +** +** ^Zero all [sqlite3_stmt_scanstatus()] related event counters. +** +** This API is only available if the library is built with pre-processor +** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. +*/ +SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index ecf93f6..f9a0665 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -28,7 +28,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** WARNING: In order to maintain backwards compatibility, add new ** interfaces to the end of this structure only. If you insert new ** interfaces in the middle of this structure, then older different -** versions of SQLite will not be able to load each others' shared +** versions of SQLite will not be able to load each other's shared ** libraries! */ struct sqlite3_api_routines { @@ -250,11 +250,28 @@ struct sqlite3_api_routines { const char *(*uri_parameter)(const char*,const char*); char *(*vsnprintf)(int,char*,const char*,va_list); int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); + /* Version 3.8.7 and later */ + int (*auto_extension)(void(*)(void)); + int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, + void(*)(void*)); + int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, + void(*)(void*),unsigned char); + int (*cancel_auto_extension)(void(*)(void)); + int (*load_extension)(sqlite3*,const char*,const char*,char**); + void *(*malloc64)(sqlite3_uint64); + sqlite3_uint64 (*msize)(void*); + void *(*realloc64)(void*,sqlite3_uint64); + void (*reset_auto_extension)(void); + void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, + void(*)(void*)); + void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, + void(*)(void*), unsigned char); + int (*strglob)(const char*,const char*); }; /* ** The following macros redefine the API routines so that they are -** redirected throught the global sqlite3_api structure. +** redirected through the global sqlite3_api structure. ** ** This header file is also used by the loadext.c source file ** (part of the main SQLite library - not an extension) so that @@ -467,6 +484,19 @@ struct sqlite3_api_routines { #define sqlite3_uri_parameter sqlite3_api->uri_parameter #define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 +/* Version 3.8.7 and later */ +#define sqlite3_auto_extension sqlite3_api->auto_extension +#define sqlite3_bind_blob64 sqlite3_api->bind_blob64 +#define sqlite3_bind_text64 sqlite3_api->bind_text64 +#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension +#define sqlite3_load_extension sqlite3_api->load_extension +#define sqlite3_malloc64 sqlite3_api->malloc64 +#define sqlite3_msize sqlite3_api->msize +#define sqlite3_realloc64 sqlite3_api->realloc64 +#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension +#define sqlite3_result_blob64 sqlite3_api->result_blob64 +#define sqlite3_result_text64 sqlite3_api->result_text64 +#define sqlite3_strglob sqlite3_api->strglob #endif /* SQLITE_CORE */ #ifndef SQLITE_CORE diff --git a/src/sqliteInt.h b/src/sqliteInt.h index ee52487..379456d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -15,6 +15,14 @@ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ +/* +** Include the header file used to customize the compiler options for MSVC. +** This should be done first so that it can successfully prevent spurious +** compiler warnings due to subsequent content in this file and other files +** that are included by this file. +*/ +#include "msvc.h" + /* ** These #defines should enable >2GB file support on POSIX if the ** underlying operating system supports it. If the OS lacks @@ -47,6 +55,15 @@ # define _LARGEFILE_SOURCE 1 #endif +/* Needed for various definitions... */ +#if defined(__GNUC__) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +#endif + +#if defined(__OpenBSD__) && !defined(_BSD_SOURCE) +# define _BSD_SOURCE +#endif + /* ** For MinGW, check to see if we can include the header file containing its ** version information, among other things. Normally, this internal MinGW @@ -104,15 +121,6 @@ #pragma warn -spa /* Suspicious pointer arithmetic */ #endif -/* Needed for various definitions... */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif - -#if defined(__OpenBSD__) && !defined(_BSD_SOURCE) -# define _BSD_SOURCE -#endif - /* ** Include standard header files as necessary */ @@ -153,6 +161,18 @@ # define SQLITE_PTR_TO_INT(X) ((int)(X)) #endif +/* +** A macro to hint to the compiler that a function should not be +** inlined. +*/ +#if defined(__GNUC__) +# define SQLITE_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) && _MSC_VER>=1310 +# define SQLITE_NOINLINE __declspec(noinline) +#else +# define SQLITE_NOINLINE +#endif + /* ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2. ** 0 means mutexes are permanently disable and the library is never @@ -181,10 +201,9 @@ #endif /* -** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1. -** It determines whether or not the features related to -** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can -** be overridden at runtime using the sqlite3_config() API. +** EVIDENCE-OF: R-25715-37072 Memory allocation statistics are enabled by +** default unless SQLite is compiled with SQLITE_DEFAULT_MEMSTATUS=0 in +** which case memory allocation statistics are disabled by default. */ #if !defined(SQLITE_DEFAULT_MEMSTATUS) # define SQLITE_DEFAULT_MEMSTATUS 1 @@ -339,7 +358,7 @@ #endif /* -** Return true (non-zero) if the input is a integer that is too large +** Return true (non-zero) if the input is an integer that is too large ** to fit in 32-bits. This macro is used inside of various testcase() ** macros to verify that we have tested SQLite for large-file support. */ @@ -422,6 +441,27 @@ # define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */ #endif +/* +** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if +** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it +** to zero. +*/ +#if SQLITE_TEMP_STORE==3 || SQLITE_THREADSAFE==0 +# undef SQLITE_MAX_WORKER_THREADS +# define SQLITE_MAX_WORKER_THREADS 0 +#endif +#ifndef SQLITE_MAX_WORKER_THREADS +# define SQLITE_MAX_WORKER_THREADS 8 +#endif +#ifndef SQLITE_DEFAULT_WORKER_THREADS +# define SQLITE_DEFAULT_WORKER_THREADS 0 +#endif +#if SQLITE_DEFAULT_WORKER_THREADS>SQLITE_MAX_WORKER_THREADS +# undef SQLITE_MAX_WORKER_THREADS +# define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS +#endif + + /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. @@ -436,6 +476,11 @@ #define MIN(A,B) ((A)<(B)?(A):(B)) #define MAX(A,B) ((A)>(B)?(A):(B)) +/* +** Swap two objects of type TYPE. +*/ +#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} + /* ** Check to see if this machine uses EBCDIC. (Yes, believe it or ** not, there are still machines out there that use EBCDIC.) @@ -525,7 +570,7 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */ ** gives a possible range of values of approximately 1.0e986 to 1e-986. ** But the allowed values are "grainy". Not every value is representable. ** For example, quantities 16 and 17 are both represented by a LogEst -** of 40. However, since LogEst quantaties are suppose to be estimates, +** of 40. However, since LogEst quantities are suppose to be estimates, ** not exact values, this imprecision is not a problem. ** ** "LogEst" is short for "Logarithmic Estimate". @@ -606,7 +651,7 @@ extern const int sqlite3one; ** all alignment restrictions correct. ** ** Except, if SQLITE_4_BYTE_ALIGNED_MALLOC is defined, then the -** underlying malloc() implemention might return us 4-byte aligned +** underlying malloc() implementation might return us 4-byte aligned ** pointers. In that case, only verify 4-byte alignment. */ #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC @@ -673,6 +718,16 @@ extern const int sqlite3one; # undef SQLITE_ENABLE_STAT3_OR_STAT4 #endif +/* +** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not +** the Select query generator tracing logic is turned on. +*/ +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE) +# define SELECTTRACE_ENABLED 1 +#else +# define SELECTTRACE_ENABLED 0 +#endif + /* ** An instance of the following structure is used to store the busy-handler ** callback for a given sqlite handle. @@ -805,12 +860,14 @@ typedef struct PrintfArguments PrintfArguments; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; +typedef struct SQLiteThread SQLiteThread; typedef struct SelectDest SelectDest; typedef struct SrcList SrcList; typedef struct StrAccum StrAccum; typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; +typedef struct TreeView TreeView; typedef struct Trigger Trigger; typedef struct TriggerPrg TriggerPrg; typedef struct TriggerStep TriggerStep; @@ -907,7 +964,7 @@ struct Schema { ** The number of different kinds of things that can be limited ** using the sqlite3_limit() interface. */ -#define SQLITE_N_LIMIT (SQLITE_LIMIT_TRIGGER_DEPTH+1) +#define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1) /* ** Lookaside malloc is a set of fixed-size buffers that can be used @@ -954,6 +1011,45 @@ struct FuncDefHash { FuncDef *a[23]; /* Hash table for functions */ }; +#ifdef SQLITE_USER_AUTHENTICATION +/* +** Information held in the "sqlite3" database connection object and used +** to manage user authentication. +*/ +typedef struct sqlite3_userauth sqlite3_userauth; +struct sqlite3_userauth { + u8 authLevel; /* Current authentication level */ + int nAuthPW; /* Size of the zAuthPW in bytes */ + char *zAuthPW; /* Password used to authenticate */ + char *zAuthUser; /* User name used to authenticate */ +}; + +/* Allowed values for sqlite3_userauth.authLevel */ +#define UAUTH_Unknown 0 /* Authentication not yet checked */ +#define UAUTH_Fail 1 /* User authentication failed */ +#define UAUTH_User 2 /* Authenticated as a normal user */ +#define UAUTH_Admin 3 /* Authenticated as an administrator */ + +/* Functions used only by user authorization logic */ +int sqlite3UserAuthTable(const char*); +int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*); +void sqlite3UserAuthInit(sqlite3*); +void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); + +#endif /* SQLITE_USER_AUTHENTICATION */ + +/* +** typedef for the authorization callback function. +*/ +#ifdef SQLITE_USER_AUTHENTICATION + typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, + const char*, const char*); +#else + typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, + const char*); +#endif + + /* ** Each database connection is an instance of the following structure. */ @@ -971,6 +1067,7 @@ struct sqlite3 { int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ u16 dbOptFlags; /* Flags to enable/disable optimizations */ + u8 enc; /* Text encoding */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ @@ -984,6 +1081,7 @@ struct sqlite3 { int nChange; /* Value returned by sqlite3_changes() */ int nTotalChange; /* Value returned by sqlite3_total_changes() */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ + int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ struct sqlite3InitInfo { /* Information used during initialization */ int newTnum; /* Rootpage of table being initialized */ u8 iDb; /* Which db file is being initialized */ @@ -1020,8 +1118,7 @@ struct sqlite3 { } u1; Lookaside lookaside; /* Lookaside malloc configuration */ #ifndef SQLITE_OMIT_AUTHORIZATION - int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); - /* Access authorization function */ + sqlite3_xauth xAuth; /* Access authorization function */ void *pAuthArg; /* 1st argument to the access auth function */ #endif #ifndef SQLITE_OMIT_PROGRESS_CALLBACK @@ -1047,7 +1144,6 @@ struct sqlite3 { i64 nDeferredCons; /* Net deferred constraints this transaction. */ i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ - #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MASTER ** mutex, not by sqlite3.mutex. They are used by code in notify.c. @@ -1065,12 +1161,16 @@ struct sqlite3 { void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif +#ifdef SQLITE_USER_AUTHENTICATION + sqlite3_userauth auth; /* User authentication information */ +#endif }; /* ** A macro to discover the encoding of a database. */ -#define ENC(db) ((db)->aDb[0].pSchema->enc) +#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc) +#define ENC(db) ((db)->enc) /* ** Possible values for the sqlite3.flags. @@ -1123,8 +1223,7 @@ struct sqlite3 { #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ #define SQLITE_Transitive 0x0200 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ -#define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */ -#define SQLITE_AdjustOutEst 0x1000 /* Adjust output estimates using WHERE */ +#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* @@ -1211,6 +1310,7 @@ struct FuncDestructor { #define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */ #define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */ #define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */ +#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are @@ -1258,6 +1358,9 @@ struct FuncDestructor { #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0} +#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \ + {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \ + SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0} /* ** All current savepoints are stored in a linked list starting at @@ -1344,18 +1447,18 @@ struct CollSeq { ** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve ** the speed a little by numbering the values consecutively. ** -** But rather than start with 0 or 1, we begin with 'a'. That way, +** But rather than start with 0 or 1, we begin with 'A'. That way, ** when multiple affinity types are concatenated into a string and ** used as the P4 operand, they will be more readable. ** ** Note also that the numeric types are grouped together so that testing -** for a numeric type is a single comparison. +** for a numeric type is a single comparison. And the NONE type is first. */ -#define SQLITE_AFF_TEXT 'a' -#define SQLITE_AFF_NONE 'b' -#define SQLITE_AFF_NUMERIC 'c' -#define SQLITE_AFF_INTEGER 'd' -#define SQLITE_AFF_REAL 'e' +#define SQLITE_AFF_NONE 'A' +#define SQLITE_AFF_TEXT 'B' +#define SQLITE_AFF_NUMERIC 'C' +#define SQLITE_AFF_INTEGER 'D' +#define SQLITE_AFF_REAL 'E' #define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) @@ -1363,7 +1466,7 @@ struct CollSeq { ** The SQLITE_AFF_MASK values masks off the significant bits of an ** affinity value. */ -#define SQLITE_AFF_MASK 0x67 +#define SQLITE_AFF_MASK 0x47 /* ** Additional bit values that can be ORed with an affinity without @@ -1374,10 +1477,10 @@ struct CollSeq { ** operator is NULL. It is added to certain comparison operators to ** prove that the operands are always NOT NULL. */ -#define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */ -#define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */ +#define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */ +#define SQLITE_STOREP2 0x20 /* Store result in reg[P2] rather than jump */ #define SQLITE_NULLEQ 0x80 /* NULL=NULL */ -#define SQLITE_NOTNULL 0x88 /* Assert that operands are never NULL */ +#define SQLITE_NOTNULL 0x90 /* Assert that operands are never NULL */ /* ** An object of this type is created for each virtual table present in @@ -1647,7 +1750,7 @@ struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ u16 nField; /* Number of entries in apMem[] */ i8 default_rc; /* Comparison result if keys are equal */ - u8 isCorrupt; /* Corruption detected by xRecordCompare() */ + u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */ Mem *aMem; /* Values */ int r1; /* Value to return if (lhs > rhs) */ int r2; /* Value to return if (rhs < lhs) */ @@ -1691,7 +1794,6 @@ struct Index { u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ Expr *pPartIdxWhere; /* WHERE clause for partial indices */ - KeyInfo *pKeyInfo; /* A KeyInfo object suitable for this index */ int tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ @@ -1702,11 +1804,14 @@ struct Index { unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ unsigned isResized:1; /* True if resizeIndexObject() has been called */ unsigned isCovering:1; /* True if this is a covering index */ + unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ + tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */ + tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */ #endif }; @@ -1904,7 +2009,7 @@ struct Expr { int iTable; /* TK_COLUMN: cursor number of table holding column ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old - ** EP_Unlikely: 1000 times likelihood */ + ** EP_Unlikely: 134217728 times likelihood */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. ** TK_VARIABLE: variable number (always >= 1). */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ @@ -1919,7 +2024,7 @@ struct Expr { /* ** The following are the meanings of bits in the Expr.flags field. */ -#define EP_FromJoin 0x000001 /* Originated in ON or USING clause of a join */ +#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ #define EP_Agg 0x000002 /* Contains one or more aggregate functions */ #define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */ #define EP_Error 0x000008 /* Expression contains one or more errors */ @@ -1939,6 +2044,7 @@ struct Expr { #define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ #define EP_Constant 0x080000 /* Node is a constant */ +#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ /* ** These macros can be used to test, set, or clear bits in the @@ -2137,7 +2243,7 @@ struct SrcList { #define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */ #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ -#define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ + /* 0x0080 // not currently used */ #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ @@ -2180,17 +2286,22 @@ struct NameContext { NameContext *pNext; /* Next outer name context. NULL for outermost */ int nRef; /* Number of names resolved by this context */ int nErr; /* Number of errors encountered while resolving names */ - u8 ncFlags; /* Zero or more NC_* flags defined below */ + u16 ncFlags; /* Zero or more NC_* flags defined below */ }; /* ** Allowed values for the NameContext, ncFlags field. +** +** Note: NC_MinMaxAgg must have the same value as SF_MinMaxAgg and +** SQLITE_FUNC_MINMAX. +** */ -#define NC_AllowAgg 0x01 /* Aggregate functions are allowed here */ -#define NC_HasAgg 0x02 /* One or more aggregate functions seen */ -#define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */ -#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */ -#define NC_PartIdx 0x10 /* True if resolving a partial index WHERE */ +#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ +#define NC_HasAgg 0x0002 /* One or more aggregate functions seen */ +#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */ +#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ +#define NC_PartIdx 0x0010 /* True if resolving a partial index WHERE */ +#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ /* ** An instance of the following structure contains all information @@ -2217,6 +2328,9 @@ struct Select { u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ u16 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ +#if SELECTTRACE_ENABLED + char zSelName[12]; /* Symbolic name of this SELECT use for debugging */ +#endif int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ u64 nSelectRow; /* Estimated number of result rows */ SrcList *pSrc; /* The FROM clause */ @@ -2241,13 +2355,13 @@ struct Select { #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ - /* 0x0040 NOT USED */ +#define SF_Compound 0x0040 /* Part of a compound query */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */ - /* 0x0100 NOT USED */ +#define SF_AllValues 0x0100 /* All terms of compound are VALUES */ #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */ #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */ #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */ -#define SF_Compound 0x1000 /* Part of a compound query */ +#define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */ /* @@ -2475,6 +2589,10 @@ struct Parse { int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRoot; /* Register holding root page number for new objects */ int nMaxArg; /* Max args passed to user function by sub-program */ +#if SELECTTRACE_ENABLED + int nSelect; /* Number of SELECT statements seen */ + int nSelectIndent; /* How far to indent SELECTTRACE() output */ +#endif #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ @@ -2554,11 +2672,11 @@ struct AuthContext { ** Bitfield flags for P5 value in various opcodes. */ #define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */ +#define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ #define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ #define OPFLAG_APPEND 0x08 /* This is likely to be an append */ #define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ -#define OPFLAG_CLEARCACHE 0x20 /* Clear pseudo-table cache in OP_Column */ #define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ #define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */ #define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */ @@ -2729,6 +2847,7 @@ struct Sqlite3Config { int nPage; /* Number of pages in pPage[] */ int mxParserStack; /* maximum depth of the parser stack */ int sharedCacheEnabled; /* true if shared-cache mode enabled */ + u32 szPma; /* Maximum Sorter PMA size */ /* The above might be initialized to non-zero. The following need to always ** initially be zero, however. */ int isInit; /* True after initialization has finished */ @@ -2784,9 +2903,11 @@ struct Walker { void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */ Parse *pParse; /* Parser context. */ int walkerDepth; /* Number of subqueries */ + u8 eCode; /* A small processing code */ union { /* Extra data for callback */ NameContext *pNC; /* Naming context */ - int i; /* Integer value */ + int n; /* A counter */ + int iCur; /* A cursor number */ SrcList *pSrcList; /* FROM clause */ struct SrcCount *pSrcCount; /* Counting column references */ } u; @@ -2822,6 +2943,17 @@ struct With { } a[1]; }; +#ifdef SQLITE_DEBUG +/* +** An instance of the TreeView object is used for printing the content of +** data structures on sqlite3DebugPrintf() using a tree-like view. +*/ +struct TreeView { + int iLevel; /* Which level of the tree we are on */ + u8 bLine[100]; /* Draw vertical in column i if bLine[i] is true */ +}; +#endif /* SQLITE_DEBUG */ + /* ** Assuming zIn points to the first byte of a UTF-8 character, ** advance zIn to point to the first byte of the next UTF-8 character. @@ -2849,11 +2981,11 @@ int sqlite3CantopenError(int); /* ** FTS4 is really an extension for FTS3. It is enabled using the -** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all -** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3. +** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also call +** the SQLITE_ENABLE_FTS4 macro to serve as an alias for SQLITE_ENABLE_FTS3. */ #if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3) -# define SQLITE_ENABLE_FTS3 +# define SQLITE_ENABLE_FTS3 1 #endif /* @@ -2887,6 +3019,7 @@ int sqlite3CantopenError(int); # define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x)) #endif +int sqlite3IsIdChar(u8); /* ** Internal function prototypes @@ -2897,15 +3030,15 @@ int sqlite3Strlen30(const char*); int sqlite3MallocInit(void); void sqlite3MallocEnd(void); -void *sqlite3Malloc(int); -void *sqlite3MallocZero(int); -void *sqlite3DbMallocZero(sqlite3*, int); -void *sqlite3DbMallocRaw(sqlite3*, int); +void *sqlite3Malloc(u64); +void *sqlite3MallocZero(u64); +void *sqlite3DbMallocZero(sqlite3*, u64); +void *sqlite3DbMallocRaw(sqlite3*, u64); char *sqlite3DbStrDup(sqlite3*,const char*); -char *sqlite3DbStrNDup(sqlite3*,const char*, int); -void *sqlite3Realloc(void*, int); -void *sqlite3DbReallocOrFree(sqlite3 *, void *, int); -void *sqlite3DbRealloc(sqlite3 *, void *, int); +char *sqlite3DbStrNDup(sqlite3*,const char*, u64); +void *sqlite3Realloc(void*, u64); +void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); +void *sqlite3DbRealloc(sqlite3 *, void *, u64); void sqlite3DbFree(sqlite3*, void*); int sqlite3MallocSize(void*); int sqlite3DbMallocSize(sqlite3*, void*); @@ -2985,25 +3118,14 @@ char *sqlite3MAppendf(sqlite3*,char*,const char*,...); void *sqlite3TestTextToPtr(const char*); #endif -/* Output formatting for SQLITE_TESTCTRL_EXPLAIN */ -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) - void sqlite3ExplainBegin(Vdbe*); - void sqlite3ExplainPrintf(Vdbe*, const char*, ...); - void sqlite3ExplainNL(Vdbe*); - void sqlite3ExplainPush(Vdbe*); - void sqlite3ExplainPop(Vdbe*); - void sqlite3ExplainFinish(Vdbe*); - void sqlite3ExplainSelect(Vdbe*, Select*); - void sqlite3ExplainExpr(Vdbe*, Expr*); - void sqlite3ExplainExprList(Vdbe*, ExprList*); - const char *sqlite3VdbeExplanation(Vdbe*); -#else -# define sqlite3ExplainBegin(X) -# define sqlite3ExplainSelect(A,B) -# define sqlite3ExplainExpr(A,B) -# define sqlite3ExplainExprList(A,B) -# define sqlite3ExplainFinish(X) -# define sqlite3VdbeExplanation(X) 0 +#if defined(SQLITE_DEBUG) + TreeView *sqlite3TreeViewPush(TreeView*,u8); + void sqlite3TreeViewPop(TreeView*); + void sqlite3TreeViewLine(TreeView*, const char*, ...); + void sqlite3TreeViewItem(TreeView*, const char*, u8); + void sqlite3TreeViewExpr(TreeView*, const Expr*, u8); + void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); + void sqlite3TreeViewSelect(TreeView*, const Select*, u8); #endif @@ -3185,7 +3307,8 @@ void sqlite3CloseSavepoints(sqlite3 *); void sqlite3LeaveMutexAndCloseZombie(sqlite3*); int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstantNotJoin(Expr*); -int sqlite3ExprIsConstantOrFunction(Expr*); +int sqlite3ExprIsConstantOrFunction(Expr*, u8); +int sqlite3ExprIsTableConstant(Expr*,int); int sqlite3ExprIsInteger(Expr*, int*); int sqlite3ExprCanBeNull(const Expr*); int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); @@ -3209,6 +3332,11 @@ ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); IdList *sqlite3IdListDup(sqlite3*,IdList*); Select *sqlite3SelectDup(sqlite3*,Select*,int); +#if SELECTTRACE_ENABLED +void sqlite3SelectSetName(Select*,const char*); +#else +# define sqlite3SelectSetName(A,B) +#endif void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*); FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8); void sqlite3RegisterBuiltinFunctions(sqlite3*); @@ -3295,38 +3423,23 @@ u64 sqlite3LogEstToInt(LogEst); /* ** Routines to read and write variable-length integers. These used to ** be defined locally, but now we use the varint routines in the util.c -** file. Code should use the MACRO forms below, as the Varint32 versions -** are coded to assume the single byte case is already handled (which -** the MACRO form does). +** file. */ int sqlite3PutVarint(unsigned char*, u64); -int sqlite3PutVarint32(unsigned char*, u32); u8 sqlite3GetVarint(const unsigned char *, u64 *); u8 sqlite3GetVarint32(const unsigned char *, u32 *); int sqlite3VarintLen(u64 v); /* -** The header of a record consists of a sequence variable-length integers. -** These integers are almost always small and are encoded as a single byte. -** The following macros take advantage this fact to provide a fast encode -** and decode of the integers in a record header. It is faster for the common -** case where the integer is a single byte. It is a little slower when the -** integer is two or more bytes. But overall it is faster. -** -** The following expressions are equivalent: -** -** x = sqlite3GetVarint32( A, &B ); -** x = sqlite3PutVarint32( A, B ); -** -** x = getVarint32( A, B ); -** x = putVarint32( A, B ); -** +** The common case is for a varint to be a single byte. They following +** macros handle the common case without a procedure call, but then call +** the procedure for larger varints. */ #define getVarint32(A,B) \ (u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B))) #define putVarint32(A,B) \ (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\ - sqlite3PutVarint32((A),(B))) + sqlite3PutVarint((A),(B))) #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint @@ -3338,7 +3451,8 @@ int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); char sqlite3ExprAffinity(Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); int sqlite3DecOrHexToI64(const char*, i64*); -void sqlite3Error(sqlite3*, int, const char*,...); +void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); +void sqlite3Error(sqlite3*,int); void *sqlite3HexToBlob(sqlite3*, const char *z, int n); u8 sqlite3HexToInt(int h); int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); @@ -3440,7 +3554,7 @@ int sqlite3OpenTempDatabase(Parse *); void sqlite3StrAccumInit(StrAccum*, char*, int, int); void sqlite3StrAccumAppend(StrAccum*,const char*,int); void sqlite3StrAccumAppendAll(StrAccum*,const char*); -void sqlite3AppendSpace(StrAccum*,int); +void sqlite3AppendChar(StrAccum*,int,char); char *sqlite3StrAccumFinish(StrAccum*); void sqlite3StrAccumReset(StrAccum*); void sqlite3SelectDestInit(SelectDest*,int,int); @@ -3460,7 +3574,7 @@ int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_value**); /* ** The interface to the LEMON-generated parser */ -void *sqlite3ParserAlloc(void*(*)(size_t)); +void *sqlite3ParserAlloc(void*(*)(u64)); void sqlite3ParserFree(void*, void(*)(void*)); void sqlite3Parser(void*, int, Token, Parse*); #ifdef YYTRACKMAXSTACKDEPTH @@ -3700,9 +3814,16 @@ SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...); # define sqlite3MemdebugNoType(X,Y) 1 #endif #define MEMTYPE_HEAP 0x01 /* General heap allocations */ -#define MEMTYPE_LOOKASIDE 0x02 /* Might have been lookaside memory */ +#define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */ #define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */ #define MEMTYPE_PCACHE 0x08 /* Page cache allocations */ -#define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */ + +/* +** Threading interface +*/ +#if SQLITE_MAX_WORKER_THREADS>0 +int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*); +int sqlite3ThreadJoin(SQLiteThread*, void**); +#endif #endif /* _SQLITEINT_H_ */ diff --git a/src/status.c b/src/status.c index 5fcb68d..4c2eabb 100644 --- a/src/status.c +++ b/src/status.c @@ -86,6 +86,9 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ if( op<0 || op>=ArraySize(wsdStat.nowValue) ){ return SQLITE_MISUSE_BKPT; } +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; +#endif *pCurrent = wsdStat.nowValue[op]; *pHighwater = wsdStat.mxValue[op]; if( resetFlag ){ @@ -105,6 +108,11 @@ int sqlite3_db_status( int resetFlag /* Reset high-water mark if true */ ){ int rc = SQLITE_OK; /* Return code */ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif sqlite3_mutex_enter(db->mutex); switch( op ){ case SQLITE_DBSTATUS_LOOKASIDE_USED: { @@ -213,7 +221,7 @@ int sqlite3_db_status( } db->pnBytesFreed = 0; - *pHighwater = 0; + *pHighwater = 0; /* IMP: R-64479-57858 */ *pCurrent = nByte; break; @@ -238,7 +246,9 @@ int sqlite3_db_status( sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); } } - *pHighwater = 0; + *pHighwater = 0; /* IMP: R-42420-56072 */ + /* IMP: R-54100-20147 */ + /* IMP: R-29431-39229 */ *pCurrent = nRet; break; } @@ -248,7 +258,7 @@ int sqlite3_db_status( ** have been satisfied. The *pHighwater is always set to zero. */ case SQLITE_DBSTATUS_DEFERRED_FKS: { - *pHighwater = 0; + *pHighwater = 0; /* IMP: R-11967-56545 */ *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0; break; } diff --git a/src/table.c b/src/table.c index 26bbfb4..235d8dd 100644 --- a/src/table.c +++ b/src/table.c @@ -29,10 +29,10 @@ typedef struct TabResult { char **azResult; /* Accumulated output */ char *zErrMsg; /* Error message text, if an error occurs */ - int nAlloc; /* Slots allocated for azResult[] */ - int nRow; /* Number of rows in the result */ - int nColumn; /* Number of columns in the result */ - int nData; /* Slots used in azResult[]. (nRow+1)*nColumn */ + u32 nAlloc; /* Slots allocated for azResult[] */ + u32 nRow; /* Number of rows in the result */ + u32 nColumn; /* Number of columns in the result */ + u32 nData; /* Slots used in azResult[]. (nRow+1)*nColumn */ int rc; /* Return code from sqlite3_exec() */ } TabResult; @@ -58,7 +58,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ if( p->nData + need > p->nAlloc ){ char **azNew; p->nAlloc = p->nAlloc*2 + need; - azNew = sqlite3_realloc( p->azResult, sizeof(char*)*p->nAlloc ); + azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc ); if( azNew==0 ) goto malloc_failed; p->azResult = azNew; } @@ -73,7 +73,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ if( z==0 ) goto malloc_failed; p->azResult[p->nData++] = z; } - }else if( p->nColumn!=nCol ){ + }else if( (int)p->nColumn!=nCol ){ sqlite3_free(p->zErrMsg); p->zErrMsg = sqlite3_mprintf( "sqlite3_get_table() called with two or more incompatible queries" @@ -126,6 +126,9 @@ int sqlite3_get_table( int rc; TabResult res; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || pazResult==0 ) return SQLITE_MISUSE_BKPT; +#endif *pazResult = 0; if( pnColumn ) *pnColumn = 0; if( pnRow ) *pnRow = 0; @@ -182,7 +185,7 @@ int sqlite3_get_table( ** This routine frees the space the sqlite3_get_table() malloced. */ void sqlite3_free_table( - char **azResult /* Result returned from from sqlite3_get_table() */ + char **azResult /* Result returned from sqlite3_get_table() */ ){ if( azResult ){ int i, n; diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 9b977e5..a912e8a 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -25,6 +25,14 @@ ** hundreds of new commands used for testing ** SQLite. This option implies -DSQLITE_TCLMD5. */ + +/* +** If requested, include the SQLite compiler options file for MSVC. +*/ +#if defined(INCLUDE_MSVC_H) +#include "msvc.h" +#endif + #include "tcl.h" #include @@ -635,6 +643,7 @@ static int DbWalHandler( Tcl_Interp *interp = pDb->interp; assert(pDb->pWalHook); + assert( db==pDb->db ); p = Tcl_DuplicateObj(pDb->pWalHook); Tcl_IncrRefCount(p); Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1)); @@ -760,7 +769,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ /* If there are arguments to the function, make a shallow copy of the ** script object, lappend the arguments, then evaluate the copy. ** - ** By "shallow" copy, we mean a only the outer list Tcl_Obj is duplicated. + ** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated. ** The new Tcl_Obj contains pointers to the original list elements. ** That way, when Tcl_EvalObjv() is run and shimmers the first element ** of the list to tclCmdNameType, that alternate representation will @@ -872,6 +881,9 @@ static int auth_callback( const char *zArg2, const char *zArg3, const char *zArg4 +#ifdef SQLITE_USER_AUTHENTICATION + ,const char *zArg5 +#endif ){ const char *zCode; Tcl_DString str; @@ -924,6 +936,9 @@ static int auth_callback( Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); +#ifdef SQLITE_USER_AUTHENTICATION + Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : ""); +#endif rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); Tcl_DStringFree(&str); zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY"; @@ -1078,10 +1093,10 @@ static int dbPrepareAndBind( SqlPreparedStmt **ppPreStmt /* OUT: Object used to cache statement */ ){ const char *zSql = zIn; /* Pointer to first SQL statement in zIn */ - sqlite3_stmt *pStmt; /* Prepared statement object */ + sqlite3_stmt *pStmt = 0; /* Prepared statement object */ SqlPreparedStmt *pPreStmt; /* Pointer to cached statement */ int nSql; /* Length of zSql in bytes */ - int nVar; /* Number of variables in statement */ + int nVar = 0; /* Number of variables in statement */ int iParm = 0; /* Next free entry in apParm */ char c; int i; @@ -1700,8 +1715,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ pDb->zAuth = 0; } if( pDb->zAuth ){ + typedef int (*sqlite3_auth_cb)( + void*,int,const char*,const char*, + const char*,const char*); pDb->interp = interp; - sqlite3_set_authorizer(pDb->db, auth_callback, pDb); + sqlite3_set_authorizer(pDb->db,(sqlite3_auth_cb)auth_callback,pDb); }else{ sqlite3_set_authorizer(pDb->db, 0, 0); } @@ -2381,7 +2399,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ if( rc==TCL_OK ){ rc = createIncrblobChannel( - interp, pDb, zDb, zTable, zColumn, iRow, isReadonly + interp, pDb, zDb, zTable, zColumn, (sqlite3_int64)iRow, isReadonly ); } #endif @@ -3092,7 +3110,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ ** The EXTERN macros are required by TCL in order to work on windows. */ EXTERN int Sqlite3_Init(Tcl_Interp *interp){ - int rc = Tcl_InitStubs(interp, "8.4", 0)==0 ? TCL_ERROR : TCL_OK; + int rc = Tcl_InitStubs(interp, "8.4", 0) ? TCL_OK : TCL_ERROR; if( rc==TCL_OK ){ Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); #ifndef SQLITE_3_SUFFIX_ONLY @@ -3632,6 +3650,45 @@ static int db_use_legacy_prepare_cmd( Tcl_ResetResult(interp); return TCL_OK; } + +/* +** Tclcmd: db_last_stmt_ptr DB +** +** If the statement cache associated with database DB is not empty, +** return the text representation of the most recently used statement +** handle. +*/ +static int db_last_stmt_ptr( + ClientData cd, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*); + Tcl_CmdInfo cmdInfo; + SqliteDb *pDb; + sqlite3_stmt *pStmt = 0; + char zBuf[100]; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB"); + return TCL_ERROR; + } + + if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){ + Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0); + return TCL_ERROR; + } + pDb = (SqliteDb*)cmdInfo.objClientData; + + if( pDb->stmtList ) pStmt = pDb->stmtList->pStmt; + if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ){ + return TCL_ERROR; + } + Tcl_SetResult(interp, zBuf, TCL_VOLATILE); + + return TCL_OK; +} #endif /* @@ -3677,6 +3734,7 @@ static void init_all(Tcl_Interp *interp){ extern int Sqlitetest9_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*); extern int Sqlitetest_autoext_Init(Tcl_Interp*); + extern int Sqlitetest_blob_Init(Tcl_Interp*); extern int Sqlitetest_demovfs_Init(Tcl_Interp *); extern int Sqlitetest_func_Init(Tcl_Interp*); extern int Sqlitetest_hexio_Init(Tcl_Interp*); @@ -3720,6 +3778,7 @@ static void init_all(Tcl_Interp *interp){ Sqlitetest9_Init(interp); Sqlitetestasync_Init(interp); Sqlitetest_autoext_Init(interp); + Sqlitetest_blob_Init(interp); Sqlitetest_demovfs_Init(interp); Sqlitetest_func_Init(interp); Sqlitetest_hexio_Init(interp); @@ -3751,6 +3810,9 @@ static void init_all(Tcl_Interp *interp){ Tcl_CreateObjCommand( interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0 ); + Tcl_CreateObjCommand( + interp, "db_last_stmt_ptr", db_last_stmt_ptr, 0, 0 + ); #ifdef SQLITE_SSE Sqlitetestsse_Init(interp); @@ -3759,6 +3821,11 @@ static void init_all(Tcl_Interp *interp){ #endif } +/* Needed for the setrlimit() system call on unix */ +#if defined(unix) +#include +#endif + #define TCLSH_MAIN main /* Needed to fake out mktclapp */ int TCLSH_MAIN(int argc, char **argv){ Tcl_Interp *interp; @@ -3772,6 +3839,17 @@ int TCLSH_MAIN(int argc, char **argv){ } #endif + /* Since the primary use case for this binary is testing of SQLite, + ** be sure to generate core files if we crash */ +#if defined(SQLITE_TEST) && defined(unix) + { struct rlimit x; + getrlimit(RLIMIT_CORE, &x); + x.rlim_cur = x.rlim_max; + setrlimit(RLIMIT_CORE, &x); + } +#endif /* SQLITE_TEST && unix */ + + /* Call sqlite3_shutdown() once before doing anything else. This is to ** test that sqlite3_shutdown() can be safely called by a process before ** sqlite3_initialize() is. */ diff --git a/src/test1.c b/src/test1.c index 56487f6..8f21660 100644 --- a/src/test1.c +++ b/src/test1.c @@ -261,6 +261,8 @@ static int test_io_trace( ** ** Returns true if the program was compiled using clang with the ** -fsanitize=address switch on the command line. False otherwise. +** +** Also return true if the OMIT_MISUSE environment variable exists. */ static int clang_sanitize_address( void *NotUsed, @@ -274,6 +276,7 @@ static int clang_sanitize_address( res = 1; # endif #endif + if( res==0 && getenv("OMIT_MISUSE")!=0 ) res = 1; Tcl_SetObjResult(interp, Tcl_NewIntObj(res)); return TCL_OK; } @@ -564,7 +567,7 @@ static int test_get_table_printf( Tcl_DString str; int rc; char *zErr = 0; - int nRow, nCol; + int nRow = 0, nCol = 0; char **aResult; int i; char zBuf[30]; @@ -1569,7 +1572,6 @@ static int test_libversion_number( ** Usage: sqlite3_table_column_metadata DB dbname tblname colname ** */ -#ifdef SQLITE_ENABLE_COLUMN_METADATA static int test_table_column_metadata( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ @@ -1589,14 +1591,14 @@ static int test_table_column_metadata( int primarykey; int autoincrement; - if( objc!=5 ){ + if( objc!=5 && objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB dbname tblname colname"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zDb = Tcl_GetString(objv[2]); zTbl = Tcl_GetString(objv[3]); - zCol = Tcl_GetString(objv[4]); + zCol = objc==5 ? Tcl_GetString(objv[4]) : 0; if( strlen(zDb)==0 ) zDb = 0; @@ -1618,7 +1620,6 @@ static int test_table_column_metadata( return TCL_OK; } -#endif #ifndef SQLITE_OMIT_INCRBLOB @@ -1651,154 +1652,6 @@ static int blobHandleFromObj( return TCL_OK; } -/* -** sqlite3_blob_bytes CHANNEL -*/ -static int test_blob_bytes( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - int nByte; - - if( objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - nByte = sqlite3_blob_bytes(pBlob); - Tcl_SetObjResult(interp, Tcl_NewIntObj(nByte)); - - return TCL_OK; -} - -/* -** sqlite3_blob_close CHANNEL -*/ -static int test_blob_close( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - - if( objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - sqlite3_blob_close(pBlob); - - return TCL_OK; -} - -/* -** sqlite3_blob_read CHANNEL OFFSET N -** -** This command is used to test the sqlite3_blob_read() in ways that -** the Tcl channel interface does not. The first argument should -** be the name of a valid channel created by the [incrblob] method -** of a database handle. This function calls sqlite3_blob_read() -** to read N bytes from offset OFFSET from the underlying SQLite -** blob handle. -** -** On success, a byte-array object containing the read data is -** returned. On failure, the interpreter result is set to the -** text representation of the returned error code (i.e. "SQLITE_NOMEM") -** and a Tcl exception is thrown. -*/ -static int test_blob_read( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - int nByte; - int iOffset; - unsigned char *zBuf = 0; - int rc; - - if( objc!=4 ){ - Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) - || TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte) - ){ - return TCL_ERROR; - } - - if( nByte>0 ){ - zBuf = (unsigned char *)Tcl_Alloc(nByte); - } - rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset); - if( rc==SQLITE_OK ){ - Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte)); - }else{ - Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); - } - Tcl_Free((char *)zBuf); - - return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); -} - -/* -** sqlite3_blob_write CHANNEL OFFSET DATA ?NDATA? -** -** This command is used to test the sqlite3_blob_write() in ways that -** the Tcl channel interface does not. The first argument should -** be the name of a valid channel created by the [incrblob] method -** of a database handle. This function calls sqlite3_blob_write() -** to write the DATA byte-array to the underlying SQLite blob handle. -** at offset OFFSET. -** -** On success, an empty string is returned. On failure, the interpreter -** result is set to the text representation of the returned error code -** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown. -*/ -static int test_blob_write( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - int iOffset; - int rc; - - unsigned char *zBuf; - int nBuf; - - if( objc!=4 && objc!=5 ){ - Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET DATA ?NDATA?"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){ - return TCL_ERROR; - } - - zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf); - if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){ - return TCL_ERROR; - } - rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset); - if( rc!=SQLITE_OK ){ - Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); - } - - return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); -} - static int test_blob_reopen( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ @@ -2267,7 +2120,7 @@ static int test_stmt_status( Tcl_Obj *CONST objv[] ){ int iValue; - int i, op, resetFlag; + int i, op = 0, resetFlag; const char *zOpName; sqlite3_stmt *pStmt; @@ -2301,6 +2154,77 @@ static int test_stmt_status( return TCL_OK; } +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +/* +** Usage: sqlite3_stmt_scanstatus STMT IDX +*/ +static int test_stmt_scanstatus( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_stmt *pStmt; /* First argument */ + int idx; /* Second argument */ + + const char *zName; + const char *zExplain; + sqlite3_int64 nLoop; + sqlite3_int64 nVisit; + double rEst; + int res; + + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX"); + return TCL_ERROR; + } + if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; + + res = sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop); + if( res==0 ){ + Tcl_Obj *pRet = Tcl_NewObj(); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nLoop", -1)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nLoop)); + sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nVisit", -1)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nVisit)); + sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EST, (void*)&rEst); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nEst", -1)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewDoubleObj(rEst)); + sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NAME, (void*)&zName); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zName", -1)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zName, -1)); + sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zExplain", -1)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zExplain, -1)); + Tcl_SetObjResult(interp, pRet); + }else{ + Tcl_ResetResult(interp); + } + return TCL_OK; +} + +/* +** Usage: sqlite3_stmt_scanstatus_reset STMT +*/ +static int test_stmt_scanstatus_reset( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_stmt *pStmt; /* First argument */ + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "STMT"); + return TCL_ERROR; + } + if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; + sqlite3_stmt_scanstatus_reset(pStmt); + return TCL_OK; +} +#endif + /* ** Usage: sqlite3_next_stmt DB STMT ** @@ -2605,7 +2529,7 @@ static int test_bind( ** SQLite selected to call. The TCL test script implements the ** "test_collate" proc. ** -** Note that this will only work with one intepreter at a time, as the +** Note that this will only work with one interpreter at a time, as the ** interp pointer to use when evaluating the TCL script is stored in ** pTestCollateInterp. */ @@ -2717,6 +2641,46 @@ bad_args: return TCL_ERROR; } +/* +** Usage: add_test_utf16bin_collate +** +** Add a utf-16 collation sequence named "utf16bin" to the database +** handle. This collation sequence compares arguments in the same way as the +** built-in collation "binary". +*/ +static int test_utf16bin_collate_func( + void *pCtx, + int nA, const void *zA, + int nB, const void *zB +){ + int nCmp = (nA>nB ? nB : nA); + int res = memcmp(zA, zB, nCmp); + if( res==0 ) res = nA - nB; + return res; +} +static int test_utf16bin_collate( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3 *db; + int rc; + + if( objc!=2 ) goto bad_args; + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + + rc = sqlite3_create_collation(db, "utf16bin", SQLITE_UTF16, 0, + test_utf16bin_collate_func + ); + if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; + return TCL_OK; + +bad_args: + Tcl_WrongNumArgs(interp, 1, objv, "DB"); + return TCL_ERROR; +} + /* ** When the collation needed callback is invoked, record the name of ** the requested collating function here. The recorded name is linked @@ -3134,7 +3098,7 @@ static int test_bind_double( ){ sqlite3_stmt *pStmt; int idx; - double value; + double value = 0; int rc; const char *zVal; int i; @@ -3675,6 +3639,7 @@ static int test_prepare_v2( ){ sqlite3 *db; const char *zSql; + char *zCopy = 0; /* malloc() copy of zSql */ int bytes; const char *zTail = 0; sqlite3_stmt *pStmt = 0; @@ -3690,11 +3655,25 @@ static int test_prepare_v2( zSql = Tcl_GetString(objv[2]); if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; - rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0); + /* Instead of using zSql directly, make a copy into a buffer obtained + ** directly from malloc(). The idea is to make it easier for valgrind + ** to spot buffer overreads. */ + if( bytes>=0 ){ + zCopy = malloc(bytes); + memcpy(zCopy, zSql, bytes); + }else{ + int n = (int)strlen(zSql) + 1; + zCopy = malloc(n); + memcpy(zCopy, zSql, n); + } + rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, objc>=5 ? &zTail : 0); + free(zCopy); + zTail = &zSql[(zTail - zCopy)]; + assert(rc==SQLITE_OK || pStmt==0); Tcl_ResetResult(interp); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; - if( zTail && objc>=5 ){ + if( rc==SQLITE_OK && zTail && objc>=5 ){ if( bytes>=0 ){ bytes = bytes - (int)(zTail-zSql); } @@ -3718,7 +3697,7 @@ static int test_prepare_v2( ** Usage: sqlite3_prepare_tkt3134 DB ** ** Generate a prepared statement for a zero-byte string as a test -** for ticket #3134. The string should be preceeded by a zero byte. +** for ticket #3134. The string should be preceded by a zero byte. */ static int test_prepare_tkt3134( void * clientData, @@ -5473,12 +5452,13 @@ static int test_limit( { "SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, { "SQLITE_LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER }, { "SQLITE_LIMIT_TRIGGER_DEPTH", SQLITE_LIMIT_TRIGGER_DEPTH }, + { "SQLITE_LIMIT_WORKER_THREADS", SQLITE_LIMIT_WORKER_THREADS }, /* Out of range test cases */ { "SQLITE_LIMIT_TOOSMALL", -1, }, - { "SQLITE_LIMIT_TOOBIG", SQLITE_LIMIT_TRIGGER_DEPTH+1 }, + { "SQLITE_LIMIT_TOOBIG", SQLITE_LIMIT_WORKER_THREADS+1 }, }; - int i, id; + int i, id = 0; int val; const char *zId; @@ -5711,10 +5691,11 @@ static int test_wal_checkpoint_v2( int nCkpt = -555; Tcl_Obj *pRet; - const char * aMode[] = { "passive", "full", "restart", 0 }; + const char * aMode[] = { "passive", "full", "restart", "truncate", 0 }; assert( SQLITE_CHECKPOINT_PASSIVE==0 ); assert( SQLITE_CHECKPOINT_FULL==1 ); assert( SQLITE_CHECKPOINT_RESTART==2 ); + assert( SQLITE_CHECKPOINT_TRUNCATE==3 ); if( objc!=3 && objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB MODE ?NAME?"); @@ -5724,15 +5705,18 @@ static int test_wal_checkpoint_v2( if( objc==4 ){ zDb = Tcl_GetString(objv[3]); } - if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) - || Tcl_GetIndexFromObj(interp, objv[2], aMode, "mode", 0, &eMode) - ){ + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) || ( + TCL_OK!=Tcl_GetIntFromObj(0, objv[2], &eMode) + && TCL_OK!=Tcl_GetIndexFromObj(interp, objv[2], aMode, "mode", 0, &eMode) + )){ return TCL_ERROR; } rc = sqlite3_wal_checkpoint_v2(db, zDb, eMode, &nLog, &nCkpt); if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ - Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE); + const char *zErrCode = sqlite3ErrName(rc); + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, zErrCode, " - ", (char *)sqlite3_errmsg(db), 0); return TCL_ERROR; } @@ -5745,6 +5729,43 @@ static int test_wal_checkpoint_v2( return TCL_OK; } +/* +** tclcmd: sqlite3_wal_autocheckpoint db VALUE +*/ +static int test_wal_autocheckpoint( + ClientData clientData, /* Unused */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3 *db; + int rc; + int iVal; + + + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB VALUE"); + return TCL_ERROR; + } + + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) + || Tcl_GetIntFromObj(0, objv[2], &iVal) + ){ + return TCL_ERROR; + } + + rc = sqlite3_wal_autocheckpoint(db, iVal); + Tcl_ResetResult(interp); + if( rc!=SQLITE_OK ){ + const char *zErrCode = sqlite3ErrName(rc); + Tcl_SetObjResult(interp, Tcl_NewStringObj(zErrCode, -1)); + return TCL_ERROR; + } + + return TCL_OK; +} + + /* ** tclcmd: test_sqlite3_log ?SCRIPT? */ @@ -5895,6 +5916,7 @@ static int test_test_control( int i; } aVerb[] = { { "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT }, + { "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP }, }; int iVerb; int iFlag; @@ -5922,6 +5944,19 @@ static int test_test_control( sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, val); break; } + + case SQLITE_TESTCTRL_SORTER_MMAP: { + int val; + sqlite3 *db; + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 2, objv, "DB LIMIT"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR; + sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, val); + break; + } } Tcl_ResetResult(interp); @@ -6238,7 +6273,8 @@ static int optimization_control( { "transitive", SQLITE_Transitive }, { "subquery-coroutine", SQLITE_SubqCoroutine }, { "omit-noop-join", SQLITE_OmitNoopJoin }, - { "stat3", SQLITE_Stat3 }, + { "stat3", SQLITE_Stat34 }, + { "stat4", SQLITE_Stat34 }, }; if( objc!=4 ){ @@ -6281,6 +6317,7 @@ static int tclLoadStaticExtensionCmd( ){ extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); + extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); @@ -6296,6 +6333,7 @@ static int tclLoadStaticExtensionCmd( } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "closure", sqlite3_closure_init }, + { "eval", sqlite3_eval_init }, { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, @@ -6335,6 +6373,298 @@ static int tclLoadStaticExtensionCmd( return TCL_OK; } +/* +** sorter_test_fakeheap BOOL +** +*/ +static int sorter_test_fakeheap( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int bArg; + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "BOOL"); + return TCL_ERROR; + } + + if( Tcl_GetBooleanFromObj(interp, objv[1], &bArg) ){ + return TCL_ERROR; + } + + if( bArg ){ + if( sqlite3GlobalConfig.pHeap==0 ){ + sqlite3GlobalConfig.pHeap = SQLITE_INT_TO_PTR(-1); + } + }else{ + if( sqlite3GlobalConfig.pHeap==SQLITE_INT_TO_PTR(-1) ){ + sqlite3GlobalConfig.pHeap = 0; + } + } + + Tcl_ResetResult(interp); + return TCL_OK; +} + +/* +** sorter_test_sort4_helper DB SQL1 NSTEP SQL2 +** +** Compile SQL statement $SQL1 and step it $NSTEP times. For each row, +** check that the leftmost and rightmost columns returned are both integers, +** and that both contain the same value. +** +** Then execute statement $SQL2. Check that the statement returns the same +** set of integers in the same order as in the previous step (using $SQL1). +*/ +static int sorter_test_sort4_helper( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + const char *zSql1; + const char *zSql2; + int nStep; + int iStep; + int iCksum1 = 0; + int iCksum2 = 0; + int rc; + int iB; + sqlite3 *db; + sqlite3_stmt *pStmt; + + if( objc!=5 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB SQL1 NSTEP SQL2"); + return TCL_ERROR; + } + + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + zSql1 = Tcl_GetString(objv[2]); + if( Tcl_GetIntFromObj(interp, objv[3], &nStep) ) return TCL_ERROR; + zSql2 = Tcl_GetString(objv[4]); + + rc = sqlite3_prepare_v2(db, zSql1, -1, &pStmt, 0); + if( rc!=SQLITE_OK ) goto sql_error; + + iB = sqlite3_column_count(pStmt)-1; + for(iStep=0; iStep0 ) w[1]++; + Tcl_SetObjResult(interp, Tcl_NewIntObj(w[1])); + break; + } + case 3: { + a = malloc( sizeof(int)*10 ); + for(j=0; j<10; j++) a[j] = j; + free(a); + Tcl_SetObjResult(interp, Tcl_NewIntObj(a[i])); + break; + } + case 4: { + Tcl_Panic("Deliberate panic"); + break; + } + } + return TCL_OK; +} + /* ** Register commands with the TCL interpreter. @@ -6352,6 +6682,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_max_blobsize; extern int sqlite3BtreeSharedCacheReport(void*, Tcl_Interp*,int,Tcl_Obj*CONST*); + static int iZero = 0; static struct { char *zName; Tcl_CmdProc *xProc; @@ -6404,6 +6735,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { + { "bad_behavior", test_bad_behavior, (void*)&iZero }, { "sqlite3_connection_pointer", get_sqlite_pointer, 0 }, { "sqlite3_bind_int", test_bind_int, 0 }, { "sqlite3_bind_zeroblob", test_bind_zeroblob, 0 }, @@ -6537,6 +6869,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "add_test_collate", test_collate, 0 }, { "add_test_collate_needed", test_collate_needed, 0 }, { "add_test_function", test_function, 0 }, + { "add_test_utf16bin_collate", test_utf16bin_collate, 0 }, #endif { "sqlite3_test_errstr", test_errstr, 0 }, { "tcl_variable_type", tcl_variable_type, 0 }, @@ -6545,15 +6878,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0}, #endif { "sqlite3_libversion_number", test_libversion_number, 0 }, -#ifdef SQLITE_ENABLE_COLUMN_METADATA { "sqlite3_table_column_metadata", test_table_column_metadata, 0 }, -#endif #ifndef SQLITE_OMIT_INCRBLOB - { "sqlite3_blob_read", test_blob_read, 0 }, - { "sqlite3_blob_write", test_blob_write, 0 }, { "sqlite3_blob_reopen", test_blob_reopen, 0 }, - { "sqlite3_blob_bytes", test_blob_bytes, 0 }, - { "sqlite3_blob_close", test_blob_close, 0 }, #endif { "pcache_stats", test_pcache_stats, 0 }, #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY @@ -6561,6 +6888,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ #endif { "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 }, { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0 }, + { "sqlite3_wal_autocheckpoint",test_wal_autocheckpoint, 0 }, { "test_sqlite3_log", test_sqlite3_log, 0 }, #ifndef SQLITE_OMIT_EXPLAIN { "print_explain_query_plan", test_print_eqp, 0 }, @@ -6570,6 +6898,19 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "getrusage", test_getrusage }, #endif { "load_static_extension", tclLoadStaticExtensionCmd }, + { "sorter_test_fakeheap", sorter_test_fakeheap }, + { "sorter_test_sort4_helper", sorter_test_sort4_helper }, +#ifdef SQLITE_USER_AUTHENTICATION + { "sqlite3_user_authenticate", test_user_authenticate, 0 }, + { "sqlite3_user_add", test_user_add, 0 }, + { "sqlite3_user_change", test_user_change, 0 }, + { "sqlite3_user_delete", test_user_delete, 0 }, +#endif +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + { "sqlite3_stmt_scanstatus", test_stmt_scanstatus, 0 }, + { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset, 0 }, +#endif + }; static int bitmask_size = sizeof(Bitmask)*8; int i; diff --git a/src/test2.c b/src/test2.c index 58f271f..7192ddf 100644 --- a/src/test2.c +++ b/src/test2.c @@ -310,7 +310,7 @@ static int page_get( ){ Pager *pPager; char zBuf[100]; - DbPage *pPage; + DbPage *pPage = 0; int pgno; int rc; if( argc!=3 ){ diff --git a/src/test8.c b/src/test8.c index 8bc835d..f37a28c 100644 --- a/src/test8.c +++ b/src/test8.c @@ -648,12 +648,12 @@ static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ ** indeed the hash of the supplied idxStr. */ static int hashString(const char *zString){ - int val = 0; + u32 val = 0; int ii; for(ii=0; zString[ii]; ii++){ val = (val << 3) + (int)zString[ii]; } - return val; + return (int)(val&0x7fffffff); } /* @@ -777,11 +777,11 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ sqlite3_stmt *pStmt = 0; Tcl_Interp *interp = pVtab->interp; - int nRow; + int nRow = 0; int useIdx = 0; int rc = SQLITE_OK; int useCost = 0; - double cost; + double cost = 0; int isIgnoreUsable = 0; if( Tcl_GetVar(interp, "echo_module_ignore_usable", TCL_GLOBAL_ONLY) ){ isIgnoreUsable = 1; @@ -927,7 +927,7 @@ int echoUpdate( sqlite3 *db = pVtab->db; int rc = SQLITE_OK; - sqlite3_stmt *pStmt; + sqlite3_stmt *pStmt = 0; char *z = 0; /* SQL statement to execute */ int bindArgZero = 0; /* True to bind apData[0] to sql var no. nData */ int bindArgOne = 0; /* True to bind apData[1] to sql var no. 1 */ diff --git a/src/test_blob.c b/src/test_blob.c new file mode 100644 index 0000000..d88c913 --- /dev/null +++ b/src/test_blob.c @@ -0,0 +1,319 @@ +/* +** 2014 October 30 +** +** 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. +** +************************************************************************* +** +*/ +#include "sqliteInt.h" +#include "tcl.h" +#include +#include +#include + +/* These functions are implemented in main.c. */ +extern const char *sqlite3ErrName(int); + +/* From test1.c: */ +extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); +extern void *sqlite3TestTextToPtr(const char *z); + +/* +** Return a pointer to a buffer containing a text representation of the +** pointer passed as the only argument. The original pointer may be extracted +** from the text using sqlite3TestTextToPtr(). +*/ +static char *ptrToText(void *p){ + static char buf[100]; + sqlite3_snprintf(sizeof(buf)-1, buf, "%p", p); + return buf; +} + +/* +** Attempt to extract a blob handle (type sqlite3_blob*) from the Tcl +** object passed as the second argument. If successful, set *ppBlob to +** point to the blob handle and return TCL_OK. Otherwise, store an error +** message in the tcl interpreter and return TCL_ERROR. The final value +** of *ppBlob is undefined in this case. +** +** If the object contains a string that begins with "incrblob_", then it +** is assumed to be the name of a Tcl channel opened using the [db incrblob] +** command (see tclsqlite.c). Otherwise, it is assumed to be a pointer +** encoded using the ptrToText() routine or similar. +*/ +static int blobHandleFromObj( + Tcl_Interp *interp, + Tcl_Obj *pObj, + sqlite3_blob **ppBlob +){ + char *z; + int n; + + z = Tcl_GetStringFromObj(pObj, &n); + if( n==0 ){ + *ppBlob = 0; + }else if( n>9 && 0==memcmp("incrblob_", z, 9) ){ + int notUsed; + Tcl_Channel channel; + ClientData instanceData; + + channel = Tcl_GetChannel(interp, z, ¬Used); + if( !channel ) return TCL_ERROR; + + Tcl_Flush(channel); + Tcl_Seek(channel, 0, SEEK_SET); + + instanceData = Tcl_GetChannelInstanceData(channel); + *ppBlob = *((sqlite3_blob **)instanceData); + }else{ + *ppBlob = (sqlite3_blob*)sqlite3TestTextToPtr(z); + } + + return TCL_OK; +} + +/* +** Like Tcl_GetString(), except that if the string is 0 bytes in size, a +** NULL Pointer is returned. +*/ +static char *blobStringFromObj(Tcl_Obj *pObj){ + int n; + char *z; + z = Tcl_GetStringFromObj(pObj, &n); + return (n ? z : 0); +} + +/* +** sqlite3_blob_open DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME +** +** Tcl test harness for the sqlite3_blob_open() function. +*/ +static int test_blob_open( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* Calling TCL interpreter */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3 *db; + const char *zDb; + const char *zTable; + const char *zColumn; + sqlite_int64 iRowid; + int flags; + const char *zVarname; + int nVarname; + + sqlite3_blob *pBlob = (sqlite3_blob*)0xFFFFFFFF; + int rc; + + if( objc!=8 ){ + const char *zUsage = "DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME"; + Tcl_WrongNumArgs(interp, 1, objv, zUsage); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + zDb = Tcl_GetString(objv[2]); + zTable = blobStringFromObj(objv[3]); + zColumn = Tcl_GetString(objv[4]); + if( Tcl_GetWideIntFromObj(interp, objv[5], &iRowid) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[6], &flags) ) return TCL_ERROR; + zVarname = Tcl_GetStringFromObj(objv[7], &nVarname); + + if( nVarname>0 ){ + rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, &pBlob); + Tcl_SetVar(interp, zVarname, ptrToText(pBlob), 0); + }else{ + rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, 0); + } + + if( rc==SQLITE_OK ){ + Tcl_ResetResult(interp); + }else{ + Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); + return TCL_ERROR; + } + return TCL_OK; +} + + +/* +** sqlite3_blob_close HANDLE +*/ +static int test_blob_close( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + int rc; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + rc = sqlite3_blob_close(pBlob); + + if( rc ){ + Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); + }else{ + Tcl_ResetResult(interp); + } + return TCL_OK; +} + +/* +** sqlite3_blob_bytes HANDLE +*/ +static int test_blob_bytes( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + int nByte; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + nByte = sqlite3_blob_bytes(pBlob); + Tcl_SetObjResult(interp, Tcl_NewIntObj(nByte)); + + return TCL_OK; +} + +/* +** sqlite3_blob_read CHANNEL OFFSET N +** +** This command is used to test the sqlite3_blob_read() in ways that +** the Tcl channel interface does not. The first argument should +** be the name of a valid channel created by the [incrblob] method +** of a database handle. This function calls sqlite3_blob_read() +** to read N bytes from offset OFFSET from the underlying SQLite +** blob handle. +** +** On success, a byte-array object containing the read data is +** returned. On failure, the interpreter result is set to the +** text representation of the returned error code (i.e. "SQLITE_NOMEM") +** and a Tcl exception is thrown. +*/ +static int test_blob_read( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + int nByte; + int iOffset; + unsigned char *zBuf = 0; + int rc; + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) + || TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte) + ){ + return TCL_ERROR; + } + + if( nByte>0 ){ + zBuf = (unsigned char *)Tcl_Alloc(nByte); + } + rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset); + if( rc==SQLITE_OK ){ + Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte)); + }else{ + Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); + } + Tcl_Free((char *)zBuf); + + return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); +} + +/* +** sqlite3_blob_write HANDLE OFFSET DATA ?NDATA? +** +** This command is used to test the sqlite3_blob_write() in ways that +** the Tcl channel interface does not. The first argument should +** be the name of a valid channel created by the [incrblob] method +** of a database handle. This function calls sqlite3_blob_write() +** to write the DATA byte-array to the underlying SQLite blob handle. +** at offset OFFSET. +** +** On success, an empty string is returned. On failure, the interpreter +** result is set to the text representation of the returned error code +** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown. +*/ +static int test_blob_write( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + int iOffset; + int rc; + + unsigned char *zBuf; + int nBuf; + + if( objc!=4 && objc!=5 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET DATA ?NDATA?"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){ + return TCL_ERROR; + } + + zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf); + if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){ + return TCL_ERROR; + } + rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset); + if( rc!=SQLITE_OK ){ + Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); + } + + return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); +} + + +/* +** Register commands with the TCL interpreter. +*/ +int Sqlitetest_blob_Init(Tcl_Interp *interp){ + static struct { + char *zName; + Tcl_ObjCmdProc *xProc; + } aObjCmd[] = { + { "sqlite3_blob_open", test_blob_open }, + { "sqlite3_blob_close", test_blob_close }, + { "sqlite3_blob_bytes", test_blob_bytes }, + { "sqlite3_blob_read", test_blob_read }, + { "sqlite3_blob_write", test_blob_write }, + }; + int i; + for(i=0; ipReal, aData, pMain->nPagesize, iOff); pMain->aCksum[ii] = genCksum(aData, pMain->nPagesize); - if( ii+1==pMain->nPage && rc==SQLITE_IOERR_SHORT_READ ) rc = SQLITE_OK; + if( ii+1==(int)pMain->nPage && rc==SQLITE_IOERR_SHORT_READ ){ + rc = SQLITE_OK; + } } } @@ -550,7 +552,8 @@ static int jtWrite( */ }else{ u32 pgno = (u32)(iOfst/p->nPagesize + 1); - assert( (iAmt==1||iAmt==p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 ); + assert( (iAmt==1||iAmt==(int)p->nPagesize) && + ((iOfst+iAmt)%p->nPagesize)==0 ); assert( pgno<=p->nPage || p->nSync>0 ); assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) ); } diff --git a/src/test_malloc.c b/src/test_malloc.c index e3cfcaa..1ea4de5 100644 --- a/src/test_malloc.c +++ b/src/test_malloc.c @@ -696,6 +696,12 @@ static int test_memdebug_pending( return TCL_OK; } +/* +** The following global variable keeps track of the number of tests +** that have run. This variable is only useful when running in the +** debugger. +*/ +static int sqlite3_memdebug_title_count = 0; /* ** Usage: sqlite3_memdebug_settitle TITLE @@ -713,6 +719,7 @@ static int test_memdebug_settitle( int objc, Tcl_Obj *CONST objv[] ){ + sqlite3_memdebug_title_count++; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "TITLE"); return TCL_ERROR; @@ -880,7 +887,7 @@ static int test_memdebug_log( ** ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH. ** The buffer is static and is of limited size. N might be -** adjusted downward as needed to accomodate the requested size. +** adjusted downward as needed to accommodate the requested size. ** The revised value of N is returned. ** ** A negative SIZE causes the buffer pointer to be NULL. @@ -920,7 +927,7 @@ static int test_config_scratch( ** ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE. ** The buffer is static and is of limited size. N might be -** adjusted downward as needed to accomodate the requested size. +** adjusted downward as needed to accommodate the requested size. ** The revised value of N is returned. ** ** A negative SIZE causes the buffer pointer to be NULL. @@ -1253,6 +1260,35 @@ static int test_config_cis( return TCL_OK; } +/* +** Usage: sqlite3_config_pmasz INTEGER +** +** Set the minimum PMA size. +*/ +static int test_config_pmasz( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int rc; + int iPmaSz; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "BOOL"); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[1], &iPmaSz) ){ + return TCL_ERROR; + } + + rc = sqlite3_config(SQLITE_CONFIG_PMASZ, iPmaSz); + Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); + + return TCL_OK; +} + + /* ** Usage: sqlite3_dump_memsys3 FILENAME ** sqlite3_dump_memsys5 FILENAME @@ -1302,7 +1338,7 @@ static int test_status( Tcl_Obj *CONST objv[] ){ int rc, iValue, mxValue; - int i, op, resetFlag; + int i, op = 0, resetFlag; const char *zOpName; static const struct { const char *zName; @@ -1359,7 +1395,7 @@ static int test_db_status( Tcl_Obj *CONST objv[] ){ int rc, iValue, mxValue; - int i, op, resetFlag; + int i, op = 0, resetFlag; const char *zOpName; sqlite3 *db; extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); @@ -1506,6 +1542,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ { "sqlite3_config_error", test_config_error ,0 }, { "sqlite3_config_uri", test_config_uri ,0 }, { "sqlite3_config_cis", test_config_cis ,0 }, + { "sqlite3_config_pmasz", test_config_pmasz ,0 }, { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 }, { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 }, { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 }, diff --git a/src/test_multiplex.c b/src/test_multiplex.c index 427cc65..8f204c6 100644 --- a/src/test_multiplex.c +++ b/src/test_multiplex.c @@ -406,7 +406,7 @@ static void multiplexControlFunc( ){ int rc = SQLITE_OK; sqlite3 *db = sqlite3_context_db_handle(context); - int op; + int op = 0; int iVal; if( !db || argc!=2 ){ @@ -535,7 +535,7 @@ static int multiplexOpen( /* assign pointers to extra space allocated */ memset(pGroup, 0, sz); pMultiplexOpen->pGroup = pGroup; - pGroup->bEnabled = -1; + pGroup->bEnabled = (unsigned char)-1; pGroup->bTruncate = sqlite3_uri_boolean(zUri, "truncate", (flags & SQLITE_OPEN_MAIN_DB)==0); pGroup->szChunk = (int)sqlite3_uri_int64(zUri, "chunksize", @@ -1002,6 +1002,26 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){ /* no-op these */ rc = SQLITE_OK; break; + case SQLITE_FCNTL_PRAGMA: { + char **aFcntl = (char**)pArg; + if( aFcntl[1] && sqlite3_stricmp(aFcntl[1],"multiplex_truncate")==0 ){ + if( aFcntl[2] && aFcntl[2][0] ){ + if( sqlite3_stricmp(aFcntl[2], "on")==0 + || sqlite3_stricmp(aFcntl[2], "1")==0 ){ + pGroup->bTruncate = 1; + }else + if( sqlite3_stricmp(aFcntl[2], "off")==0 + || sqlite3_stricmp(aFcntl[2], "0")==0 ){ + pGroup->bTruncate = 0; + } + } + aFcntl[0] = sqlite3_mprintf(pGroup->bTruncate ? "on" : "off"); + rc = SQLITE_OK; + break; + } + /* If the multiplexor does not handle the pragma, pass it through + ** into the default case. */ + } default: pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0); if( pSubOpen ){ diff --git a/src/test_quota.c b/src/test_quota.c index 80ebd05..e8e0b34 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -889,7 +889,7 @@ int sqlite3_quota_set( ** management, update its size. */ int sqlite3_quota_file(const char *zFilename){ - char *zFull; + char *zFull = 0; sqlite3_file *fd; int rc; int outFlags = 0; diff --git a/src/test_schema.c b/src/test_schema.c index 00a9f4d..4ee1819 100644 --- a/src/test_schema.c +++ b/src/test_schema.c @@ -189,7 +189,7 @@ static int schemaNext(sqlite3_vtab_cursor *cur){ /* Set zSql to the SQL to pull the list of tables from the ** sqlite_master (or sqlite_temp_master) table of the database - ** identfied by the row pointed to by the SQL statement pCur->pDbList + ** identified by the row pointed to by the SQL statement pCur->pDbList ** (iterating through a "PRAGMA database_list;" statement). */ if( sqlite3_column_int(pCur->pDbList, 0)==1 ){ diff --git a/src/test_vfs.c b/src/test_vfs.c index 7ee2a93..37081af 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -421,7 +421,7 @@ static int tvfsSync(sqlite3_file *pFile, int flags){ Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_SYNC_MASK ){ - char *zFlags; + char *zFlags = 0; switch( flags ){ case SQLITE_SYNC_NORMAL: @@ -1225,7 +1225,7 @@ static int testvfs_obj_cmd( case CMD_CANTOPENERR: case CMD_IOERR: case CMD_FULLERR: { - TestFaultInject *pTest; + TestFaultInject *pTest = 0; int iRet; switch( aSubcmd[i].eCmd ){ diff --git a/src/threads.c b/src/threads.c new file mode 100644 index 0000000..16f5249 --- /dev/null +++ b/src/threads.c @@ -0,0 +1,265 @@ +/* +** 2012 July 21 +** +** 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 presents a simple cross-platform threading interface for +** use internally by SQLite. +** +** A "thread" can be created using sqlite3ThreadCreate(). This thread +** runs independently of its creator until it is joined using +** sqlite3ThreadJoin(), at which point it terminates. +** +** Threads do not have to be real. It could be that the work of the +** "thread" is done by the main thread at either the sqlite3ThreadCreate() +** or sqlite3ThreadJoin() call. This is, in fact, what happens in +** single threaded systems. Nothing in SQLite requires multiple threads. +** This interface exists so that applications that want to take advantage +** of multiple cores can do so, while also allowing applications to stay +** single-threaded if desired. +*/ +#include "sqliteInt.h" +#if SQLITE_OS_WIN +# include "os_win.h" +#endif + +#if SQLITE_MAX_WORKER_THREADS>0 + +/********************************* Unix Pthreads ****************************/ +#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0 + +#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ +#include + +/* A running thread */ +struct SQLiteThread { + pthread_t tid; /* Thread ID */ + int done; /* Set to true when thread finishes */ + void *pOut; /* Result returned by the thread */ + void *(*xTask)(void*); /* The thread routine */ + void *pIn; /* Argument to the thread */ +}; + +/* Create a new thread */ +int sqlite3ThreadCreate( + SQLiteThread **ppThread, /* OUT: Write the thread object here */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + SQLiteThread *p; + int rc; + + assert( ppThread!=0 ); + assert( xTask!=0 ); + /* This routine is never used in single-threaded mode */ + assert( sqlite3GlobalConfig.bCoreMutex!=0 ); + + *ppThread = 0; + p = sqlite3Malloc(sizeof(*p)); + if( p==0 ) return SQLITE_NOMEM; + memset(p, 0, sizeof(*p)); + p->xTask = xTask; + p->pIn = pIn; + if( sqlite3FaultSim(200) ){ + rc = 1; + }else{ + rc = pthread_create(&p->tid, 0, xTask, pIn); + } + if( rc ){ + p->done = 1; + p->pOut = xTask(pIn); + } + *ppThread = p; + return SQLITE_OK; +} + +/* Get the results of the thread */ +int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ + int rc; + + assert( ppOut!=0 ); + if( NEVER(p==0) ) return SQLITE_NOMEM; + if( p->done ){ + *ppOut = p->pOut; + rc = SQLITE_OK; + }else{ + rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK; + } + sqlite3_free(p); + return rc; +} + +#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */ +/******************************** End Unix Pthreads *************************/ + + +/********************************* Win32 Threads ****************************/ +#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0 + +#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ +#include + +/* A running thread */ +struct SQLiteThread { + void *tid; /* The thread handle */ + unsigned id; /* The thread identifier */ + void *(*xTask)(void*); /* The routine to run as a thread */ + void *pIn; /* Argument to xTask */ + void *pResult; /* Result of xTask */ +}; + +/* Thread procedure Win32 compatibility shim */ +static unsigned __stdcall sqlite3ThreadProc( + void *pArg /* IN: Pointer to the SQLiteThread structure */ +){ + SQLiteThread *p = (SQLiteThread *)pArg; + + assert( p!=0 ); +#if 0 + /* + ** This assert appears to trigger spuriously on certain + ** versions of Windows, possibly due to _beginthreadex() + ** and/or CreateThread() not fully setting their thread + ** ID parameter before starting the thread. + */ + assert( p->id==GetCurrentThreadId() ); +#endif + assert( p->xTask!=0 ); + p->pResult = p->xTask(p->pIn); + + _endthreadex(0); + return 0; /* NOT REACHED */ +} + +/* Create a new thread */ +int sqlite3ThreadCreate( + SQLiteThread **ppThread, /* OUT: Write the thread object here */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + SQLiteThread *p; + + assert( ppThread!=0 ); + assert( xTask!=0 ); + *ppThread = 0; + p = sqlite3Malloc(sizeof(*p)); + if( p==0 ) return SQLITE_NOMEM; + if( sqlite3GlobalConfig.bCoreMutex==0 ){ + memset(p, 0, sizeof(*p)); + }else{ + p->xTask = xTask; + p->pIn = pIn; + p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id); + if( p->tid==0 ){ + memset(p, 0, sizeof(*p)); + } + } + if( p->xTask==0 ){ + p->id = GetCurrentThreadId(); + p->pResult = xTask(pIn); + } + *ppThread = p; + return SQLITE_OK; +} + +DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */ + +/* Get the results of the thread */ +int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ + DWORD rc; + BOOL bRc; + + assert( ppOut!=0 ); + if( NEVER(p==0) ) return SQLITE_NOMEM; + if( p->xTask==0 ){ + assert( p->id==GetCurrentThreadId() ); + rc = WAIT_OBJECT_0; + assert( p->tid==0 ); + }else{ + assert( p->id!=0 && p->id!=GetCurrentThreadId() ); + rc = sqlite3Win32Wait((HANDLE)p->tid); + assert( rc!=WAIT_IO_COMPLETION ); + bRc = CloseHandle((HANDLE)p->tid); + assert( bRc ); + } + if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; + sqlite3_free(p); + return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR; +} + +#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT */ +/******************************** End Win32 Threads *************************/ + + +/********************************* Single-Threaded **************************/ +#ifndef SQLITE_THREADS_IMPLEMENTED +/* +** This implementation does not actually create a new thread. It does the +** work of the thread in the main thread, when either the thread is created +** or when it is joined +*/ + +/* A running thread */ +struct SQLiteThread { + void *(*xTask)(void*); /* The routine to run as a thread */ + void *pIn; /* Argument to xTask */ + void *pResult; /* Result of xTask */ +}; + +/* Create a new thread */ +int sqlite3ThreadCreate( + SQLiteThread **ppThread, /* OUT: Write the thread object here */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + SQLiteThread *p; + + assert( ppThread!=0 ); + assert( xTask!=0 ); + *ppThread = 0; + p = sqlite3Malloc(sizeof(*p)); + if( p==0 ) return SQLITE_NOMEM; + if( (SQLITE_PTR_TO_INT(p)/17)&1 ){ + p->xTask = xTask; + p->pIn = pIn; + }else{ + p->xTask = 0; + p->pResult = xTask(pIn); + } + *ppThread = p; + return SQLITE_OK; +} + +/* Get the results of the thread */ +int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ + + assert( ppOut!=0 ); + if( NEVER(p==0) ) return SQLITE_NOMEM; + if( p->xTask ){ + *ppOut = p->xTask(p->pIn); + }else{ + *ppOut = p->pResult; + } + sqlite3_free(p); + +#if defined(SQLITE_TEST) + { + void *pTstAlloc = sqlite3Malloc(10); + if (!pTstAlloc) return SQLITE_NOMEM; + sqlite3_free(pTstAlloc); + } +#endif + + return SQLITE_OK; +} + +#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */ +/****************************** End Single-Threaded *************************/ +#endif /* SQLITE_MAX_WORKER_THREADS>0 */ diff --git a/src/tokenize.c b/src/tokenize.c index 4017c3b..f0360ee 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -77,7 +77,7 @@ const unsigned char ebcdicToAscii[] = { ** end result. ** ** Ticket #1066. the SQL standard does not allow '$' in the -** middle of identfiers. But many SQL implementations do. +** middle of identifiers. But many SQL implementations do. ** SQLite will allow '$' in identifiers for compatibility. ** But the feature is undocumented. */ @@ -102,6 +102,7 @@ const char sqlite3IsEbcdicIdChar[] = { }; #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) #endif +int sqlite3IsIdChar(u8 c){ return IdChar(c); } /* @@ -390,6 +391,9 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ int mxSqlLen; /* Max length of an SQL string */ +#ifdef SQLITE_ENABLE_API_ARMOR + if( zSql==0 || pzErrMsg==0 ) return SQLITE_MISUSE_BKPT; +#endif mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; if( db->nVdbeActive==0 ){ db->u1.isInterrupted = 0; @@ -398,7 +402,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ pParse->zTail = zSql; i = 0; assert( pzErrMsg!=0 ); - pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3Malloc); + pEngine = sqlite3ParserAlloc(sqlite3Malloc); if( pEngine==0 ){ db->mallocFailed = 1; return SQLITE_NOMEM; diff --git a/src/trigger.c b/src/trigger.c index 01f7b21..d2e7b5a 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -127,7 +127,7 @@ void sqlite3BeginTrigger( ** ^^^^^^^^ ** ** To maintain backwards compatibility, ignore the database - ** name on pTableName if we are reparsing our of SQLITE_MASTER. + ** name on pTableName if we are reparsing out of SQLITE_MASTER. */ if( db->init.busy && iDb!=1 ){ sqlite3DbFree(db, pTableName->a[0].zDatabase); @@ -180,8 +180,7 @@ void sqlite3BeginTrigger( goto trigger_cleanup; } assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), - zName, sqlite3Strlen30(zName)) ){ + if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); }else{ @@ -324,13 +323,12 @@ void sqlite3FinishTrigger( Trigger *pLink = pTrig; Hash *pHash = &db->aDb[iDb].pSchema->trigHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - pTrig = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), pTrig); + pTrig = sqlite3HashInsert(pHash, zName, pTrig); if( pTrig ){ db->mallocFailed = 1; }else if( pLink->pSchema==pLink->pTabSchema ){ Table *pTab; - int n = sqlite3Strlen30(pLink->table); - pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table, n); + pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table); assert( pTab!=0 ); pLink->pNext = pTab->pTrigger; pTab->pTrigger = pLink; @@ -489,7 +487,6 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){ int i; const char *zDb; const char *zName; - int nName; sqlite3 *db = pParse->db; if( db->mallocFailed ) goto drop_trigger_cleanup; @@ -500,13 +497,12 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){ assert( pName->nSrc==1 ); zDb = pName->a[0].zDatabase; zName = pName->a[0].zName; - nName = sqlite3Strlen30(zName); assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); - pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName); + pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName); if( pTrigger ) break; } if( !pTrigger ){ @@ -529,8 +525,7 @@ drop_trigger_cleanup: ** is set on. */ static Table *tableOfTrigger(Trigger *pTrigger){ - int n = sqlite3Strlen30(pTrigger->table); - return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n); + return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table); } @@ -602,7 +597,7 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pHash = &(db->aDb[iDb].pSchema->trigHash); - pTrigger = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), 0); + pTrigger = sqlite3HashInsert(pHash, zName, 0); if( ALWAYS(pTrigger) ){ if( pTrigger->pSchema==pTrigger->pTabSchema ){ Table *pTab = tableOfTrigger(pTrigger); diff --git a/src/update.c b/src/update.c index e152e90..3af4017 100644 --- a/src/update.c +++ b/src/update.c @@ -327,7 +327,7 @@ void sqlite3Update( } /* If we are trying to update a view, realize that view into - ** a ephemeral table. + ** an ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( isView ){ @@ -431,8 +431,8 @@ void sqlite3Update( /* Top of the update loop */ if( okOnePass ){ - if( aToOpen[iDataCur-iBaseCur] ){ - assert( pPk!=0 ); + if( aToOpen[iDataCur-iBaseCur] && !isView ){ + assert( pPk ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey); VdbeCoverageNeverTaken(v); } @@ -488,7 +488,7 @@ void sqlite3Update( } /* Populate the array of registers beginning at regNew with the new - ** row data. This array is used to check constaints, create the new + ** row data. This array is used to check constants, create the new ** table and index records, and as the values for any new.* references ** made by triggers. ** @@ -668,7 +668,7 @@ update_cleanup: return; } /* Make sure "isView" and other macros defined above are undefined. Otherwise -** thely may interfere with compilation of other functions in this file +** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView @@ -681,7 +681,7 @@ update_cleanup: /* ** Generate code for an UPDATE of a virtual table. ** -** The strategy is that we create an ephemerial table that contains +** The strategy is that we create an ephemeral table that contains ** for each row to be changed: ** ** (A) The original rowid of that row. @@ -689,7 +689,7 @@ update_cleanup: ** (C) The content of every column in the row. ** ** Then we loop over this ephemeral table and for each row in -** the ephermeral table call VUpdate. +** the ephemeral table call VUpdate. ** ** When finished, drop the ephemeral table. ** diff --git a/src/utf.c b/src/utf.c index 9789874..25f4dad 100644 --- a/src/utf.c +++ b/src/utf.c @@ -199,7 +199,7 @@ u32 sqlite3Utf8Read( ** desiredEnc. It is an error if the string is already of the desired ** encoding, or if *pMem does not contain a string value. */ -int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ +SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ int len; /* Maximum length of output string in bytes */ unsigned char *zOut; /* Output buffer */ unsigned char *zIn; /* Input iterator */ @@ -314,12 +314,13 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ *z = 0; assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); + c = pMem->flags; sqlite3VdbeMemRelease(pMem); - pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem); + pMem->flags = MEM_Str|MEM_Term|(c&MEM_AffMask); pMem->enc = desiredEnc; - pMem->flags |= (MEM_Term); pMem->z = (char*)zOut; pMem->zMalloc = pMem->z; + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->z); translate_out: #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) diff --git a/src/util.c b/src/util.c index 619af7f..6e64242 100644 --- a/src/util.c +++ b/src/util.c @@ -17,7 +17,7 @@ */ #include "sqliteInt.h" #include -#ifdef SQLITE_HAVE_ISNAN +#if HAVE_ISNAN || SQLITE_HAVE_ISNAN # include #endif @@ -58,7 +58,7 @@ int sqlite3FaultSim(int iTest){ */ int sqlite3IsNaN(double x){ int rc; /* The value return */ -#if !defined(SQLITE_HAVE_ISNAN) +#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN /* ** Systems that support the isnan() library function should probably ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have @@ -88,9 +88,9 @@ int sqlite3IsNaN(double x){ volatile double y = x; volatile double z = y; rc = (y!=z); -#else /* if defined(SQLITE_HAVE_ISNAN) */ +#else /* if HAVE_ISNAN */ rc = isnan(x); -#endif /* SQLITE_HAVE_ISNAN */ +#endif /* HAVE_ISNAN */ testcase( rc ); return rc; } @@ -111,6 +111,15 @@ int sqlite3Strlen30(const char *z){ return 0x3fffffff & (int)(z2 - z); } +/* +** Set the current error code to err_code and clear any prior error message. +*/ +void sqlite3Error(sqlite3 *db, int err_code){ + assert( db!=0 ); + db->errCode = err_code; + if( db->pErr ) sqlite3ValueSetNull(db->pErr); +} + /* ** Set the most recent error code and error string for the sqlite ** handle "db". The error code is set to "err_code". @@ -132,18 +141,18 @@ int sqlite3Strlen30(const char *z){ ** should be called with err_code set to SQLITE_OK and zFormat set ** to NULL. */ -void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){ +void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){ assert( db!=0 ); db->errCode = err_code; - if( zFormat && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){ + if( zFormat==0 ){ + sqlite3Error(db, err_code); + }else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){ char *z; va_list ap; va_start(ap, zFormat); z = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC); - }else if( db->pErr ){ - sqlite3ValueSetNull(db->pErr); } } @@ -157,12 +166,12 @@ void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){ ** %T Insert a token ** %S Insert the first element of a SrcList ** -** This function should be used to report any error that occurs whilst +** This function should be used to report any error that occurs while ** compiling an SQL statement (i.e. within sqlite3_prepare()). The ** last thing the sqlite3_prepare() function does is copy the error ** stored by this function into the database handle using sqlite3Error(). -** Function sqlite3Error() should be used during statement execution -** (sqlite3_step() etc.). +** Functions sqlite3Error() or sqlite3ErrorWithMsg() should be used +** during statement execution (sqlite3_step() etc.). */ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ char *zMsg; @@ -195,7 +204,7 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ ** occur. ** ** 2002-Feb-14: This routine is extended to remove MS-Access style -** brackets from around identifers. For example: "[a-b-c]" becomes +** brackets from around identifiers. For example: "[a-b-c]" becomes ** "a-b-c". */ int sqlite3Dequote(char *z){ @@ -242,6 +251,11 @@ int sqlite3Dequote(char *z){ */ int sqlite3_stricmp(const char *zLeft, const char *zRight){ register unsigned char *a, *b; + if( zLeft==0 ){ + return zRight ? -1 : 0; + }else if( zRight==0 ){ + return 1; + } a = (unsigned char *)zLeft; b = (unsigned char *)zRight; while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } @@ -249,6 +263,11 @@ int sqlite3_stricmp(const char *zLeft, const char *zRight){ } int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ register unsigned char *a, *b; + if( zLeft==0 ){ + return zRight ? -1 : 0; + }else if( zRight==0 ){ + return 1; + } a = (unsigned char *)zLeft; b = (unsigned char *)zRight; while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } @@ -699,7 +718,7 @@ int sqlite3Atoi(const char *z){ ** bit clear. Except, if we get to the 9th byte, it stores the full ** 8 bits and is the last byte. */ -int sqlite3PutVarint(unsigned char *p, u64 v){ +static int SQLITE_NOINLINE putVarint64(unsigned char *p, u64 v){ int i, j, n; u8 buf[10]; if( v & (((u64)0xff000000)<<32) ){ @@ -723,28 +742,17 @@ int sqlite3PutVarint(unsigned char *p, u64 v){ } return n; } - -/* -** This routine is a faster version of sqlite3PutVarint() that only -** works for 32-bit positive integers and which is optimized for -** the common case of small integers. A MACRO version, putVarint32, -** is provided which inlines the single-byte case. All code should use -** the MACRO version as this function assumes the single-byte case has -** already been handled. -*/ -int sqlite3PutVarint32(unsigned char *p, u32 v){ -#ifndef putVarint32 - if( (v & ~0x7f)==0 ){ - p[0] = v; +int sqlite3PutVarint(unsigned char *p, u64 v){ + if( v<=0x7f ){ + p[0] = v&0x7f; return 1; } -#endif - if( (v & ~0x3fff)==0 ){ - p[0] = (u8)((v>>7) | 0x80); - p[1] = (u8)(v & 0x7f); + if( v<=0x3fff ){ + p[0] = ((v>>7)&0x7f)|0x80; + p[1] = v&0x7f; return 2; } - return sqlite3PutVarint(p, v); + return putVarint64(p,v); } /* diff --git a/src/vacuum.c b/src/vacuum.c index 936a44a..9df8e08 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -87,14 +87,14 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ ** step (3) requires additional temporary disk space approximately equal ** to the size of the original database for the rollback journal. ** Hence, temporary disk space that is approximately 2x the size of the -** orginal database is required. Every page of the database is written +** original database is required. Every page of the database is written ** approximately 3 times: Once for step (2) and twice for step (3). ** Two writes per page are required in step (3) because the original ** database content must be written into the rollback journal prior to ** overwriting the database with the vacuumed content. ** ** Only 1x temporary space and only 1x writes would be required if -** the copy of step (3) were replace by deleting the original database +** the copy of step (3) were replaced by deleting the original database ** and renaming the transient database as the original. But that will ** not work if other processes are attached to the original database. ** And a power loss in between deleting the original and renaming the diff --git a/src/vdbe.c b/src/vdbe.c index 61adb9c..1e0ff96 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -146,7 +146,7 @@ int sqlite3_found_count = 0; ** already. Return non-zero if a malloc() fails. */ #define Stringify(P, enc) \ - if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc)) \ + if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc,0)) \ { goto no_mem; } /* @@ -209,11 +209,12 @@ static VdbeCursor *allocateCursor( sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); p->apCsr[iCur] = 0; } - if( SQLITE_OK==sqlite3VdbeMemGrow(pMem, nByte, 0) ){ + if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){ p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; memset(pCx, 0, sizeof(VdbeCursor)); pCx->iDb = iDb; pCx->nField = nField; + pCx->aOffset = &pCx->aType[nField]; if( isBtreeCursor ){ pCx->pCursor = (BtCursor*) &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; @@ -228,23 +229,31 @@ static VdbeCursor *allocateCursor( ** do so without loss of information. In other words, if the string ** looks like a number, convert it into a number. If it does not ** look like a number, leave it alone. +** +** If the bTryForInt flag is true, then extra effort is made to give +** an integer representation. Strings that look like floating point +** values but which have no fractional component (example: '48.00') +** will have a MEM_Int representation when bTryForInt is true. +** +** If bTryForInt is false, then if the input string contains a decimal +** point or exponential notation, the result is only MEM_Real, even +** if there is an exact integer representation of the quantity. */ -static void applyNumericAffinity(Mem *pRec){ +static void applyNumericAffinity(Mem *pRec, int bTryForInt){ double rValue; i64 iValue; u8 enc = pRec->enc; - if( (pRec->flags&MEM_Str)==0 ) return; + assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str ); if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ pRec->u.i = iValue; pRec->flags |= MEM_Int; }else{ - pRec->r = rValue; + pRec->u.r = rValue; pRec->flags |= MEM_Real; + if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec); } } -#define ApplyNumericAffinity(X) \ - if(((X)->flags&(MEM_Real|MEM_Int))==0){applyNumericAffinity(X);} /* ** Processing is determine by the affinity parameter: @@ -269,21 +278,23 @@ static void applyAffinity( char affinity, /* The affinity to be applied */ u8 enc /* Use this text encoding */ ){ - if( affinity==SQLITE_AFF_TEXT ){ + if( affinity>=SQLITE_AFF_NUMERIC ){ + assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL + || affinity==SQLITE_AFF_NUMERIC ); + if( (pRec->flags & MEM_Int)==0 ){ + if( (pRec->flags & MEM_Real)==0 ){ + if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1); + }else{ + sqlite3VdbeIntegerAffinity(pRec); + } + } + }else if( affinity==SQLITE_AFF_TEXT ){ /* Only attempt the conversion to TEXT if there is an integer or real ** representation (blob and NULL do not get converted) but no string ** representation. */ if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){ - sqlite3VdbeMemStringify(pRec, enc); - } - pRec->flags &= ~(MEM_Real|MEM_Int); - }else if( affinity!=SQLITE_AFF_NONE ){ - assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL - || affinity==SQLITE_AFF_NUMERIC ); - ApplyNumericAffinity(pRec); - if( pRec->flags & MEM_Real ){ - sqlite3VdbeIntegerAffinity(pRec); + sqlite3VdbeMemStringify(pRec, enc, 1); } } } @@ -298,7 +309,7 @@ int sqlite3_value_numeric_type(sqlite3_value *pVal){ int eType = sqlite3_value_type(pVal); if( eType==SQLITE_TEXT ){ Mem *pMem = (Mem*)pVal; - applyNumericAffinity(pMem); + applyNumericAffinity(pMem, 0); eType = sqlite3_value_type(pVal); } return eType; @@ -316,25 +327,37 @@ void sqlite3ValueApplyAffinity( applyAffinity((Mem *)pVal, affinity, enc); } +/* +** pMem currently only holds a string type (or maybe a BLOB that we can +** interpret as a string if we want to). Compute its corresponding +** numeric type, if has one. Set the pMem->u.r and pMem->u.i fields +** accordingly. +*/ +static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ + assert( (pMem->flags & (MEM_Int|MEM_Real))==0 ); + assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ); + if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){ + return 0; + } + if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){ + return MEM_Int; + } + return MEM_Real; +} + /* ** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or ** none. ** ** Unlike applyNumericAffinity(), this routine does not modify pMem->flags. -** But it does set pMem->r and pMem->u.i appropriately. +** But it does set pMem->u.r and pMem->u.i appropriately. */ static u16 numericType(Mem *pMem){ if( pMem->flags & (MEM_Int|MEM_Real) ){ return pMem->flags & (MEM_Int|MEM_Real); } if( pMem->flags & (MEM_Str|MEM_Blob) ){ - if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){ - return 0; - } - if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){ - return MEM_Int; - } - return MEM_Real; + return computeNumericType(pMem); } return 0; } @@ -437,7 +460,7 @@ static void memTracePrint(Mem *p){ printf(" i:%lld", p->u.i); #ifndef SQLITE_OMIT_FLOATING_POINT }else if( p->flags & MEM_Real ){ - printf(" r:%g", p->r); + printf(" r:%g", p->u.r); #endif }else if( p->flags & MEM_RowSet ){ printf(" (rowset)"); @@ -585,6 +608,9 @@ int sqlite3VdbeExec( #endif nVmStep++; pOp = &aOp[pc]; +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + if( p->anExec ) p->anExec[pc]++; +#endif /* Only allow tracing if SQLITE_DEBUG is defined. */ @@ -618,7 +644,7 @@ int sqlite3VdbeExec( assert( pOp->p2<=(p->nMem-p->nCursor) ); pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); - VdbeMemRelease(pOut); + if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut); pOut->flags = MEM_Int; } @@ -980,7 +1006,7 @@ case OP_Int64: { /* out2-prerelease */ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */ pOut->flags = MEM_Real; assert( !sqlite3IsNaN(*pOp->p4.pReal) ); - pOut->r = *pOp->p4.pReal; + pOut->u.r = *pOp->p4.pReal; break; } #endif @@ -1003,9 +1029,9 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */ rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); if( rc==SQLITE_TOOBIG ) goto too_big; if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; - assert( pOut->zMalloc==pOut->z ); + assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z ); assert( VdbeMemDynamic(pOut)==0 ); - pOut->zMalloc = 0; + pOut->szMalloc = 0; pOut->flags |= MEM_Static; if( pOp->p4type==P4_DYNAMIC ){ sqlite3DbFree(db, pOp->p4.z); @@ -1057,7 +1083,7 @@ case OP_Null: { /* out2-prerelease */ while( cnt>0 ){ pOut++; memAboutToChange(p, pOut); - VdbeMemRelease(pOut); + sqlite3VdbeMemSetNull(pOut); pOut->flags = nullFlag; cnt--; } @@ -1125,7 +1151,6 @@ case OP_Variable: { /* out2-prerelease */ ** for P3 to be less than 1. */ case OP_Move: { - char *zMalloc; /* Holding variable for allocated memory */ int n; /* Number of registers left to copy */ int p1; /* Register to copy from */ int p2; /* Register to copy to */ @@ -1143,17 +1168,12 @@ case OP_Move: { assert( pIn1<=&aMem[(p->nMem-p->nCursor)] ); assert( memIsValid(pIn1) ); memAboutToChange(p, pOut); - VdbeMemRelease(pOut); - zMalloc = pOut->zMalloc; - memcpy(pOut, pIn1, sizeof(Mem)); + sqlite3VdbeMemMove(pOut, pIn1); #ifdef SQLITE_DEBUG if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<&aMem[p1+pOp->p3] ){ pOut->pScopyFrom += p1 - pOp->p2; } #endif - pIn1->flags = MEM_Undefined; - pIn1->xDel = 0; - pIn1->zMalloc = zMalloc; REGISTER_TRACE(p2++, pOut); pIn1++; pOut++; @@ -1458,7 +1478,7 @@ fp_math: if( sqlite3IsNaN(rB) ){ goto arithmetic_result_is_null; } - pOut->r = rB; + pOut->u.r = rB; MemSetTypeFlag(pOut, MEM_Real); if( ((type1|type2)&MEM_Real)==0 && !bIntint ){ sqlite3VdbeIntegerAffinity(pOut); @@ -1523,8 +1543,8 @@ case OP_Function: { apVal = p->apArg; assert( apVal || n==0 ); assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); - pOut = &aMem[pOp->p3]; - memAboutToChange(p, pOut); + ctx.pOut = &aMem[pOp->p3]; + memAboutToChange(p, ctx.pOut); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) ); assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); @@ -1540,65 +1560,29 @@ case OP_Function: { ctx.pFunc = pOp->p4.pFunc; ctx.iOp = pc; ctx.pVdbe = p; - - /* The output cell may already have a buffer allocated. Move - ** the pointer to ctx.s so in case the user-function can use - ** the already allocated buffer instead of allocating a new one. - */ - memcpy(&ctx.s, pOut, sizeof(Mem)); - pOut->flags = MEM_Null; - pOut->xDel = 0; - pOut->zMalloc = 0; - MemSetTypeFlag(&ctx.s, MEM_Null); - + MemSetTypeFlag(ctx.pOut, MEM_Null); ctx.fErrorOrAux = 0; - if( ctx.pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ - assert( pOp>aOp ); - assert( pOp[-1].p4type==P4_COLLSEQ ); - assert( pOp[-1].opcode==OP_CollSeq ); - ctx.pColl = pOp[-1].p4.pColl; - } db->lastRowid = lastRowid; (*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */ - lastRowid = db->lastRowid; - - if( db->mallocFailed ){ - /* Even though a malloc() has failed, the implementation of the - ** user function may have called an sqlite3_result_XXX() function - ** to return a value. The following call releases any resources - ** associated with such a value. - */ - sqlite3VdbeMemRelease(&ctx.s); - goto no_mem; - } + lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */ /* If the function returned an error, throw an exception */ if( ctx.fErrorOrAux ){ if( ctx.isError ){ - sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s)); + sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(ctx.pOut)); rc = ctx.isError; } sqlite3VdbeDeleteAuxData(p, pc, pOp->p1); } /* Copy the result of the function into register P3 */ - sqlite3VdbeChangeEncoding(&ctx.s, encoding); - assert( pOut->flags==MEM_Null ); - memcpy(pOut, &ctx.s, sizeof(Mem)); - if( sqlite3VdbeMemTooBig(pOut) ){ + sqlite3VdbeChangeEncoding(ctx.pOut, encoding); + if( sqlite3VdbeMemTooBig(ctx.pOut) ){ goto too_big; } -#if 0 - /* The app-defined function has done something that as caused this - ** statement to expire. (Perhaps the function called sqlite3_exec() - ** with a CREATE TABLE statement.) - */ - if( p->expired ) rc = SQLITE_ABORT; -#endif - - REGISTER_TRACE(pOp->p3, pOut); - UPDATE_MAX_BLOBSIZE(pOut); + REGISTER_TRACE(pOp->p3, ctx.pOut); + UPDATE_MAX_BLOBSIZE(ctx.pOut); break; } @@ -1746,106 +1730,37 @@ case OP_RealAffinity: { /* in1 */ #endif #ifndef SQLITE_OMIT_CAST -/* Opcode: ToText P1 * * * * +/* Opcode: Cast P1 P2 * * * +** Synopsis: affinity(r[P1]) ** -** Force the value in register P1 to be text. -** If the value is numeric, convert it to a string using the -** equivalent of sprintf(). Blob values are unchanged and -** are afterwards simply interpreted as text. +** Force the value in register P1 to be the type defined by P2. +** +**
      +**
    • TEXT +**
    • BLOB +**
    • NUMERIC +**
    • INTEGER +**
    • REAL +**
    ** ** A NULL value is not changed by this routine. It remains NULL. */ -case OP_ToText: { /* same as TK_TO_TEXT, in1 */ +case OP_Cast: { /* in1 */ + assert( pOp->p2>=SQLITE_AFF_NONE && pOp->p2<=SQLITE_AFF_REAL ); + testcase( pOp->p2==SQLITE_AFF_TEXT ); + testcase( pOp->p2==SQLITE_AFF_NONE ); + testcase( pOp->p2==SQLITE_AFF_NUMERIC ); + testcase( pOp->p2==SQLITE_AFF_INTEGER ); + testcase( pOp->p2==SQLITE_AFF_REAL ); pIn1 = &aMem[pOp->p1]; memAboutToChange(p, pIn1); - if( pIn1->flags & MEM_Null ) break; - assert( MEM_Str==(MEM_Blob>>3) ); - pIn1->flags |= (pIn1->flags&MEM_Blob)>>3; - applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); rc = ExpandBlob(pIn1); - assert( pIn1->flags & MEM_Str || db->mallocFailed ); - pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero); + sqlite3VdbeMemCast(pIn1, pOp->p2, encoding); UPDATE_MAX_BLOBSIZE(pIn1); break; } - -/* Opcode: ToBlob P1 * * * * -** -** Force the value in register P1 to be a BLOB. -** If the value is numeric, convert it to a string first. -** Strings are simply reinterpreted as blobs with no change -** to the underlying data. -** -** A NULL value is not changed by this routine. It remains NULL. -*/ -case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */ - pIn1 = &aMem[pOp->p1]; - if( pIn1->flags & MEM_Null ) break; - if( (pIn1->flags & MEM_Blob)==0 ){ - applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); - assert( pIn1->flags & MEM_Str || db->mallocFailed ); - MemSetTypeFlag(pIn1, MEM_Blob); - }else{ - pIn1->flags &= ~(MEM_TypeMask&~MEM_Blob); - } - UPDATE_MAX_BLOBSIZE(pIn1); - break; -} - -/* Opcode: ToNumeric P1 * * * * -** -** Force the value in register P1 to be numeric (either an -** integer or a floating-point number.) -** If the value is text or blob, try to convert it to an using the -** equivalent of atoi() or atof() and store 0 if no such conversion -** is possible. -** -** A NULL value is not changed by this routine. It remains NULL. -*/ -case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */ - pIn1 = &aMem[pOp->p1]; - sqlite3VdbeMemNumerify(pIn1); - break; -} #endif /* SQLITE_OMIT_CAST */ -/* Opcode: ToInt P1 * * * * -** -** Force the value in register P1 to be an integer. If -** The value is currently a real number, drop its fractional part. -** If the value is text or blob, try to convert it to an integer using the -** equivalent of atoi() and store 0 if no such conversion is possible. -** -** A NULL value is not changed by this routine. It remains NULL. -*/ -case OP_ToInt: { /* same as TK_TO_INT, in1 */ - pIn1 = &aMem[pOp->p1]; - if( (pIn1->flags & MEM_Null)==0 ){ - sqlite3VdbeMemIntegerify(pIn1); - } - break; -} - -#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) -/* Opcode: ToReal P1 * * * * -** -** Force the value in register P1 to be a floating point number. -** If The value is currently an integer, convert it. -** If the value is text or blob, try to convert it to an integer using the -** equivalent of atoi() and store 0.0 if no such conversion is possible. -** -** A NULL value is not changed by this routine. It remains NULL. -*/ -case OP_ToReal: { /* same as TK_TO_REAL, in1 */ - pIn1 = &aMem[pOp->p1]; - memAboutToChange(p, pIn1); - if( (pIn1->flags & MEM_Null)==0 ){ - sqlite3VdbeMemRealify(pIn1); - } - break; -} -#endif /* !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) */ - /* Opcode: Lt P1 P2 P3 P4 P5 ** Synopsis: if r[P1]p5 & SQLITE_AFF_MASK; - if( affinity ){ - applyAffinity(pIn1, affinity, encoding); - applyAffinity(pIn3, affinity, encoding); - if( db->mallocFailed ) goto no_mem; + if( affinity>=SQLITE_AFF_NUMERIC ){ + if( (pIn1->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + applyNumericAffinity(pIn1,0); + } + if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + applyNumericAffinity(pIn3,0); + } + }else if( affinity==SQLITE_AFF_TEXT ){ + if( (pIn1->flags & MEM_Str)==0 && (pIn1->flags & (MEM_Int|MEM_Real))!=0 ){ + testcase( pIn1->flags & MEM_Int ); + testcase( pIn1->flags & MEM_Real ); + sqlite3VdbeMemStringify(pIn1, encoding, 1); + } + if( (pIn3->flags & MEM_Str)==0 && (pIn3->flags & (MEM_Int|MEM_Real))!=0 ){ + testcase( pIn3->flags & MEM_Int ); + testcase( pIn3->flags & MEM_Real ); + sqlite3VdbeMemStringify(pIn3, encoding, 1); + } } - assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); - ExpandBlob(pIn1); - ExpandBlob(pIn3); + if( pIn1->flags & MEM_Zero ){ + sqlite3VdbeMemExpandBlob(pIn1); + flags1 &= ~MEM_Zero; + } + if( pIn3->flags & MEM_Zero ){ + sqlite3VdbeMemExpandBlob(pIn3); + flags3 &= ~MEM_Zero; + } + if( db->mallocFailed ) goto no_mem; res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); } switch( pOp->opcode ){ @@ -2014,8 +1949,8 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ } } /* Undo any changes made by applyAffinity() to the input registers. */ - pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (flags1&MEM_TypeMask); - pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (flags3&MEM_TypeMask); + pIn1->flags = flags1; + pIn3->flags = flags3; break; } @@ -2183,10 +2118,10 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ case OP_Not: { /* same as TK_NOT, in1, out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; - if( pIn1->flags & MEM_Null ){ - sqlite3VdbeMemSetNull(pOut); - }else{ - sqlite3VdbeMemSetInt64(pOut, !sqlite3VdbeIntValue(pIn1)); + sqlite3VdbeMemSetNull(pOut); + if( (pIn1->flags & MEM_Null)==0 ){ + pOut->flags = MEM_Int; + pOut->u.i = !sqlite3VdbeIntValue(pIn1); } break; } @@ -2201,10 +2136,10 @@ case OP_Not: { /* same as TK_NOT, in1, out2 */ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; - if( pIn1->flags & MEM_Null ){ - sqlite3VdbeMemSetNull(pOut); - }else{ - sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1)); + sqlite3VdbeMemSetNull(pOut); + if( (pIn1->flags & MEM_Null)==0 ){ + pOut->flags = MEM_Int; + pOut->u.i = ~sqlite3VdbeIntValue(pIn1); } break; } @@ -2322,7 +2257,6 @@ case OP_Column: { int p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ BtCursor *pCrsr; /* The BTree cursor */ - u32 *aType; /* aType[i] holds the numeric type of the i-th column */ u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ int len; /* The length of the serialized data for the column */ int i; /* Loop counter */ @@ -2335,6 +2269,7 @@ case OP_Column: { u32 szField; /* Number of bytes in the content of a field */ u32 avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ + u16 fx; /* pDest->flags value */ Mem *pReg; /* PseudoTable input register */ p2 = pOp->p2; @@ -2345,8 +2280,7 @@ case OP_Column: { pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( p2nField ); - aType = pC->aType; - aOffset = aType + pC->nField; + aOffset = pC->aOffset; #ifndef SQLITE_OMIT_VIRTUALTABLE assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */ #endif @@ -2357,7 +2291,7 @@ case OP_Column: { /* If the cursor cache is stale, bring it up-to-date */ rc = sqlite3VdbeCursorMoveto(pC); if( rc ) goto abort_due_to_error; - if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){ + if( pC->cacheStatus!=p->cacheCtr ){ if( pC->nullRow ){ if( pCrsr==0 ){ assert( pC->pseudoTableReg>0 ); @@ -2367,7 +2301,7 @@ case OP_Column: { pC->payloadSize = pC->szRow = avail = pReg->n; pC->aRow = (u8*)pReg->z; }else{ - MemSetTypeFlag(pDest, MEM_Null); + sqlite3VdbeMemSetNull(pDest); goto op_column_out; } }else{ @@ -2402,14 +2336,6 @@ case OP_Column: { pC->iHdrOffset = getVarint32(pC->aRow, offset); pC->nHdrParsed = 0; aOffset[0] = offset; - if( availaRow does not have to hold the entire row, but it does at least - ** need to cover the header of the record. If pC->aRow does not contain - ** the complete header, then set it to zero, forcing the header to be - ** dynamically allocated. */ - pC->aRow = 0; - pC->szRow = 0; - } /* Make sure a corrupt database has not given us an oversize header. ** Do this now to avoid an oversize memory allocation. @@ -2424,15 +2350,32 @@ case OP_Column: { rc = SQLITE_CORRUPT_BKPT; goto op_column_error; } + + if( availaRow does not have to hold the entire row, but it does at least + ** need to cover the header of the record. If pC->aRow does not contain + ** the complete header, then set it to zero, forcing the header to be + ** dynamically allocated. */ + pC->aRow = 0; + pC->szRow = 0; + } + + /* The following goto is an optimization. It can be omitted and + ** everything will still work. But OP_Column is measurably faster + ** by skipping the subsequent conditional, which is always true. + */ + assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ + goto op_column_read_header; } /* Make sure at least the first p2+1 entries of the header have been - ** parsed and valid information is in aOffset[] and aType[]. + ** parsed and valid information is in aOffset[] and pC->aType[]. */ if( pC->nHdrParsed<=p2 ){ /* If there is more header available for parsing in the record, try ** to extract additional fields up through the p2+1-th field */ + op_column_read_header: if( pC->iHdrOffsetaRow==0 ){ @@ -2447,7 +2390,7 @@ case OP_Column: { zData = pC->aRow; } - /* Fill in aType[i] and aOffset[i] values through the p2-th field. */ + /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */ i = pC->nHdrParsed; offset = aOffset[i]; zHdr = zData + pC->iHdrOffset; @@ -2460,7 +2403,7 @@ case OP_Column: { }else{ zHdr += sqlite3GetVarint32(zHdr, &t); } - aType[i] = t; + pC->aType[i] = t; szField = sqlite3VdbeSerialTypeLen(t); offset += szField; if( offsetzEndHdr) + ** (2) the entire header was used but not all data was used + ** (zHdr==zEndHdr && offset!=pC->payloadSize) + ** (3) the end of the data extends beyond the end of the record. + ** (offset > pC->payloadSize) */ - if( (zHdr > zEndHdr) + if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset!=pC->payloadSize)) || (offset > pC->payloadSize) - || (zHdr==zEndHdr && offset!=pC->payloadSize) ){ rc = SQLITE_CORRUPT_BKPT; goto op_column_error; @@ -2500,68 +2444,68 @@ case OP_Column: { if( pOp->p4type==P4_MEM ){ sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); }else{ - MemSetTypeFlag(pDest, MEM_Null); + sqlite3VdbeMemSetNull(pDest); } goto op_column_out; } } /* Extract the content for the p2+1-th column. Control can only - ** reach this point if aOffset[p2], aOffset[p2+1], and aType[p2] are + ** reach this point if aOffset[p2], aOffset[p2+1], and pC->aType[p2] are ** all valid. */ assert( p2nHdrParsed ); assert( rc==SQLITE_OK ); assert( sqlite3VdbeCheckMemInvariants(pDest) ); + if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest); + t = pC->aType[p2]; if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ - VdbeMemRelease(pDest); - sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest); + sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest); }else{ /* This branch happens only when content is on overflow pages */ - t = aType[p2]; if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)) || (len = sqlite3VdbeSerialTypeLen(t))==0 ){ - /* Content is irrelevant for the typeof() function and for - ** the length(X) function if X is a blob. So we might as well use - ** bogus content rather than reading content from disk. NULL works - ** for text and blob and whatever is in the payloadSize64 variable - ** will work for everything else. Content is also irrelevant if - ** the content length is 0. */ - zData = t<=13 ? (u8*)&payloadSize64 : 0; - sMem.zMalloc = 0; + /* Content is irrelevant for + ** 1. the typeof() function, + ** 2. the length(X) function if X is a blob, and + ** 3. if the content length is zero. + ** So we might as well use bogus content rather than reading + ** content from disk. NULL will work for the value for strings + ** and blobs and whatever is in the payloadSize64 variable + ** will work for everything else. */ + sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest); }else{ - memset(&sMem, 0, sizeof(sMem)); - sqlite3VdbeMemMove(&sMem, pDest); rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable, - &sMem); + pDest); if( rc!=SQLITE_OK ){ goto op_column_error; } - zData = (u8*)sMem.z; - } - sqlite3VdbeSerialGet(zData, t, pDest); - /* If we dynamically allocated space to hold the data (in the - ** sqlite3VdbeMemFromBtree() call above) then transfer control of that - ** dynamically allocated space over to the pDest structure. - ** This prevents a memory copy. */ - if( sMem.zMalloc ){ - assert( sMem.z==sMem.zMalloc ); - assert( VdbeMemDynamic(pDest)==0 ); - assert( (pDest->flags & (MEM_Blob|MEM_Str))==0 || pDest->z==sMem.z ); - pDest->flags &= ~(MEM_Ephem|MEM_Static); - pDest->flags |= MEM_Term; - pDest->z = sMem.z; - pDest->zMalloc = sMem.zMalloc; + sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); + pDest->flags &= ~MEM_Ephem; } } pDest->enc = encoding; op_column_out: - Deephemeralize(pDest); + /* If the column value is an ephemeral string, go ahead and persist + ** that string in case the cursor moves before the column value is + ** used. The following code does the equivalent of Deephemeralize() + ** but does it faster. */ + if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){ + fx = pDest->flags & (MEM_Str|MEM_Blob); + assert( fx!=0 ); + zData = (const u8*)pDest->z; + len = pDest->n; + if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem; + memcpy(pDest->z, zData, len); + pDest->z[len] = 0; + pDest->z[len+1] = 0; + pDest->flags = fx|MEM_Term; + } op_column_error: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); @@ -2636,7 +2580,7 @@ case OP_MakeRecord: { ** ------------------------------------------------------------------------ ** ** Data(0) is taken from register P1. Data(1) comes from register P1+1 - ** and so froth. + ** and so forth. ** ** Each type field is a varint representing the serial type of the ** corresponding data element (see sqlite3VdbeSerialType()). The @@ -2676,7 +2620,7 @@ case OP_MakeRecord: { pRec = pLast; do{ assert( memIsValid(pRec) ); - serial_type = sqlite3VdbeSerialType(pRec, file_format); + pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format); len = sqlite3VdbeSerialTypeLen(serial_type); if( pRec->flags & MEM_Zero ){ if( nData ){ @@ -2692,7 +2636,10 @@ case OP_MakeRecord: { nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type); }while( (--pRec)>=pData0 ); - /* Add the initial header varint and total the size */ + /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint + ** which determines the total number of bytes in the header. The varint + ** value is the size of the header in bytes including the size varint + ** itself. */ testcase( nHdr==126 ); testcase( nHdr==127 ); if( nHdr<=126 ){ @@ -2712,9 +2659,9 @@ case OP_MakeRecord: { /* Make sure the output register has a buffer large enough to store ** the new record. The output register (pOp->p3) is not allowed to ** be one of the input registers (because the following call to - ** sqlite3VdbeMemGrow() could clobber the value before it is used). + ** sqlite3VdbeMemClearAndResize() could clobber the value before it is used). */ - if( sqlite3VdbeMemGrow(pOut, (int)nByte, 0) ){ + if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ goto no_mem; } zNewRecord = (u8 *)pOut->z; @@ -2725,8 +2672,12 @@ case OP_MakeRecord: { assert( pData0<=pLast ); pRec = pData0; do{ - serial_type = sqlite3VdbeSerialType(pRec, file_format); + serial_type = pRec->uTemp; + /* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more + ** additional varints, one per column. */ i += putVarint32(&zNewRecord[i], serial_type); /* serial type */ + /* EVIDENCE-OF: R-64536-51728 The values for each column in the record + ** immediately follow the header. */ j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */ }while( (++pRec)<=pLast ); assert( i==nHdr ); @@ -2735,7 +2686,6 @@ case OP_MakeRecord: { assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); pOut->n = (int)nByte; pOut->flags = MEM_Blob; - pOut->xDel = 0; if( nZero ){ pOut->u.nZero = nZero; pOut->flags |= MEM_Zero; @@ -2882,11 +2832,18 @@ case OP_Savepoint: { db->isTransactionSavepoint = 0; rc = p->rc; }else{ + int isSchemaChange; iSavepoint = db->nSavepoint - iSavepoint - 1; if( p1==SAVEPOINT_ROLLBACK ){ + isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; for(ii=0; iinDb; ii++){ - sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT); + rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, + SQLITE_ABORT_ROLLBACK, + isSchemaChange==0); + if( rc!=SQLITE_OK ) goto abort_due_to_error; } + }else{ + isSchemaChange = 0; } for(ii=0; iinDb; ii++){ rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); @@ -2894,7 +2851,7 @@ case OP_Savepoint: { goto abort_due_to_error; } } - if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){ + if( isSchemaChange ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); db->flags = (db->flags | SQLITE_InternChanges); @@ -3291,7 +3248,7 @@ case OP_OpenWrite: { || p->readOnly==0 ); if( p->expired ){ - rc = SQLITE_ABORT; + rc = SQLITE_ABORT_ROLLBACK; break; } @@ -3351,10 +3308,6 @@ case OP_OpenWrite: { assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); sqlite3BtreeCursorHints(pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR)); - /* Since it performs no memory allocation or IO, the only value that - ** sqlite3BtreeCursor() may return is SQLITE_OK. */ - assert( rc==SQLITE_OK ); - /* Set the VdbeCursor.isTable variable. Previous versions of ** SQLite used to check if the root-page flags were sane at this point ** and report database corruption if they were not, but this check has @@ -3438,11 +3391,15 @@ case OP_OpenEphemeral: { break; } -/* Opcode: SorterOpen P1 P2 * P4 * +/* Opcode: SorterOpen P1 P2 P3 P4 * ** ** This opcode works like OP_OpenEphemeral except that it opens ** a transient index that is specifically designed to sort large ** tables using an external merge-sort algorithm. +** +** If argument P3 is non-zero, then it indicates that the sorter may +** assume that a stable sort considering the first P3 fields of each +** key is sufficient to produce the required results. */ case OP_SorterOpen: { VdbeCursor *pCx; @@ -3454,7 +3411,25 @@ case OP_SorterOpen: { pCx->pKeyInfo = pOp->p4.pKeyInfo; assert( pCx->pKeyInfo->db==db ); assert( pCx->pKeyInfo->enc==ENC(db) ); - rc = sqlite3VdbeSorterInit(db, pCx); + rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx); + break; +} + +/* Opcode: SequenceTest P1 P2 * * * +** Synopsis: if( cursor[P1].ctr++ ) pc = P2 +** +** P1 is a sorter cursor. If the sequence counter is currently zero, jump +** to P2. Regardless of whether or not the jump is taken, increment the +** the sequence value. +*/ +case OP_SequenceTest: { + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC->pSorter ); + if( (pC->seqCount++)==0 ){ + pc = pOp->p2 - 1; + } break; } @@ -3601,11 +3576,12 @@ case OP_SeekGT: { /* jump, in3 */ if( pC->isTable ){ /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do - ** the seek, so covert it. */ + ** the seek, so convert it. */ pIn3 = &aMem[pOp->p3]; - ApplyNumericAffinity(pIn3); + if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + applyNumericAffinity(pIn3, 0); + } iKey = sqlite3VdbeIntValue(pIn3); - pC->rowidIsValid = 0; /* If the P3 value could not be converted into an integer without ** loss of information, then special processing is required... */ @@ -3624,7 +3600,7 @@ case OP_SeekGT: { /* jump, in3 */ ** (x > 4.9) -> (x >= 5) ** (x <= 4.9) -> (x < 5) */ - if( pIn3->r<(double)iKey ){ + if( pIn3->u.r<(double)iKey ){ assert( OP_SeekGE==(OP_SeekGT-1) ); assert( OP_SeekLT==(OP_SeekLE-1) ); assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) ); @@ -3633,7 +3609,7 @@ case OP_SeekGT: { /* jump, in3 */ /* If the approximation iKey is smaller than the actual real search ** term, substitute <= for < and > for >=. */ - else if( pIn3->r>(double)iKey ){ + else if( pIn3->u.r>(double)iKey ){ assert( OP_SeekLE==(OP_SeekLT+1) ); assert( OP_SeekGT==(OP_SeekGE+1) ); assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); @@ -3641,13 +3617,10 @@ case OP_SeekGT: { /* jump, in3 */ } } rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res); + pC->movetoTarget = iKey; /* Used by OP_Delete */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - if( res==0 ){ - pC->rowidIsValid = 1; - pC->lastRowid = iKey; - } }else{ nField = pOp->p4.i; assert( pOp->p4type==P4_INT32 ); @@ -3677,7 +3650,6 @@ case OP_SeekGT: { /* jump, in3 */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - pC->rowidIsValid = 0; } pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; @@ -3689,7 +3661,6 @@ case OP_SeekGT: { /* jump, in3 */ res = 0; rc = sqlite3BtreeNext(pC->pCursor, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; - pC->rowidIsValid = 0; }else{ res = 0; } @@ -3699,7 +3670,6 @@ case OP_SeekGT: { /* jump, in3 */ res = 0; rc = sqlite3BtreePrevious(pC->pCursor, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; - pC->rowidIsValid = 0; }else{ /* res might be negative because the table is empty. Check to ** see if this is the case. @@ -3736,7 +3706,6 @@ case OP_Seek: { /* in2 */ pC->nullRow = 0; pIn2 = &aMem[pOp->p2]; pC->movetoTarget = sqlite3VdbeIntValue(pIn2); - pC->rowidIsValid = 0; pC->deferredMoveto = 1; break; } @@ -3843,10 +3812,10 @@ case OP_Found: { /* jump, in3 */ }else{ pIdxKey = sqlite3VdbeAllocUnpackedRecord( pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree - ); + ); if( pIdxKey==0 ) goto no_mem; assert( pIn3->flags & MEM_Blob ); - assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */ + ExpandBlob(pIn3); sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); } pIdxKey->default_rc = 0; @@ -3854,8 +3823,8 @@ case OP_Found: { /* jump, in3 */ /* For the OP_NoConflict opcode, take the jump if any of the ** input fields are NULL, since any key with a NULL will not ** conflict */ - for(ii=0; iinField; ii++){ + if( pIdxKey->aMem[ii].flags & MEM_Null ){ pc = pOp->p2 - 1; VdbeBranchTaken(1,2); break; } @@ -3922,15 +3891,13 @@ case OP_NotExists: { /* jump, in3 */ res = 0; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); - pC->lastRowid = pIn3->u.i; - pC->rowidIsValid = res==0 ?1:0; + pC->movetoTarget = iKey; /* Used by OP_Delete */ pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; pC->deferredMoveto = 0; VdbeBranchTaken(res!=0,2); if( res!=0 ){ pc = pOp->p2 - 1; - assert( pC->rowidIsValid==0 ); } pC->seekResult = res; break; @@ -4064,32 +4031,20 @@ case OP_NewRowid: { /* out2-prerelease */ ** it finds one that is not previously used. */ assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is ** an AUTOINCREMENT table. */ - /* on the first attempt, simply do one more than previous */ - v = lastRowid; - v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ - v++; /* ensure non-zero */ cnt = 0; - while( ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v, + do{ + sqlite3_randomness(sizeof(v), &v); + v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */ + }while( ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v, 0, &res))==SQLITE_OK) && (res==0) - && (++cnt<100)){ - /* collision - try another random rowid */ - sqlite3_randomness(sizeof(v), &v); - if( cnt<5 ){ - /* try "small" random rowids for the initial attempts */ - v &= 0xffffff; - }else{ - v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ - } - v++; /* ensure non-zero */ - } + && (++cnt<100)); if( rc==SQLITE_OK && res==0 ){ rc = SQLITE_FULL; /* IMP: R-38219-53002 */ goto abort_due_to_error; } assert( v>0 ); /* EV: R-40812-03570 */ } - pC->rowidIsValid = 0; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } @@ -4194,7 +4149,6 @@ case OP_InsertInt: { pData->z, pData->n, nZero, (pOp->p5 & OPFLAG_APPEND)!=0, seekResult ); - pC->rowidIsValid = 0; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; @@ -4231,33 +4185,32 @@ case OP_InsertInt: { ** using OP_NotFound prior to invoking this opcode. */ case OP_Delete: { - i64 iKey; VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */ - iKey = pC->lastRowid; /* Only used for the update hook */ - - /* The OP_Delete opcode always follows an OP_NotExists or OP_Last or - ** OP_Column on the same table without any intervening operations that - ** might move or invalidate the cursor. Hence cursor pC is always pointing - ** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation - ** below is always a no-op and cannot fail. We will run it anyhow, though, - ** to guard against future changes to the code generator. - **/ assert( pC->deferredMoveto==0 ); - rc = sqlite3VdbeCursorMoveto(pC); - if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; +#ifdef SQLITE_DEBUG + /* The seek operation that positioned the cursor prior to OP_Delete will + ** have also set the pC->movetoTarget field to the rowid of the row that + ** is being deleted */ + if( pOp->p4.z && pC->isTable ){ + i64 iKey = 0; + sqlite3BtreeKeySize(pC->pCursor, &iKey); + assert( pC->movetoTarget==iKey ); + } +#endif + rc = sqlite3BtreeDelete(pC->pCursor); pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, - db->aDb[pC->iDb].zName, pOp->p4.z, iKey); + db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget); assert( pC->iDb>=0 ); } if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; @@ -4301,6 +4254,7 @@ case OP_SorterCompare: { assert( pOp->p4type==P4_INT32 ); pIn3 = &aMem[pOp->p3]; nKeyCol = pOp->p4.i; + res = 0; rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res); VdbeBranchTaken(res!=0,2); if( res ){ @@ -4309,10 +4263,17 @@ case OP_SorterCompare: { break; }; -/* Opcode: SorterData P1 P2 * * * +/* Opcode: SorterData P1 P2 P3 * * ** Synopsis: r[P2]=data ** ** Write into register P2 the current sorter data for sorter cursor P1. +** Then clear the column header cache on cursor P3. +** +** This opcode is normally use to move a record out of the sorter and into +** a register that is the source for a pseudo-table cursor created using +** OpenPseudo. That pseudo-table cursor is the one that is identified by +** parameter P3. Clearing the P3 column cache as part of this opcode saves +** us from having to issue a separate NullRow instruction to clear that cache. */ case OP_SorterData: { VdbeCursor *pC; @@ -4322,6 +4283,8 @@ case OP_SorterData: { assert( isSorter(pC) ); rc = sqlite3VdbeSorterRowkey(pC, pOut); assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); + assert( pOp->p1>=0 && pOp->p1nCursor ); + p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE; break; } @@ -4368,16 +4331,20 @@ case OP_RowData: { assert( pC->pseudoTableReg==0 ); assert( pC->pCursor!=0 ); pCrsr = pC->pCursor; - assert( sqlite3BtreeCursorIsValid(pCrsr) ); /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or ** OP_Rewind/Op_Next with no intervening instructions that might invalidate - ** the cursor. Hence the following sqlite3VdbeCursorMoveto() call is always - ** a no-op and can never fail. But we leave it in place as a safety. + ** the cursor. If this where not the case, on of the following assert()s + ** would fail. Should this ever change (because of changes in the code + ** generator) then the fix would be to insert a call to + ** sqlite3VdbeCursorMoveto(). */ assert( pC->deferredMoveto==0 ); + assert( sqlite3BtreeCursorIsValid(pCrsr) ); +#if 0 /* Not required due to the previous to assert() statements */ rc = sqlite3VdbeCursorMoveto(pC); - if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; + if( rc!=SQLITE_OK ) goto abort_due_to_error; +#endif if( pC->isTable==0 ){ assert( !pC->isTable ); @@ -4394,7 +4361,8 @@ case OP_RowData: { goto too_big; } } - if( sqlite3VdbeMemGrow(pOut, n, 0) ){ + testcase( n==0 ); + if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){ goto no_mem; } pOut->n = n; @@ -4445,14 +4413,14 @@ case OP_Rowid: { /* out2-prerelease */ #endif /* SQLITE_OMIT_VIRTUALTABLE */ }else{ assert( pC->pCursor!=0 ); - rc = sqlite3VdbeCursorMoveto(pC); + rc = sqlite3VdbeCursorRestore(pC); if( rc ) goto abort_due_to_error; - if( pC->rowidIsValid ){ - v = pC->lastRowid; - }else{ - rc = sqlite3BtreeKeySize(pC->pCursor, &v); - assert( rc==SQLITE_OK ); /* Always so because of CursorMoveto() above */ + if( pC->nullRow ){ + pOut->flags = MEM_Null; + break; } + rc = sqlite3BtreeKeySize(pC->pCursor, &v); + assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */ } pOut->u.i = v; break; @@ -4471,7 +4439,6 @@ case OP_NullRow: { pC = p->apCsr[pOp->p1]; assert( pC!=0 ); pC->nullRow = 1; - pC->rowidIsValid = 0; pC->cacheStatus = CACHE_STALE; if( pC->pCursor ){ sqlite3BtreeClearCursor(pC->pCursor); @@ -4505,7 +4472,6 @@ case OP_Last: { /* jump */ rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = (u8)res; pC->deferredMoveto = 0; - pC->rowidIsValid = 0; pC->cacheStatus = CACHE_STALE; #ifdef SQLITE_DEBUG pC->seekOp = OP_Last; @@ -4543,9 +4509,9 @@ case OP_Sort: { /* jump */ ** ** The next use of the Rowid or Column or Next instruction for P1 ** will refer to the first entry in the database table or index. -** If the table or index is empty and P2>0, then jump immediately to P2. -** If P2 is 0 or if the table or index is not empty, fall through -** to the following instruction. +** If the table or index is empty, jump immediately to P2. +** If the table or index is not empty, fall through to the following +** instruction. ** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is @@ -4565,14 +4531,13 @@ case OP_Rewind: { /* jump */ pC->seekOp = OP_Rewind; #endif if( isSorter(pC) ){ - rc = sqlite3VdbeSorterRewind(db, pC, &res); + rc = sqlite3VdbeSorterRewind(pC, &res); }else{ pCrsr = pC->pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; - pC->rowidIsValid = 0; } pC->nullRow = (u8)res; assert( pOp->p2>0 && pOp->p2nOp ); @@ -4698,7 +4663,6 @@ next_tail: }else{ pC->nullRow = 1; } - pC->rowidIsValid = 0; goto check_for_interrupt; } @@ -4743,7 +4707,7 @@ case OP_IdxInsert: { /* in2 */ rc = ExpandBlob(pIn2); if( rc==SQLITE_OK ){ if( isSorter(pC) ){ - rc = sqlite3VdbeSorterWrite(db, pC, pIn2); + rc = sqlite3VdbeSorterWrite(pC, pIn2); }else{ nKey = pIn2->n; zKey = pIn2->z; @@ -4814,10 +4778,16 @@ case OP_IdxRowid: { /* out2-prerelease */ pCrsr = pC->pCursor; assert( pCrsr!=0 ); pOut->flags = MEM_Null; - rc = sqlite3VdbeCursorMoveto(pC); - if( NEVER(rc) ) goto abort_due_to_error; - assert( pC->deferredMoveto==0 ); assert( pC->isTable==0 ); + assert( pC->deferredMoveto==0 ); + + /* sqlite3VbeCursorRestore() can only fail if the record has been deleted + ** out from under the cursor. That will never happend for an IdxRowid + ** opcode, hence the NEVER() arround the check of the return value. + */ + rc = sqlite3VdbeCursorRestore(pC); + if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; + if( !pC->nullRow ){ rowid = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid); @@ -4904,7 +4874,7 @@ case OP_IdxGE: { /* jump */ { int i; for(i=0; iopcode&1)==(OP_IdxLT&1) ){ assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT ); @@ -5457,6 +5427,9 @@ case OP_Program: { /* jump */ pFrame->token = pProgram->token; pFrame->aOnceFlag = p->aOnceFlag; pFrame->nOnceFlag = p->nOnceFlag; +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + pFrame->anExec = p->anExec; +#endif pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ @@ -5474,6 +5447,7 @@ case OP_Program: { /* jump */ pFrame->pParent = p->pFrame; pFrame->lastRowid = lastRowid; pFrame->nChange = p->nChange; + pFrame->nDbChange = p->db->nChange; p->nChange = 0; p->pFrame = pFrame; p->aMem = aMem = &VdbeFrameMem(pFrame)[-1]; @@ -5484,6 +5458,9 @@ case OP_Program: { /* jump */ p->nOp = pProgram->nOp; p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor]; p->nOnceFlag = pProgram->nOnce; +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + p->anExec = 0; +#endif pc = -1; memset(p->aOnceFlag, 0, p->nOnceFlag); @@ -5656,6 +5633,7 @@ case OP_AggStep: { int i; Mem *pMem; Mem *pRec; + Mem t; sqlite3_context ctx; sqlite3_value **apVal; @@ -5673,23 +5651,15 @@ case OP_AggStep: { assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); ctx.pMem = pMem = &aMem[pOp->p3]; pMem->n++; - ctx.s.flags = MEM_Null; - ctx.s.z = 0; - ctx.s.zMalloc = 0; - ctx.s.xDel = 0; - ctx.s.db = db; + sqlite3VdbeMemInit(&t, db, MEM_Null); + ctx.pOut = &t; ctx.isError = 0; - ctx.pColl = 0; + ctx.pVdbe = p; + ctx.iOp = pc; ctx.skipFlag = 0; - if( ctx.pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ - assert( pOp>p->aOp ); - assert( pOp[-1].p4type==P4_COLLSEQ ); - assert( pOp[-1].opcode==OP_CollSeq ); - ctx.pColl = pOp[-1].p4.pColl; - } (ctx.pFunc->xStep)(&ctx, n, apVal); /* IMP: R-24505-23230 */ if( ctx.isError ){ - sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s)); + sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&t)); rc = ctx.isError; } if( ctx.skipFlag ){ @@ -5697,9 +5667,7 @@ case OP_AggStep: { i = pOp[-1].p1; if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1); } - - sqlite3VdbeMemRelease(&ctx.s); - + sqlite3VdbeMemRelease(&t); break; } @@ -5737,8 +5705,8 @@ case OP_AggFinal: { /* Opcode: Checkpoint P1 P2 P3 * * ** ** Checkpoint database P1. This is a no-op if P1 is not currently in -** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL -** or RESTART. Write 1 or 0 into mem[P3] if the checkpoint returns +** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL, +** RESTART, or TRUNCATE. Write 1 or 0 into mem[P3] if the checkpoint returns ** SQLITE_BUSY or not, respectively. Write the number of pages in the ** WAL after the checkpoint into mem[P3+1] and the number of pages ** in the WAL that have been checkpointed after the checkpoint @@ -5756,6 +5724,7 @@ case OP_Checkpoint: { assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE || pOp->p2==SQLITE_CHECKPOINT_FULL || pOp->p2==SQLITE_CHECKPOINT_RESTART + || pOp->p2==SQLITE_CHECKPOINT_TRUNCATE ); rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]); if( rc==SQLITE_BUSY ){ @@ -6149,27 +6118,14 @@ case OP_VColumn: { pModule = pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); - - /* The output cell may already have a buffer allocated. Move - ** the current contents to sContext.s so in case the user-function - ** can use the already allocated buffer instead of allocating a - ** new one. - */ - sqlite3VdbeMemMove(&sContext.s, pDest); - MemSetTypeFlag(&sContext.s, MEM_Null); - + sContext.pOut = pDest; + MemSetTypeFlag(pDest, MEM_Null); rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2); sqlite3VtabImportErrmsg(p, pVtab); if( sContext.isError ){ rc = sContext.isError; } - - /* Copy the result of the function to the P3 register. We - ** do this regardless of whether or not an error occurred to ensure any - ** dynamic allocation in sContext.s (a Mem struct) is released. - */ - sqlite3VdbeChangeEncoding(&sContext.s, encoding); - sqlite3VdbeMemMove(pDest, &sContext.s); + sqlite3VdbeChangeEncoding(pDest, encoding); REGISTER_TRACE(pOp->p3, pDest); UPDATE_MAX_BLOBSIZE(pDest); diff --git a/src/vdbe.h b/src/vdbe.h index ef91010..b715241 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -212,10 +212,10 @@ void sqlite3VdbeSetVarmask(Vdbe*, int); int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); -int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int); +int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); -typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int); +typedef int (*RecordCompare)(int,const void*,UnpackedRecord*); RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); #ifndef SQLITE_OMIT_TRIGGER @@ -282,4 +282,10 @@ void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); # define VDBE_OFFSET_LINENO(x) 0 #endif +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); +#else +# define sqlite3VdbeScanStatus(a,b,c,d,e) +#endif + #endif diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 141573e..1a7297e 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -73,7 +73,6 @@ struct VdbeCursor { #endif i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ - u8 rowidIsValid; /* True if lastRowid is valid */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ @@ -83,7 +82,6 @@ struct VdbeCursor { sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ - i64 lastRowid; /* Rowid being deleted by OP_Delete */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ /* Cached information about the header for the data record that the @@ -100,6 +98,7 @@ struct VdbeCursor { u32 szRow; /* Byte available in aRow */ u32 iHdrOffset; /* Offset to next unparsed byte of the header */ const u8 *aRow; /* Data for the current row, if all on one page */ + u32 *aOffset; /* Pointer to aType[nField] */ u32 aType[1]; /* Type values for all entries in the record */ /* 2*nField extra array elements allocated for aType[], beyond the one ** static element declared in the structure. nField total array slots for @@ -133,6 +132,7 @@ struct VdbeFrame { Vdbe *v; /* VM this frame belongs to */ VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */ Op *aOp; /* Program instructions for parent frame */ + i64 *anExec; /* Event counters from parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ @@ -145,7 +145,8 @@ struct VdbeFrame { int nOnceFlag; /* Number of entries in aOnceFlag */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ - int nChange; /* Statement changes (Vdbe.nChanges) */ + int nChange; /* Statement changes (Vdbe.nChange) */ + int nDbChange; /* Value of db->nChange */ }; #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) @@ -161,25 +162,28 @@ struct VdbeFrame { ** integer etc.) of the same value. */ struct Mem { - sqlite3 *db; /* The associated database connection */ - char *z; /* String or BLOB value */ - double r; /* Real value */ - union { + union MemValue { + double r; /* Real value used when MEM_Real is set in flags */ i64 i; /* Integer value used when MEM_Int is set in flags */ int nZero; /* Used when bit MEM_Zero is set in flags */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ } u; - int n; /* Number of characters in string value, excluding '\0' */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ + int n; /* Number of characters in string value, excluding '\0' */ + char *z; /* String or BLOB value */ + /* ShallowCopy only needs to copy the information above */ + char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ + int szMalloc; /* Size of the zMalloc allocation */ + u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */ + sqlite3 *db; /* The associated database connection */ + void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */ #endif - void (*xDel)(void *); /* If not null, call this function to delete Mem.z */ - char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */ }; /* One or more of the following flags are set to indicate the validOK @@ -238,7 +242,7 @@ struct Mem { #endif /* -** Each auxilliary data pointer stored by a user defined function +** Each auxiliary data pointer stored by a user defined function ** implementation calling sqlite3_set_auxdata() is stored in an instance ** of this structure. All such structures associated with a single VM ** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed @@ -253,7 +257,7 @@ struct AuxData { }; /* -** The "context" argument for a installable function. A pointer to an +** The "context" argument for an installable function. A pointer to an ** instance of this structure is the first argument to the routines used ** implement the SQL functions. ** @@ -266,14 +270,13 @@ struct AuxData { ** (Mem) which are only defined there. */ struct sqlite3_context { - FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ - Mem s; /* The return value is stored here */ + Mem *pOut; /* The return value is stored here */ + FuncDef *pFunc; /* Pointer to function information */ Mem *pMem; /* Memory cell used to store aggregate context */ - CollSeq *pColl; /* Collating sequence */ Vdbe *pVdbe; /* The VM that owns this context */ int iOp; /* Instruction number of OP_Function */ int isError; /* Error code returned by the function. */ - u8 skipFlag; /* Skip skip accumulator loading if true */ + u8 skipFlag; /* Skip accumulator loading if true */ u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */ }; @@ -294,6 +297,16 @@ struct Explain { */ typedef unsigned bft; /* Bit Field Type */ +typedef struct ScanStatus ScanStatus; +struct ScanStatus { + int addrExplain; /* OP_Explain for loop */ + int addrLoop; /* Address of "loops" counter */ + int addrVisit; /* Address of "rows visited" counter */ + int iSelectID; /* The "Select-ID" for this loop */ + LogEst nEst; /* Estimated output rows per loop */ + char *zName; /* Name of table or index */ +}; + /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. @@ -358,10 +371,6 @@ struct Vdbe { i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ char *zSql; /* Text of the SQL statement that generated this */ void *pFree; /* Free this when deleting the vdbe */ -#ifdef SQLITE_ENABLE_TREE_EXPLAIN - Explain *pExplain; /* The explainer */ - char *zExplain; /* Explanation of data structures */ -#endif VdbeFrame *pFrame; /* Parent frame */ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ int nFrame; /* Number of frames in pFrame list */ @@ -370,6 +379,11 @@ struct Vdbe { int nOnceFlag; /* Size of array aOnceFlag[] */ u8 *aOnceFlag; /* Flags for OP_Once */ AuxData *pAuxData; /* Linked list of auxdata allocations */ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + i64 *anExec; /* Number of times each op has been executed */ + int nScan; /* Entries in aScan[] */ + ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ +#endif }; /* @@ -386,6 +400,7 @@ struct Vdbe { void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); void sqliteVdbePopStack(Vdbe*,int); int sqlite3VdbeCursorMoveto(VdbeCursor*); +int sqlite3VdbeCursorRestore(VdbeCursor*); #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) void sqlite3VdbePrintOp(FILE*, int, Op*); #endif @@ -396,8 +411,8 @@ u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); void sqlite3VdbeDeleteAuxData(Vdbe*, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); -int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*); -int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *); +int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*); +int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*); int sqlite3VdbeExec(Vdbe*); int sqlite3VdbeList(Vdbe*); int sqlite3VdbeHalt(Vdbe*); @@ -414,39 +429,39 @@ void sqlite3VdbeMemSetInt64(Mem*, i64); #else void sqlite3VdbeMemSetDouble(Mem*, double); #endif +void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); void sqlite3VdbeMemSetNull(Mem*); void sqlite3VdbeMemSetZeroBlob(Mem*,int); void sqlite3VdbeMemSetRowSet(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); -int sqlite3VdbeMemStringify(Mem*, int); +int sqlite3VdbeMemStringify(Mem*, u8, u8); i64 sqlite3VdbeIntValue(Mem*); int sqlite3VdbeMemIntegerify(Mem*); double sqlite3VdbeRealValue(Mem*); void sqlite3VdbeIntegerAffinity(Mem*); int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemNumerify(Mem*); +void sqlite3VdbeMemCast(Mem*,u8,u8); int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*); void sqlite3VdbeMemRelease(Mem *p); -void sqlite3VdbeMemReleaseExternal(Mem *p); #define VdbeMemDynamic(X) \ (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0) -#define VdbeMemRelease(X) \ - if( VdbeMemDynamic(X) ) sqlite3VdbeMemReleaseExternal(X); int sqlite3VdbeMemFinalize(Mem*, FuncDef*); const char *sqlite3OpcodeName(int); int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); +int sqlite3VdbeMemClearAndResize(Mem *pMem, int n); int sqlite3VdbeCloseStatement(Vdbe *, int); void sqlite3VdbeFrameDelete(VdbeFrame*); int sqlite3VdbeFrameRestore(VdbeFrame *); int sqlite3VdbeTransferError(Vdbe *p); -int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); +int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); -int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *); -int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *); +int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); +int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 5e5bb81..21c537d 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -212,9 +212,12 @@ int sqlite3_value_type(sqlite3_value* pVal){ ** The following routines are used by user-defined functions to specify ** the function result. ** -** The setStrOrError() funtion calls sqlite3VdbeMemSetStr() to store the +** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the ** result as a string or blob but if the string or blob is too large, it ** then sets the error code to SQLITE_TOOBIG +** +** The invokeValueDestructor(P,X) routine invokes destructor function X() +** on value P is not going to be used and need to be destroyed. */ static void setResultStrOrError( sqlite3_context *pCtx, /* Function context */ @@ -223,10 +226,26 @@ static void setResultStrOrError( u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ - if( sqlite3VdbeMemSetStr(&pCtx->s, z, n, enc, xDel)==SQLITE_TOOBIG ){ + if( sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel)==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(pCtx); } } +static int invokeValueDestructor( + const void *p, /* Value to destroy */ + void (*xDel)(void*), /* The destructor */ + sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */ +){ + assert( xDel!=SQLITE_DYNAMIC ); + if( xDel==0 ){ + /* noop */ + }else if( xDel==SQLITE_TRANSIENT ){ + /* noop */ + }else{ + xDel((void*)p); + } + if( pCtx ) sqlite3_result_error_toobig(pCtx); + return SQLITE_TOOBIG; +} void sqlite3_result_blob( sqlite3_context *pCtx, const void *z, @@ -234,38 +253,52 @@ void sqlite3_result_blob( void (*xDel)(void *) ){ assert( n>=0 ); - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, 0, xDel); } +void sqlite3_result_blob64( + sqlite3_context *pCtx, + const void *z, + sqlite3_uint64 n, + void (*xDel)(void *) +){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + assert( xDel!=SQLITE_DYNAMIC ); + if( n>0x7fffffff ){ + (void)invokeValueDestructor(z, xDel, pCtx); + }else{ + setResultStrOrError(pCtx, z, (int)n, 0, xDel); + } +} void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetDouble(&pCtx->s, rVal); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetDouble(pCtx->pOut, rVal); } void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; pCtx->fErrorOrAux = 1; - sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); + sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); } #ifndef SQLITE_OMIT_UTF16 void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; pCtx->fErrorOrAux = 1; - sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); + sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); } #endif void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal); } void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetInt64(&pCtx->s, iVal); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetInt64(pCtx->pOut, iVal); } void sqlite3_result_null(sqlite3_context *pCtx){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetNull(&pCtx->s); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetNull(pCtx->pOut); } void sqlite3_result_text( sqlite3_context *pCtx, @@ -273,9 +306,25 @@ void sqlite3_result_text( int n, void (*xDel)(void *) ){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel); } +void sqlite3_result_text64( + sqlite3_context *pCtx, + const char *z, + sqlite3_uint64 n, + void (*xDel)(void *), + unsigned char enc +){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + assert( xDel!=SQLITE_DYNAMIC ); + if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; + if( n>0x7fffffff ){ + (void)invokeValueDestructor(z, xDel, pCtx); + }else{ + setResultStrOrError(pCtx, z, (int)n, enc, xDel); + } +} #ifndef SQLITE_OMIT_UTF16 void sqlite3_result_text16( sqlite3_context *pCtx, @@ -283,7 +332,7 @@ void sqlite3_result_text16( int n, void (*xDel)(void *) ){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel); } void sqlite3_result_text16be( @@ -292,7 +341,7 @@ void sqlite3_result_text16be( int n, void (*xDel)(void *) ){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel); } void sqlite3_result_text16le( @@ -301,43 +350,43 @@ void sqlite3_result_text16le( int n, void (*xDel)(void *) ){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel); } #endif /* SQLITE_OMIT_UTF16 */ void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemCopy(&pCtx->s, pValue); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemCopy(pCtx->pOut, pValue); } void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetZeroBlob(&pCtx->s, n); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n); } void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ pCtx->isError = errCode; pCtx->fErrorOrAux = 1; - if( pCtx->s.flags & MEM_Null ){ - sqlite3VdbeMemSetStr(&pCtx->s, sqlite3ErrStr(errCode), -1, + if( pCtx->pOut->flags & MEM_Null ){ + sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, SQLITE_UTF8, SQLITE_STATIC); } } /* Force an SQLITE_TOOBIG error. */ void sqlite3_result_error_toobig(sqlite3_context *pCtx){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_TOOBIG; pCtx->fErrorOrAux = 1; - sqlite3VdbeMemSetStr(&pCtx->s, "string or blob too big", -1, + sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1, SQLITE_UTF8, SQLITE_STATIC); } /* An SQLITE_NOMEM error. */ void sqlite3_result_error_nomem(sqlite3_context *pCtx){ - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - sqlite3VdbeMemSetNull(&pCtx->s); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetNull(pCtx->pOut); pCtx->isError = SQLITE_NOMEM; pCtx->fErrorOrAux = 1; - pCtx->s.db->mallocFailed = 1; + pCtx->pOut->db->mallocFailed = 1; } /* @@ -351,7 +400,10 @@ static int doWalCallbacks(sqlite3 *db){ for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ - int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); + int nEntry; + sqlite3BtreeEnter(pBt); + nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); + sqlite3BtreeLeave(pBt); if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){ rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry); } @@ -513,10 +565,12 @@ int sqlite3_step(sqlite3_stmt *pStmt){ sqlite3_mutex_enter(db->mutex); v->doingRerun = 0; while( (rc = sqlite3Step(v))==SQLITE_SCHEMA - && cnt++ < SQLITE_MAX_SCHEMA_RETRY - && (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){ + && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ + int savedPc = v->pc; + rc2 = rc = sqlite3Reprepare(v); + if( rc!=SQLITE_OK) break; sqlite3_reset(pStmt); - v->doingRerun = 1; + if( savedPc>=0 ) v->doingRerun = 1; assert( v->expired==0 ); } if( rc2!=SQLITE_OK ){ @@ -529,7 +583,6 @@ int sqlite3_step(sqlite3_stmt *pStmt){ ** sqlite3_errmsg() and sqlite3_errcode(). */ const char *zErr = (const char *)sqlite3_value_text(db->pErr); - assert( zErr!=0 || db->mallocFailed ); sqlite3DbFree(db, v->zErrMsg); if( !db->mallocFailed ){ v->zErrMsg = sqlite3DbStrDup(db, zErr); @@ -566,7 +619,7 @@ void *sqlite3_user_data(sqlite3_context *p){ */ sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ assert( p && p->pFunc ); - return p->s.db; + return p->pOut->db; } /* @@ -576,7 +629,7 @@ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ Vdbe *v = p->pVdbe; int rc; if( v->iCurrentTime==0 ){ - rc = sqlite3OsCurrentTimeInt64(p->s.db->pVfs, &v->iCurrentTime); + rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, &v->iCurrentTime); if( rc ) v->iCurrentTime = 0; } return v->iCurrentTime; @@ -605,41 +658,50 @@ void sqlite3InvalidFunction( } /* -** Allocate or return the aggregate context for a user function. A new -** context is allocated on the first call. Subsequent calls return the -** same context that was returned on prior calls. +** Create a new aggregate context for p and return a pointer to +** its pMem->z element. */ -void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ - Mem *pMem; - assert( p && p->pFunc && p->pFunc->xStep ); - assert( sqlite3_mutex_held(p->s.db->mutex) ); - pMem = p->pMem; - testcase( nByte<0 ); - if( (pMem->flags & MEM_Agg)==0 ){ - if( nByte<=0 ){ - sqlite3VdbeMemReleaseExternal(pMem); - pMem->flags = MEM_Null; - pMem->z = 0; - }else{ - sqlite3VdbeMemGrow(pMem, nByte, 0); - pMem->flags = MEM_Agg; - pMem->u.pDef = p->pFunc; - if( pMem->z ){ - memset(pMem->z, 0, nByte); - } +static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){ + Mem *pMem = p->pMem; + assert( (pMem->flags & MEM_Agg)==0 ); + if( nByte<=0 ){ + sqlite3VdbeMemSetNull(pMem); + pMem->z = 0; + }else{ + sqlite3VdbeMemClearAndResize(pMem, nByte); + pMem->flags = MEM_Agg; + pMem->u.pDef = p->pFunc; + if( pMem->z ){ + memset(pMem->z, 0, nByte); } } return (void*)pMem->z; } /* -** Return the auxilary data pointer, if any, for the iArg'th argument to +** Allocate or return the aggregate context for a user function. A new +** context is allocated on the first call. Subsequent calls return the +** same context that was returned on prior calls. +*/ +void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ + assert( p && p->pFunc && p->pFunc->xStep ); + assert( sqlite3_mutex_held(p->pOut->db->mutex) ); + testcase( nByte<0 ); + if( (p->pMem->flags & MEM_Agg)==0 ){ + return createAggContext(p, nByte); + }else{ + return (void*)p->pMem->z; + } +} + +/* +** Return the auxiliary data pointer, if any, for the iArg'th argument to ** the user-function defined by pCtx. */ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; } @@ -648,7 +710,7 @@ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ } /* -** Set the auxilary data pointer and delete function, for the iArg'th +** Set the auxiliary data pointer and delete function, for the iArg'th ** argument to the user-function defined by pCtx. Any previous value is ** deleted by calling the delete function specified when it was set. */ @@ -661,7 +723,7 @@ void sqlite3_set_auxdata( AuxData *pAuxData; Vdbe *pVdbe = pCtx->pVdbe; - assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); if( iArg<0 ) goto failed; for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ @@ -694,7 +756,7 @@ failed: #ifndef SQLITE_OMIT_DEPRECATED /* -** Return the number of times the Step function of a aggregate has been +** Return the number of times the Step function of an aggregate has been ** called. ** ** This function is deprecated. Do not use it for new code. It is @@ -743,11 +805,22 @@ static const Mem *columnNullValue(void){ #if defined(SQLITE_DEBUG) && defined(__GNUC__) __attribute__((aligned(8))) #endif - = {0, "", (double)0, {0}, 0, MEM_Null, 0, + = { + /* .u = */ {0}, + /* .flags = */ MEM_Null, + /* .enc = */ 0, + /* .n = */ 0, + /* .z = */ 0, + /* .zMalloc = */ 0, + /* .szMalloc = */ 0, + /* .iPadding1 = */ 0, + /* .db = */ 0, + /* .xDel = */ 0, #ifdef SQLITE_DEBUG - 0, 0, /* pScopyFrom, pFiller */ + /* .pScopyFrom = */ 0, + /* .pFiller = */ 0, #endif - 0, 0 }; + }; return &nullMem; } @@ -768,7 +841,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){ }else{ if( pVm && ALWAYS(pVm->db) ){ sqlite3_mutex_enter(pVm->db->mutex); - sqlite3Error(pVm->db, SQLITE_RANGE, 0); + sqlite3Error(pVm->db, SQLITE_RANGE); } pOut = (Mem*)columnNullValue(); } @@ -895,11 +968,19 @@ static const void *columnName( const void *(*xFunc)(Mem*), int useType ){ - const void *ret = 0; - Vdbe *p = (Vdbe *)pStmt; + const void *ret; + Vdbe *p; int n; - sqlite3 *db = p->db; - + sqlite3 *db; +#ifdef SQLITE_ENABLE_API_ARMOR + if( pStmt==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + ret = 0; + p = (Vdbe *)pStmt; + db = p->db; assert( db!=0 ); n = sqlite3_column_count(pStmt); if( N=0 ){ @@ -964,7 +1045,7 @@ const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ /* ** Return the name of the database from which a result column derives. ** NULL is returned if the result column is an expression or constant or -** anything else which is not an unabiguous reference to a database column. +** anything else which is not an unambiguous reference to a database column. */ const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){ return columnName( @@ -980,7 +1061,7 @@ const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){ /* ** Return the name of the table from which a result column derives. ** NULL is returned if the result column is an expression or constant or -** anything else which is not an unabiguous reference to a database column. +** anything else which is not an unambiguous reference to a database column. */ const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){ return columnName( @@ -996,7 +1077,7 @@ const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ /* ** Return the name of the table column from which a result column derives. ** NULL is returned if the result column is an expression or constant or -** anything else which is not an unabiguous reference to a database column. +** anything else which is not an unambiguous reference to a database column. */ const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){ return columnName( @@ -1033,14 +1114,14 @@ static int vdbeUnbind(Vdbe *p, int i){ } sqlite3_mutex_enter(p->db->mutex); if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){ - sqlite3Error(p->db, SQLITE_MISUSE, 0); + sqlite3Error(p->db, SQLITE_MISUSE); sqlite3_mutex_leave(p->db->mutex); sqlite3_log(SQLITE_MISUSE, "bind on a busy prepared statement: [%s]", p->zSql); return SQLITE_MISUSE_BKPT; } if( i<1 || i>p->nVar ){ - sqlite3Error(p->db, SQLITE_RANGE, 0); + sqlite3Error(p->db, SQLITE_RANGE); sqlite3_mutex_leave(p->db->mutex); return SQLITE_RANGE; } @@ -1048,7 +1129,7 @@ static int vdbeUnbind(Vdbe *p, int i){ pVar = &p->aVar[i]; sqlite3VdbeMemRelease(pVar); pVar->flags = MEM_Null; - sqlite3Error(p->db, SQLITE_OK, 0); + sqlite3Error(p->db, SQLITE_OK); /* If the bit corresponding to this variable in Vdbe.expmask is set, then ** binding a new value to this variable invalidates the current query plan. @@ -1090,7 +1171,7 @@ static int bindText( if( rc==SQLITE_OK && encoding!=0 ){ rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); } - sqlite3Error(p->db, rc, 0); + sqlite3Error(p->db, rc); rc = sqlite3ApiExit(p->db, rc); } sqlite3_mutex_leave(p->db->mutex); @@ -1113,6 +1194,20 @@ int sqlite3_bind_blob( ){ return bindText(pStmt, i, zData, nData, xDel, 0); } +int sqlite3_bind_blob64( + sqlite3_stmt *pStmt, + int i, + const void *zData, + sqlite3_uint64 nData, + void (*xDel)(void*) +){ + assert( xDel!=SQLITE_DYNAMIC ); + if( nData>0x7fffffff ){ + return invokeValueDestructor(zData, xDel, 0); + }else{ + return bindText(pStmt, i, zData, (int)nData, xDel, 0); + } +} int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ int rc; Vdbe *p = (Vdbe *)pStmt; @@ -1154,6 +1249,22 @@ int sqlite3_bind_text( ){ return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8); } +int sqlite3_bind_text64( + sqlite3_stmt *pStmt, + int i, + const char *zData, + sqlite3_uint64 nData, + void (*xDel)(void*), + unsigned char enc +){ + assert( xDel!=SQLITE_DYNAMIC ); + if( nData>0x7fffffff ){ + return invokeValueDestructor(zData, xDel, 0); + }else{ + if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; + return bindText(pStmt, i, zData, (int)nData, xDel, enc); + } +} #ifndef SQLITE_OMIT_UTF16 int sqlite3_bind_text16( sqlite3_stmt *pStmt, @@ -1173,7 +1284,7 @@ int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ break; } case SQLITE_FLOAT: { - rc = sqlite3_bind_double(pStmt, i, pValue->r); + rc = sqlite3_bind_double(pStmt, i, pValue->u.r); break; } case SQLITE_BLOB: { @@ -1276,7 +1387,7 @@ int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){ ** Deprecated external interface. Internal/core SQLite code ** should call sqlite3TransferBindings. ** -** Is is misuse to call this routine with statements from different +** It is misuse to call this routine with statements from different ** database connections. But as this is a deprecated interface, we ** will not bother to check for that condition. ** @@ -1334,6 +1445,12 @@ int sqlite3_stmt_busy(sqlite3_stmt *pStmt){ */ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){ sqlite3_stmt *pNext; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(pDb) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif sqlite3_mutex_enter(pDb->mutex); if( pStmt==0 ){ pNext = (sqlite3_stmt*)pDb->pVdbe; @@ -1349,7 +1466,83 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){ */ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){ Vdbe *pVdbe = (Vdbe*)pStmt; - u32 v = pVdbe->aCounter[op]; + u32 v; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !pStmt ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + v = pVdbe->aCounter[op]; if( resetFlag ) pVdbe->aCounter[op] = 0; return (int)v; } + +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +/* +** Return status data for a single loop within query pStmt. +*/ +int sqlite3_stmt_scanstatus( + sqlite3_stmt *pStmt, /* Prepared statement being queried */ + int idx, /* Index of loop to report on */ + int iScanStatusOp, /* Which metric to return */ + void *pOut /* OUT: Write the answer here */ +){ + Vdbe *p = (Vdbe*)pStmt; + ScanStatus *pScan; + if( idx<0 || idx>=p->nScan ) return 1; + pScan = &p->aScan[idx]; + switch( iScanStatusOp ){ + case SQLITE_SCANSTAT_NLOOP: { + *(sqlite3_int64*)pOut = p->anExec[pScan->addrLoop]; + break; + } + case SQLITE_SCANSTAT_NVISIT: { + *(sqlite3_int64*)pOut = p->anExec[pScan->addrVisit]; + break; + } + case SQLITE_SCANSTAT_EST: { + double r = 1.0; + LogEst x = pScan->nEst; + while( x<100 ){ + x += 10; + r *= 0.5; + } + *(double*)pOut = r*sqlite3LogEstToInt(x); + break; + } + case SQLITE_SCANSTAT_NAME: { + *(const char**)pOut = pScan->zName; + break; + } + case SQLITE_SCANSTAT_EXPLAIN: { + if( pScan->addrExplain ){ + *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z; + }else{ + *(const char**)pOut = 0; + } + break; + } + case SQLITE_SCANSTAT_SELECTID: { + if( pScan->addrExplain ){ + *(int*)pOut = p->aOp[ pScan->addrExplain ].p1; + }else{ + *(int*)pOut = -1; + } + break; + } + default: { + return 1; + } + } + return 0; +} + +/* +** Zero all counters associated with the sqlite3_stmt_scanstatus() data. +*/ +void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe*)pStmt; + memset(p->anExec, 0, p->nOp * sizeof(i64)); +} +#endif /* SQLITE_ENABLE_STMT_SCANSTATUS */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index fb3f7c3..e07aacb 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -10,9 +10,7 @@ ** ************************************************************************* ** This file contains code used for creating, destroying, and populating -** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior -** to version 2.8.7, all this code was combined into the vdbe.c source file. -** But that file was getting too big so this subroutines were split out. +** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) */ #include "sqliteInt.h" #include "vdbeInt.h" @@ -398,6 +396,7 @@ static Op *opIterNext(VdbeOpIter *p){ */ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ int hasAbort = 0; + int hasFkCounter = 0; Op *pOp; VdbeOpIter sIter; memset(&sIter, 0, sizeof(sIter)); @@ -406,15 +405,17 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ while( (pOp = opIterNext(&sIter))!=0 ){ int opcode = pOp->opcode; if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename -#ifndef SQLITE_OMIT_FOREIGN_KEY - || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1) -#endif || ((opcode==OP_Halt || opcode==OP_HaltIfNull) && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort)) ){ hasAbort = 1; break; } +#ifndef SQLITE_OMIT_FOREIGN_KEY + if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){ + hasFkCounter = 1; + } +#endif } sqlite3DbFree(v->db, sIter.apSub); @@ -423,7 +424,7 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ ** through all opcodes and hasAbort may be set incorrectly. Return ** true for this case to prevent the assert() in the callers frame ** from failing. */ - return ( v->db->mallocFailed || hasAbort==mayAbort ); + return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter ); } #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ @@ -599,6 +600,34 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){ return addr; } +#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) +/* +** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus(). +*/ +void sqlite3VdbeScanStatus( + Vdbe *p, /* VM to add scanstatus() to */ + int addrExplain, /* Address of OP_Explain (or 0) */ + int addrLoop, /* Address of loop counter */ + int addrVisit, /* Address of rows visited counter */ + LogEst nEst, /* Estimated number of output rows */ + const char *zName /* Name of table or index being scanned */ +){ + int nByte = (p->nScan+1) * sizeof(ScanStatus); + ScanStatus *aNew; + aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); + if( aNew ){ + ScanStatus *pNew = &aNew[p->nScan++]; + pNew->addrExplain = addrExplain; + pNew->addrLoop = addrLoop; + pNew->addrVisit = addrVisit; + pNew->nEst = nEst; + pNew->zName = sqlite3DbStrDup(p->db, zName); + p->aScan = aNew; + } +} +#endif + + /* ** Change the value of the P1 operand for a specific instruction. ** This routine is useful when a large program is loaded from a @@ -698,7 +727,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ sqlite3ValueFree((sqlite3_value*)p4); }else{ Mem *p = (Mem*)p4; - sqlite3DbFree(db, p->zMalloc); + if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); sqlite3DbFree(db, p); } break; @@ -754,7 +783,8 @@ void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ } /* -** Remove the last opcode inserted +** If the last opcode is "op" and it is not a jump destination, +** then remove it. Return true if and only if an opcode was removed. */ int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){ @@ -895,7 +925,7 @@ void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){ ** routine, then a pointer to a dummy VdbeOp will be returned. That opcode ** is readable but not writable, though it is cast to a writable value. ** The return of a dummy opcode allows the call to continue functioning -** after a OOM fault without having to check to see if the return from +** after an OOM fault without having to check to see if the return from ** this routine is a valid pointer. But because the dummy.opcode is 0, ** dummy will never be written to. This is verified by code inspection and ** by running with Valgrind. @@ -1076,7 +1106,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ }else if( pMem->flags & MEM_Int ){ sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i); }else if( pMem->flags & MEM_Real ){ - sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->r); + sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->u.r); }else if( pMem->flags & MEM_Null ){ sqlite3_snprintf(nTemp, zTemp, "NULL"); }else{ @@ -1226,16 +1256,16 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ */ static void releaseMemArray(Mem *p, int N){ if( p && N ){ - Mem *pEnd; + Mem *pEnd = &p[N]; sqlite3 *db = p->db; u8 malloc_failed = db->mallocFailed; if( db->pnBytesFreed ){ - for(pEnd=&p[N]; pzMalloc); - } + do{ + if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); + }while( (++p)flags & MEM_RowSet ); if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){ sqlite3VdbeMemRelease(p); - }else if( p->zMalloc ){ + }else if( p->szMalloc ){ sqlite3DbFree(db, p->zMalloc); - p->zMalloc = 0; + p->szMalloc = 0; } p->flags = MEM_Undefined; - } + }while( (++p)mallocFailed = malloc_failed; } } @@ -1426,7 +1456,7 @@ int sqlite3VdbeList( pMem->u.i = pOp->p3; /* P3 */ pMem++; - if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */ + if( sqlite3VdbeMemClearAndResize(pMem, 32) ){ /* P4 */ assert( p->db->mallocFailed ); return SQLITE_ERROR; } @@ -1442,7 +1472,7 @@ int sqlite3VdbeList( pMem++; if( p->explain==1 ){ - if( sqlite3VdbeMemGrow(pMem, 4, 0) ){ + if( sqlite3VdbeMemClearAndResize(pMem, 4) ){ assert( p->db->mallocFailed ); return SQLITE_ERROR; } @@ -1453,7 +1483,7 @@ int sqlite3VdbeList( pMem++; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS - if( sqlite3VdbeMemGrow(pMem, 500, 0) ){ + if( sqlite3VdbeMemClearAndResize(pMem, 500) ){ assert( p->db->mallocFailed ); return SQLITE_ERROR; } @@ -1606,13 +1636,13 @@ void sqlite3VdbeRewind(Vdbe *p){ /* ** Prepare a virtual machine for execution for the first time after ** creating the virtual machine. This involves things such -** as allocating stack space and initializing the program counter. +** as allocating registers and initializing the program counter. ** After the VDBE has be prepped, it can be executed by one or more ** calls to sqlite3VdbeExec(). ** -** This function may be called exact once on a each virtual machine. +** This function may be called exactly once on each virtual machine. ** After this routine is called the VM has been "packaged" and is ready -** to run. After this routine is called, futher calls to +** to run. After this routine is called, further calls to ** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects ** the Vdbe from the Parse object that helped generate it so that the ** the Vdbe becomes an independent entity and the Parse object can be @@ -1696,6 +1726,9 @@ void sqlite3VdbeMakeReady( p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*), &zCsr, zEnd, &nByte); p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), &zCsr, zEnd, &nByte); +#endif if( nByte ){ p->pFree = sqlite3DbMallocZero(db, nByte); } @@ -1712,7 +1745,7 @@ void sqlite3VdbeMakeReady( p->aVar[n].db = db; } } - if( p->azVar ){ + if( p->azVar && pParse->nzVar>0 ){ p->nzVar = pParse->nzVar; memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0])); memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0])); @@ -1746,7 +1779,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ sqlite3BtreeCloseCursor(pCx->pCursor); } #ifndef SQLITE_OMIT_VIRTUALTABLE - if( pCx->pVtabCursor ){ + else if( pCx->pVtabCursor ){ sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor; const sqlite3_module *pModule = pVtabCursor->pVtab->pModule; p->inVtabMethod = 1; @@ -1763,6 +1796,9 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ */ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ Vdbe *v = pFrame->v; +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + v->anExec = pFrame->anExec; +#endif v->aOnceFlag = pFrame->aOnceFlag; v->nOnceFlag = pFrame->nOnceFlag; v->aOp = pFrame->aOp; @@ -1773,6 +1809,7 @@ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ v->nCursor = pFrame->nCursor; v->db->lastRowid = pFrame->lastRowid; v->nChange = pFrame->nChange; + v->db->nChange = pFrame->nDbChange; return pFrame->pc; } @@ -1789,9 +1826,10 @@ static void closeAllCursors(Vdbe *p){ VdbeFrame *pFrame; for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); sqlite3VdbeFrameRestore(pFrame); + p->pFrame = 0; + p->nFrame = 0; } - p->pFrame = 0; - p->nFrame = 0; + assert( p->nFrame==0 ); if( p->apCsr ){ int i; @@ -1813,16 +1851,12 @@ static void closeAllCursors(Vdbe *p){ } /* Delete any auxdata allocations made by the VM */ - sqlite3VdbeDeleteAuxData(p, -1, 0); + if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0); assert( p->pAuxData==0 ); } /* -** Clean up the VM after execution. -** -** This routine will automatically close any cursors, lists, and/or -** sorters that were left open. It also deletes the values of -** variables in the aVar[] array. +** Clean up the VM after a single run. */ static void Cleanup(Vdbe *p){ sqlite3 *db = p->db; @@ -1990,7 +2024,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ /* The complex case - There is a multi-file write-transaction active. ** This requires a master journal file to ensure the transaction is - ** committed atomicly. + ** committed atomically. */ #ifndef SQLITE_OMIT_DISKIO else{ @@ -2343,6 +2377,7 @@ int sqlite3VdbeHalt(Vdbe *p){ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; + p->nChange = 0; } } } @@ -2383,6 +2418,7 @@ int sqlite3VdbeHalt(Vdbe *p){ }else if( rc!=SQLITE_OK ){ p->rc = rc; sqlite3RollbackAll(db, SQLITE_OK); + p->nChange = 0; }else{ db->nDeferredCons = 0; db->nDeferredImmCons = 0; @@ -2391,6 +2427,7 @@ int sqlite3VdbeHalt(Vdbe *p){ } }else{ sqlite3RollbackAll(db, SQLITE_OK); + p->nChange = 0; } db->nStatement = 0; }else if( eStatementOp==0 ){ @@ -2402,6 +2439,7 @@ int sqlite3VdbeHalt(Vdbe *p){ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; + p->nChange = 0; } } @@ -2422,6 +2460,7 @@ int sqlite3VdbeHalt(Vdbe *p){ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; + p->nChange = 0; } } @@ -2497,7 +2536,7 @@ int sqlite3VdbeTransferError(Vdbe *p){ db->mallocFailed = mallocFailed; db->errCode = rc; }else{ - sqlite3Error(db, rc, 0); + sqlite3Error(db, rc); } return rc; } @@ -2560,7 +2599,7 @@ int sqlite3VdbeReset(Vdbe *p){ ** to sqlite3_step(). For consistency (since sqlite3_step() was ** called), set the database error in this case as well. */ - sqlite3Error(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg); + sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg); sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } @@ -2638,7 +2677,7 @@ int sqlite3VdbeFinalize(Vdbe *p){ ** from left to right), or ** ** * the corresponding bit in argument mask is clear (where the first -** function parameter corrsponds to bit 0 etc.). +** function parameter corresponds to bit 0 etc.). */ void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){ AuxData **pp = &pVdbe->pAuxData; @@ -2683,9 +2722,11 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) - sqlite3DbFree(db, p->zExplain); - sqlite3DbFree(db, p->pExplain); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + for(i=0; inScan; i++){ + sqlite3DbFree(db, p->aScan[i].zName); + } + sqlite3DbFree(db, p->aScan); #endif } @@ -2713,6 +2754,57 @@ void sqlite3VdbeDelete(Vdbe *p){ sqlite3DbFree(db, p); } +/* +** The cursor "p" has a pending seek operation that has not yet been +** carried out. Seek the cursor now. If an error occurs, return +** the appropriate error code. +*/ +static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){ + int res, rc; +#ifdef SQLITE_TEST + extern int sqlite3_search_count; +#endif + assert( p->deferredMoveto ); + assert( p->isTable ); + rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res); + if( rc ) return rc; + if( res!=0 ) return SQLITE_CORRUPT_BKPT; +#ifdef SQLITE_TEST + sqlite3_search_count++; +#endif + p->deferredMoveto = 0; + p->cacheStatus = CACHE_STALE; + return SQLITE_OK; +} + +/* +** Something has moved cursor "p" out of place. Maybe the row it was +** pointed to was deleted out from under it. Or maybe the btree was +** rebalanced. Whatever the cause, try to restore "p" to the place it +** is supposed to be pointing. If the row was deleted out from under the +** cursor, set the cursor to point to a NULL row. +*/ +static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){ + int isDifferentRow, rc; + assert( p->pCursor!=0 ); + assert( sqlite3BtreeCursorHasMoved(p->pCursor) ); + rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow); + p->cacheStatus = CACHE_STALE; + if( isDifferentRow ) p->nullRow = 1; + return rc; +} + +/* +** Check to ensure that the cursor is valid. Restore the cursor +** if need be. Return any I/O error from the restore operation. +*/ +int sqlite3VdbeCursorRestore(VdbeCursor *p){ + if( sqlite3BtreeCursorHasMoved(p->pCursor) ){ + return handleMovedCursor(p); + } + return SQLITE_OK; +} + /* ** Make sure the cursor p is ready to read or write the row to which it ** was last positioned. Return an error code if an OOM fault or I/O error @@ -2728,29 +2820,10 @@ void sqlite3VdbeDelete(Vdbe *p){ */ int sqlite3VdbeCursorMoveto(VdbeCursor *p){ if( p->deferredMoveto ){ - int res, rc; -#ifdef SQLITE_TEST - extern int sqlite3_search_count; -#endif - assert( p->isTable ); - rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res); - if( rc ) return rc; - p->lastRowid = p->movetoTarget; - if( res!=0 ) return SQLITE_CORRUPT_BKPT; - p->rowidIsValid = 1; -#ifdef SQLITE_TEST - sqlite3_search_count++; -#endif - p->deferredMoveto = 0; - p->cacheStatus = CACHE_STALE; - }else if( p->pCursor ){ - int hasMoved; - int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved); - if( rc ) return rc; - if( hasMoved ){ - p->cacheStatus = CACHE_STALE; - if( hasMoved==2 ) p->nullRow = 1; - } + return handleDeferredMoveto(p); + } + if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){ + return handleMovedCursor(p); } return SQLITE_OK; } @@ -2813,9 +2886,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){ i64 i = pMem->u.i; u64 u; if( i<0 ){ - if( i<(-MAX_6BYTE) ) return 6; - /* Previous test prevents: u = -(-9223372036854775808) */ - u = -i; + u = ~i; }else{ u = i; } @@ -2926,17 +2997,18 @@ u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ u64 v; u32 i; if( serial_type==7 ){ - assert( sizeof(v)==sizeof(pMem->r) ); - memcpy(&v, &pMem->r, sizeof(v)); + assert( sizeof(v)==sizeof(pMem->u.r) ); + memcpy(&v, &pMem->u.r, sizeof(v)); swapMixedEndianFloat(v); }else{ v = pMem->u.i; } len = i = sqlite3VdbeSerialTypeLen(serial_type); - while( i-- ){ - buf[i] = (u8)(v&0xFF); + assert( i>0 ); + do{ + buf[--i] = (u8)(v&0xFF); v >>= 8; - } + }while( i ); return len; } @@ -2960,51 +3032,101 @@ u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ #define TWO_BYTE_INT(x) (256*(i8)((x)[0])|(x)[1]) #define THREE_BYTE_INT(x) (65536*(i8)((x)[0])|((x)[1]<<8)|(x)[2]) #define FOUR_BYTE_UINT(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) +#define FOUR_BYTE_INT(x) (16777216*(i8)((x)[0])|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) /* ** Deserialize the data blob pointed to by buf as serial type serial_type ** and store the result in pMem. Return the number of bytes read. +** +** This function is implemented as two separate routines for performance. +** The few cases that require local variables are broken out into a separate +** routine so that in most cases the overhead of moving the stack pointer +** is avoided. */ +static u32 SQLITE_NOINLINE serialGet( + const unsigned char *buf, /* Buffer to deserialize from */ + u32 serial_type, /* Serial type to deserialize */ + Mem *pMem /* Memory cell to write value into */ +){ + u64 x = FOUR_BYTE_UINT(buf); + u32 y = FOUR_BYTE_UINT(buf+4); + x = (x<<32) + y; + if( serial_type==6 ){ + /* EVIDENCE-OF: R-29851-52272 Value is a big-endian 64-bit + ** twos-complement integer. */ + pMem->u.i = *(i64*)&x; + pMem->flags = MEM_Int; + testcase( pMem->u.i<0 ); + }else{ + /* EVIDENCE-OF: R-57343-49114 Value is a big-endian IEEE 754-2008 64-bit + ** floating point number. */ +#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT) + /* Verify that integers and floating point values use the same + ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is + ** defined that 64-bit floating point values really are mixed + ** endian. + */ + static const u64 t1 = ((u64)0x3ff00000)<<32; + static const double r1 = 1.0; + u64 t2 = t1; + swapMixedEndianFloat(t2); + assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 ); +#endif + assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); + swapMixedEndianFloat(x); + memcpy(&pMem->u.r, &x, sizeof(x)); + pMem->flags = sqlite3IsNaN(pMem->u.r) ? MEM_Null : MEM_Real; + } + return 8; +} u32 sqlite3VdbeSerialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ ){ - u64 x; - u32 y; switch( serial_type ){ case 10: /* Reserved for future use */ case 11: /* Reserved for future use */ - case 0: { /* NULL */ + case 0: { /* Null */ + /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */ pMem->flags = MEM_Null; break; } - case 1: { /* 1-byte signed integer */ + case 1: { + /* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement + ** integer. */ pMem->u.i = ONE_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return 1; } case 2: { /* 2-byte signed integer */ + /* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit + ** twos-complement integer. */ pMem->u.i = TWO_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return 2; } case 3: { /* 3-byte signed integer */ + /* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit + ** twos-complement integer. */ pMem->u.i = THREE_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return 3; } case 4: { /* 4-byte signed integer */ - y = FOUR_BYTE_UINT(buf); - pMem->u.i = (i64)*(int*)&y; + /* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit + ** twos-complement integer. */ + pMem->u.i = FOUR_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return 4; } case 5: { /* 6-byte signed integer */ + /* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit + ** twos-complement integer. */ pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); @@ -3012,52 +3134,32 @@ u32 sqlite3VdbeSerialGet( } case 6: /* 8-byte signed integer */ case 7: { /* IEEE floating point */ -#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT) - /* Verify that integers and floating point values use the same - ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is - ** defined that 64-bit floating point values really are mixed - ** endian. - */ - static const u64 t1 = ((u64)0x3ff00000)<<32; - static const double r1 = 1.0; - u64 t2 = t1; - swapMixedEndianFloat(t2); - assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 ); -#endif - x = FOUR_BYTE_UINT(buf); - y = FOUR_BYTE_UINT(buf+4); - x = (x<<32) | y; - if( serial_type==6 ){ - pMem->u.i = *(i64*)&x; - pMem->flags = MEM_Int; - testcase( pMem->u.i<0 ); - }else{ - assert( sizeof(x)==8 && sizeof(pMem->r)==8 ); - swapMixedEndianFloat(x); - memcpy(&pMem->r, &x, sizeof(x)); - pMem->flags = sqlite3IsNaN(pMem->r) ? MEM_Null : MEM_Real; - } - return 8; + /* These use local variables, so do them in a separate routine + ** to avoid having to move the frame pointer in the common case */ + return serialGet(buf,serial_type,pMem); } case 8: /* Integer 0 */ case 9: { /* Integer 1 */ + /* EVIDENCE-OF: R-12976-22893 Value is the integer 0. */ + /* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */ pMem->u.i = serial_type-8; pMem->flags = MEM_Int; return 0; } default: { + /* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in + ** length. + ** EVIDENCE-OF: R-28401-00140 Value is a string in the text encoding and + ** (N-13)/2 bytes in length. */ static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem }; - u32 len = (serial_type-12)/2; pMem->z = (char *)buf; - pMem->n = len; - pMem->xDel = 0; + pMem->n = (serial_type-12)/2; pMem->flags = aFlag[serial_type&1]; - return len; + return pMem->n; } } return 0; } - /* ** This routine is used to allocate sufficient space for an UnpackedRecord ** structure large enough to be used with sqlite3VdbeRecordUnpack() if @@ -3127,17 +3229,17 @@ void sqlite3VdbeRecordUnpack( idx = getVarint32(aKey, szHdr); d = szHdr; u = 0; - while( idxnField && d<=nKey ){ + while( idxenc = pKeyInfo->enc; pMem->db = pKeyInfo->db; /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */ - pMem->zMalloc = 0; + pMem->szMalloc = 0; d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); pMem++; - u++; + if( (++u)>=p->nField ) break; } assert( u<=pKeyInfo->nField + 1 ); p->nField = u; @@ -3151,10 +3253,14 @@ void sqlite3VdbeRecordUnpack( ** sqlite3VdbeSerialGet() and sqlite3MemCompare() functions. It is used ** in assert() statements to ensure that the optimized code in ** sqlite3VdbeRecordCompare() returns results with these two primitives. +** +** Return true if the result of comparison is equivalent to desiredResult. +** Return false if there is a disagreement. */ static int vdbeRecordCompareDebug( int nKey1, const void *pKey1, /* Left key */ - const UnpackedRecord *pPKey2 /* Right key */ + const UnpackedRecord *pPKey2, /* Right key */ + int desiredResult /* Correct answer */ ){ u32 d1; /* Offset into aKey[] of next data element */ u32 idx1; /* Offset into aKey[] of next header element */ @@ -3166,10 +3272,11 @@ static int vdbeRecordCompareDebug( Mem mem1; pKeyInfo = pPKey2->pKeyInfo; + if( pKeyInfo->db==0 ) return 1; mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; /* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */ - VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ + VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ /* Compilers may complain that mem1.u.i is potentially uninitialized. ** We could initialize it, as shown here, to silence those complaints. @@ -3212,11 +3319,11 @@ static int vdbeRecordCompareDebug( */ rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]); if( rc!=0 ){ - assert( mem1.zMalloc==0 ); /* See comment below */ + assert( mem1.szMalloc==0 ); /* See comment below */ if( pKeyInfo->aSortOrder[i] ){ rc = -rc; /* Invert the result for DESC sort order. */ } - return rc; + goto debugCompareEnd; } i++; }while( idx1nField ); @@ -3225,15 +3332,58 @@ static int vdbeRecordCompareDebug( ** the following assert(). If the assert() fails, it indicates a ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */ - assert( mem1.zMalloc==0 ); + assert( mem1.szMalloc==0 ); /* rc==0 here means that one of the keys ran out of fields and - ** all the fields up to that point were equal. Return the the default_rc + ** all the fields up to that point were equal. Return the default_rc ** value. */ - return pPKey2->default_rc; + rc = pPKey2->default_rc; + +debugCompareEnd: + if( desiredResult==0 && rc==0 ) return 1; + if( desiredResult<0 && rc<0 ) return 1; + if( desiredResult>0 && rc>0 ) return 1; + if( CORRUPT_DB ) return 1; + if( pKeyInfo->db->mallocFailed ) return 1; + return 0; } #endif +#if SQLITE_DEBUG +/* +** Count the number of fields (a.k.a. columns) in the record given by +** pKey,nKey. The verify that this count is less than or equal to the +** limit given by pKeyInfo->nField + pKeyInfo->nXField. +** +** If this constraint is not satisfied, it means that the high-speed +** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will +** not work correctly. If this assert() ever fires, it probably means +** that the KeyInfo.nField or KeyInfo.nXField values were computed +** incorrectly. +*/ +static void vdbeAssertFieldCountWithinLimits( + int nKey, const void *pKey, /* The record to verify */ + const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */ +){ + int nField = 0; + u32 szHdr; + u32 idx; + u32 notUsed; + const unsigned char *aKey = (const unsigned char*)pKey; + + if( CORRUPT_DB ) return; + idx = getVarint32(aKey, szHdr); + assert( szHdr<=nKey ); + while( idxnField+pKeyInfo->nXField ); +} +#else +# define vdbeAssertFieldCountWithinLimits(A,B,C) +#endif + /* ** Both *pMem1 and *pMem2 contain string values. Compare the two values ** using the collation sequence pColl. As usual, return a negative , zero @@ -3243,7 +3393,8 @@ static int vdbeRecordCompareDebug( static int vdbeCompareMemString( const Mem *pMem1, const Mem *pMem2, - const CollSeq *pColl + const CollSeq *pColl, + u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */ ){ if( pMem1->enc==pColl->enc ){ /* The strings are already in the correct encoding. Call the @@ -3255,8 +3406,8 @@ static int vdbeCompareMemString( int n1, n2; Mem c1; Mem c2; - memset(&c1, 0, sizeof(c1)); - memset(&c2, 0, sizeof(c2)); + sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null); + sqlite3VdbeMemInit(&c2, pMem1->db, MEM_Null); sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); @@ -3266,10 +3417,23 @@ static int vdbeCompareMemString( rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); sqlite3VdbeMemRelease(&c1); sqlite3VdbeMemRelease(&c2); + if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM; return rc; } } +/* +** Compare two blobs. Return negative, zero, or positive if the first +** is less than, equal to, or greater than the second, respectively. +** If one blob is a prefix of the other, then the shorter is the lessor. +*/ +static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){ + int c = memcmp(pB1->z, pB2->z, pB1->n>pB2->n ? pB2->n : pB1->n); + if( c ) return c; + return pB1->n - pB2->n; +} + + /* ** Compare the values contained by the two memory cells, returning ** negative, zero or positive if pMem1 is less than, equal to, or greater @@ -3280,7 +3444,6 @@ static int vdbeCompareMemString( ** Two NULL values are considered equal by this function. */ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ - int rc; int f1, f2; int combined_flags; @@ -3308,14 +3471,14 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ return 0; } if( (f1&MEM_Real)!=0 ){ - r1 = pMem1->r; + r1 = pMem1->u.r; }else if( (f1&MEM_Int)!=0 ){ r1 = (double)pMem1->u.i; }else{ return 1; } if( (f2&MEM_Real)!=0 ){ - r2 = pMem2->r; + r2 = pMem2->u.r; }else if( (f2&MEM_Int)!=0 ){ r2 = (double)pMem2->u.i; }else{ @@ -3348,18 +3511,14 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ assert( !pColl || pColl->xCmp ); if( pColl ){ - return vdbeCompareMemString(pMem1, pMem2, pColl); + return vdbeCompareMemString(pMem1, pMem2, pColl, 0); } /* If a NULL pointer was passed as the collate function, fall through ** to the blob case and use memcmp(). */ } /* Both values must be blobs. Compare using memcmp(). */ - rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n); - if( rc==0 ){ - rc = pMem1->n - pMem2->n; - } - return rc; + return sqlite3BlobCompare(pMem1, pMem2); } @@ -3409,7 +3568,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ ** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero ** or positive integer if key1 is less than, equal to or ** greater than key2. The {nKey1, pKey1} key must be a blob -** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 +** created by the OP_MakeRecord opcode of the VDBE. The pPKey2 ** key must be a parsed key such as obtained from ** sqlite3VdbeParseRecord. ** @@ -3420,10 +3579,12 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ ** fields that appear in both keys are equal, then pPKey2->default_rc is ** returned. ** -** If database corruption is discovered, set pPKey2->isCorrupt to non-zero -** and return 0. +** If database corruption is discovered, set pPKey2->errCode to +** SQLITE_CORRUPT and return 0. If an OOM error is encountered, +** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the +** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db). */ -int sqlite3VdbeRecordCompare( +static int vdbeRecordCompareWithSkip( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2, /* Right key */ int bSkip /* If true, skip the first field */ @@ -3452,13 +3613,13 @@ int sqlite3VdbeRecordCompare( idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; if( d1>(unsigned)nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ } i = 0; } - VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ + VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB ); assert( pPKey2->pKeyInfo->aSortOrder!=0 ); @@ -3478,9 +3639,9 @@ int sqlite3VdbeRecordCompare( }else if( serial_type==7 ){ double rhs = (double)pRhs->u.i; sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); - if( mem1.rrhs ){ + }else if( mem1.u.r>rhs ){ rc = +1; } }else{ @@ -3502,11 +3663,11 @@ int sqlite3VdbeRecordCompare( }else if( serial_type==0 ){ rc = -1; }else{ - double rhs = pRhs->r; + double rhs = pRhs->u.r; double lhs; sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); if( serial_type==7 ){ - lhs = mem1.r; + lhs = mem1.u.r; }else{ lhs = (double)mem1.u.i; } @@ -3531,14 +3692,16 @@ int sqlite3VdbeRecordCompare( testcase( (d1+mem1.n)==(unsigned)nKey1 ); testcase( (d1+mem1.n+1)==(unsigned)nKey1 ); if( (d1+mem1.n) > (unsigned)nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ }else if( pKeyInfo->aColl[i] ){ mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; mem1.flags = MEM_Str; mem1.z = (char*)&aKey1[d1]; - rc = vdbeCompareMemString(&mem1, pRhs, pKeyInfo->aColl[i]); + rc = vdbeCompareMemString( + &mem1, pRhs, pKeyInfo->aColl[i], &pPKey2->errCode + ); }else{ int nCmp = MIN(mem1.n, pRhs->n); rc = memcmp(&aKey1[d1], pRhs->z, nCmp); @@ -3558,7 +3721,7 @@ int sqlite3VdbeRecordCompare( testcase( (d1+nStr)==(unsigned)nKey1 ); testcase( (d1+nStr+1)==(unsigned)nKey1 ); if( (d1+nStr) > (unsigned)nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ }else{ int nCmp = MIN(nStr, pRhs->n); @@ -3578,12 +3741,8 @@ int sqlite3VdbeRecordCompare( if( pKeyInfo->aSortOrder[i] ){ rc = -rc; } - assert( CORRUPT_DB - || (rc<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) - || (rc>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) - || pKeyInfo->db->mallocFailed - ); - assert( mem1.zMalloc==0 ); /* See comment below */ + assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) ); + assert( mem1.szMalloc==0 ); /* See comment below */ return rc; } @@ -3596,17 +3755,24 @@ int sqlite3VdbeRecordCompare( /* No memory allocation is ever used on mem1. Prove this using ** the following assert(). If the assert() fails, it indicates a ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */ - assert( mem1.zMalloc==0 ); + assert( mem1.szMalloc==0 ); /* rc==0 here means that one or both of the keys ran out of fields and - ** all the fields up to that point were equal. Return the the default_rc + ** all the fields up to that point were equal. Return the default_rc ** value. */ assert( CORRUPT_DB - || pPKey2->default_rc==vdbeRecordCompareDebug(nKey1, pKey1, pPKey2) + || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) || pKeyInfo->db->mallocFailed ); return pPKey2->default_rc; } +int sqlite3VdbeRecordCompare( + int nKey1, const void *pKey1, /* Left key */ + UnpackedRecord *pPKey2 /* Right key */ +){ + return vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0); +} + /* ** This function is an optimized version of sqlite3VdbeRecordCompare() @@ -3619,8 +3785,7 @@ int sqlite3VdbeRecordCompare( */ static int vdbeRecordCompareInt( int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2, /* Right key */ - int bSkip /* Ignored */ + UnpackedRecord *pPKey2 /* Right key */ ){ const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F]; int serial_type = ((const u8*)pKey1)[1]; @@ -3629,9 +3794,8 @@ static int vdbeRecordCompareInt( u64 x; i64 v = pPKey2->aMem[0].u.i; i64 lhs; - UNUSED_PARAMETER(bSkip); - assert( bSkip==0 ); + vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB ); switch( serial_type ){ case 1: { /* 1-byte signed integer */ @@ -3681,10 +3845,10 @@ static int vdbeRecordCompareInt( ** (as gcc is clever enough to combine the two like cases). Other ** compilers might be similar. */ case 0: case 7: - return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0); + return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); default: - return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0); + return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); } if( v>lhs ){ @@ -3694,18 +3858,14 @@ static int vdbeRecordCompareInt( }else if( pPKey2->nField>1 ){ /* The first fields of the two keys are equal. Compare the trailing ** fields. */ - res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1); + res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); }else{ /* The first fields of the two keys are equal and there are no trailing ** fields. Return pPKey2->default_rc in this case. */ res = pPKey2->default_rc; } - assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0) - || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) - || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) - || CORRUPT_DB - ); + assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) ); return res; } @@ -3717,17 +3877,14 @@ static int vdbeRecordCompareInt( */ static int vdbeRecordCompareString( int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord *pPKey2, /* Right key */ - int bSkip + UnpackedRecord *pPKey2 /* Right key */ ){ const u8 *aKey1 = (const u8*)pKey1; int serial_type; int res; - UNUSED_PARAMETER(bSkip); - assert( bSkip==0 ); + vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); getVarint32(&aKey1[1], serial_type); - if( serial_type<12 ){ res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */ }else if( !(serial_type & 0x01) ){ @@ -3739,7 +3896,7 @@ static int vdbeRecordCompareString( nStr = (serial_type-12) / 2; if( (szHdr + nStr) > nKey1 ){ - pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ } nCmp = MIN( pPKey2->aMem[0].n, nStr ); @@ -3749,7 +3906,7 @@ static int vdbeRecordCompareString( res = nStr - pPKey2->aMem[0].n; if( res==0 ){ if( pPKey2->nField>1 ){ - res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1); + res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); }else{ res = pPKey2->default_rc; } @@ -3765,9 +3922,7 @@ static int vdbeRecordCompareString( } } - assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0) - || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) - || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) + assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) || CORRUPT_DB || pPKey2->pKeyInfo->db->mallocFailed ); @@ -3833,8 +3988,6 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ u32 lenRowid; /* Size of the rowid */ Mem m, v; - UNUSED_PARAMETER(db); - /* Get the size of the index entry. Only indices entries of less ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so @@ -3846,7 +3999,7 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); /* Read in the complete content of the index entry */ - memset(&m, 0, sizeof(m)); + sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m); if( rc ){ return rc; @@ -3889,7 +4042,7 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ /* Jump here if database corruption is detected after m has been ** allocated. Free the m object and return SQLITE_CORRUPT. */ idx_rowid_corruption: - testcase( m.zMalloc!=0 ); + testcase( m.szMalloc!=0 ); sqlite3VdbeMemRelease(&m); return SQLITE_CORRUPT_BKPT; } @@ -3906,6 +4059,7 @@ idx_rowid_corruption: ** of the keys prior to the final rowid, not the entire key. */ int sqlite3VdbeIdxKeyCompare( + sqlite3 *db, /* Database connection */ VdbeCursor *pC, /* The cursor to compare against */ UnpackedRecord *pUnpacked, /* Unpacked version of key */ int *res /* Write the comparison result here */ @@ -3924,12 +4078,12 @@ int sqlite3VdbeIdxKeyCompare( *res = 0; return SQLITE_CORRUPT_BKPT; } - memset(&m, 0, sizeof(m)); + sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m); if( rc ){ return rc; } - *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked, 0); + *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked); sqlite3VdbeMemRelease(&m); return SQLITE_OK; } diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 083f3f4..cf1eb59 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -153,6 +153,11 @@ int sqlite3_blob_open( Parse *pParse = 0; Incrblob *pBlob = 0; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || ppBlob==0 || zTable==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif flags = !!flags; /* flags = (flags ? 1 : 0); */ *ppBlob = 0; @@ -318,7 +323,7 @@ blob_open_out: if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt); sqlite3DbFree(db, pBlob); } - sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr); + sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); sqlite3ParserReset(pParse); sqlite3StackFree(db, pParse); @@ -371,7 +376,6 @@ static int blobReadWrite( if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){ /* Request is out of range. Return a transient error. */ rc = SQLITE_ERROR; - sqlite3Error(db, SQLITE_ERROR, 0); }else if( v==0 ){ /* If there is no statement handle, then the blob-handle has ** already been invalidated. Return SQLITE_ABORT in this case. @@ -389,10 +393,10 @@ static int blobReadWrite( sqlite3VdbeFinalize(v); p->pStmt = 0; }else{ - db->errCode = rc; v->rc = rc; } } + sqlite3Error(db, rc); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; @@ -451,7 +455,7 @@ int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ char *zErr; rc = blobSeekToRow(p, iRow, &zErr); if( rc!=SQLITE_OK ){ - sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr); + sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); } assert( rc!=SQLITE_SCHEMA ); diff --git a/src/vdbemem.c b/src/vdbemem.c index cf44aa7..870fb5b 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -26,29 +26,40 @@ ** this: assert( sqlite3VdbeCheckMemInvariants(pMem) ); */ int sqlite3VdbeCheckMemInvariants(Mem *p){ - /* The MEM_Dyn bit is set if and only if Mem.xDel is a non-NULL destructor - ** function for Mem.z + /* If MEM_Dyn is set then Mem.xDel!=0. + ** Mem.xDel is might not be initialized if MEM_Dyn is clear. */ assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); - assert( (p->flags & MEM_Dyn)!=0 || p->xDel==0 ); + + /* MEM_Dyn may only be set if Mem.szMalloc==0. In this way we + ** ensure that if Mem.szMalloc>0 then it is safe to do + ** Mem.z = Mem.zMalloc without having to check Mem.flags&MEM_Dyn. + ** That saves a few cycles in inner loops. */ + assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 ); + + /* Cannot be both MEM_Int and MEM_Real at the same time */ + assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) ); + + /* The szMalloc field holds the correct memory allocation size */ + assert( p->szMalloc==0 + || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) ); /* If p holds a string or blob, the Mem.z must point to exactly ** one of the following: ** ** (1) Memory in Mem.zMalloc and managed by the Mem object ** (2) Memory to be freed using Mem.xDel - ** (3) An ephermal string or blob + ** (3) An ephemeral string or blob ** (4) A static string or blob */ - if( (p->flags & (MEM_Str|MEM_Blob)) && p->z!=0 ){ + if( (p->flags & (MEM_Str|MEM_Blob)) && p->n>0 ){ assert( - ((p->z==p->zMalloc)? 1 : 0) + + ((p->szMalloc>0 && p->z==p->zMalloc)? 1 : 0) + ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + ((p->flags&MEM_Static)!=0 ? 1 : 0) == 1 ); } - return 1; } #endif @@ -102,7 +113,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ ** blob if bPreserve is true. If bPreserve is false, any prior content ** in pMem->z is discarded. */ -int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ +SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( sqlite3VdbeCheckMemInvariants(pMem) ); assert( (pMem->flags&MEM_RowSet)==0 ); @@ -111,24 +122,28 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( bPreserve==0 || pMem->flags&(MEM_Blob|MEM_Str) ); testcase( bPreserve && pMem->z==0 ); - if( pMem->zMalloc==0 || sqlite3DbMallocSize(pMem->db, pMem->zMalloc)szMalloc==0 + || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) ); + if( pMem->szMallocz==pMem->zMalloc ){ + if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); bPreserve = 0; }else{ - sqlite3DbFree(pMem->db, pMem->zMalloc); + if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc); pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); } if( pMem->zMalloc==0 ){ - VdbeMemRelease(pMem); + sqlite3VdbeMemSetNull(pMem); pMem->z = 0; - pMem->flags = MEM_Null; + pMem->szMalloc = 0; return SQLITE_NOMEM; + }else{ + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); } } - if( pMem->z && bPreserve && pMem->z!=pMem->zMalloc ){ + if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){ memcpy(pMem->zMalloc, pMem->z, pMem->n); } if( (pMem->flags&MEM_Dyn)!=0 ){ @@ -138,15 +153,37 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ pMem->z = pMem->zMalloc; pMem->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Static); - pMem->xDel = 0; return SQLITE_OK; } /* -** Make the given Mem object MEM_Dyn. In other words, make it so -** that any TEXT or BLOB content is stored in memory obtained from -** malloc(). In this way, we know that the memory is safe to be -** overwritten or altered. +** Change the pMem->zMalloc allocation to be at least szNew bytes. +** If pMem->zMalloc already meets or exceeds the requested size, this +** routine is a no-op. +** +** Any prior string or blob content in the pMem object may be discarded. +** The pMem->xDel destructor is called, if it exists. Though MEM_Str +** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null +** values are preserved. +** +** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM) +** if unable to complete the resizing. +*/ +int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ + assert( szNew>0 ); + assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 ); + if( pMem->szMallocflags & MEM_Dyn)==0 ); + pMem->z = pMem->zMalloc; + pMem->flags &= (MEM_Null|MEM_Int|MEM_Real); + return SQLITE_OK; +} + +/* +** Change pMem so that its MEM_Str or MEM_Blob value is stored in +** MEM.zMalloc, where it can be safely written. ** ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ @@ -156,7 +193,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ assert( (pMem->flags&MEM_RowSet)==0 ); ExpandBlob(pMem); f = pMem->flags; - if( (f&(MEM_Str|MEM_Blob)) && pMem->z!=pMem->zMalloc ){ + if( (f&(MEM_Str|MEM_Blob)) && (pMem->szMalloc==0 || pMem->z!=pMem->zMalloc) ){ if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){ return SQLITE_NOMEM; } @@ -200,15 +237,11 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){ } #endif - /* -** Make sure the given Mem is \u0000 terminated. +** It is already known that pMem contains an unterminated string. +** Add the zero terminator. */ -int sqlite3VdbeMemNulTerminate(Mem *pMem){ - assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){ - return SQLITE_OK; /* Nothing to do */ - } +static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ return SQLITE_NOMEM; } @@ -218,21 +251,35 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){ return SQLITE_OK; } +/* +** Make sure the given Mem is \u0000 terminated. +*/ +int sqlite3VdbeMemNulTerminate(Mem *pMem){ + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) ); + testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 ); + if( (pMem->flags & (MEM_Term|MEM_Str))!=MEM_Str ){ + return SQLITE_OK; /* Nothing to do */ + }else{ + return vdbeMemAddTerminator(pMem); + } +} + /* ** Add MEM_Str to the set of representations for the given Mem. Numbers ** are converted using sqlite3_snprintf(). Converting a BLOB to a string ** is a no-op. ** -** Existing representations MEM_Int and MEM_Real are *not* invalidated. +** Existing representations MEM_Int and MEM_Real are invalidated if +** bForce is true but are retained if bForce is false. ** ** A MEM_Null value will never be passed to this function. This function is ** used for converting values to text for returning to the user (i.e. via ** sqlite3_value_text()), or for ensuring that values to be used as btree ** keys are strings. In the former case a NULL pointer is returned the -** user and the later is an internal programming error. +** user and the latter is an internal programming error. */ -int sqlite3VdbeMemStringify(Mem *pMem, int enc){ - int rc = SQLITE_OK; +int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ int fg = pMem->flags; const int nByte = 32; @@ -244,11 +291,11 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){ assert( EIGHT_BYTE_ALIGNMENT(pMem) ); - if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){ + if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){ return SQLITE_NOMEM; } - /* For a Real or Integer, use sqlite3_mprintf() to produce the UTF-8 + /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 ** string representation of the value. Then, if the required encoding ** is UTF-16le or UTF-16be do a translation. ** @@ -258,13 +305,14 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){ sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i); }else{ assert( fg & MEM_Real ); - sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->r); + sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r); } pMem->n = sqlite3Strlen30(pMem->z); pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str|MEM_Term; + if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real); sqlite3VdbeChangeEncoding(pMem, enc); - return rc; + return SQLITE_OK; } /* @@ -279,59 +327,90 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ int rc = SQLITE_OK; if( ALWAYS(pFunc && pFunc->xFinalize) ){ sqlite3_context ctx; + Mem t; assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); memset(&ctx, 0, sizeof(ctx)); - ctx.s.flags = MEM_Null; - ctx.s.db = pMem->db; + memset(&t, 0, sizeof(t)); + t.flags = MEM_Null; + t.db = pMem->db; + ctx.pOut = &t; ctx.pMem = pMem; ctx.pFunc = pFunc; pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */ - assert( 0==(pMem->flags&MEM_Dyn) && !pMem->xDel ); - sqlite3DbFree(pMem->db, pMem->zMalloc); - memcpy(pMem, &ctx.s, sizeof(ctx.s)); + assert( (pMem->flags & MEM_Dyn)==0 ); + if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc); + memcpy(pMem, &t, sizeof(t)); rc = ctx.isError; } return rc; } /* -** If the memory cell contains a string value that must be freed by -** invoking an external callback, free it now. Calling this function -** does not free any Mem.zMalloc buffer. +** If the memory cell contains a value that must be freed by +** invoking the external callback in Mem.xDel, then this routine +** will free that value. It also sets Mem.flags to MEM_Null. +** +** This is a helper routine for sqlite3VdbeMemSetNull() and +** for sqlite3VdbeMemRelease(). Use those other routines as the +** entry point for releasing Mem resources. */ -void sqlite3VdbeMemReleaseExternal(Mem *p){ +static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){ assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); + assert( VdbeMemDynamic(p) ); if( p->flags&MEM_Agg ){ sqlite3VdbeMemFinalize(p, p->u.pDef); assert( (p->flags & MEM_Agg)==0 ); - sqlite3VdbeMemRelease(p); - }else if( p->flags&MEM_Dyn ){ + testcase( p->flags & MEM_Dyn ); + } + if( p->flags&MEM_Dyn ){ assert( (p->flags&MEM_RowSet)==0 ); assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 ); p->xDel((void *)p->z); - p->xDel = 0; }else if( p->flags&MEM_RowSet ){ sqlite3RowSetClear(p->u.pRowSet); }else if( p->flags&MEM_Frame ){ - sqlite3VdbeMemSetNull(p); + VdbeFrame *pFrame = p->u.pFrame; + pFrame->pParent = pFrame->v->pDelFrame; + pFrame->v->pDelFrame = pFrame; } + p->flags = MEM_Null; } /* -** Release any memory held by the Mem. This may leave the Mem in an -** inconsistent state, for example with (Mem.z==0) and -** (Mem.flags==MEM_Str). +** Release memory held by the Mem p, both external memory cleared +** by p->xDel and memory in p->zMalloc. +** +** This is a helper routine invoked by sqlite3VdbeMemRelease() in +** the unusual case where there really is memory in p that needs +** to be freed. +*/ +static SQLITE_NOINLINE void vdbeMemClear(Mem *p){ + if( VdbeMemDynamic(p) ){ + vdbeMemClearExternAndSetNull(p); + } + if( p->szMalloc ){ + sqlite3DbFree(p->db, p->zMalloc); + p->szMalloc = 0; + } + p->z = 0; +} + +/* +** Release any memory resources held by the Mem. Both the memory that is +** free by Mem.xDel and the Mem.zMalloc allocation are freed. +** +** Use this routine prior to clean up prior to abandoning a Mem, or to +** reset a Mem back to its minimum memory utilization. +** +** Use sqlite3VdbeMemSetNull() to release just the Mem.xDel space +** prior to inserting new content into the Mem. */ void sqlite3VdbeMemRelease(Mem *p){ assert( sqlite3VdbeCheckMemInvariants(p) ); - VdbeMemRelease(p); - if( p->zMalloc ){ - sqlite3DbFree(p->db, p->zMalloc); - p->zMalloc = 0; + if( VdbeMemDynamic(p) || p->szMalloc ){ + vdbeMemClear(p); } - p->z = 0; - assert( p->xDel==0 ); /* Zeroed by VdbeMemRelease() above */ } /* @@ -370,7 +449,7 @@ static i64 doubleToInt64(double r){ ** If pMem is an integer, then the value is exact. If pMem is ** a floating-point then the value returned is the integer part. ** If pMem is a string or blob, then we make an attempt to convert -** it into a integer and return that. If pMem represents an +** it into an integer and return that. If pMem represents an ** an SQL-NULL value, return 0. ** ** If pMem represents a string value, its encoding might be changed. @@ -383,11 +462,10 @@ i64 sqlite3VdbeIntValue(Mem *pMem){ if( flags & MEM_Int ){ return pMem->u.i; }else if( flags & MEM_Real ){ - return doubleToInt64(pMem->r); + return doubleToInt64(pMem->u.r); }else if( flags & (MEM_Str|MEM_Blob) ){ i64 value = 0; assert( pMem->z || pMem->n==0 ); - testcase( pMem->z==0 ); sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); return value; }else{ @@ -405,7 +483,7 @@ double sqlite3VdbeRealValue(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( pMem->flags & MEM_Real ){ - return pMem->r; + return pMem->u.r; }else if( pMem->flags & MEM_Int ){ return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ @@ -424,12 +502,13 @@ double sqlite3VdbeRealValue(Mem *pMem){ ** MEM_Int if we can. */ void sqlite3VdbeIntegerAffinity(Mem *pMem){ + i64 ix; assert( pMem->flags & MEM_Real ); assert( (pMem->flags & MEM_RowSet)==0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); - pMem->u.i = doubleToInt64(pMem->r); + ix = doubleToInt64(pMem->u.r); /* Only mark the value as an integer if ** @@ -441,11 +520,9 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){ ** the second condition under the assumption that addition overflow causes ** values to wrap around. */ - if( pMem->r==(double)pMem->u.i - && pMem->u.i>SMALLEST_INT64 - && pMem->u.iflags |= MEM_Int; + if( pMem->u.r==ix && ix>SMALLEST_INT64 && ixu.i = ix; + MemSetTypeFlag(pMem, MEM_Int); } } @@ -470,7 +547,7 @@ int sqlite3VdbeMemRealify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); - pMem->r = sqlite3VdbeRealValue(pMem); + pMem->u.r = sqlite3VdbeRealValue(pMem); MemSetTypeFlag(pMem, MEM_Real); return SQLITE_OK; } @@ -490,7 +567,7 @@ int sqlite3VdbeMemNumerify(Mem *pMem){ if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){ MemSetTypeFlag(pMem, MEM_Int); }else{ - pMem->r = sqlite3VdbeRealValue(pMem); + pMem->u.r = sqlite3VdbeRealValue(pMem); MemSetTypeFlag(pMem, MEM_Real); sqlite3VdbeIntegerAffinity(pMem); } @@ -500,19 +577,81 @@ int sqlite3VdbeMemNumerify(Mem *pMem){ return SQLITE_OK; } +/* +** Cast the datatype of the value in pMem according to the affinity +** "aff". Casting is different from applying affinity in that a cast +** is forced. In other words, the value is converted into the desired +** affinity even if that results in loss of data. This routine is +** used (for example) to implement the SQL "cast()" operator. +*/ +void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ + if( pMem->flags & MEM_Null ) return; + switch( aff ){ + case SQLITE_AFF_NONE: { /* Really a cast to BLOB */ + if( (pMem->flags & MEM_Blob)==0 ){ + sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); + assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); + MemSetTypeFlag(pMem, MEM_Blob); + }else{ + pMem->flags &= ~(MEM_TypeMask&~MEM_Blob); + } + break; + } + case SQLITE_AFF_NUMERIC: { + sqlite3VdbeMemNumerify(pMem); + break; + } + case SQLITE_AFF_INTEGER: { + sqlite3VdbeMemIntegerify(pMem); + break; + } + case SQLITE_AFF_REAL: { + sqlite3VdbeMemRealify(pMem); + break; + } + default: { + assert( aff==SQLITE_AFF_TEXT ); + assert( MEM_Str==(MEM_Blob>>3) ); + pMem->flags |= (pMem->flags&MEM_Blob)>>3; + sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); + assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); + pMem->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero); + break; + } + } +} + +/* +** Initialize bulk memory to be a consistent Mem object. +** +** The minimum amount of initialization feasible is performed. +*/ +void sqlite3VdbeMemInit(Mem *pMem, sqlite3 *db, u16 flags){ + assert( (flags & ~MEM_TypeMask)==0 ); + pMem->flags = flags; + pMem->db = db; + pMem->szMalloc = 0; +} + + /* ** Delete any previous value and set the value stored in *pMem to NULL. +** +** This routine calls the Mem.xDel destructor to dispose of values that +** require the destructor. But it preserves the Mem.zMalloc memory allocation. +** To free all resources, use sqlite3VdbeMemRelease(), which both calls this +** routine to invoke the destructor and deallocates Mem.zMalloc. +** +** Use this routine to reset the Mem prior to insert a new value. +** +** Use sqlite3VdbeMemRelease() to complete erase the Mem prior to abandoning it. */ void sqlite3VdbeMemSetNull(Mem *pMem){ - if( pMem->flags & MEM_Frame ){ - VdbeFrame *pFrame = pMem->u.pFrame; - pFrame->pParent = pFrame->v->pDelFrame; - pFrame->v->pDelFrame = pFrame; + if( VdbeMemDynamic(pMem) ){ + vdbeMemClearExternAndSetNull(pMem); + }else{ + pMem->flags = MEM_Null; } - if( pMem->flags & MEM_RowSet ){ - sqlite3RowSetClear(pMem->u.pRowSet); - } - MemSetTypeFlag(pMem, MEM_Null); } void sqlite3ValueSetNull(sqlite3_value *p){ sqlite3VdbeMemSetNull((Mem*)p); @@ -529,14 +668,18 @@ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ if( n<0 ) n = 0; pMem->u.nZero = n; pMem->enc = SQLITE_UTF8; + pMem->z = 0; +} -#ifdef SQLITE_OMIT_INCRBLOB - sqlite3VdbeMemGrow(pMem, n, 0); - if( pMem->z ){ - pMem->n = n; - memset(pMem->z, 0, n); - } -#endif +/* +** The pMem is known to contain content that needs to be destroyed prior +** to a value change. So invoke the destructor, then set the value to +** a 64-bit integer. +*/ +static SQLITE_NOINLINE void vdbeReleaseAndSetInt64(Mem *pMem, i64 val){ + sqlite3VdbeMemSetNull(pMem); + pMem->u.i = val; + pMem->flags = MEM_Int; } /* @@ -544,9 +687,12 @@ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ ** manifest type INTEGER. */ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ - sqlite3VdbeMemRelease(pMem); - pMem->u.i = val; - pMem->flags = MEM_Int; + if( VdbeMemDynamic(pMem) ){ + vdbeReleaseAndSetInt64(pMem, val); + }else{ + pMem->u.i = val; + pMem->flags = MEM_Int; + } } #ifndef SQLITE_OMIT_FLOATING_POINT @@ -555,11 +701,9 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ ** manifest type REAL. */ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ - if( sqlite3IsNaN(val) ){ - sqlite3VdbeMemSetNull(pMem); - }else{ - sqlite3VdbeMemRelease(pMem); - pMem->r = val; + sqlite3VdbeMemSetNull(pMem); + if( !sqlite3IsNaN(val) ){ + pMem->u.r = val; pMem->flags = MEM_Real; } } @@ -577,10 +721,11 @@ void sqlite3VdbeMemSetRowSet(Mem *pMem){ pMem->zMalloc = sqlite3DbMallocRaw(db, 64); if( db->mallocFailed ){ pMem->flags = MEM_Null; + pMem->szMalloc = 0; }else{ assert( pMem->zMalloc ); - pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, - sqlite3DbMallocSize(db, pMem->zMalloc)); + pMem->szMalloc = sqlite3DbMallocSize(db, pMem->zMalloc); + pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, pMem->szMalloc); assert( pMem->u.pRowSet!=0 ); pMem->flags = MEM_RowSet; } @@ -604,7 +749,7 @@ int sqlite3VdbeMemTooBig(Mem *p){ #ifdef SQLITE_DEBUG /* -** This routine prepares a memory cell for modication by breaking +** This routine prepares a memory cell for modification by breaking ** its link to a shallow copy and by marking any current shallow ** copies of this cell as invalid. ** @@ -637,9 +782,9 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ */ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ assert( (pFrom->flags & MEM_RowSet)==0 ); - VdbeMemRelease(pTo); + assert( pTo->db==pFrom->db ); + if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); - pTo->xDel = 0; if( (pFrom->flags&MEM_Static)==0 ){ pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem); assert( srcType==MEM_Ephem || srcType==MEM_Static ); @@ -654,12 +799,11 @@ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; + assert( pTo->db==pFrom->db ); assert( (pFrom->flags & MEM_RowSet)==0 ); - VdbeMemRelease(pTo); + if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->flags &= ~MEM_Dyn; - pTo->xDel = 0; - if( pTo->flags&(MEM_Str|MEM_Blob) ){ if( 0==(pFrom->flags&MEM_Static) ){ pTo->flags |= MEM_Ephem; @@ -684,8 +828,7 @@ void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ sqlite3VdbeMemRelease(pTo); memcpy(pTo, pFrom, sizeof(Mem)); pFrom->flags = MEM_Null; - pFrom->xDel = 0; - pFrom->zMalloc = 0; + pFrom->szMalloc = 0; } /* @@ -732,7 +875,8 @@ int sqlite3VdbeMemSetStr( if( nByte<0 ){ assert( enc!=0 ); if( enc==SQLITE_UTF8 ){ - for(nByte=0; nByte<=iLimit && z[nByte]; nByte++){} + nByte = sqlite3Strlen30(z); + if( nByte>iLimit ) nByte = iLimit+1; }else{ for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){} } @@ -751,14 +895,17 @@ int sqlite3VdbeMemSetStr( if( nByte>iLimit ){ return SQLITE_TOOBIG; } - if( sqlite3VdbeMemGrow(pMem, nAlloc, 0) ){ + testcase( nAlloc==0 ); + testcase( nAlloc==31 ); + testcase( nAlloc==32 ); + if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){ return SQLITE_NOMEM; } memcpy(pMem->z, z, nAlloc); }else if( xDel==SQLITE_DYNAMIC ){ sqlite3VdbeMemRelease(pMem); pMem->zMalloc = pMem->z = (char *)z; - pMem->xDel = 0; + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); }else{ sqlite3VdbeMemRelease(pMem); pMem->z = (char *)z; @@ -790,8 +937,11 @@ int sqlite3VdbeMemSetStr( ** key is true to get the key or false to get data. The result is written ** into the pMem element. ** -** The pMem structure is assumed to be uninitialized. Any prior content -** is overwritten without being freed. +** The pMem object must have been initialized. This routine will use +** pMem->zMalloc to hold the content from the btree, if possible. New +** pMem->zMalloc space will be allocated if necessary. The calling routine +** is responsible for making sure that the pMem object is eventually +** destroyed. ** ** If this routine fails for any reason (malloc returns NULL or unable ** to read from the disk) then the pMem is left in an inconsistent state. @@ -808,6 +958,7 @@ int sqlite3VdbeMemFromBtree( int rc = SQLITE_OK; /* Return code */ assert( sqlite3BtreeCursorIsValid(pCur) ); + assert( !VdbeMemDynamic(pMem) ); /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ @@ -820,29 +971,70 @@ int sqlite3VdbeMemFromBtree( assert( zData!=0 ); if( offset+amt<=available ){ - sqlite3VdbeMemRelease(pMem); pMem->z = &zData[offset]; pMem->flags = MEM_Blob|MEM_Ephem; pMem->n = (int)amt; - }else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){ - if( key ){ - rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z); - }else{ - rc = sqlite3BtreeData(pCur, offset, amt, pMem->z); - } - if( rc==SQLITE_OK ){ - pMem->z[amt] = 0; - pMem->z[amt+1] = 0; - pMem->flags = MEM_Blob|MEM_Term; - pMem->n = (int)amt; - }else{ - sqlite3VdbeMemRelease(pMem); + }else{ + pMem->flags = MEM_Null; + if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){ + if( key ){ + rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z); + }else{ + rc = sqlite3BtreeData(pCur, offset, amt, pMem->z); + } + if( rc==SQLITE_OK ){ + pMem->z[amt] = 0; + pMem->z[amt+1] = 0; + pMem->flags = MEM_Blob|MEM_Term; + pMem->n = (int)amt; + }else{ + sqlite3VdbeMemRelease(pMem); + } } } return rc; } +/* +** The pVal argument is known to be a value other than NULL. +** Convert it into a string with encoding enc and return a pointer +** to a zero-terminated version of that string. +*/ +static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ + assert( pVal!=0 ); + assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); + assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); + assert( (pVal->flags & MEM_RowSet)==0 ); + assert( (pVal->flags & (MEM_Null))==0 ); + if( pVal->flags & (MEM_Blob|MEM_Str) ){ + pVal->flags |= MEM_Str; + if( pVal->flags & MEM_Zero ){ + sqlite3VdbeMemExpandBlob(pVal); + } + if( pVal->enc != (enc & ~SQLITE_UTF16_ALIGNED) ){ + sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); + } + if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&SQLITE_PTR_TO_INT(pVal->z)) ){ + assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 ); + if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){ + return 0; + } + } + sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-31275-44060 */ + }else{ + sqlite3VdbeMemStringify(pVal, enc, 0); + assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) ); + } + assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 + || pVal->db->mallocFailed ); + if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ + return pVal->z; + }else{ + return 0; + } +} + /* This function is only available internally, it is not part of the ** external API. It works in a similar way to sqlite3_value_text(), ** except the data returned is in the encoding specified by the second @@ -855,38 +1047,16 @@ int sqlite3VdbeMemFromBtree( */ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ if( !pVal ) return 0; - assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( (pVal->flags & MEM_RowSet)==0 ); - + if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ + return pVal->z; + } if( pVal->flags&MEM_Null ){ return 0; } - assert( (MEM_Blob>>3) == MEM_Str ); - pVal->flags |= (pVal->flags & MEM_Blob)>>3; - ExpandBlob(pVal); - if( pVal->flags&MEM_Str ){ - sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); - if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&SQLITE_PTR_TO_INT(pVal->z)) ){ - assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 ); - if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){ - return 0; - } - } - sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-31275-44060 */ - }else{ - assert( (pVal->flags&MEM_Blob)==0 ); - sqlite3VdbeMemStringify(pVal, enc); - assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) ); - } - assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 - || pVal->db->mallocFailed ); - if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ - return pVal->z; - }else{ - return 0; - } + return valueToText(pVal, enc); } /* @@ -993,9 +1163,20 @@ static int valueFromExpr( *ppVal = 0; return SQLITE_OK; } - op = pExpr->op; + while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft; if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; + if( op==TK_CAST ){ + u8 aff = sqlite3AffinityType(pExpr->u.zToken,0); + rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx); + testcase( rc!=SQLITE_OK ); + if( *ppVal ){ + sqlite3VdbeMemCast(*ppVal, aff, SQLITE_UTF8); + sqlite3ValueApplyAffinity(*ppVal, affinity, SQLITE_UTF8); + } + return rc; + } + /* Handle negative integers in a single step. This is needed in the ** case when the value is -9223372036854775808. */ @@ -1032,14 +1213,14 @@ static int valueFromExpr( && pVal!=0 ){ sqlite3VdbeMemNumerify(pVal); - if( pVal->u.i==SMALLEST_INT64 ){ - pVal->flags &= ~MEM_Int; - pVal->flags |= MEM_Real; - pVal->r = (double)SMALLEST_INT64; + if( pVal->flags & MEM_Real ){ + pVal->u.r = -pVal->u.r; + }else if( pVal->u.i==SMALLEST_INT64 ){ + pVal->u.r = -(double)SMALLEST_INT64; + MemSetTypeFlag(pVal, MEM_Real); }else{ pVal->u.i = -pVal->u.i; } - pVal->r = -pVal->r; sqlite3ValueApplyAffinity(pVal, affinity, enc); } }else if( op==TK_NULL ){ @@ -1130,7 +1311,7 @@ static void recordFunc( sqlite3_result_error_nomem(context); }else{ aRet[0] = nSerial+1; - sqlite3PutVarint(&aRet[1], iSerial); + putVarint32(&aRet[1], iSerial); sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial); sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT); sqlite3DbFree(db, aRet); @@ -1347,7 +1528,7 @@ void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){ Mem *aMem = pRec->aMem; sqlite3 *db = aMem[0].db; for(i=0; ipKeyInfo); sqlite3DbFree(db, pRec); diff --git a/src/vdbesort.c b/src/vdbesort.c index 6a5855f..5a43a10 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -1,5 +1,5 @@ /* -** 2011 July 9 +** 2011-07-09 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -10,44 +10,205 @@ ** ************************************************************************* ** This file contains code for the VdbeSorter object, used in concert with -** a VdbeCursor to sort large numbers of keys (as may be required, for -** example, by CREATE INDEX statements on tables too large to fit in main -** memory). +** a VdbeCursor to sort large numbers of keys for CREATE INDEX statements +** or by SELECT statements with ORDER BY clauses that cannot be satisfied +** using indexes and without LIMIT clauses. +** +** The VdbeSorter object implements a multi-threaded external merge sort +** algorithm that is efficient even if the number of elements being sorted +** exceeds the available memory. +** +** Here is the (internal, non-API) interface between this module and the +** rest of the SQLite system: +** +** sqlite3VdbeSorterInit() Create a new VdbeSorter object. +** +** sqlite3VdbeSorterWrite() Add a single new row to the VdbeSorter +** object. The row is a binary blob in the +** OP_MakeRecord format that contains both +** the ORDER BY key columns and result columns +** in the case of a SELECT w/ ORDER BY, or +** the complete record for an index entry +** in the case of a CREATE INDEX. +** +** sqlite3VdbeSorterRewind() Sort all content previously added. +** Position the read cursor on the +** first sorted element. +** +** sqlite3VdbeSorterNext() Advance the read cursor to the next sorted +** element. +** +** sqlite3VdbeSorterRowkey() Return the complete binary blob for the +** row currently under the read cursor. +** +** sqlite3VdbeSorterCompare() Compare the binary blob for the row +** currently under the read cursor against +** another binary blob X and report if +** X is strictly less than the read cursor. +** Used to enforce uniqueness in a +** CREATE UNIQUE INDEX statement. +** +** sqlite3VdbeSorterClose() Close the VdbeSorter object and reclaim +** all resources. +** +** sqlite3VdbeSorterReset() Refurbish the VdbeSorter for reuse. This +** is like Close() followed by Init() only +** much faster. +** +** The interfaces above must be called in a particular order. Write() can +** only occur in between Init()/Reset() and Rewind(). Next(), Rowkey(), and +** Compare() can only occur in between Rewind() and Close()/Reset(). i.e. +** +** Init() +** for each record: Write() +** Rewind() +** Rowkey()/Compare() +** Next() +** Close() +** +** Algorithm: +** +** Records passed to the sorter via calls to Write() are initially held +** unsorted in main memory. Assuming the amount of memory used never exceeds +** a threshold, when Rewind() is called the set of records is sorted using +** an in-memory merge sort. In this case, no temporary files are required +** and subsequent calls to Rowkey(), Next() and Compare() read records +** directly from main memory. +** +** If the amount of space used to store records in main memory exceeds the +** threshold, then the set of records currently in memory are sorted and +** written to a temporary file in "Packed Memory Array" (PMA) format. +** A PMA created at this point is known as a "level-0 PMA". Higher levels +** of PMAs may be created by merging existing PMAs together - for example +** merging two or more level-0 PMAs together creates a level-1 PMA. +** +** The threshold for the amount of main memory to use before flushing +** records to a PMA is roughly the same as the limit configured for the +** page-cache of the main database. Specifically, the threshold is set to +** the value returned by "PRAGMA main.page_size" multipled by +** that returned by "PRAGMA main.cache_size", in bytes. +** +** If the sorter is running in single-threaded mode, then all PMAs generated +** are appended to a single temporary file. Or, if the sorter is running in +** multi-threaded mode then up to (N+1) temporary files may be opened, where +** N is the configured number of worker threads. In this case, instead of +** sorting the records and writing the PMA to a temporary file itself, the +** calling thread usually launches a worker thread to do so. Except, if +** there are already N worker threads running, the main thread does the work +** itself. +** +** The sorter is running in multi-threaded mode if (a) the library was built +** with pre-processor symbol SQLITE_MAX_WORKER_THREADS set to a value greater +** than zero, and (b) worker threads have been enabled at runtime by calling +** "PRAGMA threads=N" with some value of N greater than 0. +** +** When Rewind() is called, any data remaining in memory is flushed to a +** final PMA. So at this point the data is stored in some number of sorted +** PMAs within temporary files on disk. +** +** If there are fewer than SORTER_MAX_MERGE_COUNT PMAs in total and the +** sorter is running in single-threaded mode, then these PMAs are merged +** incrementally as keys are retreived from the sorter by the VDBE. The +** MergeEngine object, described in further detail below, performs this +** merge. +** +** Or, if running in multi-threaded mode, then a background thread is +** launched to merge the existing PMAs. Once the background thread has +** merged T bytes of data into a single sorted PMA, the main thread +** begins reading keys from that PMA while the background thread proceeds +** with merging the next T bytes of data. And so on. +** +** Parameter T is set to half the value of the memory threshold used +** by Write() above to determine when to create a new PMA. +** +** If there are more than SORTER_MAX_MERGE_COUNT PMAs in total when +** Rewind() is called, then a hierarchy of incremental-merges is used. +** First, T bytes of data from the first SORTER_MAX_MERGE_COUNT PMAs on +** disk are merged together. Then T bytes of data from the second set, and +** so on, such that no operation ever merges more than SORTER_MAX_MERGE_COUNT +** PMAs at a time. This done is to improve locality. +** +** If running in multi-threaded mode and there are more than +** SORTER_MAX_MERGE_COUNT PMAs on disk when Rewind() is called, then more +** than one background thread may be created. Specifically, there may be +** one background thread for each temporary file on disk, and one background +** thread to merge the output of each of the others to a single PMA for +** the main thread to read from. */ - #include "sqliteInt.h" #include "vdbeInt.h" - -typedef struct VdbeSorterIter VdbeSorterIter; -typedef struct SorterRecord SorterRecord; -typedef struct FileWriter FileWriter; +/* +** If SQLITE_DEBUG_SORTER_THREADS is defined, this module outputs various +** messages to stderr that may be helpful in understanding the performance +** characteristics of the sorter in multi-threaded mode. +*/ +#if 0 +# define SQLITE_DEBUG_SORTER_THREADS 1 +#endif /* -** NOTES ON DATA STRUCTURE USED FOR N-WAY MERGES: +** Hard-coded maximum amount of data to accumulate in memory before flushing +** to a level 0 PMA. The purpose of this limit is to prevent various integer +** overflows. 512MiB. +*/ +#define SQLITE_MAX_PMASZ (1<<29) + +/* +** Private objects used by the sorter +*/ +typedef struct MergeEngine MergeEngine; /* Merge PMAs together */ +typedef struct PmaReader PmaReader; /* Incrementally read one PMA */ +typedef struct PmaWriter PmaWriter; /* Incrementally write one PMA */ +typedef struct SorterRecord SorterRecord; /* A record being sorted */ +typedef struct SortSubtask SortSubtask; /* A sub-task in the sort process */ +typedef struct SorterFile SorterFile; /* Temporary file object wrapper */ +typedef struct SorterList SorterList; /* In-memory list of records */ +typedef struct IncrMerger IncrMerger; /* Read & merge multiple PMAs */ + +/* +** A container for a temp file handle and the current amount of data +** stored in the file. +*/ +struct SorterFile { + sqlite3_file *pFd; /* File handle */ + i64 iEof; /* Bytes of data stored in pFd */ +}; + +/* +** An in-memory list of objects to be sorted. ** -** As keys are added to the sorter, they are written to disk in a series -** of sorted packed-memory-arrays (PMAs). The size of each PMA is roughly -** the same as the cache-size allowed for temporary databases. In order -** to allow the caller to extract keys from the sorter in sorted order, -** all PMAs currently stored on disk must be merged together. This comment -** describes the data structure used to do so. The structure supports -** merging any number of arrays in a single pass with no redundant comparison -** operations. +** If aMemory==0 then each object is allocated separately and the objects +** are connected using SorterRecord.u.pNext. If aMemory!=0 then all objects +** are stored in the aMemory[] bulk memory, one right after the other, and +** are connected using SorterRecord.u.iNext. +*/ +struct SorterList { + SorterRecord *pList; /* Linked list of records */ + u8 *aMemory; /* If non-NULL, bulk memory to hold pList */ + int szPMA; /* Size of pList as PMA in bytes */ +}; + +/* +** The MergeEngine object is used to combine two or more smaller PMAs into +** one big PMA using a merge operation. Separate PMAs all need to be +** combined into one big PMA in order to be able to step through the sorted +** records in order. ** -** The aIter[] array contains an iterator for each of the PMAs being merged. -** An aIter[] iterator either points to a valid key or else is at EOF. For -** the purposes of the paragraphs below, we assume that the array is actually -** N elements in size, where N is the smallest power of 2 greater to or equal -** to the number of iterators being merged. The extra aIter[] elements are -** treated as if they are empty (always at EOF). +** The aReadr[] array contains a PmaReader object for each of the PMAs being +** merged. An aReadr[] object either points to a valid key or else is at EOF. +** ("EOF" means "End Of File". When aReadr[] is at EOF there is no more data.) +** For the purposes of the paragraphs below, we assume that the array is +** actually N elements in size, where N is the smallest power of 2 greater +** to or equal to the number of PMAs being merged. The extra aReadr[] elements +** are treated as if they are empty (always at EOF). ** ** The aTree[] array is also N elements in size. The value of N is stored in -** the VdbeSorter.nTree variable. +** the MergeEngine.nTree variable. ** ** The final (N/2) elements of aTree[] contain the results of comparing -** pairs of iterator keys together. Element i contains the result of -** comparing aIter[2*i-N] and aIter[2*i-N+1]. Whichever key is smaller, the +** pairs of PMA keys together. Element i contains the result of +** comparing aReadr[2*i-N] and aReadr[2*i-N+1]. Whichever key is smaller, the ** aTree element is set to the index of it. ** ** For the purposes of this comparison, EOF is considered greater than any @@ -55,34 +216,34 @@ typedef struct FileWriter FileWriter; ** values), it doesn't matter which index is stored. ** ** The (N/4) elements of aTree[] that precede the final (N/2) described -** above contains the index of the smallest of each block of 4 iterators. -** And so on. So that aTree[1] contains the index of the iterator that +** above contains the index of the smallest of each block of 4 PmaReaders +** And so on. So that aTree[1] contains the index of the PmaReader that ** currently points to the smallest key value. aTree[0] is unused. ** ** Example: ** -** aIter[0] -> Banana -** aIter[1] -> Feijoa -** aIter[2] -> Elderberry -** aIter[3] -> Currant -** aIter[4] -> Grapefruit -** aIter[5] -> Apple -** aIter[6] -> Durian -** aIter[7] -> EOF +** aReadr[0] -> Banana +** aReadr[1] -> Feijoa +** aReadr[2] -> Elderberry +** aReadr[3] -> Currant +** aReadr[4] -> Grapefruit +** aReadr[5] -> Apple +** aReadr[6] -> Durian +** aReadr[7] -> EOF ** ** aTree[] = { X, 5 0, 5 0, 3, 5, 6 } ** ** The current element is "Apple" (the value of the key indicated by -** iterator 5). When the Next() operation is invoked, iterator 5 will +** PmaReader 5). When the Next() operation is invoked, PmaReader 5 will ** be advanced to the next key in its segment. Say the next key is ** "Eggplant": ** -** aIter[5] -> Eggplant +** aReadr[5] -> Eggplant ** -** The contents of aTree[] are updated first by comparing the new iterator -** 5 key to the current key of iterator 4 (still "Grapefruit"). The iterator +** The contents of aTree[] are updated first by comparing the new PmaReader +** 5 key to the current key of PmaReader 4 (still "Grapefruit"). The PmaReader ** 5 value is still smaller, so aTree[6] is set to 5. And so on up the tree. -** The value of iterator 6 - "Durian" - is now smaller than that of iterator +** The value of PmaReader 6 - "Durian" - is now smaller than that of PmaReader ** 5, so aTree[3] is set to 6. Key 0 is smaller than key 6 (Bananafile2. And instead of using a +** background thread to prepare data for the PmaReader, with a single +** threaded IncrMerger the allocate part of pTask->file2 is "refilled" with +** keys from pMerger by the calling thread whenever the PmaReader runs out +** of data. */ -struct FileWriter { +struct IncrMerger { + SortSubtask *pTask; /* Task that owns this merger */ + MergeEngine *pMerger; /* Merge engine thread reads data from */ + i64 iStartOff; /* Offset to start writing file at */ + int mxSz; /* Maximum bytes of data to store */ + int bEof; /* Set to true when merge is finished */ + int bUseThread; /* True to use a bg thread for this object */ + SorterFile aFile[2]; /* aFile[0] for reading, [1] for writing */ +}; + +/* +** An instance of this object is used for writing a PMA. +** +** The PMA is written one record at a time. Each record is of an arbitrary +** size. But I/O is more efficient if it occurs in page-sized blocks where +** each block is aligned on a page boundary. This object caches writes to +** the PMA so that aligned, page-size blocks are written. +*/ +struct PmaWriter { int eFWErr; /* Non-zero if in an error state */ u8 *aBuffer; /* Pointer to write buffer */ int nBuffer; /* Size of write buffer in bytes */ int iBufStart; /* First byte of buffer to write */ int iBufEnd; /* Last byte of buffer to write */ i64 iWriteOff; /* Offset of start of buffer in file */ - sqlite3_file *pFile; /* File to write to */ + sqlite3_file *pFd; /* File handle to write to */ }; /* -** A structure to store a single record. All in-memory records are connected -** together into a linked list headed at VdbeSorter.pRecord using the -** SorterRecord.pNext pointer. +** This object is the header on a single record while that record is being +** held in memory and prior to being written out as part of a PMA. +** +** How the linked list is connected depends on how memory is being managed +** by this module. If using a separate allocation for each in-memory record +** (VdbeSorter.list.aMemory==0), then the list is always connected using the +** SorterRecord.u.pNext pointers. +** +** Or, if using the single large allocation method (VdbeSorter.list.aMemory!=0), +** then while records are being accumulated the list is linked using the +** SorterRecord.u.iNext offset. This is because the aMemory[] array may +** be sqlite3Realloc()ed while records are being accumulated. Once the VM +** has finished passing records to the sorter, or when the in-memory buffer +** is full, the list is sorted. As part of the sorting process, it is +** converted to use the SorterRecord.u.pNext pointers. See function +** vdbeSorterSort() for details. */ struct SorterRecord { - void *pVal; - int nVal; - SorterRecord *pNext; + int nVal; /* Size of the record in bytes */ + union { + SorterRecord *pNext; /* Pointer to next record in list */ + int iNext; /* Offset within aMemory of next record */ + } u; + /* The data for the record immediately follows this header */ }; -/* Minimum allowable value for the VdbeSorter.nWorking variable */ -#define SORTER_MIN_WORKING 10 +/* Return a pointer to the buffer containing the record data for SorterRecord +** object p. Should be used as if: +** +** void *SRVAL(SorterRecord *p) { return (void*)&p[1]; } +*/ +#define SRVAL(p) ((void*)((SorterRecord*)(p) + 1)) -/* Maximum number of segments to merge in a single pass. */ + +/* Maximum number of PMAs that a single MergeEngine can merge */ #define SORTER_MAX_MERGE_COUNT 16 +static int vdbeIncrSwap(IncrMerger*); +static void vdbeIncrFree(IncrMerger *); + /* -** Free all memory belonging to the VdbeSorterIter object passed as the second +** Free all memory belonging to the PmaReader object passed as the ** argument. All structure fields are set to zero before returning. */ -static void vdbeSorterIterZero(sqlite3 *db, VdbeSorterIter *pIter){ - sqlite3DbFree(db, pIter->aAlloc); - sqlite3DbFree(db, pIter->aBuffer); - memset(pIter, 0, sizeof(VdbeSorterIter)); +static void vdbePmaReaderClear(PmaReader *pReadr){ + sqlite3_free(pReadr->aAlloc); + sqlite3_free(pReadr->aBuffer); + if( pReadr->aMap ) sqlite3OsUnfetch(pReadr->pFd, 0, pReadr->aMap); + vdbeIncrFree(pReadr->pIncr); + memset(pReadr, 0, sizeof(PmaReader)); } /* -** Read nByte bytes of data from the stream of data iterated by object p. +** Read the next nByte bytes of data from the PMA p. ** If successful, set *ppOut to point to a buffer containing the data ** and return SQLITE_OK. Otherwise, if an error occurs, return an SQLite ** error code. ** -** The buffer indicated by *ppOut may only be considered valid until the +** The buffer returned in *ppOut is only valid until the ** next call to this function. */ -static int vdbeSorterIterRead( - sqlite3 *db, /* Database handle (for malloc) */ - VdbeSorterIter *p, /* Iterator */ +static int vdbePmaReadBlob( + PmaReader *p, /* PmaReader from which to take the blob */ int nByte, /* Bytes of data to read */ u8 **ppOut /* OUT: Pointer to buffer containing data */ ){ int iBuf; /* Offset within buffer to read from */ int nAvail; /* Bytes of data available in buffer */ + + if( p->aMap ){ + *ppOut = &p->aMap[p->iReadOff]; + p->iReadOff += nByte; + return SQLITE_OK; + } + assert( p->aBuffer ); /* If there is no more data to be read from the buffer, read the next @@ -201,8 +508,8 @@ static int vdbeSorterIterRead( } assert( nRead>0 ); - /* Read data from the file. Return early if an error occurs. */ - rc = sqlite3OsRead(p->pFile, p->aBuffer, nRead, p->iReadOff); + /* Readr data from the file. Return early if an error occurs. */ + rc = sqlite3OsRead(p->pFd, p->aBuffer, nRead, p->iReadOff); assert( rc!=SQLITE_IOERR_SHORT_READ ); if( rc!=SQLITE_OK ) return rc; } @@ -222,11 +529,13 @@ static int vdbeSorterIterRead( /* Extend the p->aAlloc[] allocation if required. */ if( p->nAllocnAlloc*2; + u8 *aNew; + int nNew = MAX(128, p->nAlloc*2); while( nByte>nNew ) nNew = nNew*2; - p->aAlloc = sqlite3DbReallocOrFree(db, p->aAlloc, nNew); - if( !p->aAlloc ) return SQLITE_NOMEM; + aNew = sqlite3Realloc(p->aAlloc, nNew); + if( !aNew ) return SQLITE_NOMEM; p->nAlloc = nNew; + p->aAlloc = aNew; } /* Copy as much data as is available in the buffer into the start of @@ -238,13 +547,13 @@ static int vdbeSorterIterRead( /* The following loop copies up to p->nBuffer bytes per iteration into ** the p->aAlloc[] buffer. */ while( nRem>0 ){ - int rc; /* vdbeSorterIterRead() return code */ + int rc; /* vdbePmaReadBlob() return code */ int nCopy; /* Number of bytes to copy */ u8 *aNext; /* Pointer to buffer to copy data from */ nCopy = nRem; if( nRem>p->nBuffer ) nCopy = p->nBuffer; - rc = vdbeSorterIterRead(db, p, nCopy, &aNext); + rc = vdbePmaReadBlob(p, nCopy, &aNext); if( rc!=SQLITE_OK ) return rc; assert( aNext!=p->aAlloc ); memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy); @@ -261,108 +570,174 @@ static int vdbeSorterIterRead( ** Read a varint from the stream of data accessed by p. Set *pnOut to ** the value read. */ -static int vdbeSorterIterVarint(sqlite3 *db, VdbeSorterIter *p, u64 *pnOut){ +static int vdbePmaReadVarint(PmaReader *p, u64 *pnOut){ int iBuf; - iBuf = p->iReadOff % p->nBuffer; - if( iBuf && (p->nBuffer-iBuf)>=9 ){ - p->iReadOff += sqlite3GetVarint(&p->aBuffer[iBuf], pnOut); + if( p->aMap ){ + p->iReadOff += sqlite3GetVarint(&p->aMap[p->iReadOff], pnOut); }else{ - u8 aVarint[16], *a; - int i = 0, rc; - do{ - rc = vdbeSorterIterRead(db, p, 1, &a); - if( rc ) return rc; - aVarint[(i++)&0xf] = a[0]; - }while( (a[0]&0x80)!=0 ); - sqlite3GetVarint(aVarint, pnOut); + iBuf = p->iReadOff % p->nBuffer; + if( iBuf && (p->nBuffer-iBuf)>=9 ){ + p->iReadOff += sqlite3GetVarint(&p->aBuffer[iBuf], pnOut); + }else{ + u8 aVarint[16], *a; + int i = 0, rc; + do{ + rc = vdbePmaReadBlob(p, 1, &a); + if( rc ) return rc; + aVarint[(i++)&0xf] = a[0]; + }while( (a[0]&0x80)!=0 ); + sqlite3GetVarint(aVarint, pnOut); + } } return SQLITE_OK; } +/* +** Attempt to memory map file pFile. If successful, set *pp to point to the +** new mapping and return SQLITE_OK. If the mapping is not attempted +** (because the file is too large or the VFS layer is configured not to use +** mmap), return SQLITE_OK and set *pp to NULL. +** +** Or, if an error occurs, return an SQLite error code. The final value of +** *pp is undefined in this case. +*/ +static int vdbeSorterMapFile(SortSubtask *pTask, SorterFile *pFile, u8 **pp){ + int rc = SQLITE_OK; + if( pFile->iEof<=(i64)(pTask->pSorter->db->nMaxSorterMmap) ){ + sqlite3_file *pFd = pFile->pFd; + if( pFd->pMethods->iVersion>=3 ){ + rc = sqlite3OsFetch(pFd, 0, (int)pFile->iEof, (void**)pp); + testcase( rc!=SQLITE_OK ); + } + } + return rc; +} /* -** Advance iterator pIter to the next key in its PMA. Return SQLITE_OK if -** no error occurs, or an SQLite error code if one does. +** Attach PmaReader pReadr to file pFile (if it is not already attached to +** that file) and seek it to offset iOff within the file. Return SQLITE_OK +** if successful, or an SQLite error code if an error occurs. */ -static int vdbeSorterIterNext( - sqlite3 *db, /* Database handle (for sqlite3DbMalloc() ) */ - VdbeSorterIter *pIter /* Iterator to advance */ +static int vdbePmaReaderSeek( + SortSubtask *pTask, /* Task context */ + PmaReader *pReadr, /* Reader whose cursor is to be moved */ + SorterFile *pFile, /* Sorter file to read from */ + i64 iOff /* Offset in pFile */ ){ - int rc; /* Return Code */ - u64 nRec = 0; /* Size of record in bytes */ + int rc = SQLITE_OK; - if( pIter->iReadOff>=pIter->iEof ){ - /* This is an EOF condition */ - vdbeSorterIterZero(db, pIter); - return SQLITE_OK; + assert( pReadr->pIncr==0 || pReadr->pIncr->bEof==0 ); + + if( sqlite3FaultSim(201) ) return SQLITE_IOERR_READ; + if( pReadr->aMap ){ + sqlite3OsUnfetch(pReadr->pFd, 0, pReadr->aMap); + pReadr->aMap = 0; } + pReadr->iReadOff = iOff; + pReadr->iEof = pFile->iEof; + pReadr->pFd = pFile->pFd; - rc = vdbeSorterIterVarint(db, pIter, &nRec); - if( rc==SQLITE_OK ){ - pIter->nKey = (int)nRec; - rc = vdbeSorterIterRead(db, pIter, (int)nRec, &pIter->aKey); + rc = vdbeSorterMapFile(pTask, pFile, &pReadr->aMap); + if( rc==SQLITE_OK && pReadr->aMap==0 ){ + int pgsz = pTask->pSorter->pgsz; + int iBuf = pReadr->iReadOff % pgsz; + if( pReadr->aBuffer==0 ){ + pReadr->aBuffer = (u8*)sqlite3Malloc(pgsz); + if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM; + pReadr->nBuffer = pgsz; + } + if( rc==SQLITE_OK && iBuf ){ + int nRead = pgsz - iBuf; + if( (pReadr->iReadOff + nRead) > pReadr->iEof ){ + nRead = (int)(pReadr->iEof - pReadr->iReadOff); + } + rc = sqlite3OsRead( + pReadr->pFd, &pReadr->aBuffer[iBuf], nRead, pReadr->iReadOff + ); + testcase( rc!=SQLITE_OK ); + } } return rc; } /* -** Initialize iterator pIter to scan through the PMA stored in file pFile -** starting at offset iStart and ending at offset iEof-1. This function -** leaves the iterator pointing to the first key in the PMA (or EOF if the -** PMA is empty). +** Advance PmaReader pReadr to the next key in its PMA. Return SQLITE_OK if +** no error occurs, or an SQLite error code if one does. */ -static int vdbeSorterIterInit( - sqlite3 *db, /* Database handle */ - const VdbeSorter *pSorter, /* Sorter object */ - i64 iStart, /* Start offset in pFile */ - VdbeSorterIter *pIter, /* Iterator to populate */ - i64 *pnByte /* IN/OUT: Increment this value by PMA size */ -){ - int rc = SQLITE_OK; - int nBuf; +static int vdbePmaReaderNext(PmaReader *pReadr){ + int rc = SQLITE_OK; /* Return Code */ + u64 nRec = 0; /* Size of record in bytes */ - nBuf = sqlite3BtreeGetPageSize(db->aDb[0].pBt); - assert( pSorter->iWriteOff>iStart ); - assert( pIter->aAlloc==0 ); - assert( pIter->aBuffer==0 ); - pIter->pFile = pSorter->pTemp1; - pIter->iReadOff = iStart; - pIter->nAlloc = 128; - pIter->aAlloc = (u8 *)sqlite3DbMallocRaw(db, pIter->nAlloc); - pIter->nBuffer = nBuf; - pIter->aBuffer = (u8 *)sqlite3DbMallocRaw(db, nBuf); - - if( !pIter->aBuffer ){ - rc = SQLITE_NOMEM; - }else{ - int iBuf; - - iBuf = iStart % nBuf; - if( iBuf ){ - int nRead = nBuf - iBuf; - if( (iStart + nRead) > pSorter->iWriteOff ){ - nRead = (int)(pSorter->iWriteOff - iStart); + if( pReadr->iReadOff>=pReadr->iEof ){ + IncrMerger *pIncr = pReadr->pIncr; + int bEof = 1; + if( pIncr ){ + rc = vdbeIncrSwap(pIncr); + if( rc==SQLITE_OK && pIncr->bEof==0 ){ + rc = vdbePmaReaderSeek( + pIncr->pTask, pReadr, &pIncr->aFile[0], pIncr->iStartOff + ); + bEof = 0; } - rc = sqlite3OsRead( - pSorter->pTemp1, &pIter->aBuffer[iBuf], nRead, iStart - ); } - if( rc==SQLITE_OK ){ - u64 nByte; /* Size of PMA in bytes */ - pIter->iEof = pSorter->iWriteOff; - rc = vdbeSorterIterVarint(db, pIter, &nByte); - pIter->iEof = pIter->iReadOff + nByte; - *pnByte += nByte; + if( bEof ){ + /* This is an EOF condition */ + vdbePmaReaderClear(pReadr); + testcase( rc!=SQLITE_OK ); + return rc; } } if( rc==SQLITE_OK ){ - rc = vdbeSorterIterNext(db, pIter); + rc = vdbePmaReadVarint(pReadr, &nRec); + } + if( rc==SQLITE_OK ){ + pReadr->nKey = (int)nRec; + rc = vdbePmaReadBlob(pReadr, (int)nRec, &pReadr->aKey); + testcase( rc!=SQLITE_OK ); + } + + return rc; +} + +/* +** Initialize PmaReader pReadr to scan through the PMA stored in file pFile +** starting at offset iStart and ending at offset iEof-1. This function +** leaves the PmaReader pointing to the first key in the PMA (or EOF if the +** PMA is empty). +** +** If the pnByte parameter is NULL, then it is assumed that the file +** contains a single PMA, and that that PMA omits the initial length varint. +*/ +static int vdbePmaReaderInit( + SortSubtask *pTask, /* Task context */ + SorterFile *pFile, /* Sorter file to read from */ + i64 iStart, /* Start offset in pFile */ + PmaReader *pReadr, /* PmaReader to populate */ + i64 *pnByte /* IN/OUT: Increment this value by PMA size */ +){ + int rc; + + assert( pFile->iEof>iStart ); + assert( pReadr->aAlloc==0 && pReadr->nAlloc==0 ); + assert( pReadr->aBuffer==0 ); + assert( pReadr->aMap==0 ); + + rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart); + if( rc==SQLITE_OK ){ + u64 nByte; /* Size of PMA in bytes */ + rc = vdbePmaReadVarint(pReadr, &nByte); + pReadr->iEof = pReadr->iReadOff + nByte; + *pnByte += nByte; + } + + if( rc==SQLITE_OK ){ + rc = vdbePmaReaderNext(pReadr); } return rc; } @@ -370,125 +745,129 @@ static int vdbeSorterIterInit( /* ** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, -** size nKey2 bytes). Argument pKeyInfo supplies the collation functions -** used by the comparison. If an error occurs, return an SQLite error code. -** Otherwise, return SQLITE_OK and set *pRes to a negative, zero or positive -** value, depending on whether key1 is smaller, equal to or larger than key2. +** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences +** used by the comparison. Return the result of the comparison. ** -** If the bOmitRowid argument is non-zero, assume both keys end in a rowid -** field. For the purposes of the comparison, ignore it. Also, if bOmitRowid -** is true and key1 contains even a single NULL value, it is considered to -** be less than key2. Even if key2 also contains NULL values. +** Before returning, object (pTask->pUnpacked) is populated with the +** unpacked version of key2. Or, if pKey2 is passed a NULL pointer, then it +** is assumed that the (pTask->pUnpacked) structure already contains the +** unpacked key to use as key2. ** -** If pKey2 is passed a NULL pointer, then it is assumed that the pCsr->aSpace -** has been allocated and contains an unpacked record that is used as key2. +** If an OOM error is encountered, (pTask->pUnpacked->error_rc) is set +** to SQLITE_NOMEM. */ -static void vdbeSorterCompare( - const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */ - int nKeyCol, /* Num of columns. 0 means "all" */ +static int vdbeSorterCompare( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ const void *pKey1, int nKey1, /* Left side of comparison */ - const void *pKey2, int nKey2, /* Right side of comparison */ - int *pRes /* OUT: Result of comparison */ + const void *pKey2, int nKey2 /* Right side of comparison */ ){ - KeyInfo *pKeyInfo = pCsr->pKeyInfo; - VdbeSorter *pSorter = pCsr->pSorter; - UnpackedRecord *r2 = pSorter->pUnpacked; - int i; - + UnpackedRecord *r2 = pTask->pUnpacked; if( pKey2 ){ - sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2); + sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); } - - if( nKeyCol ){ - r2->nField = nKeyCol; - for(i=0; iaMem[i].flags & MEM_Null ){ - *pRes = -1; - return; - } - } - assert( r2->default_rc==0 ); - } - - *pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2, 0); -} - -/* -** This function is called to compare two iterator keys when merging -** multiple b-tree segments. Parameter iOut is the index of the aTree[] -** value to recalculate. -*/ -static int vdbeSorterDoCompare(const VdbeCursor *pCsr, int iOut){ - VdbeSorter *pSorter = pCsr->pSorter; - int i1; - int i2; - int iRes; - VdbeSorterIter *p1; - VdbeSorterIter *p2; - - assert( iOutnTree && iOut>0 ); - - if( iOut>=(pSorter->nTree/2) ){ - i1 = (iOut - pSorter->nTree/2) * 2; - i2 = i1 + 1; - }else{ - i1 = pSorter->aTree[iOut*2]; - i2 = pSorter->aTree[iOut*2+1]; - } - - p1 = &pSorter->aIter[i1]; - p2 = &pSorter->aIter[i2]; - - if( p1->pFile==0 ){ - iRes = i2; - }else if( p2->pFile==0 ){ - iRes = i1; - }else{ - int res; - assert( pCsr->pSorter->pUnpacked!=0 ); /* allocated in vdbeSorterMerge() */ - vdbeSorterCompare( - pCsr, 0, p1->aKey, p1->nKey, p2->aKey, p2->nKey, &res - ); - if( res<=0 ){ - iRes = i1; - }else{ - iRes = i2; - } - } - - pSorter->aTree[iOut] = iRes; - return SQLITE_OK; + return sqlite3VdbeRecordCompare(nKey1, pKey1, r2); } /* ** Initialize the temporary index cursor just opened as a sorter cursor. +** +** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField) +** to determine the number of fields that should be compared from the +** records being sorted. However, if the value passed as argument nField +** is non-zero and the sorter is able to guarantee a stable sort, nField +** is used instead. This is used when sorting records for a CREATE INDEX +** statement. In this case, keys are always delivered to the sorter in +** order of the primary key, which happens to be make up the final part +** of the records being sorted. So if the sort is stable, there is never +** any reason to compare PK fields and they can be ignored for a small +** performance boost. +** +** The sorter can guarantee a stable sort when running in single-threaded +** mode, but not in multi-threaded mode. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ -int sqlite3VdbeSorterInit(sqlite3 *db, VdbeCursor *pCsr){ +int sqlite3VdbeSorterInit( + sqlite3 *db, /* Database connection (for malloc()) */ + int nField, /* Number of key fields in each record */ + VdbeCursor *pCsr /* Cursor that holds the new sorter */ +){ int pgsz; /* Page size of main database */ + int i; /* Used to iterate through aTask[] */ int mxCache; /* Cache size */ VdbeSorter *pSorter; /* The new sorter */ - char *d; /* Dummy */ + KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */ + int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */ + int sz; /* Size of pSorter in bytes */ + int rc = SQLITE_OK; +#if SQLITE_MAX_WORKER_THREADS==0 +# define nWorker 0 +#else + int nWorker; +#endif + + /* Initialize the upper limit on the number of worker threads */ +#if SQLITE_MAX_WORKER_THREADS>0 + if( sqlite3TempInMemory(db) || sqlite3GlobalConfig.bCoreMutex==0 ){ + nWorker = 0; + }else{ + nWorker = db->aLimit[SQLITE_LIMIT_WORKER_THREADS]; + } +#endif + + /* Do not allow the total number of threads (main thread + all workers) + ** to exceed the maximum merge count */ +#if SQLITE_MAX_WORKER_THREADS>=SORTER_MAX_MERGE_COUNT + if( nWorker>=SORTER_MAX_MERGE_COUNT ){ + nWorker = SORTER_MAX_MERGE_COUNT-1; + } +#endif assert( pCsr->pKeyInfo && pCsr->pBt==0 ); - pCsr->pSorter = pSorter = sqlite3DbMallocZero(db, sizeof(VdbeSorter)); + szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*); + sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); + + pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); + pCsr->pSorter = pSorter; if( pSorter==0 ){ - return SQLITE_NOMEM; - } - - pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo, 0, 0, &d); - if( pSorter->pUnpacked==0 ) return SQLITE_NOMEM; - assert( pSorter->pUnpacked==(UnpackedRecord *)d ); + rc = SQLITE_NOMEM; + }else{ + pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); + memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); + pKeyInfo->db = 0; + if( nField && nWorker==0 ) pKeyInfo->nField = nField; + pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); + pSorter->nTask = nWorker + 1; + pSorter->bUseThreads = (pSorter->nTask>1); + pSorter->db = db; + for(i=0; inTask; i++){ + SortSubtask *pTask = &pSorter->aTask[i]; + pTask->pSorter = pSorter; + } - if( !sqlite3TempInMemory(db) ){ - pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); - pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz; - mxCache = db->aDb[0].pSchema->cache_size; - if( mxCachemxPmaSize = mxCache * pgsz; + if( !sqlite3TempInMemory(db) ){ + u32 szPma = sqlite3GlobalConfig.szPma; + pSorter->mnPmaSize = szPma * pgsz; + mxCache = db->aDb[0].pSchema->cache_size; + if( mxCache<(int)szPma ) mxCache = (int)szPma; + pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ); + + /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of + ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary + ** large heap allocations. + */ + if( sqlite3GlobalConfig.pScratch==0 ){ + assert( pSorter->iMemory==0 ); + pSorter->nMemory = pgsz; + pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); + if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM; + } + } } - return SQLITE_OK; + return rc; } +#undef nWorker /* Defined at the top of this function */ /* ** Free the list of sorted records starting at pRecord. @@ -497,38 +876,233 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ SorterRecord *p; SorterRecord *pNext; for(p=pRecord; p; p=pNext){ - pNext = p->pNext; + pNext = p->u.pNext; sqlite3DbFree(db, p); } } +/* +** Free all resources owned by the object indicated by argument pTask. All +** fields of *pTask are zeroed before returning. +*/ +static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){ + sqlite3DbFree(db, pTask->pUnpacked); + pTask->pUnpacked = 0; +#if SQLITE_MAX_WORKER_THREADS>0 + /* pTask->list.aMemory can only be non-zero if it was handed memory + ** from the main thread. That only occurs SQLITE_MAX_WORKER_THREADS>0 */ + if( pTask->list.aMemory ){ + sqlite3_free(pTask->list.aMemory); + pTask->list.aMemory = 0; + }else +#endif + { + assert( pTask->list.aMemory==0 ); + vdbeSorterRecordFree(0, pTask->list.pList); + } + pTask->list.pList = 0; + if( pTask->file.pFd ){ + sqlite3OsCloseFree(pTask->file.pFd); + pTask->file.pFd = 0; + pTask->file.iEof = 0; + } + if( pTask->file2.pFd ){ + sqlite3OsCloseFree(pTask->file2.pFd); + pTask->file2.pFd = 0; + pTask->file2.iEof = 0; + } +} + +#ifdef SQLITE_DEBUG_SORTER_THREADS +static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){ + i64 t; + int iTask = (pTask - pTask->pSorter->aTask); + sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); + fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent); +} +static void vdbeSorterRewindDebug(const char *zEvent){ + i64 t; + sqlite3OsCurrentTimeInt64(sqlite3_vfs_find(0), &t); + fprintf(stderr, "%lld:X %s\n", t, zEvent); +} +static void vdbeSorterPopulateDebug( + SortSubtask *pTask, + const char *zEvent +){ + i64 t; + int iTask = (pTask - pTask->pSorter->aTask); + sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); + fprintf(stderr, "%lld:bg%d %s\n", t, iTask, zEvent); +} +static void vdbeSorterBlockDebug( + SortSubtask *pTask, + int bBlocked, + const char *zEvent +){ + if( bBlocked ){ + i64 t; + sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); + fprintf(stderr, "%lld:main %s\n", t, zEvent); + } +} +#else +# define vdbeSorterWorkDebug(x,y) +# define vdbeSorterRewindDebug(y) +# define vdbeSorterPopulateDebug(x,y) +# define vdbeSorterBlockDebug(x,y,z) +#endif + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** Join thread pTask->thread. +*/ +static int vdbeSorterJoinThread(SortSubtask *pTask){ + int rc = SQLITE_OK; + if( pTask->pThread ){ +#ifdef SQLITE_DEBUG_SORTER_THREADS + int bDone = pTask->bDone; +#endif + void *pRet = SQLITE_INT_TO_PTR(SQLITE_ERROR); + vdbeSorterBlockDebug(pTask, !bDone, "enter"); + (void)sqlite3ThreadJoin(pTask->pThread, &pRet); + vdbeSorterBlockDebug(pTask, !bDone, "exit"); + rc = SQLITE_PTR_TO_INT(pRet); + assert( pTask->bDone==1 ); + pTask->bDone = 0; + pTask->pThread = 0; + } + return rc; +} + +/* +** Launch a background thread to run xTask(pIn). +*/ +static int vdbeSorterCreateThread( + SortSubtask *pTask, /* Thread will use this task object */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + assert( pTask->pThread==0 && pTask->bDone==0 ); + return sqlite3ThreadCreate(&pTask->pThread, xTask, pIn); +} + +/* +** Join all outstanding threads launched by SorterWrite() to create +** level-0 PMAs. +*/ +static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){ + int rc = rcin; + int i; + + /* This function is always called by the main user thread. + ** + ** If this function is being called after SorterRewind() has been called, + ** it is possible that thread pSorter->aTask[pSorter->nTask-1].pThread + ** is currently attempt to join one of the other threads. To avoid a race + ** condition where this thread also attempts to join the same object, join + ** thread pSorter->aTask[pSorter->nTask-1].pThread first. */ + for(i=pSorter->nTask-1; i>=0; i--){ + SortSubtask *pTask = &pSorter->aTask[i]; + int rc2 = vdbeSorterJoinThread(pTask); + if( rc==SQLITE_OK ) rc = rc2; + } + return rc; +} +#else +# define vdbeSorterJoinAll(x,rcin) (rcin) +# define vdbeSorterJoinThread(pTask) SQLITE_OK +#endif + +/* +** Allocate a new MergeEngine object capable of handling up to +** nReader PmaReader inputs. +** +** nReader is automatically rounded up to the next power of two. +** nReader may not exceed SORTER_MAX_MERGE_COUNT even after rounding up. +*/ +static MergeEngine *vdbeMergeEngineNew(int nReader){ + int N = 2; /* Smallest power of two >= nReader */ + int nByte; /* Total bytes of space to allocate */ + MergeEngine *pNew; /* Pointer to allocated object to return */ + + assert( nReader<=SORTER_MAX_MERGE_COUNT ); + + while( NnTree = N; + pNew->pTask = 0; + pNew->aReadr = (PmaReader*)&pNew[1]; + pNew->aTree = (int*)&pNew->aReadr[N]; + } + return pNew; +} + +/* +** Free the MergeEngine object passed as the only argument. +*/ +static void vdbeMergeEngineFree(MergeEngine *pMerger){ + int i; + if( pMerger ){ + for(i=0; inTree; i++){ + vdbePmaReaderClear(&pMerger->aReadr[i]); + } + } + sqlite3_free(pMerger); +} + +/* +** Free all resources associated with the IncrMerger object indicated by +** the first argument. +*/ +static void vdbeIncrFree(IncrMerger *pIncr){ + if( pIncr ){ +#if SQLITE_MAX_WORKER_THREADS>0 + if( pIncr->bUseThread ){ + vdbeSorterJoinThread(pIncr->pTask); + if( pIncr->aFile[0].pFd ) sqlite3OsCloseFree(pIncr->aFile[0].pFd); + if( pIncr->aFile[1].pFd ) sqlite3OsCloseFree(pIncr->aFile[1].pFd); + } +#endif + vdbeMergeEngineFree(pIncr->pMerger); + sqlite3_free(pIncr); + } +} + /* ** Reset a sorting cursor back to its original empty state. */ void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){ - if( pSorter->aIter ){ - int i; - for(i=0; inTree; i++){ - vdbeSorterIterZero(db, &pSorter->aIter[i]); - } - sqlite3DbFree(db, pSorter->aIter); - pSorter->aIter = 0; + int i; + (void)vdbeSorterJoinAll(pSorter, SQLITE_OK); + assert( pSorter->bUseThreads || pSorter->pReader==0 ); +#if SQLITE_MAX_WORKER_THREADS>0 + if( pSorter->pReader ){ + vdbePmaReaderClear(pSorter->pReader); + sqlite3DbFree(db, pSorter->pReader); + pSorter->pReader = 0; } - if( pSorter->pTemp1 ){ - sqlite3OsCloseFree(pSorter->pTemp1); - pSorter->pTemp1 = 0; +#endif + vdbeMergeEngineFree(pSorter->pMerger); + pSorter->pMerger = 0; + for(i=0; inTask; i++){ + SortSubtask *pTask = &pSorter->aTask[i]; + vdbeSortSubtaskCleanup(db, pTask); } - vdbeSorterRecordFree(db, pSorter->pRecord); - pSorter->pRecord = 0; - pSorter->iWriteOff = 0; - pSorter->iReadOff = 0; - pSorter->nInMemory = 0; - pSorter->nTree = 0; - pSorter->nPMA = 0; - pSorter->aTree = 0; + if( pSorter->list.aMemory==0 ){ + vdbeSorterRecordFree(0, pSorter->list.pList); + } + pSorter->list.pList = 0; + pSorter->list.szPMA = 0; + pSorter->bUsePMA = 0; + pSorter->iMemory = 0; + pSorter->mxKeysize = 0; + sqlite3DbFree(db, pSorter->pUnpacked); + pSorter->pUnpacked = 0; } - /* ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. */ @@ -536,54 +1110,110 @@ void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ VdbeSorter *pSorter = pCsr->pSorter; if( pSorter ){ sqlite3VdbeSorterReset(db, pSorter); - sqlite3DbFree(db, pSorter->pUnpacked); + sqlite3_free(pSorter->list.aMemory); sqlite3DbFree(db, pSorter); pCsr->pSorter = 0; } } +#if SQLITE_MAX_MMAP_SIZE>0 +/* +** The first argument is a file-handle open on a temporary file. The file +** is guaranteed to be nByte bytes or smaller in size. This function +** attempts to extend the file to nByte bytes in size and to ensure that +** the VFS has memory mapped it. +** +** Whether or not the file does end up memory mapped of course depends on +** the specific VFS implementation. +*/ +static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){ + if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){ + void *p = 0; + int chunksize = 4*1024; + sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize); + sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte); + sqlite3OsFetch(pFd, 0, (int)nByte, &p); + sqlite3OsUnfetch(pFd, 0, p); + } +} +#else +# define vdbeSorterExtendFile(x,y,z) +#endif + /* ** Allocate space for a file-handle and open a temporary file. If successful, -** set *ppFile to point to the malloc'd file-handle and return SQLITE_OK. -** Otherwise, set *ppFile to 0 and return an SQLite error code. +** set *ppFd to point to the malloc'd file-handle and return SQLITE_OK. +** Otherwise, set *ppFd to 0 and return an SQLite error code. */ -static int vdbeSorterOpenTempFile(sqlite3 *db, sqlite3_file **ppFile){ - int dummy; - return sqlite3OsOpenMalloc(db->pVfs, 0, ppFile, +static int vdbeSorterOpenTempFile( + sqlite3 *db, /* Database handle doing sort */ + i64 nExtend, /* Attempt to extend file to this size */ + sqlite3_file **ppFd +){ + int rc; + rc = sqlite3OsOpenMalloc(db->pVfs, 0, ppFd, SQLITE_OPEN_TEMP_JOURNAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | - SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &dummy + SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &rc ); + if( rc==SQLITE_OK ){ + i64 max = SQLITE_MAX_MMAP_SIZE; + sqlite3OsFileControlHint(*ppFd, SQLITE_FCNTL_MMAP_SIZE, (void*)&max); + if( nExtend>0 ){ + vdbeSorterExtendFile(db, *ppFd, nExtend); + } + } + return rc; } +/* +** If it has not already been allocated, allocate the UnpackedRecord +** structure at pTask->pUnpacked. Return SQLITE_OK if successful (or +** if no allocation was required), or SQLITE_NOMEM otherwise. +*/ +static int vdbeSortAllocUnpacked(SortSubtask *pTask){ + if( pTask->pUnpacked==0 ){ + char *pFree; + pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord( + pTask->pSorter->pKeyInfo, 0, 0, &pFree + ); + assert( pTask->pUnpacked==(UnpackedRecord*)pFree ); + if( pFree==0 ) return SQLITE_NOMEM; + pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField; + pTask->pUnpacked->errCode = 0; + } + return SQLITE_OK; +} + + /* ** Merge the two sorted lists p1 and p2 into a single list. ** Set *ppOut to the head of the new list. */ static void vdbeSorterMerge( - const VdbeCursor *pCsr, /* For pKeyInfo */ + SortSubtask *pTask, /* Calling thread context */ SorterRecord *p1, /* First list to merge */ SorterRecord *p2, /* Second list to merge */ SorterRecord **ppOut /* OUT: Head of merged list */ ){ SorterRecord *pFinal = 0; SorterRecord **pp = &pFinal; - void *pVal2 = p2 ? p2->pVal : 0; + void *pVal2 = p2 ? SRVAL(p2) : 0; while( p1 && p2 ){ int res; - vdbeSorterCompare(pCsr, 0, p1->pVal, p1->nVal, pVal2, p2->nVal, &res); + res = vdbeSorterCompare(pTask, SRVAL(p1), p1->nVal, pVal2, p2->nVal); if( res<=0 ){ *pp = p1; - pp = &p1->pNext; - p1 = p1->pNext; + pp = &p1->u.pNext; + p1 = p1->u.pNext; pVal2 = 0; }else{ *pp = p2; - pp = &p2->pNext; - p2 = p2->pNext; + pp = &p2->u.pNext; + p2 = p2->u.pNext; if( p2==0 ) break; - pVal2 = p2->pVal; + pVal2 = SRVAL(p2); } } *pp = p1 ? p1 : p2; @@ -591,27 +1221,41 @@ static void vdbeSorterMerge( } /* -** Sort the linked list of records headed at pCsr->pRecord. Return SQLITE_OK -** if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if an error -** occurs. +** Sort the linked list of records headed at pTask->pList. Return +** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if +** an error occurs. */ -static int vdbeSorterSort(const VdbeCursor *pCsr){ +static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ int i; SorterRecord **aSlot; SorterRecord *p; - VdbeSorter *pSorter = pCsr->pSorter; + int rc; + + rc = vdbeSortAllocUnpacked(pTask); + if( rc!=SQLITE_OK ) return rc; aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *)); if( !aSlot ){ return SQLITE_NOMEM; } - p = pSorter->pRecord; + p = pList->pList; while( p ){ - SorterRecord *pNext = p->pNext; - p->pNext = 0; + SorterRecord *pNext; + if( pList->aMemory ){ + if( (u8*)p==pList->aMemory ){ + pNext = 0; + }else{ + assert( p->u.iNextaMemory) ); + pNext = (SorterRecord*)&pList->aMemory[p->u.iNext]; + } + }else{ + pNext = p->u.pNext; + } + + p->u.pNext = 0; for(i=0; aSlot[i]; i++){ - vdbeSorterMerge(pCsr, p, aSlot[i], &p); + vdbeSorterMerge(pTask, p, aSlot[i], &p); aSlot[i] = 0; } aSlot[i] = p; @@ -620,42 +1264,43 @@ static int vdbeSorterSort(const VdbeCursor *pCsr){ p = 0; for(i=0; i<64; i++){ - vdbeSorterMerge(pCsr, p, aSlot[i], &p); + vdbeSorterMerge(pTask, p, aSlot[i], &p); } - pSorter->pRecord = p; + pList->pList = p; sqlite3_free(aSlot); - return SQLITE_OK; + assert( pTask->pUnpacked->errCode==SQLITE_OK + || pTask->pUnpacked->errCode==SQLITE_NOMEM + ); + return pTask->pUnpacked->errCode; } /* -** Initialize a file-writer object. +** Initialize a PMA-writer object. */ -static void fileWriterInit( - sqlite3 *db, /* Database (for malloc) */ - sqlite3_file *pFile, /* File to write to */ - FileWriter *p, /* Object to populate */ - i64 iStart /* Offset of pFile to begin writing at */ +static void vdbePmaWriterInit( + sqlite3_file *pFd, /* File handle to write to */ + PmaWriter *p, /* Object to populate */ + int nBuf, /* Buffer size */ + i64 iStart /* Offset of pFd to begin writing at */ ){ - int nBuf = sqlite3BtreeGetPageSize(db->aDb[0].pBt); - - memset(p, 0, sizeof(FileWriter)); - p->aBuffer = (u8 *)sqlite3DbMallocRaw(db, nBuf); + memset(p, 0, sizeof(PmaWriter)); + p->aBuffer = (u8*)sqlite3Malloc(nBuf); if( !p->aBuffer ){ p->eFWErr = SQLITE_NOMEM; }else{ p->iBufEnd = p->iBufStart = (iStart % nBuf); p->iWriteOff = iStart - p->iBufStart; p->nBuffer = nBuf; - p->pFile = pFile; + p->pFd = pFd; } } /* -** Write nData bytes of data to the file-write object. Return SQLITE_OK +** Write nData bytes of data to the PMA. Return SQLITE_OK ** if successful, or an SQLite error code if an error occurs. */ -static void fileWriterWrite(FileWriter *p, u8 *pData, int nData){ +static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){ int nRem = nData; while( nRem>0 && p->eFWErr==0 ){ int nCopy = nRem; @@ -666,7 +1311,7 @@ static void fileWriterWrite(FileWriter *p, u8 *pData, int nData){ memcpy(&p->aBuffer[p->iBufEnd], &pData[nData-nRem], nCopy); p->iBufEnd += nCopy; if( p->iBufEnd==p->nBuffer ){ - p->eFWErr = sqlite3OsWrite(p->pFile, + p->eFWErr = sqlite3OsWrite(p->pFd, &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, p->iWriteOff + p->iBufStart ); @@ -680,43 +1325,44 @@ static void fileWriterWrite(FileWriter *p, u8 *pData, int nData){ } /* -** Flush any buffered data to disk and clean up the file-writer object. -** The results of using the file-writer after this call are undefined. +** Flush any buffered data to disk and clean up the PMA-writer object. +** The results of using the PMA-writer after this call are undefined. ** Return SQLITE_OK if flushing the buffered data succeeds or is not ** required. Otherwise, return an SQLite error code. ** ** Before returning, set *piEof to the offset immediately following the ** last byte written to the file. */ -static int fileWriterFinish(sqlite3 *db, FileWriter *p, i64 *piEof){ +static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){ int rc; if( p->eFWErr==0 && ALWAYS(p->aBuffer) && p->iBufEnd>p->iBufStart ){ - p->eFWErr = sqlite3OsWrite(p->pFile, + p->eFWErr = sqlite3OsWrite(p->pFd, &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, p->iWriteOff + p->iBufStart ); } *piEof = (p->iWriteOff + p->iBufEnd); - sqlite3DbFree(db, p->aBuffer); + sqlite3_free(p->aBuffer); rc = p->eFWErr; - memset(p, 0, sizeof(FileWriter)); + memset(p, 0, sizeof(PmaWriter)); return rc; } /* -** Write value iVal encoded as a varint to the file-write object. Return +** Write value iVal encoded as a varint to the PMA. Return ** SQLITE_OK if successful, or an SQLite error code if an error occurs. */ -static void fileWriterWriteVarint(FileWriter *p, u64 iVal){ +static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){ int nByte; u8 aByte[10]; nByte = sqlite3PutVarint(aByte, iVal); - fileWriterWrite(p, aByte, nByte); + vdbePmaWriteBlob(p, aByte, nByte); } /* -** Write the current contents of the in-memory linked-list to a PMA. Return -** SQLITE_OK if successful, or an SQLite error code otherwise. +** Write the current contents of in-memory linked-list pList to a level-0 +** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if +** successful, or an SQLite error code otherwise. ** ** The format of a PMA is: ** @@ -727,76 +1373,246 @@ static void fileWriterWriteVarint(FileWriter *p, u64 iVal){ ** Each record consists of a varint followed by a blob of data (the ** key). The varint is the number of bytes in the blob of data. */ -static int vdbeSorterListToPMA(sqlite3 *db, const VdbeCursor *pCsr){ +static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){ + sqlite3 *db = pTask->pSorter->db; int rc = SQLITE_OK; /* Return code */ - VdbeSorter *pSorter = pCsr->pSorter; - FileWriter writer; + PmaWriter writer; /* Object used to write to the file */ - memset(&writer, 0, sizeof(FileWriter)); +#ifdef SQLITE_DEBUG + /* Set iSz to the expected size of file pTask->file after writing the PMA. + ** This is used by an assert() statement at the end of this function. */ + i64 iSz = pList->szPMA + sqlite3VarintLen(pList->szPMA) + pTask->file.iEof; +#endif - if( pSorter->nInMemory==0 ){ - assert( pSorter->pRecord==0 ); - return rc; - } - - rc = vdbeSorterSort(pCsr); + vdbeSorterWorkDebug(pTask, "enter"); + memset(&writer, 0, sizeof(PmaWriter)); + assert( pList->szPMA>0 ); /* If the first temporary PMA file has not been opened, open it now. */ - if( rc==SQLITE_OK && pSorter->pTemp1==0 ){ - rc = vdbeSorterOpenTempFile(db, &pSorter->pTemp1); - assert( rc!=SQLITE_OK || pSorter->pTemp1 ); - assert( pSorter->iWriteOff==0 ); - assert( pSorter->nPMA==0 ); + if( pTask->file.pFd==0 ){ + rc = vdbeSorterOpenTempFile(db, 0, &pTask->file.pFd); + assert( rc!=SQLITE_OK || pTask->file.pFd ); + assert( pTask->file.iEof==0 ); + assert( pTask->nPMA==0 ); + } + + /* Try to get the file to memory map */ + if( rc==SQLITE_OK ){ + vdbeSorterExtendFile(db, pTask->file.pFd, pTask->file.iEof+pList->szPMA+9); + } + + /* Sort the list */ + if( rc==SQLITE_OK ){ + rc = vdbeSorterSort(pTask, pList); } if( rc==SQLITE_OK ){ SorterRecord *p; SorterRecord *pNext = 0; - fileWriterInit(db, pSorter->pTemp1, &writer, pSorter->iWriteOff); - pSorter->nPMA++; - fileWriterWriteVarint(&writer, pSorter->nInMemory); - for(p=pSorter->pRecord; p; p=pNext){ - pNext = p->pNext; - fileWriterWriteVarint(&writer, p->nVal); - fileWriterWrite(&writer, p->pVal, p->nVal); - sqlite3DbFree(db, p); + vdbePmaWriterInit(pTask->file.pFd, &writer, pTask->pSorter->pgsz, + pTask->file.iEof); + pTask->nPMA++; + vdbePmaWriteVarint(&writer, pList->szPMA); + for(p=pList->pList; p; p=pNext){ + pNext = p->u.pNext; + vdbePmaWriteVarint(&writer, p->nVal); + vdbePmaWriteBlob(&writer, SRVAL(p), p->nVal); + if( pList->aMemory==0 ) sqlite3_free(p); + } + pList->pList = p; + rc = vdbePmaWriterFinish(&writer, &pTask->file.iEof); + } + + vdbeSorterWorkDebug(pTask, "exit"); + assert( rc!=SQLITE_OK || pList->pList==0 ); + assert( rc!=SQLITE_OK || pTask->file.iEof==iSz ); + return rc; +} + +/* +** Advance the MergeEngine to its next entry. +** Set *pbEof to true there is no next entry because +** the MergeEngine has reached the end of all its inputs. +** +** Return SQLITE_OK if successful or an error code if an error occurs. +*/ +static int vdbeMergeEngineStep( + MergeEngine *pMerger, /* The merge engine to advance to the next row */ + int *pbEof /* Set TRUE at EOF. Set false for more content */ +){ + int rc; + int iPrev = pMerger->aTree[1];/* Index of PmaReader to advance */ + SortSubtask *pTask = pMerger->pTask; + + /* Advance the current PmaReader */ + rc = vdbePmaReaderNext(&pMerger->aReadr[iPrev]); + + /* Update contents of aTree[] */ + if( rc==SQLITE_OK ){ + int i; /* Index of aTree[] to recalculate */ + PmaReader *pReadr1; /* First PmaReader to compare */ + PmaReader *pReadr2; /* Second PmaReader to compare */ + u8 *pKey2; /* To pReadr2->aKey, or 0 if record cached */ + + /* Find the first two PmaReaders to compare. The one that was just + ** advanced (iPrev) and the one next to it in the array. */ + pReadr1 = &pMerger->aReadr[(iPrev & 0xFFFE)]; + pReadr2 = &pMerger->aReadr[(iPrev | 0x0001)]; + pKey2 = pReadr2->aKey; + + for(i=(pMerger->nTree+iPrev)/2; i>0; i=i/2){ + /* Compare pReadr1 and pReadr2. Store the result in variable iRes. */ + int iRes; + if( pReadr1->pFd==0 ){ + iRes = +1; + }else if( pReadr2->pFd==0 ){ + iRes = -1; + }else{ + iRes = vdbeSorterCompare(pTask, + pReadr1->aKey, pReadr1->nKey, pKey2, pReadr2->nKey + ); + } + + /* If pReadr1 contained the smaller value, set aTree[i] to its index. + ** Then set pReadr2 to the next PmaReader to compare to pReadr1. In this + ** case there is no cache of pReadr2 in pTask->pUnpacked, so set + ** pKey2 to point to the record belonging to pReadr2. + ** + ** Alternatively, if pReadr2 contains the smaller of the two values, + ** set aTree[i] to its index and update pReadr1. If vdbeSorterCompare() + ** was actually called above, then pTask->pUnpacked now contains + ** a value equivalent to pReadr2. So set pKey2 to NULL to prevent + ** vdbeSorterCompare() from decoding pReadr2 again. + ** + ** If the two values were equal, then the value from the oldest + ** PMA should be considered smaller. The VdbeSorter.aReadr[] array + ** is sorted from oldest to newest, so pReadr1 contains older values + ** than pReadr2 iff (pReadr1aTree[i] = (int)(pReadr1 - pMerger->aReadr); + pReadr2 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; + pKey2 = pReadr2->aKey; + }else{ + if( pReadr1->pFd ) pKey2 = 0; + pMerger->aTree[i] = (int)(pReadr2 - pMerger->aReadr); + pReadr1 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; + } + } + *pbEof = (pMerger->aReadr[pMerger->aTree[1]].pFd==0); + } + + return (rc==SQLITE_OK ? pTask->pUnpacked->errCode : rc); +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** The main routine for background threads that write level-0 PMAs. +*/ +static void *vdbeSorterFlushThread(void *pCtx){ + SortSubtask *pTask = (SortSubtask*)pCtx; + int rc; /* Return code */ + assert( pTask->bDone==0 ); + rc = vdbeSorterListToPMA(pTask, &pTask->list); + pTask->bDone = 1; + return SQLITE_INT_TO_PTR(rc); +} +#endif /* SQLITE_MAX_WORKER_THREADS>0 */ + +/* +** Flush the current contents of VdbeSorter.list to a new PMA, possibly +** using a background thread. +*/ +static int vdbeSorterFlushPMA(VdbeSorter *pSorter){ +#if SQLITE_MAX_WORKER_THREADS==0 + pSorter->bUsePMA = 1; + return vdbeSorterListToPMA(&pSorter->aTask[0], &pSorter->list); +#else + int rc = SQLITE_OK; + int i; + SortSubtask *pTask = 0; /* Thread context used to create new PMA */ + int nWorker = (pSorter->nTask-1); + + /* Set the flag to indicate that at least one PMA has been written. + ** Or will be, anyhow. */ + pSorter->bUsePMA = 1; + + /* Select a sub-task to sort and flush the current list of in-memory + ** records to disk. If the sorter is running in multi-threaded mode, + ** round-robin between the first (pSorter->nTask-1) tasks. Except, if + ** the background thread from a sub-tasks previous turn is still running, + ** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy, + ** fall back to using the final sub-task. The first (pSorter->nTask-1) + ** sub-tasks are prefered as they use background threads - the final + ** sub-task uses the main thread. */ + for(i=0; iiPrev + i + 1) % nWorker; + pTask = &pSorter->aTask[iTest]; + if( pTask->bDone ){ + rc = vdbeSorterJoinThread(pTask); + } + if( rc!=SQLITE_OK || pTask->pThread==0 ) break; + } + + if( rc==SQLITE_OK ){ + if( i==nWorker ){ + /* Use the foreground thread for this operation */ + rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker], &pSorter->list); + }else{ + /* Launch a background thread for this operation */ + u8 *aMem = pTask->list.aMemory; + void *pCtx = (void*)pTask; + + assert( pTask->pThread==0 && pTask->bDone==0 ); + assert( pTask->list.pList==0 ); + assert( pTask->list.aMemory==0 || pSorter->list.aMemory!=0 ); + + pSorter->iPrev = (u8)(pTask - pSorter->aTask); + pTask->list = pSorter->list; + pSorter->list.pList = 0; + pSorter->list.szPMA = 0; + if( aMem ){ + pSorter->list.aMemory = aMem; + pSorter->nMemory = sqlite3MallocSize(aMem); + }else if( pSorter->list.aMemory ){ + pSorter->list.aMemory = sqlite3Malloc(pSorter->nMemory); + if( !pSorter->list.aMemory ) return SQLITE_NOMEM; + } + + rc = vdbeSorterCreateThread(pTask, vdbeSorterFlushThread, pCtx); } - pSorter->pRecord = p; - rc = fileWriterFinish(db, &writer, &pSorter->iWriteOff); } return rc; +#endif /* SQLITE_MAX_WORKER_THREADS!=0 */ } /* ** Add a record to the sorter. */ int sqlite3VdbeSorterWrite( - sqlite3 *db, /* Database handle */ - const VdbeCursor *pCsr, /* Sorter cursor */ + const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal /* Memory cell containing record */ ){ VdbeSorter *pSorter = pCsr->pSorter; int rc = SQLITE_OK; /* Return Code */ SorterRecord *pNew; /* New list element */ + int bFlush; /* True to flush contents of memory to PMA */ + int nReq; /* Bytes of memory required */ + int nPMA; /* Bytes of PMA space required */ + assert( pSorter ); - pSorter->nInMemory += sqlite3VarintLen(pVal->n) + pVal->n; - pNew = (SorterRecord *)sqlite3DbMallocRaw(db, pVal->n + sizeof(SorterRecord)); - if( pNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - pNew->pVal = (void *)&pNew[1]; - memcpy(pNew->pVal, pVal->z, pVal->n); - pNew->nVal = pVal->n; - pNew->pNext = pSorter->pRecord; - pSorter->pRecord = pNew; - } - - /* See if the contents of the sorter should now be written out. They - ** are written out when either of the following are true: + /* Figure out whether or not the current contents of memory should be + ** flushed to a PMA before continuing. If so, do so. + ** + ** If using the single large allocation mode (pSorter->aMemory!=0), then + ** flush the contents of memory to a new PMA if (a) at least one value is + ** already in memory and (b) the new value will not fit in memory. + ** + ** Or, if using separate allocations for each record, flush the contents + ** of memory to a PMA if either of the following are true: ** ** * The total memory allocated for the in-memory list is greater ** than (page-size * cache-size), or @@ -804,161 +1620,778 @@ int sqlite3VdbeSorterWrite( ** * The total memory allocated for the in-memory list is greater ** than (page-size * 10) and sqlite3HeapNearlyFull() returns true. */ - if( rc==SQLITE_OK && pSorter->mxPmaSize>0 && ( - (pSorter->nInMemory>pSorter->mxPmaSize) - || (pSorter->nInMemory>pSorter->mnPmaSize && sqlite3HeapNearlyFull()) - )){ -#ifdef SQLITE_DEBUG - i64 nExpect = pSorter->iWriteOff - + sqlite3VarintLen(pSorter->nInMemory) - + pSorter->nInMemory; + nReq = pVal->n + sizeof(SorterRecord); + nPMA = pVal->n + sqlite3VarintLen(pVal->n); + if( pSorter->mxPmaSize ){ + if( pSorter->list.aMemory ){ + bFlush = pSorter->iMemory && (pSorter->iMemory+nReq) > pSorter->mxPmaSize; + }else{ + bFlush = ( + (pSorter->list.szPMA > pSorter->mxPmaSize) + || (pSorter->list.szPMA > pSorter->mnPmaSize && sqlite3HeapNearlyFull()) + ); + } + if( bFlush ){ + rc = vdbeSorterFlushPMA(pSorter); + pSorter->list.szPMA = 0; + pSorter->iMemory = 0; + assert( rc!=SQLITE_OK || pSorter->list.pList==0 ); + } + } + + pSorter->list.szPMA += nPMA; + if( nPMA>pSorter->mxKeysize ){ + pSorter->mxKeysize = nPMA; + } + + if( pSorter->list.aMemory ){ + int nMin = pSorter->iMemory + nReq; + + if( nMin>pSorter->nMemory ){ + u8 *aNew; + int nNew = pSorter->nMemory * 2; + while( nNew < nMin ) nNew = nNew*2; + if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize; + if( nNew < nMin ) nNew = nMin; + + aNew = sqlite3Realloc(pSorter->list.aMemory, nNew); + if( !aNew ) return SQLITE_NOMEM; + pSorter->list.pList = (SorterRecord*)( + aNew + ((u8*)pSorter->list.pList - pSorter->list.aMemory) + ); + pSorter->list.aMemory = aNew; + pSorter->nMemory = nNew; + } + + pNew = (SorterRecord*)&pSorter->list.aMemory[pSorter->iMemory]; + pSorter->iMemory += ROUND8(nReq); + pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory); + }else{ + pNew = (SorterRecord *)sqlite3Malloc(nReq); + if( pNew==0 ){ + return SQLITE_NOMEM; + } + pNew->u.pNext = pSorter->list.pList; + } + + memcpy(SRVAL(pNew), pVal->z, pVal->n); + pNew->nVal = pVal->n; + pSorter->list.pList = pNew; + + return rc; +} + +/* +** Read keys from pIncr->pMerger and populate pIncr->aFile[1]. The format +** of the data stored in aFile[1] is the same as that used by regular PMAs, +** except that the number-of-bytes varint is omitted from the start. +*/ +static int vdbeIncrPopulate(IncrMerger *pIncr){ + int rc = SQLITE_OK; + int rc2; + i64 iStart = pIncr->iStartOff; + SorterFile *pOut = &pIncr->aFile[1]; + SortSubtask *pTask = pIncr->pTask; + MergeEngine *pMerger = pIncr->pMerger; + PmaWriter writer; + assert( pIncr->bEof==0 ); + + vdbeSorterPopulateDebug(pTask, "enter"); + + vdbePmaWriterInit(pOut->pFd, &writer, pTask->pSorter->pgsz, iStart); + while( rc==SQLITE_OK ){ + int dummy; + PmaReader *pReader = &pMerger->aReadr[ pMerger->aTree[1] ]; + int nKey = pReader->nKey; + i64 iEof = writer.iWriteOff + writer.iBufEnd; + + /* Check if the output file is full or if the input has been exhausted. + ** In either case exit the loop. */ + if( pReader->pFd==0 ) break; + if( (iEof + nKey + sqlite3VarintLen(nKey))>(iStart + pIncr->mxSz) ) break; + + /* Write the next key to the output. */ + vdbePmaWriteVarint(&writer, nKey); + vdbePmaWriteBlob(&writer, pReader->aKey, nKey); + assert( pIncr->pMerger->pTask==pTask ); + rc = vdbeMergeEngineStep(pIncr->pMerger, &dummy); + } + + rc2 = vdbePmaWriterFinish(&writer, &pOut->iEof); + if( rc==SQLITE_OK ) rc = rc2; + vdbeSorterPopulateDebug(pTask, "exit"); + return rc; +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** The main routine for background threads that populate aFile[1] of +** multi-threaded IncrMerger objects. +*/ +static void *vdbeIncrPopulateThread(void *pCtx){ + IncrMerger *pIncr = (IncrMerger*)pCtx; + void *pRet = SQLITE_INT_TO_PTR( vdbeIncrPopulate(pIncr) ); + pIncr->pTask->bDone = 1; + return pRet; +} + +/* +** Launch a background thread to populate aFile[1] of pIncr. +*/ +static int vdbeIncrBgPopulate(IncrMerger *pIncr){ + void *p = (void*)pIncr; + assert( pIncr->bUseThread ); + return vdbeSorterCreateThread(pIncr->pTask, vdbeIncrPopulateThread, p); +} #endif - rc = vdbeSorterListToPMA(db, pCsr); - pSorter->nInMemory = 0; - assert( rc!=SQLITE_OK || (nExpect==pSorter->iWriteOff) ); + +/* +** This function is called when the PmaReader corresponding to pIncr has +** finished reading the contents of aFile[0]. Its purpose is to "refill" +** aFile[0] such that the PmaReader should start rereading it from the +** beginning. +** +** For single-threaded objects, this is accomplished by literally reading +** keys from pIncr->pMerger and repopulating aFile[0]. +** +** For multi-threaded objects, all that is required is to wait until the +** background thread is finished (if it is not already) and then swap +** aFile[0] and aFile[1] in place. If the contents of pMerger have not +** been exhausted, this function also launches a new background thread +** to populate the new aFile[1]. +** +** SQLITE_OK is returned on success, or an SQLite error code otherwise. +*/ +static int vdbeIncrSwap(IncrMerger *pIncr){ + int rc = SQLITE_OK; + +#if SQLITE_MAX_WORKER_THREADS>0 + if( pIncr->bUseThread ){ + rc = vdbeSorterJoinThread(pIncr->pTask); + + if( rc==SQLITE_OK ){ + SorterFile f0 = pIncr->aFile[0]; + pIncr->aFile[0] = pIncr->aFile[1]; + pIncr->aFile[1] = f0; + } + + if( rc==SQLITE_OK ){ + if( pIncr->aFile[0].iEof==pIncr->iStartOff ){ + pIncr->bEof = 1; + }else{ + rc = vdbeIncrBgPopulate(pIncr); + } + } + }else +#endif + { + rc = vdbeIncrPopulate(pIncr); + pIncr->aFile[0] = pIncr->aFile[1]; + if( pIncr->aFile[0].iEof==pIncr->iStartOff ){ + pIncr->bEof = 1; + } } return rc; } /* -** Helper function for sqlite3VdbeSorterRewind(). +** Allocate and return a new IncrMerger object to read data from pMerger. +** +** If an OOM condition is encountered, return NULL. In this case free the +** pMerger argument before returning. */ -static int vdbeSorterInitMerge( - sqlite3 *db, /* Database handle */ - const VdbeCursor *pCsr, /* Cursor handle for this sorter */ - i64 *pnByte /* Sum of bytes in all opened PMAs */ +static int vdbeIncrMergerNew( + SortSubtask *pTask, /* The thread that will be using the new IncrMerger */ + MergeEngine *pMerger, /* The MergeEngine that the IncrMerger will control */ + IncrMerger **ppOut /* Write the new IncrMerger here */ ){ + int rc = SQLITE_OK; + IncrMerger *pIncr = *ppOut = (IncrMerger*) + (sqlite3FaultSim(100) ? 0 : sqlite3MallocZero(sizeof(*pIncr))); + if( pIncr ){ + pIncr->pMerger = pMerger; + pIncr->pTask = pTask; + pIncr->mxSz = MAX(pTask->pSorter->mxKeysize+9,pTask->pSorter->mxPmaSize/2); + pTask->file2.iEof += pIncr->mxSz; + }else{ + vdbeMergeEngineFree(pMerger); + rc = SQLITE_NOMEM; + } + return rc; +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** Set the "use-threads" flag on object pIncr. +*/ +static void vdbeIncrMergerSetThreads(IncrMerger *pIncr){ + pIncr->bUseThread = 1; + pIncr->pTask->file2.iEof -= pIncr->mxSz; +} +#endif /* SQLITE_MAX_WORKER_THREADS>0 */ + + + +/* +** Recompute pMerger->aTree[iOut] by comparing the next keys on the +** two PmaReaders that feed that entry. Neither of the PmaReaders +** are advanced. This routine merely does the comparison. +*/ +static void vdbeMergeEngineCompare( + MergeEngine *pMerger, /* Merge engine containing PmaReaders to compare */ + int iOut /* Store the result in pMerger->aTree[iOut] */ +){ + int i1; + int i2; + int iRes; + PmaReader *p1; + PmaReader *p2; + + assert( iOutnTree && iOut>0 ); + + if( iOut>=(pMerger->nTree/2) ){ + i1 = (iOut - pMerger->nTree/2) * 2; + i2 = i1 + 1; + }else{ + i1 = pMerger->aTree[iOut*2]; + i2 = pMerger->aTree[iOut*2+1]; + } + + p1 = &pMerger->aReadr[i1]; + p2 = &pMerger->aReadr[i2]; + + if( p1->pFd==0 ){ + iRes = i2; + }else if( p2->pFd==0 ){ + iRes = i1; + }else{ + int res; + assert( pMerger->pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */ + res = vdbeSorterCompare( + pMerger->pTask, p1->aKey, p1->nKey, p2->aKey, p2->nKey + ); + if( res<=0 ){ + iRes = i1; + }else{ + iRes = i2; + } + } + + pMerger->aTree[iOut] = iRes; +} + +/* +** Allowed values for the eMode parameter to vdbeMergeEngineInit() +** and vdbePmaReaderIncrMergeInit(). +** +** Only INCRINIT_NORMAL is valid in single-threaded builds (when +** SQLITE_MAX_WORKER_THREADS==0). The other values are only used +** when there exists one or more separate worker threads. +*/ +#define INCRINIT_NORMAL 0 +#define INCRINIT_TASK 1 +#define INCRINIT_ROOT 2 + +/* Forward reference. +** The vdbeIncrMergeInit() and vdbePmaReaderIncrMergeInit() routines call each +** other (when building a merge tree). +*/ +static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode); + +/* +** Initialize the MergeEngine object passed as the second argument. Once this +** function returns, the first key of merged data may be read from the +** MergeEngine object in the usual fashion. +** +** If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge +** objects attached to the PmaReader objects that the merger reads from have +** already been populated, but that they have not yet populated aFile[0] and +** set the PmaReader objects up to read from it. In this case all that is +** required is to call vdbePmaReaderNext() on each PmaReader to point it at +** its first key. +** +** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use +** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data +** to pMerger. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int vdbeMergeEngineInit( + SortSubtask *pTask, /* Thread that will run pMerger */ + MergeEngine *pMerger, /* MergeEngine to initialize */ + int eMode /* One of the INCRINIT_XXX constants */ +){ + int rc = SQLITE_OK; /* Return code */ + int i; /* For looping over PmaReader objects */ + int nTree = pMerger->nTree; + + /* eMode is always INCRINIT_NORMAL in single-threaded mode */ + assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); + + /* Verify that the MergeEngine is assigned to a single thread */ + assert( pMerger->pTask==0 ); + pMerger->pTask = pTask; + + for(i=0; i0 && eMode==INCRINIT_ROOT ){ + /* PmaReaders should be normally initialized in order, as if they are + ** reading from the same temp file this makes for more linear file IO. + ** However, in the INCRINIT_ROOT case, if PmaReader aReadr[nTask-1] is + ** in use it will block the vdbePmaReaderNext() call while it uses + ** the main thread to fill its buffer. So calling PmaReaderNext() + ** on this PmaReader before any of the multi-threaded PmaReaders takes + ** better advantage of multi-processor hardware. */ + rc = vdbePmaReaderNext(&pMerger->aReadr[nTree-i-1]); + }else{ + rc = vdbePmaReaderIncrMergeInit(&pMerger->aReadr[i], INCRINIT_NORMAL); + } + if( rc!=SQLITE_OK ) return rc; + } + + for(i=pMerger->nTree-1; i>0; i--){ + vdbeMergeEngineCompare(pMerger, i); + } + return pTask->pUnpacked->errCode; +} + +/* +** Initialize the IncrMerge field of a PmaReader. +** +** If the PmaReader passed as the first argument is not an incremental-reader +** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it serves +** to open and/or initialize the temp file related fields of the IncrMerge +** object at (pReadr->pIncr). +** +** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders +** in the sub-tree headed by pReadr are also initialized. Data is then loaded +** into the buffers belonging to pReadr and it is set to +** point to the first key in its range. +** +** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed +** to be a multi-threaded PmaReader and this function is being called in a +** background thread. In this case all PmaReaders in the sub-tree are +** initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to +** pReadr is populated. However, pReadr itself is not set up to point +** to its first key. A call to vdbePmaReaderNext() is still required to do +** that. +** +** The reason this function does not call vdbePmaReaderNext() immediately +** in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has +** to block on thread (pTask->thread) before accessing aFile[1]. But, since +** this entire function is being run by thread (pTask->thread), that will +** lead to the current background thread attempting to join itself. +** +** Finally, if argument eMode is set to INCRINIT_ROOT, it may be assumed +** that pReadr->pIncr is a multi-threaded IncrMerge objects, and that all +** child-trees have already been initialized using IncrInit(INCRINIT_TASK). +** In this case vdbePmaReaderNext() is called on all child PmaReaders and +** the current PmaReader set to point to the first key in its range. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){ + int rc = SQLITE_OK; + IncrMerger *pIncr = pReadr->pIncr; + + /* eMode is always INCRINIT_NORMAL in single-threaded mode */ + assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); + + if( pIncr ){ + SortSubtask *pTask = pIncr->pTask; + sqlite3 *db = pTask->pSorter->db; + + rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode); + + /* Set up the required files for pIncr. A multi-theaded IncrMerge object + ** requires two temp files to itself, whereas a single-threaded object + ** only requires a region of pTask->file2. */ + if( rc==SQLITE_OK ){ + int mxSz = pIncr->mxSz; +#if SQLITE_MAX_WORKER_THREADS>0 + if( pIncr->bUseThread ){ + rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd); + if( rc==SQLITE_OK ){ + rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd); + } + }else +#endif + /*if( !pIncr->bUseThread )*/{ + if( pTask->file2.pFd==0 ){ + assert( pTask->file2.iEof>0 ); + rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd); + pTask->file2.iEof = 0; + } + if( rc==SQLITE_OK ){ + pIncr->aFile[1].pFd = pTask->file2.pFd; + pIncr->iStartOff = pTask->file2.iEof; + pTask->file2.iEof += mxSz; + } + } + } + +#if SQLITE_MAX_WORKER_THREADS>0 + if( rc==SQLITE_OK && pIncr->bUseThread ){ + /* Use the current thread to populate aFile[1], even though this + ** PmaReader is multi-threaded. The reason being that this function + ** is already running in background thread pIncr->pTask->thread. */ + assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK ); + rc = vdbeIncrPopulate(pIncr); + } +#endif + + if( rc==SQLITE_OK + && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) + ){ + rc = vdbePmaReaderNext(pReadr); + } + } + return rc; +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** The main routine for vdbePmaReaderIncrMergeInit() operations run in +** background threads. +*/ +static void *vdbePmaReaderBgInit(void *pCtx){ + PmaReader *pReader = (PmaReader*)pCtx; + void *pRet = SQLITE_INT_TO_PTR( + vdbePmaReaderIncrMergeInit(pReader,INCRINIT_TASK) + ); + pReader->pIncr->pTask->bDone = 1; + return pRet; +} + +/* +** Use a background thread to invoke vdbePmaReaderIncrMergeInit(INCRINIT_TASK) +** on the PmaReader object passed as the first argument. +** +** This call will initialize the various fields of the pReadr->pIncr +** structure and, if it is a multi-threaded IncrMerger, launch a +** background thread to populate aFile[1]. +*/ +static int vdbePmaReaderBgIncrInit(PmaReader *pReadr){ + void *pCtx = (void*)pReadr; + return vdbeSorterCreateThread(pReadr->pIncr->pTask, vdbePmaReaderBgInit, pCtx); +} +#endif + +/* +** Allocate a new MergeEngine object to merge the contents of nPMA level-0 +** PMAs from pTask->file. If no error occurs, set *ppOut to point to +** the new object and return SQLITE_OK. Or, if an error does occur, set *ppOut +** to NULL and return an SQLite error code. +** +** When this function is called, *piOffset is set to the offset of the +** first PMA to read from pTask->file. Assuming no error occurs, it is +** set to the offset immediately following the last byte of the last +** PMA before returning. If an error does occur, then the final value of +** *piOffset is undefined. +*/ +static int vdbeMergeEngineLevel0( + SortSubtask *pTask, /* Sorter task to read from */ + int nPMA, /* Number of PMAs to read */ + i64 *piOffset, /* IN/OUT: Readr offset in pTask->file */ + MergeEngine **ppOut /* OUT: New merge-engine */ +){ + MergeEngine *pNew; /* Merge engine to return */ + i64 iOff = *piOffset; + int i; + int rc = SQLITE_OK; + + *ppOut = pNew = vdbeMergeEngineNew(nPMA); + if( pNew==0 ) rc = SQLITE_NOMEM; + + for(i=0; iaReadr[i]; + rc = vdbePmaReaderInit(pTask, &pTask->file, iOff, pReadr, &nDummy); + iOff = pReadr->iEof; + } + + if( rc!=SQLITE_OK ){ + vdbeMergeEngineFree(pNew); + *ppOut = 0; + } + *piOffset = iOff; + return rc; +} + +/* +** Return the depth of a tree comprising nPMA PMAs, assuming a fanout of +** SORTER_MAX_MERGE_COUNT. The returned value does not include leaf nodes. +** +** i.e. +** +** nPMA<=16 -> TreeDepth() == 0 +** nPMA<=256 -> TreeDepth() == 1 +** nPMA<=65536 -> TreeDepth() == 2 +*/ +static int vdbeSorterTreeDepth(int nPMA){ + int nDepth = 0; + i64 nDiv = SORTER_MAX_MERGE_COUNT; + while( nDiv < (i64)nPMA ){ + nDiv = nDiv * SORTER_MAX_MERGE_COUNT; + nDepth++; + } + return nDepth; +} + +/* +** pRoot is the root of an incremental merge-tree with depth nDepth (according +** to vdbeSorterTreeDepth()). pLeaf is the iSeq'th leaf to be added to the +** tree, counting from zero. This function adds pLeaf to the tree. +** +** If successful, SQLITE_OK is returned. If an error occurs, an SQLite error +** code is returned and pLeaf is freed. +*/ +static int vdbeSorterAddToTree( + SortSubtask *pTask, /* Task context */ + int nDepth, /* Depth of tree according to TreeDepth() */ + int iSeq, /* Sequence number of leaf within tree */ + MergeEngine *pRoot, /* Root of tree */ + MergeEngine *pLeaf /* Leaf to add to tree */ +){ + int rc = SQLITE_OK; + int nDiv = 1; + int i; + MergeEngine *p = pRoot; + IncrMerger *pIncr; + + rc = vdbeIncrMergerNew(pTask, pLeaf, &pIncr); + + for(i=1; iaReadr[iIter]; + + if( pReadr->pIncr==0 ){ + MergeEngine *pNew = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = vdbeIncrMergerNew(pTask, pNew, &pReadr->pIncr); + } + } + if( rc==SQLITE_OK ){ + p = pReadr->pIncr->pMerger; + nDiv = nDiv / SORTER_MAX_MERGE_COUNT; + } + } + + if( rc==SQLITE_OK ){ + p->aReadr[iSeq % SORTER_MAX_MERGE_COUNT].pIncr = pIncr; + }else{ + vdbeIncrFree(pIncr); + } + return rc; +} + +/* +** This function is called as part of a SorterRewind() operation on a sorter +** that has already written two or more level-0 PMAs to one or more temp +** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that +** can be used to incrementally merge all PMAs on disk. +** +** If successful, SQLITE_OK is returned and *ppOut set to point to the +** MergeEngine object at the root of the tree before returning. Or, if an +** error occurs, an SQLite error code is returned and the final value +** of *ppOut is undefined. +*/ +static int vdbeSorterMergeTreeBuild( + VdbeSorter *pSorter, /* The VDBE cursor that implements the sort */ + MergeEngine **ppOut /* Write the MergeEngine here */ +){ + MergeEngine *pMain = 0; + int rc = SQLITE_OK; + int iTask; + +#if SQLITE_MAX_WORKER_THREADS>0 + /* If the sorter uses more than one task, then create the top-level + ** MergeEngine here. This MergeEngine will read data from exactly + ** one PmaReader per sub-task. */ + assert( pSorter->bUseThreads || pSorter->nTask==1 ); + if( pSorter->nTask>1 ){ + pMain = vdbeMergeEngineNew(pSorter->nTask); + if( pMain==0 ) rc = SQLITE_NOMEM; + } +#endif + + for(iTask=0; rc==SQLITE_OK && iTasknTask; iTask++){ + SortSubtask *pTask = &pSorter->aTask[iTask]; + assert( pTask->nPMA>0 || SQLITE_MAX_WORKER_THREADS>0 ); + if( SQLITE_MAX_WORKER_THREADS==0 || pTask->nPMA ){ + MergeEngine *pRoot = 0; /* Root node of tree for this task */ + int nDepth = vdbeSorterTreeDepth(pTask->nPMA); + i64 iReadOff = 0; + + if( pTask->nPMA<=SORTER_MAX_MERGE_COUNT ){ + rc = vdbeMergeEngineLevel0(pTask, pTask->nPMA, &iReadOff, &pRoot); + }else{ + int i; + int iSeq = 0; + pRoot = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT); + if( pRoot==0 ) rc = SQLITE_NOMEM; + for(i=0; inPMA && rc==SQLITE_OK; i += SORTER_MAX_MERGE_COUNT){ + MergeEngine *pMerger = 0; /* New level-0 PMA merger */ + int nReader; /* Number of level-0 PMAs to merge */ + + nReader = MIN(pTask->nPMA - i, SORTER_MAX_MERGE_COUNT); + rc = vdbeMergeEngineLevel0(pTask, nReader, &iReadOff, &pMerger); + if( rc==SQLITE_OK ){ + rc = vdbeSorterAddToTree(pTask, nDepth, iSeq++, pRoot, pMerger); + } + } + } + + if( rc==SQLITE_OK ){ +#if SQLITE_MAX_WORKER_THREADS>0 + if( pMain!=0 ){ + rc = vdbeIncrMergerNew(pTask, pRoot, &pMain->aReadr[iTask].pIncr); + }else +#endif + { + assert( pMain==0 ); + pMain = pRoot; + } + }else{ + vdbeMergeEngineFree(pRoot); + } + } + } + + if( rc!=SQLITE_OK ){ + vdbeMergeEngineFree(pMain); + pMain = 0; + } + *ppOut = pMain; + return rc; +} + +/* +** This function is called as part of an sqlite3VdbeSorterRewind() operation +** on a sorter that has written two or more PMAs to temporary files. It sets +** up either VdbeSorter.pMerger (for single threaded sorters) or pReader +** (for multi-threaded sorters) so that it can be used to iterate through +** all records stored in the sorter. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int vdbeSorterSetupMerge(VdbeSorter *pSorter){ + int rc; /* Return code */ + SortSubtask *pTask0 = &pSorter->aTask[0]; + MergeEngine *pMain = 0; +#if SQLITE_MAX_WORKER_THREADS + sqlite3 *db = pTask0->pSorter->db; +#endif + + rc = vdbeSorterMergeTreeBuild(pSorter, &pMain); + if( rc==SQLITE_OK ){ +#if SQLITE_MAX_WORKER_THREADS + assert( pSorter->bUseThreads==0 || pSorter->nTask>1 ); + if( pSorter->bUseThreads ){ + int iTask; + PmaReader *pReadr = 0; + SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1]; + rc = vdbeSortAllocUnpacked(pLast); + if( rc==SQLITE_OK ){ + pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader)); + pSorter->pReader = pReadr; + if( pReadr==0 ) rc = SQLITE_NOMEM; + } + if( rc==SQLITE_OK ){ + rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr); + if( rc==SQLITE_OK ){ + vdbeIncrMergerSetThreads(pReadr->pIncr); + for(iTask=0; iTask<(pSorter->nTask-1); iTask++){ + IncrMerger *pIncr; + if( (pIncr = pMain->aReadr[iTask].pIncr) ){ + vdbeIncrMergerSetThreads(pIncr); + assert( pIncr->pTask!=pLast ); + } + } + for(iTask=0; rc==SQLITE_OK && iTasknTask; iTask++){ + PmaReader *p = &pMain->aReadr[iTask]; + assert( p->pIncr==0 || p->pIncr->pTask==&pSorter->aTask[iTask] ); + if( p->pIncr ){ + if( iTask==pSorter->nTask-1 ){ + rc = vdbePmaReaderIncrMergeInit(p, INCRINIT_TASK); + }else{ + rc = vdbePmaReaderBgIncrInit(p); + } + } + } + } + pMain = 0; + } + if( rc==SQLITE_OK ){ + rc = vdbePmaReaderIncrMergeInit(pReadr, INCRINIT_ROOT); + } + }else +#endif + { + rc = vdbeMergeEngineInit(pTask0, pMain, INCRINIT_NORMAL); + pSorter->pMerger = pMain; + pMain = 0; + } + } + + if( rc!=SQLITE_OK ){ + vdbeMergeEngineFree(pMain); + } + return rc; +} + + +/* +** Once the sorter has been populated by calls to sqlite3VdbeSorterWrite, +** this function is called to prepare for iterating through the records +** in sorted order. +*/ +int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ VdbeSorter *pSorter = pCsr->pSorter; int rc = SQLITE_OK; /* Return code */ - int i; /* Used to iterator through aIter[] */ - i64 nByte = 0; /* Total bytes in all opened PMAs */ - - /* Initialize the iterators. */ - for(i=0; iaIter[i]; - rc = vdbeSorterIterInit(db, pSorter, pSorter->iReadOff, pIter, &nByte); - pSorter->iReadOff = pIter->iEof; - assert( rc!=SQLITE_OK || pSorter->iReadOff<=pSorter->iWriteOff ); - if( rc!=SQLITE_OK || pSorter->iReadOff>=pSorter->iWriteOff ) break; - } - - /* Initialize the aTree[] array. */ - for(i=pSorter->nTree-1; rc==SQLITE_OK && i>0; i--){ - rc = vdbeSorterDoCompare(pCsr, i); - } - - *pnByte = nByte; - return rc; -} - -/* -** Once the sorter has been populated, this function is called to prepare -** for iterating through its contents in sorted order. -*/ -int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){ - VdbeSorter *pSorter = pCsr->pSorter; - int rc; /* Return code */ - sqlite3_file *pTemp2 = 0; /* Second temp file to use */ - i64 iWrite2 = 0; /* Write offset for pTemp2 */ - int nIter; /* Number of iterators used */ - int nByte; /* Bytes of space required for aIter/aTree */ - int N = 2; /* Power of 2 >= nIter */ assert( pSorter ); /* If no data has been written to disk, then do not do so now. Instead, ** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly ** from the in-memory list. */ - if( pSorter->nPMA==0 ){ - *pbEof = !pSorter->pRecord; - assert( pSorter->aTree==0 ); - return vdbeSorterSort(pCsr); - } - - /* Write the current in-memory list to a PMA. */ - rc = vdbeSorterListToPMA(db, pCsr); - if( rc!=SQLITE_OK ) return rc; - - /* Allocate space for aIter[] and aTree[]. */ - nIter = pSorter->nPMA; - if( nIter>SORTER_MAX_MERGE_COUNT ) nIter = SORTER_MAX_MERGE_COUNT; - assert( nIter>0 ); - while( NaIter = (VdbeSorterIter *)sqlite3DbMallocZero(db, nByte); - if( !pSorter->aIter ) return SQLITE_NOMEM; - pSorter->aTree = (int *)&pSorter->aIter[N]; - pSorter->nTree = N; - - do { - int iNew; /* Index of new, merged, PMA */ - - for(iNew=0; - rc==SQLITE_OK && iNew*SORTER_MAX_MERGE_COUNTnPMA; - iNew++ - ){ - int rc2; /* Return code from fileWriterFinish() */ - FileWriter writer; /* Object used to write to disk */ - i64 nWrite; /* Number of bytes in new PMA */ - - memset(&writer, 0, sizeof(FileWriter)); - - /* If there are SORTER_MAX_MERGE_COUNT or less PMAs in file pTemp1, - ** initialize an iterator for each of them and break out of the loop. - ** These iterators will be incrementally merged as the VDBE layer calls - ** sqlite3VdbeSorterNext(). - ** - ** Otherwise, if pTemp1 contains more than SORTER_MAX_MERGE_COUNT PMAs, - ** initialize interators for SORTER_MAX_MERGE_COUNT of them. These PMAs - ** are merged into a single PMA that is written to file pTemp2. - */ - rc = vdbeSorterInitMerge(db, pCsr, &nWrite); - assert( rc!=SQLITE_OK || pSorter->aIter[ pSorter->aTree[1] ].pFile ); - if( rc!=SQLITE_OK || pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){ - break; - } - - /* Open the second temp file, if it is not already open. */ - if( pTemp2==0 ){ - assert( iWrite2==0 ); - rc = vdbeSorterOpenTempFile(db, &pTemp2); - } - - if( rc==SQLITE_OK ){ - int bEof = 0; - fileWriterInit(db, pTemp2, &writer, iWrite2); - fileWriterWriteVarint(&writer, nWrite); - while( rc==SQLITE_OK && bEof==0 ){ - VdbeSorterIter *pIter = &pSorter->aIter[ pSorter->aTree[1] ]; - assert( pIter->pFile ); - - fileWriterWriteVarint(&writer, pIter->nKey); - fileWriterWrite(&writer, pIter->aKey, pIter->nKey); - rc = sqlite3VdbeSorterNext(db, pCsr, &bEof); - } - rc2 = fileWriterFinish(db, &writer, &iWrite2); - if( rc==SQLITE_OK ) rc = rc2; - } - } - - if( pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){ - break; + if( pSorter->bUsePMA==0 ){ + if( pSorter->list.pList ){ + *pbEof = 0; + rc = vdbeSorterSort(&pSorter->aTask[0], &pSorter->list); }else{ - sqlite3_file *pTmp = pSorter->pTemp1; - pSorter->nPMA = iNew; - pSorter->pTemp1 = pTemp2; - pTemp2 = pTmp; - pSorter->iWriteOff = iWrite2; - pSorter->iReadOff = 0; - iWrite2 = 0; + *pbEof = 1; } - }while( rc==SQLITE_OK ); - - if( pTemp2 ){ - sqlite3OsCloseFree(pTemp2); + return rc; } - *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); + + /* Write the current in-memory list to a PMA. When the VdbeSorterWrite() + ** function flushes the contents of memory to disk, it immediately always + ** creates a new list consisting of a single key immediately afterwards. + ** So the list is never empty at this point. */ + assert( pSorter->list.pList ); + rc = vdbeSorterFlushPMA(pSorter); + + /* Join all threads */ + rc = vdbeSorterJoinAll(pSorter, rc); + + vdbeSorterRewindDebug("rewind"); + + /* Assuming no errors have occurred, set up a merger structure to + ** incrementally read and merge all remaining PMAs. */ + assert( pSorter->pReader==0 ); + if( rc==SQLITE_OK ){ + rc = vdbeSorterSetupMerge(pSorter); + *pbEof = 0; + } + + vdbeSorterRewindDebug("rewinddone"); return rc; } @@ -969,63 +2402,28 @@ int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){ VdbeSorter *pSorter = pCsr->pSorter; int rc; /* Return code */ - if( pSorter->aTree ){ - int iPrev = pSorter->aTree[1];/* Index of iterator to advance */ - rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]); - if( rc==SQLITE_OK ){ - int i; /* Index of aTree[] to recalculate */ - VdbeSorterIter *pIter1; /* First iterator to compare */ - VdbeSorterIter *pIter2; /* Second iterator to compare */ - u8 *pKey2; /* To pIter2->aKey, or 0 if record cached */ - - /* Find the first two iterators to compare. The one that was just - ** advanced (iPrev) and the one next to it in the array. */ - pIter1 = &pSorter->aIter[(iPrev & 0xFFFE)]; - pIter2 = &pSorter->aIter[(iPrev | 0x0001)]; - pKey2 = pIter2->aKey; - - for(i=(pSorter->nTree+iPrev)/2; i>0; i=i/2){ - /* Compare pIter1 and pIter2. Store the result in variable iRes. */ - int iRes; - if( pIter1->pFile==0 ){ - iRes = +1; - }else if( pIter2->pFile==0 ){ - iRes = -1; - }else{ - vdbeSorterCompare(pCsr, 0, - pIter1->aKey, pIter1->nKey, pKey2, pIter2->nKey, &iRes - ); - } - - /* If pIter1 contained the smaller value, set aTree[i] to its index. - ** Then set pIter2 to the next iterator to compare to pIter1. In this - ** case there is no cache of pIter2 in pSorter->pUnpacked, so set - ** pKey2 to point to the record belonging to pIter2. - ** - ** Alternatively, if pIter2 contains the smaller of the two values, - ** set aTree[i] to its index and update pIter1. If vdbeSorterCompare() - ** was actually called above, then pSorter->pUnpacked now contains - ** a value equivalent to pIter2. So set pKey2 to NULL to prevent - ** vdbeSorterCompare() from decoding pIter2 again. */ - if( iRes<=0 ){ - pSorter->aTree[i] = (int)(pIter1 - pSorter->aIter); - pIter2 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ]; - pKey2 = pIter2->aKey; - }else{ - if( pIter1->pFile ) pKey2 = 0; - pSorter->aTree[i] = (int)(pIter2 - pSorter->aIter); - pIter1 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ]; - } - - } - *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); + assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) ); + if( pSorter->bUsePMA ){ + assert( pSorter->pReader==0 || pSorter->pMerger==0 ); + assert( pSorter->bUseThreads==0 || pSorter->pReader ); + assert( pSorter->bUseThreads==1 || pSorter->pMerger ); +#if SQLITE_MAX_WORKER_THREADS>0 + if( pSorter->bUseThreads ){ + rc = vdbePmaReaderNext(pSorter->pReader); + *pbEof = (pSorter->pReader->pFd==0); + }else +#endif + /*if( !pSorter->bUseThreads )*/ { + assert( pSorter->pMerger!=0 ); + assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) ); + rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof); } }else{ - SorterRecord *pFree = pSorter->pRecord; - pSorter->pRecord = pFree->pNext; - pFree->pNext = 0; - vdbeSorterRecordFree(db, pFree); - *pbEof = !pSorter->pRecord; + SorterRecord *pFree = pSorter->list.pList; + pSorter->list.pList = pFree->u.pNext; + pFree->u.pNext = 0; + if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree); + *pbEof = !pSorter->list.pList; rc = SQLITE_OK; } return rc; @@ -1040,14 +2438,21 @@ static void *vdbeSorterRowkey( int *pnKey /* OUT: Size of current key in bytes */ ){ void *pKey; - if( pSorter->aTree ){ - VdbeSorterIter *pIter; - pIter = &pSorter->aIter[ pSorter->aTree[1] ]; - *pnKey = pIter->nKey; - pKey = pIter->aKey; + if( pSorter->bUsePMA ){ + PmaReader *pReader; +#if SQLITE_MAX_WORKER_THREADS>0 + if( pSorter->bUseThreads ){ + pReader = pSorter->pReader; + }else +#endif + /*if( !pSorter->bUseThreads )*/{ + pReader = &pSorter->pMerger->aReadr[pSorter->pMerger->aTree[1]]; + } + *pnKey = pReader->nKey; + pKey = pReader->aKey; }else{ - *pnKey = pSorter->pRecord->nVal; - pKey = pSorter->pRecord->pVal; + *pnKey = pSorter->list.pList->nVal; + pKey = SRVAL(pSorter->list.pList); } return pKey; } @@ -1060,7 +2465,7 @@ int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ void *pKey; int nKey; /* Sorter key to copy into pOut */ pKey = vdbeSorterRowkey(pSorter, &nKey); - if( sqlite3VdbeMemGrow(pOut, nKey, 0) ){ + if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){ return SQLITE_NOMEM; } pOut->n = nKey; @@ -1075,21 +2480,47 @@ int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ ** passed as the first argument currently points to. For the purposes of ** the comparison, ignore the rowid field at the end of each record. ** +** If the sorter cursor key contains any NULL values, consider it to be +** less than pVal. Even if pVal also contains NULL values. +** ** If an error occurs, return an SQLite error code (i.e. SQLITE_NOMEM). ** Otherwise, set *pRes to a negative, zero or positive value if the ** key in pVal is smaller than, equal to or larger than the current sorter ** key. +** +** This routine forms the core of the OP_SorterCompare opcode, which in +** turn is used to verify uniqueness when constructing a UNIQUE INDEX. */ int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal, /* Value to compare to current sorter key */ - int nKeyCol, /* Only compare this many fields */ + int nKeyCol, /* Compare this many columns */ int *pRes /* OUT: Result of comparison */ ){ VdbeSorter *pSorter = pCsr->pSorter; + UnpackedRecord *r2 = pSorter->pUnpacked; + KeyInfo *pKeyInfo = pCsr->pKeyInfo; + int i; void *pKey; int nKey; /* Sorter key to compare pVal with */ + if( r2==0 ){ + char *p; + r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p); + assert( pSorter->pUnpacked==(UnpackedRecord*)p ); + if( r2==0 ) return SQLITE_NOMEM; + r2->nField = nKeyCol; + } + assert( r2->nField==nKeyCol ); + pKey = vdbeSorterRowkey(pSorter, &nKey); - vdbeSorterCompare(pCsr, nKeyCol, pVal->z, pVal->n, pKey, nKey, pRes); + sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, r2); + for(i=0; iaMem[i].flags & MEM_Null ){ + *pRes = -1; + return SQLITE_OK; + } + } + + *pRes = sqlite3VdbeRecordCompare(pVal->n, pVal->z, r2); return SQLITE_OK; } diff --git a/src/vdbetrace.c b/src/vdbetrace.c index 4a39e26..507c2f1 100644 --- a/src/vdbetrace.c +++ b/src/vdbetrace.c @@ -64,7 +64,7 @@ static int findNextHostParameter(const char *zSql, int *pnToken){ ** ALGORITHM: Scan the input string looking for host parameters in any of ** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within ** string literals, quoted identifier names, and comments. For text forms, -** the host parameter index is found by scanning the perpared +** the host parameter index is found by scanning the prepared ** statement for the corresponding OP_Variable opcode. Once the host ** parameter index is known, locate the value in p->aVar[]. Then render ** the value as a literal in place of the host parameter name. @@ -127,7 +127,7 @@ char *sqlite3VdbeExpandSql( }else if( pVar->flags & MEM_Int ){ sqlite3XPrintf(&out, 0, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ - sqlite3XPrintf(&out, 0, "%!.15g", pVar->r); + sqlite3XPrintf(&out, 0, "%!.15g", pVar->u.r); }else if( pVar->flags & MEM_Str ){ int nOut; /* Number of bytes of the string text to include in output */ #ifndef SQLITE_OMIT_UTF16 @@ -183,118 +183,3 @@ char *sqlite3VdbeExpandSql( } #endif /* #ifndef SQLITE_OMIT_TRACE */ - -/***************************************************************************** -** The following code implements the data-structure explaining logic -** for the Vdbe. -*/ - -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) - -/* -** Allocate a new Explain object -*/ -void sqlite3ExplainBegin(Vdbe *pVdbe){ - if( pVdbe ){ - Explain *p; - sqlite3BeginBenignMalloc(); - p = (Explain *)sqlite3MallocZero( sizeof(Explain) ); - if( p ){ - p->pVdbe = pVdbe; - sqlite3_free(pVdbe->pExplain); - pVdbe->pExplain = p; - sqlite3StrAccumInit(&p->str, p->zBase, sizeof(p->zBase), - SQLITE_MAX_LENGTH); - p->str.useMalloc = 2; - }else{ - sqlite3EndBenignMalloc(); - } - } -} - -/* -** Return true if the Explain ends with a new-line. -*/ -static int endsWithNL(Explain *p){ - return p && p->str.zText && p->str.nChar - && p->str.zText[p->str.nChar-1]=='\n'; -} - -/* -** Append text to the indentation -*/ -void sqlite3ExplainPrintf(Vdbe *pVdbe, const char *zFormat, ...){ - Explain *p; - if( pVdbe && (p = pVdbe->pExplain)!=0 ){ - va_list ap; - if( p->nIndent && endsWithNL(p) ){ - int n = p->nIndent; - if( n>ArraySize(p->aIndent) ) n = ArraySize(p->aIndent); - sqlite3AppendSpace(&p->str, p->aIndent[n-1]); - } - va_start(ap, zFormat); - sqlite3VXPrintf(&p->str, SQLITE_PRINTF_INTERNAL, zFormat, ap); - va_end(ap); - } -} - -/* -** Append a '\n' if there is not already one. -*/ -void sqlite3ExplainNL(Vdbe *pVdbe){ - Explain *p; - if( pVdbe && (p = pVdbe->pExplain)!=0 && !endsWithNL(p) ){ - sqlite3StrAccumAppend(&p->str, "\n", 1); - } -} - -/* -** Push a new indentation level. Subsequent lines will be indented -** so that they begin at the current cursor position. -*/ -void sqlite3ExplainPush(Vdbe *pVdbe){ - Explain *p; - if( pVdbe && (p = pVdbe->pExplain)!=0 ){ - if( p->str.zText && p->nIndentaIndent) ){ - const char *z = p->str.zText; - int i = p->str.nChar-1; - int x; - while( i>=0 && z[i]!='\n' ){ i--; } - x = (p->str.nChar - 1) - i; - if( p->nIndent && xaIndent[p->nIndent-1] ){ - x = p->aIndent[p->nIndent-1]; - } - p->aIndent[p->nIndent] = x; - } - p->nIndent++; - } -} - -/* -** Pop the indentation stack by one level. -*/ -void sqlite3ExplainPop(Vdbe *p){ - if( p && p->pExplain ) p->pExplain->nIndent--; -} - -/* -** Free the indentation structure -*/ -void sqlite3ExplainFinish(Vdbe *pVdbe){ - if( pVdbe && pVdbe->pExplain ){ - sqlite3_free(pVdbe->zExplain); - sqlite3ExplainNL(pVdbe); - pVdbe->zExplain = sqlite3StrAccumFinish(&pVdbe->pExplain->str); - sqlite3_free(pVdbe->pExplain); - pVdbe->pExplain = 0; - sqlite3EndBenignMalloc(); - } -} - -/* -** Return the explanation of a virtual machine. -*/ -const char *sqlite3VdbeExplanation(Vdbe *pVdbe){ - return (pVdbe && pVdbe->zExplain) ? pVdbe->zExplain : 0; -} -#endif /* defined(SQLITE_DEBUG) */ diff --git a/src/vtab.c b/src/vtab.c index ca0db21..00d0882 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -43,7 +43,7 @@ static int createModule( sqlite3_mutex_enter(db->mutex); nName = sqlite3Strlen30(zName); - if( sqlite3HashFind(&db->aModule, zName, nName) ){ + if( sqlite3HashFind(&db->aModule, zName) ){ rc = SQLITE_MISUSE_BKPT; }else{ Module *pMod; @@ -56,7 +56,7 @@ static int createModule( pMod->pModule = pModule; pMod->pAux = pAux; pMod->xDestroy = xDestroy; - pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,nName,(void*)pMod); + pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); assert( pDel==0 || pDel==pMod ); if( pDel ){ db->mallocFailed = 1; @@ -81,6 +81,9 @@ int sqlite3_create_module( const sqlite3_module *pModule, /* The definition of the module */ void *pAux /* Context pointer for xCreate/xConnect */ ){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; +#endif return createModule(db, zName, pModule, pAux, 0); } @@ -94,6 +97,9 @@ int sqlite3_create_module_v2( void *pAux, /* Context pointer for xCreate/xConnect */ void (*xDestroy)(void *) /* Module destructor function */ ){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; +#endif return createModule(db, zName, pModule, pAux, xDestroy); } @@ -326,7 +332,12 @@ void sqlite3VtabBeginParse( addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); addModuleArgument(db, pTable, 0); addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); - pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z); + assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0) + || (pParse->sNameToken.z==pName1->z && pName2->z==0) + ); + pParse->sNameToken.n = (int)( + &pModuleName->z[pModuleName->n] - pParse->sNameToken.z + ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Creating a virtual table invokes the authorization callback twice. @@ -425,9 +436,8 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ Table *pOld; Schema *pSchema = pTab->pSchema; const char *zName = pTab->zName; - int nName = sqlite3Strlen30(zName); assert( sqlite3SchemaMutexHeld(db, 0, pSchema) ); - pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab); + pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab); if( pOld ){ db->mallocFailed = 1; assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ @@ -520,6 +530,7 @@ static int vtabCallConstructor( }else if( ALWAYS(pVTable->pVtab) ){ /* Justification of ALWAYS(): A correct vtab constructor must allocate ** the sqlite3_vtab object if successful. */ + memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0])); pVTable->pVtab->pModule = pMod->pModule; pVTable->nRef = 1; if( sCtx.pTab ){ @@ -593,7 +604,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ /* Locate the required virtual table module */ zMod = pTab->azModuleArg[0]; - pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod)); + pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); if( !pMod ){ const char *zModule = pTab->azModuleArg[0]; @@ -661,7 +672,7 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ /* Locate the required virtual table module */ zMod = pTab->azModuleArg[0]; - pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod)); + pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); /* If the module has been registered and includes a Create method, ** invoke it now. If the module has not been registered, return an @@ -698,9 +709,12 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ Table *pTab; char *zErr = 0; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){ - sqlite3Error(db, SQLITE_MISUSE, 0); + sqlite3Error(db, SQLITE_MISUSE); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } @@ -728,7 +742,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ } db->pVtabCtx->pTab = 0; }else{ - sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); + sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); rc = SQLITE_ERROR; } @@ -1054,6 +1068,9 @@ int sqlite3_vtab_on_conflict(sqlite3 *db){ static const unsigned char aMap[] = { SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE }; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 ); assert( OE_Ignore==4 && OE_Replace==5 ); assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 ); @@ -1069,8 +1086,10 @@ int sqlite3_vtab_config(sqlite3 *db, int op, ...){ va_list ap; int rc = SQLITE_OK; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif sqlite3_mutex_enter(db->mutex); - va_start(ap, op); switch( op ){ case SQLITE_VTAB_CONSTRAINT_SUPPORT: { @@ -1089,7 +1108,7 @@ int sqlite3_vtab_config(sqlite3 *db, int op, ...){ } va_end(ap); - if( rc!=SQLITE_OK ) sqlite3Error(db, rc, 0); + if( rc!=SQLITE_OK ) sqlite3Error(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } diff --git a/src/wal.c b/src/wal.c index 70395f8..71f4a3d 100644 --- a/src/wal.c +++ b/src/wal.c @@ -574,7 +574,7 @@ static volatile WalIndexHdr *walIndexHdr(Wal *pWal){ ** The argument to this macro must be of type u32. On a little-endian ** architecture, it returns the u32 value that results from interpreting ** the 4 bytes as a big-endian value. On a big-endian architecture, it -** returns the value that would be produced by intepreting the 4 bytes +** returns the value that would be produced by interpreting the 4 bytes ** of the input value as a little-endian integer. */ #define BYTESWAP32(x) ( \ @@ -988,7 +988,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ assert( idx <= HASHTABLE_NSLOT/2 + 1 ); /* If this is the first entry to be added to this hash-table, zero the - ** entire hash table and aPgno[] array before proceding. + ** entire hash table and aPgno[] array before proceeding. */ if( idx==1 ){ int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]); @@ -1504,7 +1504,7 @@ static void walMergesort( ** Free an iterator allocated by walIteratorInit(). */ static void walIteratorFree(WalIterator *p){ - sqlite3ScratchFree(p); + sqlite3_free(p); } /* @@ -1539,7 +1539,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){ nByte = sizeof(WalIterator) + (nSegment-1)*sizeof(struct WalSegment) + iLast*sizeof(ht_slot); - p = (WalIterator *)sqlite3ScratchMalloc(nByte); + p = (WalIterator *)sqlite3_malloc(nByte); if( !p ){ return SQLITE_NOMEM; } @@ -1549,7 +1549,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){ /* Allocate temporary space used by the merge-sort routine. This block ** of memory will be freed before this function returns. */ - aTmp = (ht_slot *)sqlite3ScratchMalloc( + aTmp = (ht_slot *)sqlite3_malloc( sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) ); if( !aTmp ){ @@ -1586,7 +1586,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){ p->aSegment[i].aPgno = (u32 *)aPgno; } } - sqlite3ScratchFree(aTmp); + sqlite3_free(aTmp); if( rc!=SQLITE_OK ){ walIteratorFree(p); @@ -1623,6 +1623,38 @@ static int walPagesize(Wal *pWal){ return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16); } +/* +** The following is guaranteed when this function is called: +** +** a) the WRITER lock is held, +** b) the entire log file has been checkpointed, and +** c) any existing readers are reading exclusively from the database +** file - there are no readers that may attempt to read a frame from +** the log file. +** +** This function updates the shared-memory structures so that the next +** client to write to the database (which may be this one) does so by +** writing frames into the start of the log file. +** +** The value of parameter salt1 is used as the aSalt[1] value in the +** new wal-index header. It should be passed a pseudo-random value (i.e. +** one obtained from sqlite3_randomness()). +*/ +static void walRestartHdr(Wal *pWal, u32 salt1){ + volatile WalCkptInfo *pInfo = walCkptInfo(pWal); + int i; /* Loop counter */ + u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ + pWal->nCkpt++; + pWal->hdr.mxFrame = 0; + sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); + memcpy(&pWal->hdr.aSalt[1], &salt1, 4); + walIndexWriteHdr(pWal); + pInfo->nBackfill = 0; + pInfo->aReadMark[1] = 0; + for(i=2; iaReadMark[i] = READMARK_NOT_USED; + assert( pInfo->aReadMark[0]==0 ); +} + /* ** Copy as much content as we can from the WAL back into the database file ** in response to an sqlite3_wal_checkpoint() request or the equivalent. @@ -1646,7 +1678,7 @@ static int walPagesize(Wal *pWal){ ** database file. ** ** This routine uses and updates the nBackfill field of the wal-index header. -** This is the only routine tha will increase the value of nBackfill. +** This is the only routine that will increase the value of nBackfill. ** (A WAL reset or recovery will revert nBackfill to zero, but not increase ** its value.) ** @@ -1657,12 +1689,12 @@ static int walPagesize(Wal *pWal){ static int walCheckpoint( Wal *pWal, /* Wal connection */ int eMode, /* One of PASSIVE, FULL or RESTART */ - int (*xBusyCall)(void*), /* Function to call when busy */ + int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int sync_flags, /* Flags for OsSync() (or 0) */ u8 *zBuf /* Temporary buffer to use */ ){ - int rc; /* Return code */ + int rc = SQLITE_OK; /* Return code */ int szPage; /* Database page-size */ WalIterator *pIter = 0; /* Wal iterator context */ u32 iDbpage = 0; /* Next database page to write */ @@ -1671,123 +1703,146 @@ static int walCheckpoint( u32 mxPage; /* Max database page to write */ int i; /* Loop counter */ volatile WalCkptInfo *pInfo; /* The checkpoint status information */ - int (*xBusy)(void*) = 0; /* Function to call when waiting for locks */ szPage = walPagesize(pWal); testcase( szPage<=32768 ); testcase( szPage>=65536 ); pInfo = walCkptInfo(pWal); - if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK; + if( pInfo->nBackfillhdr.mxFrame ){ - /* Allocate the iterator */ - rc = walIteratorInit(pWal, &pIter); - if( rc!=SQLITE_OK ){ - return rc; - } - assert( pIter ); - - if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall; - - /* Compute in mxSafeFrame the index of the last frame of the WAL that is - ** safe to write into the database. Frames beyond mxSafeFrame might - ** overwrite database pages that are in use by active readers and thus - ** cannot be backfilled from the WAL. - */ - mxSafeFrame = pWal->hdr.mxFrame; - mxPage = pWal->hdr.nPage; - for(i=1; iaReadMark[i]; - if( mxSafeFrame>y ){ - assert( y<=pWal->hdr.mxFrame ); - rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); - if( rc==SQLITE_OK ){ - pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED); - walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); - }else if( rc==SQLITE_BUSY ){ - mxSafeFrame = y; - xBusy = 0; - }else{ - goto walcheckpoint_out; - } + /* Allocate the iterator */ + rc = walIteratorInit(pWal, &pIter); + if( rc!=SQLITE_OK ){ + return rc; } - } + assert( pIter ); - if( pInfo->nBackfillnBackfill; + /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked + ** in the SQLITE_CHECKPOINT_PASSIVE mode. */ + assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); - /* Sync the WAL to disk */ - if( sync_flags ){ - rc = sqlite3OsSync(pWal->pWalFd, sync_flags); - } - - /* If the database may grow as a result of this checkpoint, hint - ** about the eventual size of the db file to the VFS layer. + /* Compute in mxSafeFrame the index of the last frame of the WAL that is + ** safe to write into the database. Frames beyond mxSafeFrame might + ** overwrite database pages that are in use by active readers and thus + ** cannot be backfilled from the WAL. */ - if( rc==SQLITE_OK ){ - i64 nReq = ((i64)mxPage * szPage); - rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); - if( rc==SQLITE_OK && nSizepDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); - } - } - - - /* Iterate through the contents of the WAL, copying data to the db file. */ - while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ - i64 iOffset; - assert( walFramePgno(pWal, iFrame)==iDbpage ); - if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue; - iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; - /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ - rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); - if( rc!=SQLITE_OK ) break; - iOffset = (iDbpage-1)*(i64)szPage; - testcase( IS_BIG_INT(iOffset) ); - rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); - if( rc!=SQLITE_OK ) break; - } - - /* If work was actually accomplished... */ - if( rc==SQLITE_OK ){ - if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ - i64 szDb = pWal->hdr.nPage*(i64)szPage; - testcase( IS_BIG_INT(szDb) ); - rc = sqlite3OsTruncate(pWal->pDbFd, szDb); - if( rc==SQLITE_OK && sync_flags ){ - rc = sqlite3OsSync(pWal->pDbFd, sync_flags); + mxSafeFrame = pWal->hdr.mxFrame; + mxPage = pWal->hdr.nPage; + for(i=1; iaReadMark[i]; + if( mxSafeFrame>y ){ + assert( y<=pWal->hdr.mxFrame ); + rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); + if( rc==SQLITE_OK ){ + pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED); + walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); + }else if( rc==SQLITE_BUSY ){ + mxSafeFrame = y; + xBusy = 0; + }else{ + goto walcheckpoint_out; } } - if( rc==SQLITE_OK ){ - pInfo->nBackfill = mxSafeFrame; - } } - /* Release the reader lock held while backfilling */ - walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); + if( pInfo->nBackfillnBackfill; + + /* Sync the WAL to disk */ + if( sync_flags ){ + rc = sqlite3OsSync(pWal->pWalFd, sync_flags); + } + + /* If the database may grow as a result of this checkpoint, hint + ** about the eventual size of the db file to the VFS layer. + */ + if( rc==SQLITE_OK ){ + i64 nReq = ((i64)mxPage * szPage); + rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); + if( rc==SQLITE_OK && nSizepDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); + } + } + + + /* Iterate through the contents of the WAL, copying data to the db file */ + while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ + i64 iOffset; + assert( walFramePgno(pWal, iFrame)==iDbpage ); + if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){ + continue; + } + iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; + /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ + rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); + if( rc!=SQLITE_OK ) break; + iOffset = (iDbpage-1)*(i64)szPage; + testcase( IS_BIG_INT(iOffset) ); + rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); + if( rc!=SQLITE_OK ) break; + } + + /* If work was actually accomplished... */ + if( rc==SQLITE_OK ){ + if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ + i64 szDb = pWal->hdr.nPage*(i64)szPage; + testcase( IS_BIG_INT(szDb) ); + rc = sqlite3OsTruncate(pWal->pDbFd, szDb); + if( rc==SQLITE_OK && sync_flags ){ + rc = sqlite3OsSync(pWal->pDbFd, sync_flags); + } + } + if( rc==SQLITE_OK ){ + pInfo->nBackfill = mxSafeFrame; + } + } + + /* Release the reader lock held while backfilling */ + walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); + } + + if( rc==SQLITE_BUSY ){ + /* Reset the return code so as not to report a checkpoint failure + ** just because there are active readers. */ + rc = SQLITE_OK; + } } - if( rc==SQLITE_BUSY ){ - /* Reset the return code so as not to report a checkpoint failure - ** just because there are active readers. */ - rc = SQLITE_OK; - } - - /* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal - ** file has been copied into the database file, then block until all - ** readers have finished using the wal file. This ensures that the next - ** process to write to the database restarts the wal file. + /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the + ** entire wal file has been copied into the database file, then block + ** until all readers have finished using the wal file. This ensures that + ** the next process to write to the database restarts the wal file. */ if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){ assert( pWal->writeLock ); if( pInfo->nBackfillhdr.mxFrame ){ rc = SQLITE_BUSY; - }else if( eMode==SQLITE_CHECKPOINT_RESTART ){ - assert( mxSafeFrame==pWal->hdr.mxFrame ); + }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){ + u32 salt1; + sqlite3_randomness(4, &salt1); + assert( pInfo->nBackfill==pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1); if( rc==SQLITE_OK ){ + if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){ + /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as + ** SQLITE_CHECKPOINT_RESTART with the addition that it also + ** truncates the log file to zero bytes just prior to a + ** successful return. + ** + ** In theory, it might be safe to do this without updating the + ** wal-index header in shared memory, as all subsequent reader or + ** writer clients should see that the entire log file has been + ** checkpointed and behave accordingly. This seems unsafe though, + ** as it would leave the system in a state where the contents of + ** the wal-index header do not match the contents of the + ** file-system. To avoid this, update the wal-index header to + ** indicate that the log file contains zero valid frames. */ + walRestartHdr(pWal, salt1); + rc = sqlite3OsTruncate(pWal->pWalFd, 0); + } walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); } } @@ -1950,7 +2005,7 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){ ** wal-index from the WAL before returning. ** ** Set *pChanged to 1 if the wal-index header value in pWal->hdr is -** changed by this opertion. If pWal->hdr is unchanged, set *pChanged +** changed by this operation. If pWal->hdr is unchanged, set *pChanged ** to 0. ** ** If the wal-index header is successfully read, return SQLITE_OK. @@ -2154,7 +2209,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** may have been appended to the log before READ_LOCK(0) was obtained. ** When holding READ_LOCK(0), the reader ignores the entire log file, ** which implies that the database file contains a trustworthy - ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from + ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from ** happening, this is usually correct. ** ** However, if frames have been appended to the log (or if the log @@ -2360,7 +2415,7 @@ int sqlite3WalFindFrame( for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){ u32 iFrame = aHash[iKey] + iZero; if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){ - /* assert( iFrame>iRead ); -- not true if there is corruption */ + assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } if( (nCollide--)==0 ){ @@ -2525,7 +2580,6 @@ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){ } if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal); } - assert( rc==SQLITE_OK ); return rc; } @@ -2574,7 +2628,6 @@ int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){ return rc; } - /* ** This function is called just before writing a set of frames to the log ** file (see sqlite3WalFrames()). It checks to see if, instead of appending @@ -2607,20 +2660,8 @@ static int walRestartLog(Wal *pWal){ ** In theory it would be Ok to update the cache of the header only ** at this point. But updating the actual wal-index header is also ** safe and means there is no special case for sqlite3WalUndo() - ** to handle if this transaction is rolled back. - */ - int i; /* Loop counter */ - u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ - - pWal->nCkpt++; - pWal->hdr.mxFrame = 0; - sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); - aSalt[1] = salt1; - walIndexWriteHdr(pWal); - pInfo->nBackfill = 0; - pInfo->aReadMark[1] = 0; - for(i=2; iaReadMark[i] = READMARK_NOT_USED; - assert( pInfo->aReadMark[0]==0 ); + ** to handle if this transaction is rolled back. */ + walRestartHdr(pWal, salt1); walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); }else if( rc!=SQLITE_BUSY ){ return rc; @@ -2822,7 +2863,7 @@ int sqlite3WalFrames( ** ** Padding and syncing only occur if this set of frames complete a ** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL - ** or synchonous==OFF, then no padding or syncing are needed. + ** or synchronous==OFF, then no padding or syncing are needed. ** ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not ** needed and only the sync is done. If padding is needed, then the @@ -2908,7 +2949,7 @@ int sqlite3WalFrames( */ int sqlite3WalCheckpoint( Wal *pWal, /* Wal connection */ - int eMode, /* PASSIVE, FULL or RESTART */ + int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int sync_flags, /* Flags to sync db file with (or 0) */ @@ -2920,29 +2961,42 @@ int sqlite3WalCheckpoint( int rc; /* Return code */ int isChanged = 0; /* True if a new wal-index header is loaded */ int eMode2 = eMode; /* Mode to pass to walCheckpoint() */ + int (*xBusy2)(void*) = xBusy; /* Busy handler for eMode2 */ assert( pWal->ckptLock==0 ); assert( pWal->writeLock==0 ); + /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked + ** in the SQLITE_CHECKPOINT_PASSIVE mode. */ + assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); + if( pWal->readOnly ) return SQLITE_READONLY; WALTRACE(("WAL%p: checkpoint begins\n", pWal)); + + /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive + ** "checkpoint" lock on the database file. */ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); if( rc ){ - /* Usually this is SQLITE_BUSY meaning that another thread or process - ** is already running a checkpoint, or maybe a recovery. But it might - ** also be SQLITE_IOERR. */ + /* EVIDENCE-OF: R-10421-19736 If any other process is running a + ** checkpoint operation at the same time, the lock cannot be obtained and + ** SQLITE_BUSY is returned. + ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured, + ** it will not be invoked in this case. + */ + testcase( rc==SQLITE_BUSY ); + testcase( xBusy!=0 ); return rc; } pWal->ckptLock = 1; - /* If this is a blocking-checkpoint, then obtain the write-lock as well - ** to prevent any writers from running while the checkpoint is underway. - ** This has to be done before the call to walIndexReadHdr() below. + /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and + ** TRUNCATE modes also obtain the exclusive "writer" lock on the database + ** file. ** - ** If the writer lock cannot be obtained, then a passive checkpoint is - ** run instead. Since the checkpointer is not holding the writer lock, - ** there is no point in blocking waiting for any readers. Assuming no - ** other error occurs, this function will return SQLITE_BUSY to the caller. + ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained + ** immediately, and a busy-handler is configured, it is invoked and the + ** writer lock retried until either the busy-handler returns 0 or the + ** lock is successfully obtained. */ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1); @@ -2950,6 +3004,7 @@ int sqlite3WalCheckpoint( pWal->writeLock = 1; }else if( rc==SQLITE_BUSY ){ eMode2 = SQLITE_CHECKPOINT_PASSIVE; + xBusy2 = 0; rc = SQLITE_OK; } } @@ -2967,7 +3022,7 @@ int sqlite3WalCheckpoint( if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ rc = SQLITE_CORRUPT_BKPT; }else{ - rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf); + rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); } /* If no error occurred, set the output variables. */ diff --git a/src/walker.c b/src/walker.c index 016ae77..e30bb60 100644 --- a/src/walker.c +++ b/src/walker.c @@ -19,7 +19,7 @@ /* ** Walk an expression tree. Invoke the callback once for each node -** of the expression, while decending. (In other words, the callback +** of the expression, while descending. (In other words, the callback ** is invoked before visiting children.) ** ** The return value from the callback should be one of the WRC_* diff --git a/src/where.c b/src/where.c index 9c30136..f45da74 100644 --- a/src/where.c +++ b/src/where.c @@ -222,10 +222,11 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){ sqlite3DbFree(db, pOld); } pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); + memset(&pWC->a[pWC->nTerm], 0, sizeof(pWC->a[0])*(pWC->nSlot-pWC->nTerm)); } pTerm = &pWC->a[idx = pWC->nTerm++]; if( p && ExprHasProperty(p, EP_Unlikely) ){ - pTerm->truthProb = sqlite3LogEst(p->iTable) - 99; + pTerm->truthProb = sqlite3LogEst(p->iTable) - 270; }else{ pTerm->truthProb = 1; } @@ -364,11 +365,6 @@ static int allowedOp(int op){ return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL; } -/* -** Swap two objects of type TYPE. -*/ -#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} - /* ** Commute a comparison operator. Expressions of the form "X op Y" ** are converted into "Y op X". @@ -701,7 +697,7 @@ static int isLikeOrGlob( ** value of the variable means there is no need to invoke the LIKE ** function, then no OP_Variable will be added to the program. ** This causes problems for the sqlite3_bind_parameter_name() - ** API. To workaround them, add a dummy OP_Variable here. + ** API. To work around them, add a dummy OP_Variable here. */ int r1 = sqlite3GetTempReg(pParse); sqlite3ExprCodeTarget(pParse, pRight, r1); @@ -761,6 +757,15 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ } } +/* +** Mark term iChild as being a child of term iParent +*/ +static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){ + pWC->a[iChild].iParent = iParent; + pWC->a[iChild].truthProb = pWC->a[iParent].truthProb; + pWC->a[iParent].nChild++; +} + #if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) /* ** Analyze a term that consists of two or more OR-connected @@ -821,7 +826,7 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ ** appropriate for indexing exist. ** ** All examples A through E above satisfy case 2. But if a term -** also statisfies case 1 (such as B) we know that the optimizer will +** also satisfies case 1 (such as B) we know that the optimizer will ** always prefer case 1, so in that case we pretend that case 2 is not ** satisfied. ** @@ -979,7 +984,7 @@ static void exprAnalyzeOrTerm( } if( (chngToIN & getMask(&pWInfo->sMaskSet, pOrTerm->leftCursor))==0 ){ /* This term must be of the form t1.a==t2.b where t2 is in the - ** chngToIN set but t1 is not. This term will be either preceeded + ** chngToIN set but t1 is not. This term will be either preceded ** or follwed by an inverted copy (t2.b==t1.a). Skip this term ** and use its inversion. */ testcase( pOrTerm->wtFlags & TERM_COPIED ); @@ -1058,8 +1063,7 @@ static void exprAnalyzeOrTerm( testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); pTerm = &pWC->a[idxTerm]; - pWC->a[idxNew].iParent = idxTerm; - pTerm->nChild = 1; + markTermAsChild(pWC, idxNew, idxTerm); }else{ sqlite3ExprListDelete(db, pList); } @@ -1161,9 +1165,8 @@ static void exprAnalyze( idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC); if( idxNew==0 ) return; pNew = &pWC->a[idxNew]; - pNew->iParent = idxTerm; + markTermAsChild(pWC, idxNew, idxTerm); pTerm = &pWC->a[idxTerm]; - pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; if( pExpr->op==TK_EQ && !ExprHasProperty(pExpr, EP_FromJoin) @@ -1220,9 +1223,8 @@ static void exprAnalyze( testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); pTerm = &pWC->a[idxTerm]; - pWC->a[idxNew].iParent = idxTerm; + markTermAsChild(pWC, idxNew, idxTerm); } - pTerm->nChild = 2; } #endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */ @@ -1297,9 +1299,8 @@ static void exprAnalyze( exprAnalyze(pSrc, pWC, idxNew2); pTerm = &pWC->a[idxTerm]; if( isComplete ){ - pWC->a[idxNew1].iParent = idxTerm; - pWC->a[idxNew2].iParent = idxTerm; - pTerm->nChild = 2; + markTermAsChild(pWC, idxNew1, idxTerm); + markTermAsChild(pWC, idxNew2, idxTerm); } } #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ @@ -1332,9 +1333,8 @@ static void exprAnalyze( pNewTerm->leftCursor = pLeft->iTable; pNewTerm->u.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_MATCH; - pNewTerm->iParent = idxTerm; + markTermAsChild(pWC, idxNew, idxTerm); pTerm = &pWC->a[idxTerm]; - pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } @@ -1355,7 +1355,7 @@ static void exprAnalyze( if( pExpr->op==TK_NOTNULL && pExpr->pLeft->op==TK_COLUMN && pExpr->pLeft->iColumn>=0 - && OptimizationEnabled(db, SQLITE_Stat3) + && OptimizationEnabled(db, SQLITE_Stat34) ){ Expr *pNewExpr; Expr *pLeft = pExpr->pLeft; @@ -1374,9 +1374,8 @@ static void exprAnalyze( pNewTerm->leftCursor = pLeft->iTable; pNewTerm->u.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_GT; - pNewTerm->iParent = idxTerm; + markTermAsChild(pWC, idxNew, idxTerm); pTerm = &pWC->a[idxTerm]; - pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } @@ -1390,7 +1389,7 @@ static void exprAnalyze( } /* -** This function searches pList for a entry that matches the iCol-th column +** This function searches pList for an entry that matches the iCol-th column ** of index pIdx. ** ** If such an expression is found, its index in pList->a[] is returned. If @@ -1596,6 +1595,8 @@ static void constructAutomaticIndex( Bitmask idxCols; /* Bitmap of columns used for indexing */ Bitmask extraCols; /* Bitmap of additional columns */ u8 sentWarning = 0; /* True if a warnning has been issued */ + Expr *pPartial = 0; /* Partial Index Expression */ + int iContinue = 0; /* Jump here to skip excluded rows */ /* Generate code to skip over the creation and initialization of the ** transient index on 2nd and subsequent iterations of the loop. */ @@ -1611,6 +1612,13 @@ static void constructAutomaticIndex( pLoop = pLevel->pWLoop; idxCols = 0; for(pTerm=pWC->a; pTermprereq==0 + && (pTerm->wtFlags & TERM_VIRTUAL)==0 + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + && sqlite3ExprIsTableConstant(pTerm->pExpr, pSrc->iCursor) ){ + pPartial = sqlite3ExprAnd(pParse->db, pPartial, + sqlite3ExprDup(pParse->db, pTerm->pExpr, 0)); + } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ int iCol = pTerm->u.leftColumn; Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); @@ -1623,7 +1631,9 @@ static void constructAutomaticIndex( sentWarning = 1; } if( (idxCols & cMask)==0 ){ - if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ) return; + if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ){ + goto end_auto_index_create; + } pLoop->aLTerm[nKeyCol++] = pTerm; idxCols |= cMask; } @@ -1643,7 +1653,7 @@ static void constructAutomaticIndex( ** if they go out of sync. */ extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); - mxBitCol = (pTable->nCol >= BMS-1) ? BMS-1 : pTable->nCol; + mxBitCol = MIN(BMS-1,pTable->nCol); testcase( pTable->nCol==BMS-1 ); testcase( pTable->nCol==BMS-2 ); for(i=0; icolUsed & MASKBIT(BMS-1) ){ nKeyCol += pTable->nCol - BMS + 1; } - pLoop->wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY; /* Construct the Index object to describe this index */ pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed); - if( pIdx==0 ) return; + if( pIdx==0 ) goto end_auto_index_create; pLoop->u.btree.pIndex = pIdx; pIdx->zName = "auto-index"; pIdx->pTable = pTable; @@ -1708,18 +1717,29 @@ static void constructAutomaticIndex( VdbeComment((v, "for %s", pTable->zName)); /* Fill the automatic index with content */ + sqlite3ExprCachePush(pParse); addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); + if( pPartial ){ + iContinue = sqlite3VdbeMakeLabel(v); + sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL); + pLoop->wsFlags |= WHERE_PARTIALIDX; + } regRecord = sqlite3GetTempReg(pParse); sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0); sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); sqlite3VdbeJumpHere(v, addrTop); sqlite3ReleaseTempReg(pParse, regRecord); + sqlite3ExprCachePop(pParse); /* Jump here when skipping the initialization */ sqlite3VdbeJumpHere(v, addrInit); + +end_auto_index_create: + sqlite3ExprDelete(pParse->db, pPartial); } #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ @@ -1879,7 +1899,6 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ } #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ - #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* ** Estimate the location of a particular key among all keys in an @@ -1888,9 +1907,10 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ ** aStat[0] Est. number of rows less than pVal ** aStat[1] Est. number of rows equal to pVal ** -** Return SQLITE_OK on success. +** Return the index of the sample that is the smallest sample that +** is greater than or equal to pRec. */ -static void whereKeyStats( +static int whereKeyStats( Parse *pParse, /* Database connection */ Index *pIdx, /* Index to consider domain of */ UnpackedRecord *pRec, /* Vector of values to consider */ @@ -1913,7 +1933,7 @@ static void whereKeyStats( assert( pRec->nField>0 && iColnSampleCol ); do{ iTest = (iMin+i)/2; - res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec, 0); + res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec); if( res<0 ){ iMin = iTest+1; }else{ @@ -1928,16 +1948,16 @@ static void whereKeyStats( if( res==0 ){ /* If (res==0) is true, then sample $i must be equal to pRec */ assert( inSample ); - assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0) + assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec) || pParse->db->mallocFailed ); }else{ /* Otherwise, pRec must be smaller than sample $i and larger than ** sample ($i-1). */ assert( i==pIdx->nSample - || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0)>0 + || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0 || pParse->db->mallocFailed ); assert( i==0 - || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec, 0)<0 + || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0 || pParse->db->mallocFailed ); } #endif /* ifdef SQLITE_DEBUG */ @@ -1972,6 +1992,7 @@ static void whereKeyStats( } aStat[0] = iLower + iGap; } + return i; } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ @@ -2122,7 +2143,7 @@ static int whereRangeSkipScanEst( ** If either of the upper or lower bound is not present, then NULL is passed in ** place of the corresponding WhereTerm. ** -** The value in (pBuilder->pNew->u.btree.nEq) is the index of the index +** The value in (pBuilder->pNew->u.btree.nEq) is the number of the index ** column subject to the range constraint. Or, equivalently, the number of ** equality constraints optimized by the proposed index scan. For example, ** assuming index p is on t1(a, b), and the SQL query is: @@ -2138,9 +2159,9 @@ static int whereRangeSkipScanEst( ** ** When this function is called, *pnOut is set to the sqlite3LogEst() of the ** number of rows that the index scan is expected to visit without -** considering the range constraints. If nEq is 0, this is the number of +** considering the range constraints. If nEq is 0, then *pnOut is the number of ** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced) -** to account for the range contraints pLower and pUpper. +** to account for the range constraints pLower and pUpper. ** ** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be ** used, a single range inequality reduces the search space by a factor of 4. @@ -2162,10 +2183,7 @@ static int whereRangeScanEst( Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; - if( p->nSample>0 - && nEqnSampleCol - && OptimizationEnabled(pParse->db, SQLITE_Stat3) - ){ + if( p->nSample>0 && nEqnSampleCol ){ if( nEq==pBuilder->nRecValid ){ UnpackedRecord *pRec = pBuilder->pRec; tRowcnt a[2]; @@ -2181,16 +2199,24 @@ static int whereRangeScanEst( ** is not a simple variable or literal value), the lower bound of the ** range is $P. Due to a quirk in the way whereKeyStats() works, even ** if $L is available, whereKeyStats() is called for both ($P) and - ** ($P:$L) and the larger of the two returned values used. + ** ($P:$L) and the larger of the two returned values is used. ** ** Similarly, iUpper is to be set to the estimate of the number of rows ** less than the upper bound of the range query. Where the upper bound ** is either ($P) or ($P:$U). Again, even if $U is available, both values ** of iUpper are requested of whereKeyStats() and the smaller used. + ** + ** The number of rows between the two bounds is then just iUpper-iLower. */ - tRowcnt iLower; - tRowcnt iUpper; + tRowcnt iLower; /* Rows less than the lower bound */ + tRowcnt iUpper; /* Rows less than the upper bound */ + int iLwrIdx = -2; /* aSample[] for the lower bound */ + int iUprIdx = -1; /* aSample[] for the upper bound */ + if( pRec ){ + testcase( pRec->nField!=pBuilder->nRecValid ); + pRec->nField = pBuilder->nRecValid; + } if( nEq==p->nKeyCol ){ aff = SQLITE_AFF_INTEGER; }else{ @@ -2199,7 +2225,7 @@ static int whereRangeScanEst( /* Determine iLower and iUpper using ($P) only. */ if( nEq==0 ){ iLower = 0; - iUpper = sqlite3LogEstToInt(p->aiRowLogEst[0]); + iUpper = p->nRowEst0; }else{ /* Note: this call could be optimized away - since the same values must ** have been requested when testing key $P in whereEqualScanEst(). */ @@ -2208,18 +2234,26 @@ static int whereRangeScanEst( iUpper = a[0] + a[1]; } + assert( pLower==0 || (pLower->eOperator & (WO_GT|WO_GE))!=0 ); + assert( pUpper==0 || (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); + assert( p->aSortOrder!=0 ); + if( p->aSortOrder[nEq] ){ + /* The roles of pLower and pUpper are swapped for a DESC index */ + SWAP(WhereTerm*, pLower, pUpper); + } + /* If possible, improve on the iLower estimate using ($P:$L). */ if( pLower ){ int bOk; /* True if value is extracted from pExpr */ Expr *pExpr = pLower->pExpr->pRight; - assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 ); rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ tRowcnt iNew; - whereKeyStats(pParse, p, pRec, 0, a); - iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0); + iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a); + iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); if( iNew>iLower ) iLower = iNew; nOut--; + pLower = 0; } } @@ -2227,14 +2261,14 @@ static int whereRangeScanEst( if( pUpper ){ int bOk; /* True if value is extracted from pExpr */ Expr *pExpr = pUpper->pExpr->pRight; - assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ tRowcnt iNew; - whereKeyStats(pParse, p, pRec, 1, a); - iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0); + iUprIdx = whereKeyStats(pParse, p, pRec, 1, a); + iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); if( iNewiLower ){ nNew = sqlite3LogEst(iUpper - iLower); + /* TUNING: If both iUpper and iLower are derived from the same + ** sample, then assume they are 4x more selective. This brings + ** the estimated selectivity more in line with what it would be + ** if estimated without the use of STAT3/4 tables. */ + if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) ); }else{ nNew = 10; assert( 10==sqlite3LogEst(2) ); } if( nNewnOut = (LogEst)nOut; - WHERETRACE(0x10, ("range scan regions: %u..%u est=%d\n", + WHERETRACE(0x10, ("STAT4 range scan: %u..%u est=%d\n", (u32)iLower, (u32)iUpper, nOut)); - return SQLITE_OK; } }else{ int bDone = 0; @@ -2262,22 +2299,31 @@ static int whereRangeScanEst( #else UNUSED_PARAMETER(pParse); UNUSED_PARAMETER(pBuilder); -#endif assert( pLower || pUpper ); +#endif assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 ); nNew = whereRangeAdjust(pLower, nOut); nNew = whereRangeAdjust(pUpper, nNew); - /* TUNING: If there is both an upper and lower limit, assume the range is + /* TUNING: If there is both an upper and lower limit and neither limit + ** has an application-defined likelihood(), assume the range is ** reduced by an additional 75%. This means that, by default, an open-ended ** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the ** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to ** match 1/64 of the index. */ - if( pLower && pUpper ) nNew -= 20; + if( pLower && pLower->truthProb>0 && pUpper && pUpper->truthProb>0 ){ + nNew -= 20; + } nOut -= (pLower!=0) + (pUpper!=0); if( nNew<10 ) nNew = 10; if( nNewnOut>nOut ){ + WHERETRACE(0x10,("Range scan lowers nOut from %d to %d\n", + pLoop->nOut, nOut)); + } +#endif pLoop->nOut = (LogEst)nOut; return rc; } @@ -2390,7 +2436,7 @@ static int whereInScanEst( if( rc==SQLITE_OK ){ if( nRowEst > nRow0 ) nRowEst = nRow0; *pnRow = nRowEst; - WHERETRACE(0x10,("IN row estimate: est=%g\n", nRowEst)); + WHERETRACE(0x10,("IN row estimate: est=%d\n", nRowEst)); } assert( pBuilder->nRecValid==nRecValid ); return rc; @@ -2627,7 +2673,7 @@ static int codeAllEqualityTerms( pLoop = pLevel->pWLoop; assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); nEq = pLoop->u.btree.nEq; - nSkip = pLoop->u.btree.nSkip; + nSkip = pLoop->nSkip; pIdx = pLoop->u.btree.pIndex; assert( pIdx!=0 ); @@ -2726,9 +2772,8 @@ static void explainAppendTerm( /* ** Argument pLevel describes a strategy for scanning table pTab. This -** function returns a pointer to a string buffer containing a description -** of the subset of table rows scanned by the strategy in the form of an -** SQL expression. Or, if all rows are scanned, NULL is returned. +** function appends text to pStr that describes the subset of table +** rows scanned by the strategy in the form of an SQL expression. ** ** For example, if the query: ** @@ -2738,58 +2783,49 @@ static void explainAppendTerm( ** string similar to: ** ** "a=? AND b>?" -** -** The returned pointer points to memory obtained from sqlite3DbMalloc(). -** It is the responsibility of the caller to free the buffer when it is -** no longer required. */ -static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){ +static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ Index *pIndex = pLoop->u.btree.pIndex; u16 nEq = pLoop->u.btree.nEq; - u16 nSkip = pLoop->u.btree.nSkip; + u16 nSkip = pLoop->nSkip; int i, j; Column *aCol = pTab->aCol; i16 *aiColumn = pIndex->aiColumn; - StrAccum txt; - if( nEq==0 && (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){ - return 0; - } - sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH); - txt.db = db; - sqlite3StrAccumAppend(&txt, " (", 2); + if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; + sqlite3StrAccumAppend(pStr, " (", 2); for(i=0; i=nSkip ){ - explainAppendTerm(&txt, i, z, "="); + explainAppendTerm(pStr, i, z, "="); }else{ - if( i ) sqlite3StrAccumAppend(&txt, " AND ", 5); - sqlite3StrAccumAppend(&txt, "ANY(", 4); - sqlite3StrAccumAppendAll(&txt, z); - sqlite3StrAccumAppend(&txt, ")", 1); + if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5); + sqlite3XPrintf(pStr, 0, "ANY(%s)", z); } } j = i; if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; - explainAppendTerm(&txt, i++, z, ">"); + explainAppendTerm(pStr, i++, z, ">"); } if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; - explainAppendTerm(&txt, i, z, "<"); + explainAppendTerm(pStr, i, z, "<"); } - sqlite3StrAccumAppend(&txt, ")", 1); - return sqlite3StrAccumFinish(&txt); + sqlite3StrAccumAppend(pStr, ")", 1); } /* ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN -** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single -** record is added to the output to describe the table scan strategy in -** pLevel. +** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was +** defined at compile-time. If it is not a no-op, a single OP_Explain opcode +** is added to the output to describe the table scan strategy in pLevel. +** +** If an OP_Explain opcode is added to the VM, its address is returned. +** Otherwise, if no OP_Explain is coded, zero is returned. */ -static void explainOneScan( +static int explainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ @@ -2797,82 +2833,136 @@ static void explainOneScan( int iFrom, /* Value for "from" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ -#ifndef SQLITE_DEBUG + int ret = 0; +#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( pParse->explain==2 ) #endif { struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ - char *zMsg; /* Text to add to EQP output */ int iId = pParse->iSelectId; /* Select id (left-most output column) */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ + char *zMsg; /* Text to add to EQP output */ + StrAccum str; /* EQP output string */ + char zBuf[100]; /* Initial space for EQP output string */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; - if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return; + if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); - zMsg = sqlite3MPrintf(db, "%s", isSearch?"SEARCH":"SCAN"); + sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); + str.db = db; + sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s SUBQUERY %d", zMsg,pItem->iSelectId); + sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); }else{ - zMsg = sqlite3MAppendf(db, zMsg, "%s TABLE %s", zMsg, pItem->zName); + sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias); + sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias); } - if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 - && ALWAYS(pLoop->u.btree.pIndex!=0) - ){ - const char *zFmt; - Index *pIdx = pLoop->u.btree.pIndex; - char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); + if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ + const char *zFmt = 0; + Index *pIdx; + + assert( pLoop->u.btree.pIndex!=0 ); + pIdx = pLoop->u.btree.pIndex; assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ - zFmt = zWhere ? "%s USING PRIMARY KEY%.0s%s" : "%s%.0s%s"; + if( isSearch ){ + zFmt = "PRIMARY KEY"; + } + }else if( flags & WHERE_PARTIALIDX ){ + zFmt = "AUTOMATIC PARTIAL COVERING INDEX"; }else if( flags & WHERE_AUTO_INDEX ){ - zFmt = "%s USING AUTOMATIC COVERING INDEX%.0s%s"; + zFmt = "AUTOMATIC COVERING INDEX"; }else if( flags & WHERE_IDX_ONLY ){ - zFmt = "%s USING COVERING INDEX %s%s"; + zFmt = "COVERING INDEX %s"; }else{ - zFmt = "%s USING INDEX %s%s"; + zFmt = "INDEX %s"; + } + if( zFmt ){ + sqlite3StrAccumAppend(&str, " USING ", 7); + sqlite3XPrintf(&str, 0, zFmt, pIdx->zName); + explainIndexRange(&str, pLoop, pItem->pTab); } - zMsg = sqlite3MAppendf(db, zMsg, zFmt, zMsg, pIdx->zName, zWhere); - sqlite3DbFree(db, zWhere); }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg); - + const char *zRange; if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg); + zRange = "(rowid=?)"; }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid? AND rowid?)", zMsg); - }else if( ALWAYS(flags&WHERE_TOP_LIMIT) ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid?)"; + }else{ + assert( flags&WHERE_TOP_LIMIT); + zRange = "(rowidu.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif - zMsg = sqlite3MAppendf(db, zMsg, "%s", zMsg); - sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); +#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS + if( pLoop->nOut>=10 ){ + sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); + }else{ + sqlite3StrAccumAppend(&str, " (~1 row)", 9); + } +#endif + zMsg = sqlite3StrAccumFinish(&str); + ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC); } + return ret; } #else -# define explainOneScan(u,v,w,x,y,z) +# define explainOneScan(u,v,w,x,y,z) 0 #endif /* SQLITE_OMIT_EXPLAIN */ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +/* +** Configure the VM passed as the first argument with an +** sqlite3_stmt_scanstatus() entry corresponding to the scan used to +** implement level pLvl. Argument pSrclist is a pointer to the FROM +** clause that the scan reads data from. +** +** If argument addrExplain is not 0, it must be the address of an +** OP_Explain instruction that describes the same loop. +*/ +static void addScanStatus( + Vdbe *v, /* Vdbe to add scanstatus entry to */ + SrcList *pSrclist, /* FROM clause pLvl reads data from */ + WhereLevel *pLvl, /* Level to add scanstatus() entry for */ + int addrExplain /* Address of OP_Explain (or 0) */ +){ + const char *zObj = 0; + WhereLoop *pLoop = pLvl->pWLoop; + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){ + zObj = pLoop->u.btree.pIndex->zName; + }else{ + zObj = pSrclist->a[pLvl->iFrom].zName; + } + sqlite3VdbeScanStatus( + v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj + ); +} +#else +# define addScanStatus(a, b, c, d) ((void)d) +#endif + + /* ** Generate code for the start of the iLevel-th loop in the WHERE clause @@ -3173,7 +3263,7 @@ static Bitmask codeOneLoopStart( pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; - assert( nEq>=pLoop->u.btree.nSkip ); + assert( nEq>=pLoop->nSkip ); /* If this loop satisfies a sort order (pOrderBy) request that ** was passed to this function to implement a "SELECT min(x) ..." @@ -3190,7 +3280,7 @@ static Bitmask codeOneLoopStart( && pWInfo->nOBSat>0 && (pIdx->nKeyCol>nEq) ){ - assert( pLoop->u.btree.nSkip==0 ); + assert( pLoop->nSkip==0 ); bSeekPastNull = 1; nExtraReg = 1; } @@ -3407,7 +3497,7 @@ static Bitmask codeOneLoopStart( ** B: ** ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then - ** use an ephermeral index instead of a RowSet to record the primary + ** use an ephemeral index instead of a RowSet to record the primary ** keys of the rows we have already seen. ** */ @@ -3458,7 +3548,7 @@ static Bitmask codeOneLoopStart( } /* Initialize the rowset register to contain NULL. An SQL NULL is - ** equivalent to an empty rowset. Or, create an ephermeral index + ** equivalent to an empty rowset. Or, create an ephemeral index ** capable of holding primary keys in the case of a WITHOUT ROWID. ** ** Also initialize regReturn to contain the address of the instruction @@ -3503,10 +3593,9 @@ static Bitmask codeOneLoopStart( Expr *pExpr = pWC->a[iTerm].pExpr; if( &pWC->a[iTerm] == pTerm ) continue; if( ExprHasProperty(pExpr, EP_FromJoin) ) continue; - testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO ); - testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL ); - if( pWC->a[iTerm].wtFlags & (TERM_ORINFO|TERM_VIRTUAL) ) continue; + if( (pWC->a[iTerm].wtFlags & TERM_VIRTUAL)!=0 ) continue; if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; + testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO ); pExpr = sqlite3ExprDup(db, pExpr, 0); pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr); } @@ -3519,8 +3608,9 @@ static Bitmask codeOneLoopStart( ** eliminating duplicates from other WHERE clauses, the action for each ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ - wctrlFlags = WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY | - WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY; + wctrlFlags = WHERE_OMIT_OPEN_CLOSE + | WHERE_FORCE_TABLE + | WHERE_ONETABLE_ONLY; for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ @@ -3532,14 +3622,17 @@ static Bitmask codeOneLoopStart( pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ + WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, wctrlFlags, iCovCur); assert( pSubWInfo || pParse->nErr || db->mallocFailed ); if( pSubWInfo ){ WhereLoop *pSubLoop; - explainOneScan( + int addrExplain = explainOneScan( pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 ); + addScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain); + /* This is the sub-WHERE clause body. First skip over ** duplicate rows from prior sub-WHERE clauses, and record the ** rowid (or PRIMARY KEY) for the current row so that the same @@ -3670,6 +3763,10 @@ static Bitmask codeOneLoopStart( } } +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + pLevel->addrVisit = sqlite3VdbeCurrentAddr(v); +#endif + /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. */ @@ -3751,21 +3848,26 @@ static Bitmask codeOneLoopStart( return pLevel->notReady; } -#if defined(WHERETRACE_ENABLED) && defined(SQLITE_ENABLE_TREE_EXPLAIN) +#ifdef WHERETRACE_ENABLED /* -** Generate "Explanation" text for a WhereTerm. +** Print the content of a WhereTerm object */ -static void whereExplainTerm(Vdbe *v, WhereTerm *pTerm){ - char zType[4]; - memcpy(zType, "...", 4); - if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; - if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; - if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; - sqlite3ExplainPrintf(v, "%s ", zType); - sqlite3ExplainExpr(v, pTerm->pExpr); +static void whereTermPrint(WhereTerm *pTerm, int iTerm){ + if( pTerm==0 ){ + sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); + }else{ + char zType[4]; + memcpy(zType, "...", 4); + if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; + if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; + if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; + sqlite3DebugPrintf("TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x\n", + iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb, + pTerm->eOperator); + sqlite3TreeViewExpr(0, pTerm->pExpr, 0); + } } -#endif /* WHERETRACE_ENABLED && SQLITE_ENABLE_TREE_EXPLAIN */ - +#endif #ifdef WHERETRACE_ENABLED /* @@ -3781,8 +3883,8 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ sqlite3DebugPrintf(" %12s", pItem->zAlias ? pItem->zAlias : pTab->zName); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ - const char *zName; - if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){ + const char *zName; + if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){ if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){ int i = sqlite3Strlen30(zName) - 1; while( zName[i]!='_' ) i--; @@ -3803,29 +3905,18 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ sqlite3DebugPrintf(" %-19s", z); sqlite3_free(z); } - sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); + if( p->wsFlags & WHERE_SKIPSCAN ){ + sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip); + }else{ + sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); + } sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); -#ifdef SQLITE_ENABLE_TREE_EXPLAIN - /* If the 0x100 bit of wheretracing is set, then show all of the constraint - ** expressions in the WhereLoop.aLTerm[] array. - */ - if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ /* WHERETRACE 0x100 */ + if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ int i; - Vdbe *v = pWInfo->pParse->pVdbe; - sqlite3ExplainBegin(v); for(i=0; inLTerm; i++){ - WhereTerm *pTerm = p->aLTerm[i]; - if( pTerm==0 ) continue; - sqlite3ExplainPrintf(v, " (%d) #%-2d ", i+1, (int)(pTerm-pWC->a)); - sqlite3ExplainPush(v); - whereExplainTerm(v, pTerm); - sqlite3ExplainPop(v); - sqlite3ExplainNL(v); + whereTermPrint(p->aLTerm[i], i); } - sqlite3ExplainFinish(v); - sqlite3DebugPrintf("%s", sqlite3VdbeExplanation(v)); } -#endif } #endif @@ -3851,7 +3942,6 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ p->u.vtab.idxStr = 0; }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){ sqlite3DbFree(db, p->u.btree.pIndex->zColAff); - sqlite3KeyInfoUnref(p->u.btree.pIndex->pKeyInfo); sqlite3DbFree(db, p->u.btree.pIndex); p->u.btree.pIndex = 0; } @@ -3926,10 +4016,11 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ } /* -** Return TRUE if both of the following are true: +** Return TRUE if all of the following are true: ** ** (1) X has the same or lower cost that Y ** (2) X is a proper subset of Y +** (3) X skips at least as many columns as Y ** ** By "proper subset" we mean that X uses fewer WHERE clause terms ** than Y and that every WHERE clause term used by X is also used @@ -3937,19 +4028,25 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** ** If X is a proper subset of Y then Y is a better choice and ought ** to have a lower cost. This routine returns TRUE when that cost -** relationship is inverted and needs to be adjusted. +** relationship is inverted and needs to be adjusted. The third rule +** was added because if X uses skip-scan less than Y it still might +** deserve a lower cost even if it is a proper subset of Y. */ static int whereLoopCheaperProperSubset( const WhereLoop *pX, /* First WhereLoop to compare */ const WhereLoop *pY /* Compare against this WhereLoop */ ){ int i, j; - if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */ + if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){ + return 0; /* X is not a subset of Y */ + } + if( pY->nSkip > pX->nSkip ) return 0; if( pX->rRun >= pY->rRun ){ if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */ if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */ } for(i=pX->nLTerm-1; i>=0; i--){ + if( pX->aLTerm[i]==0 ) continue; for(j=pY->nLTerm-1; j>=0; j--){ if( pY->aLTerm[j]==pX->aLTerm[i] ) break; } @@ -3971,33 +4068,24 @@ static int whereLoopCheaperProperSubset( ** To say "WhereLoop X is a proper subset of Y" means that X uses fewer ** WHERE clause terms than Y and that every WHERE clause term used by X is ** also used by Y. -** -** This adjustment is omitted for SKIPSCAN loops. In a SKIPSCAN loop, the -** WhereLoop.nLTerm field is not an accurate measure of the number of WHERE -** clause terms covered, since some of the first nLTerm entries in aLTerm[] -** will be NULL (because they are skipped). That makes it more difficult -** to compare the loops. We could add extra code to do the comparison, and -** perhaps we will someday. But SKIPSCAN is sufficiently uncommon, and this -** adjustment is sufficient minor, that it is very difficult to construct -** a test case where the extra code would improve the query plan. Better -** to avoid the added complexity and just omit cost adjustments to SKIPSCAN -** loops. */ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return; - if( (pTemplate->wsFlags & WHERE_SKIPSCAN)!=0 ) return; for(; p; p=p->pNextLoop){ if( p->iTab!=pTemplate->iTab ) continue; if( (p->wsFlags & WHERE_INDEXED)==0 ) continue; - if( (p->wsFlags & WHERE_SKIPSCAN)!=0 ) continue; if( whereLoopCheaperProperSubset(p, pTemplate) ){ /* Adjust pTemplate cost downward so that it is cheaper than its - ** subset p */ + ** subset p. */ + WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", + pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1)); pTemplate->rRun = p->rRun; pTemplate->nOut = p->nOut - 1; }else if( whereLoopCheaperProperSubset(pTemplate, p) ){ /* Adjust pTemplate cost upward so that it is costlier than p since ** pTemplate is a proper subset of p */ + WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", + pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut+1)); pTemplate->rRun = p->rRun; pTemplate->nOut = p->nOut + 1; } @@ -4042,8 +4130,9 @@ static WhereLoop **whereLoopFindLesser( /* Any loop using an appliation-defined index (or PRIMARY KEY or ** UNIQUE constraint) with one or more == constraints is better - ** than an automatic index. */ + ** than an automatic index. Unless it is a skip-scan. */ if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 + && (pTemplate->nSkip)==0 && (pTemplate->wsFlags & WHERE_INDEXED)!=0 && (pTemplate->wsFlags & WHERE_COLUMN_EQ)!=0 && (p->prereq & pTemplate->prereq)==pTemplate->prereq @@ -4138,7 +4227,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ** than pTemplate, so just ignore pTemplate */ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ - sqlite3DebugPrintf("ins-noop: "); + sqlite3DebugPrintf(" skip: "); whereLoopPrint(pTemplate, pBuilder->pWC); } #endif @@ -4154,10 +4243,10 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ if( p!=0 ){ - sqlite3DebugPrintf("ins-del: "); + sqlite3DebugPrintf("replace: "); whereLoopPrint(p, pBuilder->pWC); } - sqlite3DebugPrintf("ins-new: "); + sqlite3DebugPrintf(" add: "); whereLoopPrint(pTemplate, pBuilder->pWC); } #endif @@ -4181,7 +4270,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ *ppTail = pToDel->pNextLoop; #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ - sqlite3DebugPrintf("ins-del: "); + sqlite3DebugPrintf(" delete: "); whereLoopPrint(pToDel, pBuilder->pWC); } #endif @@ -4202,19 +4291,42 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ** Adjust the WhereLoop.nOut value downward to account for terms of the ** WHERE clause that reference the loop but which are not used by an ** index. +* +** For every WHERE clause term that is not used by the index +** and which has a truth probability assigned by one of the likelihood(), +** likely(), or unlikely() SQL functions, reduce the estimated number +** of output rows by the probability specified. ** -** In the current implementation, the first extra WHERE clause term reduces -** the number of output rows by a factor of 10 and each additional term -** reduces the number of output rows by sqrt(2). +** TUNING: For every WHERE clause term that is not used by the index +** and which does not have an assigned truth probability, heuristics +** described below are used to try to estimate the truth probability. +** TODO --> Perhaps this is something that could be improved by better +** table statistics. +** +** Heuristic 1: Estimate the truth probability as 93.75%. The 93.75% +** value corresponds to -1 in LogEst notation, so this means decrement +** the WhereLoop.nOut field for every such WHERE clause term. +** +** Heuristic 2: If there exists one or more WHERE clause terms of the +** form "x==EXPR" and EXPR is not a constant 0 or 1, then make sure the +** final output row estimate is no greater than 1/4 of the total number +** of rows in the table. In other words, assume that x==EXPR will filter +** out at least 3 out of 4 rows. If EXPR is -1 or 0 or 1, then maybe the +** "x" column is boolean or else -1 or 0 or 1 is a common default value +** on the "x" column and so in that case only cap the output row estimate +** at 1/2 instead of 1/4. */ -static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){ +static void whereLoopOutputAdjust( + WhereClause *pWC, /* The WHERE clause */ + WhereLoop *pLoop, /* The loop to adjust downward */ + LogEst nRow /* Number of rows in the entire table */ +){ WhereTerm *pTerm, *pX; Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf); - int i, j; + int i, j, k; + LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */ - if( !OptimizationEnabled(pWC->pWInfo->pParse->db, SQLITE_AdjustOutEst) ){ - return; - } + assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){ if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break; if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue; @@ -4226,9 +4338,27 @@ static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){ if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; } if( j<0 ){ - pLoop->nOut += (pTerm->truthProb<=0 ? pTerm->truthProb : -1); + if( pTerm->truthProb<=0 ){ + /* If a truth probability is specified using the likelihood() hints, + ** then use the probability provided by the application. */ + pLoop->nOut += pTerm->truthProb; + }else{ + /* In the absence of explicit truth probabilities, use heuristics to + ** guess a reasonable truth probability. */ + pLoop->nOut--; + if( pTerm->eOperator&WO_EQ ){ + Expr *pRight = pTerm->pExpr->pRight; + if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){ + k = 10; + }else{ + k = 20; + } + if( iReducenOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce; } /* @@ -4269,11 +4399,12 @@ static int whereLoopAddBtreeIndex( Bitmask saved_prereq; /* Original value of pNew->prereq */ u16 saved_nLTerm; /* Original value of pNew->nLTerm */ u16 saved_nEq; /* Original value of pNew->u.btree.nEq */ - u16 saved_nSkip; /* Original value of pNew->u.btree.nSkip */ + u16 saved_nSkip; /* Original value of pNew->nSkip */ u32 saved_wsFlags; /* Original value of pNew->wsFlags */ LogEst saved_nOut; /* Original value of pNew->nOut */ int iCol; /* Index of the column in the table */ int rc = SQLITE_OK; /* Return code */ + LogEst rSize; /* Number of rows in the table */ LogEst rLogSize; /* Logarithm of table size */ WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ @@ -4297,41 +4428,14 @@ static int whereLoopAddBtreeIndex( pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, opMask, pProbe); saved_nEq = pNew->u.btree.nEq; - saved_nSkip = pNew->u.btree.nSkip; + saved_nSkip = pNew->nSkip; saved_nLTerm = pNew->nLTerm; saved_wsFlags = pNew->wsFlags; saved_prereq = pNew->prereq; saved_nOut = pNew->nOut; pNew->rSetup = 0; - rLogSize = estLog(pProbe->aiRowLogEst[0]); - - /* Consider using a skip-scan if there are no WHERE clause constraints - ** available for the left-most terms of the index, and if the average - ** number of repeats in the left-most terms is at least 18. - ** - ** The magic number 18 is selected on the basis that scanning 17 rows - ** is almost always quicker than an index seek (even though if the index - ** contains fewer than 2^17 rows we assume otherwise in other parts of - ** the code). And, even if it is not, it should not be too much slower. - ** On the other hand, the extra seeks could end up being significantly - ** more expensive. */ - assert( 42==sqlite3LogEst(18) ); - if( pTerm==0 - && saved_nEq==saved_nSkip - && saved_nEq+1nKeyCol - && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ - && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK - ){ - LogEst nIter; - pNew->u.btree.nEq++; - pNew->u.btree.nSkip++; - pNew->aLTerm[pNew->nLTerm++] = 0; - pNew->wsFlags |= WHERE_SKIPSCAN; - nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1]; - pNew->nOut -= nIter; - whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul); - pNew->nOut = saved_nOut; - } + rSize = pProbe->aiRowLogEst[0]; + rLogSize = estLog(rSize); for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */ LogEst rCostIdx; @@ -4426,7 +4530,6 @@ static int whereLoopAddBtreeIndex( if( nInMul==0 && pProbe->nSample && pNew->u.btree.nEq<=pProbe->nSampleCol - && OptimizationEnabled(db, SQLITE_Stat3) && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) ){ Expr *pExpr = pTerm->pExpr; @@ -4473,7 +4576,7 @@ static int whereLoopAddBtreeIndex( nOutUnadjusted = pNew->nOut; pNew->rRun += nInMul + nIn; pNew->nOut += nInMul + nIn; - whereLoopOutputAdjust(pBuilder->pWC, pNew); + whereLoopOutputAdjust(pBuilder->pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ @@ -4494,10 +4597,45 @@ static int whereLoopAddBtreeIndex( } pNew->prereq = saved_prereq; pNew->u.btree.nEq = saved_nEq; - pNew->u.btree.nSkip = saved_nSkip; + pNew->nSkip = saved_nSkip; pNew->wsFlags = saved_wsFlags; pNew->nOut = saved_nOut; pNew->nLTerm = saved_nLTerm; + + /* Consider using a skip-scan if there are no WHERE clause constraints + ** available for the left-most terms of the index, and if the average + ** number of repeats in the left-most terms is at least 18. + ** + ** The magic number 18 is selected on the basis that scanning 17 rows + ** is almost always quicker than an index seek (even though if the index + ** contains fewer than 2^17 rows we assume otherwise in other parts of + ** the code). And, even if it is not, it should not be too much slower. + ** On the other hand, the extra seeks could end up being significantly + ** more expensive. */ + assert( 42==sqlite3LogEst(18) ); + if( saved_nEq==saved_nSkip + && saved_nEq+1nKeyCol + && pProbe->noSkipScan==0 + && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ + && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK + ){ + LogEst nIter; + pNew->u.btree.nEq++; + pNew->nSkip++; + pNew->aLTerm[pNew->nLTerm++] = 0; + pNew->wsFlags |= WHERE_SKIPSCAN; + nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1]; + pNew->nOut -= nIter; + /* TUNING: Because uncertainties in the estimates for skip-scan queries, + ** add a 1.375 fudge factor to make skip-scan slightly less likely. */ + nIter += 5; + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul); + pNew->nOut = saved_nOut; + pNew->u.btree.nEq = saved_nEq; + pNew->nSkip = saved_nSkip; + pNew->wsFlags = saved_wsFlags; + } + return rc; } @@ -4523,6 +4661,7 @@ static int indexMightHelpWithOrderBy( Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr); if( pExpr->op!=TK_COLUMN ) return 0; if( pExpr->iTable==iCursor ){ + if( pExpr->iColumn<0 ) return 1; for(jj=0; jjnKeyCol; jj++){ if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; } @@ -4556,7 +4695,11 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){ int i; WhereTerm *pTerm; for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){ - if( sqlite3ExprImpliesExpr(pTerm->pExpr, pWhere, iTab) ) return 1; + if( sqlite3ExprImpliesExpr(pTerm->pExpr, pWhere, iTab) + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + ){ + return 1; + } } return 0; } @@ -4675,18 +4818,26 @@ static int whereLoopAddBtree( if( pTerm->prereqRight & pNew->maskSelf ) continue; if( termCanDriveIndex(pTerm, pSrc, 0) ){ pNew->u.btree.nEq = 1; - pNew->u.btree.nSkip = 0; + pNew->nSkip = 0; pNew->u.btree.pIndex = 0; pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm; /* TUNING: One-time cost for computing the automatic index is - ** approximately 7*N*log2(N) where N is the number of rows in - ** the table being indexed. */ - pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) ); + ** estimated to be X*N*log2(N) where N is the number of rows in + ** the table being indexed and where X is 7 (LogEst=28) for normal + ** tables or 1.375 (LogEst=4) for views and subqueries. The value + ** of X is smaller for views and subqueries so that the query planner + ** will be more aggressive about generating automatic indexes for + ** those objects, since there is no opportunity to add schema + ** indexes on subqueries and views. */ + pNew->rSetup = rLogSize + rSize + 4; + if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){ + pNew->rSetup += 24; + } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); /* TUNING: Each index lookup yields 20 rows in the table. This ** is more than the usual guess of 10 rows, since we have no way - ** of knowning how selective the index will ultimately be. It would + ** of knowing how selective the index will ultimately be. It would ** not be unreasonable to make this value much larger. */ pNew->nOut = 43; assert( 43==sqlite3LogEst(20) ); pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut); @@ -4702,12 +4853,13 @@ static int whereLoopAddBtree( */ for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){ if( pProbe->pPartIdxWhere!=0 - && !whereUsablePartialIndex(pNew->iTab, pWC, pProbe->pPartIdxWhere) ){ + && !whereUsablePartialIndex(pSrc->iCursor, pWC, pProbe->pPartIdxWhere) ){ + testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */ continue; /* Partial index inappropriate for this query */ } rSize = pProbe->aiRowLogEst[0]; pNew->u.btree.nEq = 0; - pNew->u.btree.nSkip = 0; + pNew->nSkip = 0; pNew->nLTerm = 0; pNew->iSortIdx = 0; pNew->rSetup = 0; @@ -4726,7 +4878,7 @@ static int whereLoopAddBtree( /* TUNING: Cost of full table scan is (N*3.0). */ pNew->rRun = rSize + 16; ApplyCostMultiplier(pNew->rRun, pTab->costMult); - whereLoopOutputAdjust(pWC, pNew); + whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; @@ -4762,7 +4914,7 @@ static int whereLoopAddBtree( pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16); } ApplyCostMultiplier(pNew->rRun, pTab->costMult); - whereLoopOutputAdjust(pWC, pNew); + whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; @@ -4969,7 +5121,6 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ struct SrcList_item *pItem; pWC = pBuilder->pWC; - if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK; pWCEnd = pWC->a + pWC->nTerm; pNew = pBuilder->pNew; memset(&sSum, 0, sizeof(sSum)); @@ -4990,6 +5141,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ sSubBuild.pOrderBy = 0; sSubBuild.pOrSet = &sCur; + WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm)); for(pOrTerm=pOrWC->a; pOrTermeOperator & WO_AND)!=0 ){ sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; @@ -5004,6 +5156,15 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ continue; } sCur.n = 0; +#ifdef WHERETRACE_ENABLED + WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", + (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); + if( sqlite3WhereTrace & 0x400 ){ + for(i=0; inTerm; i++){ + whereTermPrint(&sSubBuild.pWC->a[i], i); + } + } +#endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mExtra); @@ -5012,6 +5173,9 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ { rc = whereLoopAddBtree(&sSubBuild, mExtra); } + if( rc==SQLITE_OK ){ + rc = whereLoopAddOr(&sSubBuild, mExtra); + } assert( rc==SQLITE_OK || sCur.n==0 ); if( sCur.n==0 ){ sSum.n = 0; @@ -5056,6 +5220,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ pNew->prereq = sSum.a[i].prereq; rc = whereLoopInsert(pBuilder, pNew); } + WHERETRACE(0x200, ("End processing OR-clause %p\n", pTerm)); } } return rc; @@ -5115,7 +5280,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ ** strict. With GROUP BY and DISTINCT the only requirement is that ** equivalent rows appear immediately adjacent to one another. GROUP BY ** and DISTINCT do not require rows to appear in any particular order as long -** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT +** as equivalent rows are grouped together. Thus for GROUP BY and DISTINCT ** the pOrderBy terms can be matched in any order. With ORDER BY, the ** pOrderBy terms must be matched in strict left-to-right order. */ @@ -5244,7 +5409,7 @@ static i8 wherePathSatisfiesOrderBy( /* Skip over == and IS NULL terms */ if( ju.btree.nEq - && pLoop->u.btree.nSkip==0 + && pLoop->nSkip==0 && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0 ){ if( i & WO_ISNULL ){ @@ -5299,7 +5464,7 @@ static i8 wherePathSatisfiesOrderBy( isMatch = 1; break; } - if( isMatch && (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ + if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){ /* Make sure the sort order is compatible in an ORDER BY clause. ** Sort order is irrelevant for a GROUP BY clause. */ if( revSet ){ @@ -5698,7 +5863,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ } #ifdef WHERETRACE_ENABLED /* >=2 */ - if( sqlite3WhereTrace>=2 ){ + if( sqlite3WhereTrace & 0x02 ){ sqlite3DebugPrintf("---- after round %d ----\n", iLoop); for(ii=0, pTo=aTo; iiwctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr ){ - Bitmask notUsed = 0; + Bitmask revMask = 0; int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, - pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used + pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask ); assert( pWInfo->sorted==0 ); - pWInfo->sorted = (nOrder==pWInfo->pOrderBy->nExpr); + if( nOrder==pWInfo->pOrderBy->nExpr ){ + pWInfo->sorted = 1; + pWInfo->revMask = revMask; + } } } @@ -5814,7 +5982,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pWC = &pWInfo->sWC; pLoop = pBuilder->pNew; pLoop->wsFlags = 0; - pLoop->u.btree.nSkip = 0; + pLoop->nSkip = 0; pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ, 0); if( pTerm ){ pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW; @@ -5826,7 +5994,6 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ }else{ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pLoop->aLTermSpace==pLoop->aLTerm ); - assert( ArraySize(pLoop->aLTermSpace)==4 ); if( !IsUniqueIndex(pIdx) || pIdx->pPartIdxWhere!=0 || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) @@ -6122,23 +6289,16 @@ WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(0xffff,("*** Optimizer Start ***\n")); +#if defined(WHERETRACE_ENABLED) /* Display all terms of the WHERE clause */ -#if defined(WHERETRACE_ENABLED) && defined(SQLITE_ENABLE_TREE_EXPLAIN) if( sqlite3WhereTrace & 0x100 ){ int i; - Vdbe *v = pParse->pVdbe; - sqlite3ExplainBegin(v); for(i=0; inTerm; i++){ - sqlite3ExplainPrintf(v, "#%-2d ", i); - sqlite3ExplainPush(v); - whereExplainTerm(v, &sWLB.pWC->a[i]); - sqlite3ExplainPop(v); - sqlite3ExplainNL(v); + whereTermPrint(&sWLB.pWC->a[i], i); } - sqlite3ExplainFinish(v); - sqlite3DebugPrintf("%s", sqlite3VdbeExplanation(v)); } #endif + if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; @@ -6342,7 +6502,10 @@ WhereInfo *sqlite3WhereBegin( */ notReady = ~(Bitmask)0; for(ii=0; iia[ii]; + wsFlags = pLevel->pWLoop->wsFlags; #ifndef SQLITE_OMIT_AUTOMATIC_INDEX if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){ constructAutomaticIndex(pParse, &pWInfo->sWC, @@ -6350,10 +6513,15 @@ WhereInfo *sqlite3WhereBegin( if( db->mallocFailed ) goto whereBeginError; } #endif - explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags); + addrExplain = explainOneScan( + pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags + ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = codeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; + if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){ + addScanStatus(v, pTabList, pLevel, addrExplain); + } } /* Done. */ diff --git a/src/whereInt.h b/src/whereInt.h index 81f4a03..2ccc6ec 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -85,6 +85,9 @@ struct WhereLevel { } u; struct WhereLoop *pWLoop; /* The selected WhereLoop object */ Bitmask notReady; /* FROM entries not usable at this level */ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + int addrVisit; /* Address at which row is visited */ +#endif }; /* @@ -115,7 +118,6 @@ struct WhereLoop { union { struct { /* Information for internal btree tables */ u16 nEq; /* Number of equality constraints */ - u16 nSkip; /* Number of initial index columns to skip */ Index *pIndex; /* Index used, or NULL */ } btree; struct { /* Information for virtual tables */ @@ -128,12 +130,13 @@ struct WhereLoop { } u; u32 wsFlags; /* WHERE_* flags describing the plan */ u16 nLTerm; /* Number of entries in aLTerm[] */ + u16 nSkip; /* Number of NULL aLTerm[] entries */ /**** whereLoopXfer() copies fields above ***********************/ # define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot) u16 nLSlot; /* Number of slots allocated for aLTerm[] */ WhereTerm **aLTerm; /* WhereTerms used */ WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */ - WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */ + WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */ }; /* This object holds the prerequisites and the cost of running a @@ -176,7 +179,7 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int); ** 1. Then using those as a basis to compute the N best WherePath objects ** of length 2. And so forth until the length of WherePaths equals the ** number of nodes in the FROM clause. The best (lowest cost) WherePath -** at the end is the choosen query plan. +** at the end is the chosen query plan. */ struct WherePath { Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ @@ -459,3 +462,4 @@ struct WhereInfo { #define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */ #define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */ #define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/ +#define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */ diff --git a/test/aggnested.test b/test/aggnested.test index 6e2fd65..a87c751 100644 --- a/test/aggnested.test +++ b/test/aggnested.test @@ -156,8 +156,14 @@ do_test aggnested-3.2 { (SELECT value1 as xyz, max(x1) AS pqr FROM t1 GROUP BY id1); + SELECT + (SELECT sum(value2<>xyz) FROM t2) + FROM + (SELECT value1 as xyz, max(x1) AS pqr + FROM t1 + GROUP BY id1); } -} {0} +} {1 0} do_test aggnested-3.3 { db eval { DROP TABLE IF EXISTS t1; diff --git a/test/alter4.test b/test/alter4.test index eaad37e..ac39d61 100644 --- a/test/alter4.test +++ b/test/alter4.test @@ -145,7 +145,7 @@ do_test alter4-2.6 { } {1 {Cannot add a column with non-constant default}} do_test alter4-2.7 { catchsql { - alter table t1 add column d default (-+1); + alter table t1 add column d default (-5+1); } } {1 {Cannot add a column with non-constant default}} do_test alter4-2.99 { diff --git a/test/analyze8.test b/test/analyze8.test index 4384c39..1079e68 100644 --- a/test/analyze8.test +++ b/test/analyze8.test @@ -86,23 +86,23 @@ do_test 2.1 { # range. # # Test 3.2 is a little unstable. It depends on the planner estimating -# that (b BETWEEN 50 AND 54) will match more rows than (c BETWEEN +# that (b BETWEEN 30 AND 34) will match more rows than (c BETWEEN # 800000 AND 900000). Which is a pretty close call (50 vs. 32), so # the planner could get it wrong with an unlucky set of samples. This # case happens to work, but others ("b BETWEEN 40 AND 44" for example) # will fail. # do_execsql_test 3.0 { - SELECT count(*) FROM t1 WHERE b BETWEEN 50 AND 54; + SELECT count(*) FROM t1 WHERE b BETWEEN 30 AND 34; SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 100000; SELECT count(*) FROM t1 WHERE c BETWEEN 800000 AND 900000; } {50 376 32} do_test 3.1 { - eqp {SELECT * FROM t1 WHERE b BETWEEN 50 AND 54 AND c BETWEEN 0 AND 100000} + eqp {SELECT * FROM t1 WHERE b BETWEEN 30 AND 34 AND c BETWEEN 0 AND 100000} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b? AND c? AND b=? term. Better than + # (a<20) but not as good as (a<10). + do_eqp_test 25.4.1 { + SELECT * FROM t6 WHERE a < 10 AND (b BETWEEN ? AND 60) + } { + 0 0 0 {SEARCH TABLE t6 USING INDEX aa (a? AND b? AND c? AND b? AND b? AND c? AND c2500 +} {/SEARCH TABLE t1 USING INDEX t1a/} +do_execsql_test analyzeE-1.8 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a>1900 +} {/SEARCH TABLE t1 USING INDEX t1a/} +do_execsql_test analyzeE-1.9 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a>1100 +} {/SCAN TABLE t1/} +do_execsql_test analyzeE-1.10 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a<1100 +} {/SEARCH TABLE t1 USING INDEX t1a/} +do_execsql_test analyzeE-1.11 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a<1900 +} {/SCAN TABLE t1/} + +# Verify that everything works the same on a DESCENDING index. +# +do_execsql_test analyzeE-2.0 { + DROP INDEX t1a; + CREATE INDEX t1a ON t1(a DESC); + ANALYZE; +} {} +do_execsql_test analyzeE-2.1 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500; +} {/SCAN TABLE t1/} +do_execsql_test analyzeE-2.2 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000; +} {/SEARCH TABLE t1 USING INDEX t1a/} +do_execsql_test analyzeE-2.3 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750; +} {/SEARCH TABLE t1 USING INDEX t1a/} +do_execsql_test analyzeE-2.4 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 +} {/SEARCH TABLE t1 USING INDEX t1a/} +do_execsql_test analyzeE-2.5 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 +} {/SEARCH TABLE t1 USING INDEX t1a/} +do_execsql_test analyzeE-2.6 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a<500 +} {/SEARCH TABLE t1 USING INDEX t1a/} +do_execsql_test analyzeE-2.7 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a>2500 +} {/SEARCH TABLE t1 USING INDEX t1a/} +do_execsql_test analyzeE-2.8 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a>1900 +} {/SEARCH TABLE t1 USING INDEX t1a/} +do_execsql_test analyzeE-2.9 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a>1100 +} {/SCAN TABLE t1/} +do_execsql_test analyzeE-2.10 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a<1100 +} {/SEARCH TABLE t1 USING INDEX t1a/} +do_execsql_test analyzeE-2.11 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a<1900 +} {/SCAN TABLE t1/} + +# Now do a range query on the second term of an ASCENDING index +# where the first term is constrained by equality. +# +do_execsql_test analyzeE-3.0 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c); + WITH RECURSIVE + cnt(x) AS (VALUES(1000) UNION ALL SELECT x+1 FROM cnt WHERE x<2000) + INSERT INTO t1(a,b,c) SELECT x, x, 123 FROM cnt; + CREATE INDEX t1ca ON t1(c,a); + ANALYZE; +} {} +do_execsql_test analyzeE-3.1 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500 AND c=123; +} {/SCAN TABLE t1/} +do_execsql_test analyzeE-3.2 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000 AND c=123; +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-3.3 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750 AND c=123; +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-3.4 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-3.5 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-3.6 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a<500 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-3.7 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a>2500 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-3.8 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a>1900 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-3.9 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a>1100 AND c=123 +} {/SCAN TABLE t1/} +do_execsql_test analyzeE-3.10 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a<1100 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-3.11 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a<1900 AND c=123 +} {/SCAN TABLE t1/} + +# Repeat the 3.x tests using a DESCENDING index +# +do_execsql_test analyzeE-4.0 { + DROP INDEX t1ca; + CREATE INDEX t1ca ON t1(c ASC,a DESC); + ANALYZE; +} {} +do_execsql_test analyzeE-4.1 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500 AND c=123; +} {/SCAN TABLE t1/} +do_execsql_test analyzeE-4.2 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000 AND c=123; +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-4.3 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750 AND c=123; +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-4.4 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-4.5 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-4.6 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a<500 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-4.7 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a>2500 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-4.8 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a>1900 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-4.9 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a>1100 AND c=123 +} {/SCAN TABLE t1/} +do_execsql_test analyzeE-4.10 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a<1100 AND c=123 +} {/SEARCH TABLE t1 USING INDEX t1ca/} +do_execsql_test analyzeE-4.11 { + EXPLAIN QUERY PLAN + SELECT * FROM t1 WHERE a<1900 AND c=123 +} {/SCAN TABLE t1/} + +finish_test diff --git a/test/auth.test b/test/auth.test index 43e53ef..f3c2fa7 100644 --- a/test/auth.test +++ b/test/auth.test @@ -36,7 +36,7 @@ proc_real proc {name arguments script} { do_test auth-1.1.1 { db close set ::DB [sqlite3 db test.db] - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} { return SQLITE_DENY } @@ -61,7 +61,7 @@ do_test auth-1.2 { execsql {SELECT name FROM sqlite_master} } {} do_test auth-1.3.1 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -82,7 +82,7 @@ do_test auth-1.4 { ifcapable tempdb { do_test auth-1.5 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} { return SQLITE_DENY } @@ -94,7 +94,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {} do_test auth-1.7.1 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TEMP_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -112,7 +112,7 @@ ifcapable tempdb { } do_test auth-1.9 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} { return SQLITE_IGNORE } @@ -124,7 +124,7 @@ do_test auth-1.10 { execsql {SELECT name FROM sqlite_master} } {} do_test auth-1.11 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -139,7 +139,7 @@ do_test auth-1.12 { ifcapable tempdb { do_test auth-1.13 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} { return SQLITE_IGNORE } @@ -151,7 +151,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {} do_test auth-1.15 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TEMP_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -165,7 +165,7 @@ ifcapable tempdb { } {} do_test auth-1.17 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -181,7 +181,7 @@ ifcapable tempdb { do_test auth-1.19.1 { set ::authargs {} - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TEMP_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -198,7 +198,7 @@ do_test auth-1.20 { } {t2} do_test auth-1.21.1 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -214,7 +214,7 @@ do_test auth-1.22 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.23.1 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -232,7 +232,7 @@ do_test auth-1.24 { ifcapable tempdb { do_test auth-1.25 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TEMP_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -245,7 +245,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.27 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TEMP_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -260,7 +260,7 @@ ifcapable tempdb { } do_test auth-1.29 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="t2"} { return SQLITE_DENY } @@ -272,7 +272,7 @@ do_test auth-1.30 { execsql {SELECT * FROM t2} } {} do_test auth-1.31 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="t2"} { return SQLITE_IGNORE } @@ -284,7 +284,7 @@ do_test auth-1.32 { execsql {SELECT * FROM t2} } {} do_test auth-1.33 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="t1"} { return SQLITE_IGNORE } @@ -297,7 +297,7 @@ do_test auth-1.34 { } {1 2 3} do_test auth-1.35.1 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} { return SQLITE_DENY } @@ -313,7 +313,7 @@ ifcapable attach { execsql {DETACH DATABASE two} } do_test auth-1.36 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} { return SQLITE_IGNORE } @@ -322,7 +322,7 @@ do_test auth-1.36 { catchsql {SELECT * FROM t2} } {0 {1 {} 3}} do_test auth-1.37 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} { return SQLITE_IGNORE } @@ -331,7 +331,7 @@ do_test auth-1.37 { catchsql {SELECT * FROM t2 WHERE b=2} } {0 {}} do_test auth-1.38 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="a"} { return SQLITE_IGNORE } @@ -340,7 +340,7 @@ do_test auth-1.38 { catchsql {SELECT * FROM t2 WHERE b=2} } {0 {{} 2 3}} do_test auth-1.39 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} { return SQLITE_IGNORE } @@ -349,7 +349,7 @@ do_test auth-1.39 { catchsql {SELECT * FROM t2 WHERE b IS NULL} } {0 {1 {} 3}} do_test auth-1.40 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} { return SQLITE_DENY } @@ -359,7 +359,7 @@ do_test auth-1.40 { } {1 {access to t2.b is prohibited}} do_test auth-1.41 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_UPDATE" && $arg1=="t2" && $arg2=="b"} { return SQLITE_DENY } @@ -371,7 +371,7 @@ do_test auth-1.42 { execsql {SELECT * FROM t2} } {11 2 3} do_test auth-1.43 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_UPDATE" && $arg1=="t2" && $arg2=="b"} { return SQLITE_DENY } @@ -383,7 +383,7 @@ do_test auth-1.44 { execsql {SELECT * FROM t2} } {11 2 3} do_test auth-1.45 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_UPDATE" && $arg1=="t2" && $arg2=="b"} { return SQLITE_IGNORE } @@ -396,7 +396,7 @@ do_test auth-1.46 { } {11 2 33} do_test auth-1.47 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="t2"} { return SQLITE_DENY } @@ -408,7 +408,7 @@ do_test auth-1.48 { execsql {SELECT * FROM t2} } {11 2 33} do_test auth-1.49 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="t2"} { return SQLITE_IGNORE } @@ -424,7 +424,7 @@ do_test auth-1.50.2 { } {} do_test auth-1.51 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_SELECT"} { return SQLITE_DENY } @@ -433,7 +433,7 @@ do_test auth-1.51 { catchsql {SELECT * FROM t2} } {1 {not authorized}} do_test auth-1.52 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_SELECT"} { return SQLITE_IGNORE } @@ -442,7 +442,7 @@ do_test auth-1.52 { catchsql {SELECT * FROM t2} } {0 {}} do_test auth-1.53 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_SELECT"} { return SQLITE_OK } @@ -462,7 +462,7 @@ do_test auth-1.55 { } {11 2 33 7 8 9} do_test auth-1.63 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} { return SQLITE_DENY } @@ -474,7 +474,7 @@ do_test auth-1.64 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.65 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="t2"} { return SQLITE_DENY } @@ -488,7 +488,7 @@ do_test auth-1.66 { ifcapable tempdb { do_test auth-1.67 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} { return SQLITE_DENY } @@ -500,7 +500,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.69 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="t1"} { return SQLITE_DENY } @@ -514,7 +514,7 @@ ifcapable tempdb { } do_test auth-1.71 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} { return SQLITE_IGNORE } @@ -526,7 +526,7 @@ do_test auth-1.72 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.73 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="t2"} { return SQLITE_IGNORE } @@ -540,7 +540,7 @@ do_test auth-1.74 { ifcapable tempdb { do_test auth-1.75 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} { return SQLITE_IGNORE } @@ -552,7 +552,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.77 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="t1"} { return SQLITE_IGNORE } @@ -569,7 +569,7 @@ ifcapable tempdb { # Omit these if the library was compiled with views omitted. ifcapable view { do_test auth-1.79 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_VIEW"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -585,7 +585,7 @@ do_test auth-1.81 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.82 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_VIEW"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -603,7 +603,7 @@ do_test auth-1.84 { ifcapable tempdb { do_test auth-1.85 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TEMP_VIEW"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -619,7 +619,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.88 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TEMP_VIEW"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -637,7 +637,7 @@ ifcapable tempdb { } do_test auth-1.91 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} { return SQLITE_DENY } @@ -649,7 +649,7 @@ do_test auth-1.92 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.93 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} { return SQLITE_IGNORE } @@ -663,7 +663,7 @@ do_test auth-1.94 { ifcapable tempdb { do_test auth-1.95 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} { return SQLITE_DENY } @@ -675,7 +675,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.97 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} { return SQLITE_IGNORE } @@ -689,7 +689,7 @@ ifcapable tempdb { } do_test auth-1.99 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} { return SQLITE_DENY } @@ -704,7 +704,7 @@ do_test auth-1.100 { execsql {SELECT name FROM sqlite_master} } {t2 v2} do_test auth-1.101 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_VIEW"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -720,7 +720,7 @@ do_test auth-1.103 { execsql {SELECT name FROM sqlite_master} } {t2 v2} do_test auth-1.104 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} { return SQLITE_IGNORE } @@ -732,7 +732,7 @@ do_test auth-1.105 { execsql {SELECT name FROM sqlite_master} } {t2 v2} do_test auth-1.106 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_VIEW"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -748,7 +748,7 @@ do_test auth-1.108 { execsql {SELECT name FROM sqlite_master} } {t2 v2} do_test auth-1.109 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_VIEW"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -767,7 +767,7 @@ do_test auth-1.111 { ifcapable tempdb { do_test auth-1.112 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} { return SQLITE_DENY } @@ -782,7 +782,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1 v1} do_test auth-1.114 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TEMP_VIEW"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -798,7 +798,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1 v1} do_test auth-1.117 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} { return SQLITE_IGNORE } @@ -810,7 +810,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1 v1} do_test auth-1.119 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TEMP_VIEW"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -826,7 +826,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1 v1} do_test auth-1.122 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TEMP_VIEW"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -849,7 +849,7 @@ ifcapable tempdb { # ifcapable trigger&&tempdb { do_test auth-1.125 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -869,7 +869,7 @@ do_test auth-1.127 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.128 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} { return SQLITE_DENY } @@ -885,7 +885,7 @@ do_test auth-1.129 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.130 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -905,7 +905,7 @@ do_test auth-1.132 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.133 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} { return SQLITE_IGNORE } @@ -921,7 +921,7 @@ do_test auth-1.134 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.135 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -944,7 +944,7 @@ do_test auth-1.136.2 { } } {r2} do_test auth-1.136.3 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { lappend ::authargs $code $arg1 $arg2 $arg3 $arg4 return SQLITE_OK } @@ -963,7 +963,7 @@ do_test auth-1.137 { execsql {SELECT name FROM sqlite_master} } {t2 tx r2} do_test auth-1.138 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TEMP_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -983,7 +983,7 @@ do_test auth-1.140 { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.141 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} { return SQLITE_DENY } @@ -999,7 +999,7 @@ do_test auth-1.142 { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.143 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TEMP_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1019,7 +1019,7 @@ do_test auth-1.145 { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.146 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} { return SQLITE_IGNORE } @@ -1035,7 +1035,7 @@ do_test auth-1.147 { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.148 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TEMP_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1056,7 +1056,7 @@ do_test auth-1.150 { } {t1 r1} do_test auth-1.151 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} { return SQLITE_DENY } @@ -1068,7 +1068,7 @@ do_test auth-1.152 { execsql {SELECT name FROM sqlite_master} } {t2 tx r2} do_test auth-1.153 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1084,7 +1084,7 @@ do_test auth-1.155 { execsql {SELECT name FROM sqlite_master} } {t2 tx r2} do_test auth-1.156 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} { return SQLITE_IGNORE } @@ -1096,7 +1096,7 @@ do_test auth-1.157 { execsql {SELECT name FROM sqlite_master} } {t2 tx r2} do_test auth-1.158 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1112,7 +1112,7 @@ do_test auth-1.160 { execsql {SELECT name FROM sqlite_master} } {t2 tx r2} do_test auth-1.161 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1133,7 +1133,7 @@ do_test auth-1.163 { } {t2} do_test auth-1.164 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} { return SQLITE_DENY } @@ -1145,7 +1145,7 @@ do_test auth-1.165 { execsql {SELECT name FROM sqlite_temp_master} } {t1 r1} do_test auth-1.166 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TEMP_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1161,7 +1161,7 @@ do_test auth-1.168 { execsql {SELECT name FROM sqlite_temp_master} } {t1 r1} do_test auth-1.169 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} { return SQLITE_IGNORE } @@ -1173,7 +1173,7 @@ do_test auth-1.170 { execsql {SELECT name FROM sqlite_temp_master} } {t1 r1} do_test auth-1.171 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TEMP_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1189,7 +1189,7 @@ do_test auth-1.173 { execsql {SELECT name FROM sqlite_temp_master} } {t1 r1} do_test auth-1.174 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TEMP_TRIGGER"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1207,7 +1207,7 @@ do_test auth-1.176 { } ;# ifcapable trigger do_test auth-1.177 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1223,7 +1223,7 @@ do_test auth-1.179 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.180 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} { return SQLITE_DENY } @@ -1235,7 +1235,7 @@ do_test auth-1.181 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.182 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1251,7 +1251,7 @@ do_test auth-1.184 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.185 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} { return SQLITE_IGNORE } @@ -1263,7 +1263,7 @@ do_test auth-1.186 { execsql {SELECT name FROM sqlite_master} } {t2} do_test auth-1.187 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1281,7 +1281,7 @@ do_test auth-1.189 { ifcapable tempdb { do_test auth-1.190 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TEMP_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1297,7 +1297,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.193 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} { return SQLITE_DENY } @@ -1309,7 +1309,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.195 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TEMP_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1325,7 +1325,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.198 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} { return SQLITE_IGNORE } @@ -1337,7 +1337,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1} do_test auth-1.200 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_CREATE_TEMP_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1355,7 +1355,7 @@ ifcapable tempdb { } do_test auth-1.203 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} { return SQLITE_DENY } @@ -1367,7 +1367,7 @@ do_test auth-1.204 { execsql {SELECT name FROM sqlite_master} } {t2 i2} do_test auth-1.205 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1383,7 +1383,7 @@ do_test auth-1.207 { execsql {SELECT name FROM sqlite_master} } {t2 i2} do_test auth-1.208 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} { return SQLITE_IGNORE } @@ -1395,7 +1395,7 @@ do_test auth-1.209 { execsql {SELECT name FROM sqlite_master} } {t2 i2} do_test auth-1.210 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1411,7 +1411,7 @@ do_test auth-1.212 { execsql {SELECT name FROM sqlite_master} } {t2 i2} do_test auth-1.213 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1429,7 +1429,7 @@ do_test auth-1.215 { ifcapable tempdb { do_test auth-1.216 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} { return SQLITE_DENY } @@ -1441,7 +1441,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1 i1} do_test auth-1.218 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TEMP_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1457,7 +1457,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1 i1} do_test auth-1.221 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} { return SQLITE_IGNORE } @@ -1469,7 +1469,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1 i1} do_test auth-1.223 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TEMP_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1485,7 +1485,7 @@ ifcapable tempdb { execsql {SELECT name FROM sqlite_temp_master} } {t1 i1} do_test auth-1.226 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DROP_TEMP_INDEX"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1503,7 +1503,7 @@ ifcapable tempdb { } do_test auth-1.229 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_PRAGMA"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1519,7 +1519,7 @@ do_test auth-1.231 { execsql2 {SELECT a FROM t2} } {a 11 a 7} do_test auth-1.232 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_PRAGMA"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1535,7 +1535,7 @@ do_test auth-1.234 { execsql2 {SELECT a FROM t2} } {a 11 a 7} do_test auth-1.235 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_PRAGMA"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1548,7 +1548,7 @@ do_test auth-1.236 { execsql2 {SELECT a FROM t2} } {t2.a 11 t2.a 7} do_test auth-1.237 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_PRAGMA"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1565,7 +1565,7 @@ do_test auth-1.239 { } {a 11 a 7} do_test auth-1.240 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_TRANSACTION"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1578,7 +1578,7 @@ do_test auth-1.241 { set ::authargs } {BEGIN {} {} {}} do_test auth-1.242 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_TRANSACTION" && $arg1!="BEGIN"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1618,7 +1618,7 @@ do_test auth-1.250 { ifcapable attach { do_test auth-1.251 { db authorizer ::auth - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ATTACH"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] } @@ -1644,7 +1644,7 @@ ifcapable attach { } {{} {} {} {}} do_test auth-1.253 { catchsql {DETACH DATABASE test1} - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ATTACH"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1660,7 +1660,7 @@ ifcapable attach { } {} do_test auth-1.255 { catchsql {DETACH DATABASE test1} - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ATTACH"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1675,7 +1675,7 @@ ifcapable attach { lindex [execsql {PRAGMA database_list}] 7 } {} do_test auth-1.257 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DETACH"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1692,7 +1692,7 @@ ifcapable attach { } {} do_test auth-1.259 { execsql {ATTACH DATABASE ':memory:' AS test1} - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DETACH"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1710,7 +1710,7 @@ ifcapable attach { } {test1} } ;# ifcapable schema_pragmas do_test auth-1.261 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DETACH"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1735,7 +1735,7 @@ ifcapable attach { ifcapable altertable { do_test auth-1.263 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1753,7 +1753,7 @@ ifcapable attach { set authargs } {temp t1 {} {}} do_test auth-1.266 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1771,7 +1771,7 @@ ifcapable attach { set authargs } {temp t1x {} {}} do_test auth-1.269 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1804,7 +1804,7 @@ db authorizer {} catchsql {ALTER TABLE t1x RENAME TO t1} db authorizer ::auth do_test auth-1.272 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -1822,7 +1822,7 @@ do_test auth-1.274 { set authargs } {main t2 {} {}} do_test auth-1.275 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -1840,7 +1840,7 @@ do_test auth-1.277 { set authargs } {main t2x {} {}} do_test auth-1.278 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -1867,7 +1867,7 @@ ifcapable reindex { proc auth {code args} { if {$code=="SQLITE_REINDEX"} { - set ::authargs [concat $::authargs $args] + set ::authargs [concat $::authargs [lrange $args 0 3]] } return SQLITE_OK } @@ -1950,7 +1950,7 @@ ifcapable tempdb { } {t3_idx2 {} temp {} t3_idx1 {} temp {} sqlite_autoindex_t3_1 {} temp {}} proc auth {code args} { if {$code=="SQLITE_REINDEX"} { - set ::authargs [concat $::authargs $args] + set ::authargs [concat $::authargs [lrange $args 0 3]] return SQLITE_DENY } return SQLITE_OK @@ -1973,7 +1973,7 @@ ifcapable tempdb { ifcapable analyze { proc auth {code args} { if {$code=="SQLITE_ANALYZE"} { - set ::authargs [concat $::authargs $args] + set ::authargs [concat $::authargs [lrange $args 0 3]] } return SQLITE_OK } @@ -2020,7 +2020,7 @@ ifcapable analyze { ifcapable {altertable} { do_test auth-1.300 { execsql {CREATE TABLE t5(x)} - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK @@ -2039,7 +2039,7 @@ ifcapable {altertable} { set authargs } {main t5 {} {}} do_test auth-1.303 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE @@ -2058,7 +2058,7 @@ ifcapable {altertable} { set authargs } {main t5 {} {}} do_test auth-1.306 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY @@ -2082,7 +2082,7 @@ ifcapable {altertable} { ifcapable {cte} { do_test auth-1.310 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_RECURSIVE"} { return SQLITE_DENY } @@ -2117,7 +2117,7 @@ ifcapable {cte} { } ;# ifcapable cte do_test auth-2.1 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="x"} { return SQLITE_DENY } @@ -2137,7 +2137,7 @@ do_test auth-2.3 { catchsql {SELECT OID,y,z FROM t3} } {1 {access to t3.x is prohibited}} do_test auth-2.4 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="x"} { return SQLITE_IGNORE } @@ -2150,7 +2150,7 @@ do_test auth-2.5 { catchsql {SELECT rowid,y,z FROM t3} } {0 {{} 55 66}} do_test auth-2.6 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="ROWID"} { return SQLITE_IGNORE } @@ -2162,7 +2162,7 @@ do_test auth-2.7 { catchsql {SELECT ROWID,y,z FROM t3} } {0 {44 55 66}} do_test auth-2.8 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="ROWID"} { return SQLITE_IGNORE } @@ -2181,7 +2181,7 @@ do_test auth-2.9.1 { # db cache flush - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="ROWID"} { return bogus } @@ -2193,7 +2193,7 @@ do_test auth-2.9.2 { db errorcode } {1} do_test auth-2.10 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_SELECT"} { return bogus } @@ -2202,7 +2202,7 @@ do_test auth-2.10 { catchsql {SELECT ROWID,b,c FROM t2} } {1 {authorizer malfunction}} do_test auth-2.11.1 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg2=="a"} { return SQLITE_IGNORE } @@ -2211,7 +2211,7 @@ do_test auth-2.11.1 { catchsql {SELECT * FROM t2, t3} } {0 {{} 2 33 44 55 66 {} 8 9 44 55 66}} do_test auth-2.11.2 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg2=="x"} { return SQLITE_IGNORE } @@ -2224,7 +2224,7 @@ do_test auth-2.11.2 { # ifcapable trigger { do_test auth-3.1 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { return SQLITE_OK } execsql { @@ -2237,7 +2237,7 @@ ifcapable trigger { } } {11 12 2 2 33 33 7 8 8 8 9 9} do_test auth-3.2 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="c"} { return SQLITE_IGNORE } @@ -2255,7 +2255,7 @@ ifcapable trigger { # ifcapable trigger { do_test auth-4.1 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { lappend ::authargs $code $arg1 $arg2 $arg3 $arg4 return SQLITE_OK } @@ -2340,7 +2340,7 @@ do_test auth-4.5 { # clause. # do_test auth-5.1 { - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { return SQLITE_OK } execsql { @@ -2393,7 +2393,7 @@ ifcapable trigger { } {} set ::authargs [list] proc auth {args} { - eval lappend ::authargs $args + eval lappend ::authargs [lrange $args 0 4] return SQLITE_OK } do_test auth-5.3.2 { @@ -2419,7 +2419,7 @@ do_test auth-6.1 { } {} set ::authargs [list] proc auth {args} { - eval lappend ::authargs $args + eval lappend ::authargs [lrange $args 0 4] return SQLITE_OK } do_test auth-6.2 { diff --git a/test/auth2.test b/test/auth2.test index 65e0591..a9d64d0 100644 --- a/test/auth2.test +++ b/test/auth2.test @@ -31,7 +31,7 @@ do_test auth2-1.1 { INSERT INTO t1 VALUES(1,2,3); } set ::flist {} - proc auth {code arg1 arg2 arg3 arg4} { + proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_FUNCTION"} { lappend ::flist $arg2 if {$arg2=="max"} { @@ -80,7 +80,7 @@ sqlite3 db test.db sqlite3 db2 test.db proc auth {args} { global authargs - append authargs $args\n + append authargs [lrange $args 0 4]\n return SQLITE_OK } db auth auth diff --git a/test/auth3.test b/test/auth3.test index 21e2b3b..eef10b3 100644 --- a/test/auth3.test +++ b/test/auth3.test @@ -30,7 +30,7 @@ if {[catch {db auth {}} msg]} { db cache size 0 db authorizer ::auth -proc auth {code arg1 arg2 arg3 arg4} { +proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE"} { return $::authcode } diff --git a/test/autoindex1.test b/test/autoindex1.test index 6cb0ab1..bcde5bc 100644 --- a/test/autoindex1.test +++ b/test/autoindex1.test @@ -413,4 +413,101 @@ do_execsql_test autoindex1-801 { WHERE mimetypes._id=10 AND data14 IS NOT NULL; } {/SEARCH TABLE data .*SEARCH TABLE raw_contacts/} +# Another test case from an important user of SQLite. The key feature of +# this test is that the "aggindex" subquery should make use of an +# automatic index. If it does, the query is fast. If it does not, the +# query is deathly slow. It worked OK in 3.7.17 but started going slow +# with version 3.8.0. The problem was fixed for 3.8.7 by reducing the +# cost estimate for automatic indexes on views and subqueries. +# +db close +forcedelete test.db +sqlite3 db test.db +do_execsql_test autoindex1-900 { + CREATE TABLE messages (ROWID INTEGER PRIMARY KEY AUTOINCREMENT, message_id, document_id BLOB, in_reply_to, remote_id INTEGER, sender INTEGER, subject_prefix, subject INTEGER, date_sent INTEGER, date_received INTEGER, date_created INTEGER, date_last_viewed INTEGER, mailbox INTEGER, remote_mailbox INTEGER, original_mailbox INTEGER, flags INTEGER, read, flagged, size INTEGER, color, encoding, type INTEGER, pad, conversation_id INTEGER DEFAULT -1, snippet TEXT DEFAULT NULL, fuzzy_ancestor INTEGER DEFAULT NULL, automated_conversation INTEGER DEFAULT 0, root_status INTEGER DEFAULT -1, conversation_position INTEGER DEFAULT -1); + CREATE INDEX date_index ON messages(date_received); + CREATE INDEX date_last_viewed_index ON messages(date_last_viewed); + CREATE INDEX date_created_index ON messages(date_created); + CREATE INDEX message_message_id_mailbox_index ON messages(message_id, mailbox); + CREATE INDEX message_document_id_index ON messages(document_id); + CREATE INDEX message_read_index ON messages(read); + CREATE INDEX message_flagged_index ON messages(flagged); + CREATE INDEX message_mailbox_index ON messages(mailbox, date_received); + CREATE INDEX message_remote_mailbox_index ON messages(remote_mailbox, remote_id); + CREATE INDEX message_type_index ON messages(type); + CREATE INDEX message_conversation_id_conversation_position_index ON messages(conversation_id, conversation_position); + CREATE INDEX message_fuzzy_ancestor_index ON messages(fuzzy_ancestor); + CREATE INDEX message_subject_fuzzy_ancestor_index ON messages(subject, fuzzy_ancestor); + CREATE INDEX message_sender_subject_automated_conversation_index ON messages(sender, subject, automated_conversation); + CREATE INDEX message_sender_index ON messages(sender); + CREATE INDEX message_root_status ON messages(root_status); + CREATE TABLE subjects (ROWID INTEGER PRIMARY KEY, subject COLLATE RTRIM, normalized_subject COLLATE RTRIM); + CREATE INDEX subject_subject_index ON subjects(subject); + CREATE INDEX subject_normalized_subject_index ON subjects(normalized_subject); + CREATE TABLE addresses (ROWID INTEGER PRIMARY KEY, address COLLATE NOCASE, comment, UNIQUE(address, comment)); + CREATE INDEX addresses_address_index ON addresses(address); + CREATE TABLE mailboxes (ROWID INTEGER PRIMARY KEY, url UNIQUE, total_count INTEGER DEFAULT 0, unread_count INTEGER DEFAULT 0, unseen_count INTEGER DEFAULT 0, deleted_count INTEGER DEFAULT 0, unread_count_adjusted_for_duplicates INTEGER DEFAULT 0, change_identifier, source INTEGER, alleged_change_identifier); + CREATE INDEX mailboxes_source_index ON mailboxes(source); + CREATE TABLE labels (ROWID INTEGER PRIMARY KEY, message_id INTEGER NOT NULL, mailbox_id INTEGER NOT NULL, UNIQUE(message_id, mailbox_id)); + CREATE INDEX labels_message_id_mailbox_id_index ON labels(message_id, mailbox_id); + CREATE INDEX labels_mailbox_id_index ON labels(mailbox_id); + + explain query plan + SELECT messages.ROWID, + messages.message_id, + messages.remote_id, + messages.date_received, + messages.date_sent, + messages.flags, + messages.size, + messages.color, + messages.date_last_viewed, + messages.subject_prefix, + subjects.subject, + sender.comment, + sender.address, + NULL, + messages.mailbox, + messages.original_mailbox, + NULL, + NULL, + messages.type, + messages.document_id, + sender, + NULL, + messages.conversation_id, + messages.conversation_position, + agglabels.labels + FROM mailboxes AS mailbox + JOIN messages ON mailbox.ROWID = messages.mailbox + LEFT OUTER JOIN subjects ON messages.subject = subjects.ROWID + LEFT OUTER JOIN addresses AS sender ON messages.sender = sender.ROWID + LEFT OUTER JOIN ( + SELECT message_id, group_concat(mailbox_id) as labels + FROM labels GROUP BY message_id + ) AS agglabels ON messages.ROWID = agglabels.message_id + WHERE (mailbox.url = 'imap://email.app@imap.gmail.com/%5BGmail%5D/All%20Mail') + AND (messages.ROWID IN ( + SELECT labels.message_id + FROM labels JOIN mailboxes ON labels.mailbox_id = mailboxes.ROWID + WHERE mailboxes.url = 'imap://email.app@imap.gmail.com/INBOX')) + AND messages.mailbox in (6,12,18,24,30,36,42,1,7,13,19,25,31,37,43,2,8, + 14,20,26,32,38,3,9,15,21,27,33,39,4,10,16,22,28, + 34,40,5,11,17,23,35,41) + ORDER BY date_received DESC; +} {/agglabels USING AUTOMATIC COVERING INDEX/} + +# A test case for VIEWs +# +do_execsql_test autoindex1-901 { + CREATE TABLE t1(x INTEGER PRIMARY KEY, y, z); + CREATE TABLE t2(a, b); + CREATE VIEW agg2 AS SELECT a, sum(b) AS m FROM t2 GROUP BY a; + EXPLAIN QUERY PLAN + SELECT t1.z, agg2.m + FROM t1 JOIN agg2 ON t1.y=agg2.m + WHERE t1.x IN (1,2,3); +} {/USING AUTOMATIC COVERING INDEX/} + + finish_test diff --git a/test/autoindex2.test b/test/autoindex2.test index f4da416..c8abdf4 100644 --- a/test/autoindex2.test +++ b/test/autoindex2.test @@ -224,48 +224,4 @@ do_execsql_test autoindex2-120 { # on t3 and reordering the tables so that t3 was in the outer loop and # implementing the ORDER BY clause using a B-Tree. -do_execsql_test autoindex2-120 { - EXPLAIN QUERY PLAN - SELECT - t1_id, - t1.did, - param2, - param3, - t1.ptime, - t1.trange, - t1.exmass, - t1.mass, - t1.vstatus, - type, - subtype, - t1.deviation, - t1.formula, - dparam1, - reserve1, - reserve2, - param4, - t1.last_operation, - t1.admin_uuid, - t1.previous_value, - t1.job_id, - client_did, - t1.last_t1, - t1.data_t1, - t1.previous_date, - param5, - param6, - mgr_uuid - FROM - t3, - t2, - t1 - WHERE - t1.ptime > 1393520400 - AND param3<>9001 - AND t3.flg7 = 1 - AND t1.did = t2.did - AND t2.uid = t3.uid - ORDER BY t1.ptime desc LIMIT 500; -} {0 0 2 {SEARCH TABLE t1 USING INDEX t1x1 (ptime>?)} 0 1 1 {SEARCH TABLE t2 USING INDEX t2x0 (did=?)} 0 2 0 {SEARCH TABLE t3 USING INDEX t3x0 (uid=?)}} - finish_test diff --git a/test/autoindex3.test b/test/autoindex3.test index 33053bb..c99a175 100644 --- a/test/autoindex3.test +++ b/test/autoindex3.test @@ -17,6 +17,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix autoindex3 # The t1b and t2d indexes are not very selective. It used to be that # the autoindex mechanism would create automatic indexes on t1(b) or @@ -54,5 +55,38 @@ do_execsql_test autoindex3-140 { EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE d IN (5,b) AND x=y; } {/AUTO/} +reset_db +do_execsql_test 210 { + CREATE TABLE v(b, d, e); + CREATE TABLE u(a, b, c); + ANALYZE sqlite_master; + INSERT INTO "sqlite_stat1" VALUES('u','uab','40000 400 1'); + INSERT INTO "sqlite_stat1" VALUES('v','vbde','40000 400 1 1'); + INSERT INTO "sqlite_stat1" VALUES('v','ve','40000 21'); + + CREATE INDEX uab on u(a, b); + CREATE INDEX ve on v(e); + CREATE INDEX vbde on v(b,d,e); + + DROP TABLE IF EXISTS sqlite_stat4; + ANALYZE sqlite_master; +} + +# At one point, SQLite was using the inferior plan: +# +# 0|0|1|SEARCH TABLE v USING INDEX ve (e>?) +# 0|1|0|SEARCH TABLE u USING COVERING INDEX uab (ANY(a) AND b=?) +# +# on the basis that the real index "uab" must be better than the automatic +# index. This is not right - a skip-scan is not necessarily better than an +# automatic index scan. +# +do_eqp_test 220 { + select count(*) from u, v where u.b = v.b and v.e > 34; +} { + 0 0 1 {SEARCH TABLE v USING INDEX ve (e>?)} + 0 1 0 {SEARCH TABLE u USING AUTOMATIC COVERING INDEX (b=?)} +} + finish_test diff --git a/test/autoindex4.test b/test/autoindex4.test new file mode 100644 index 0000000..0e7a80d --- /dev/null +++ b/test/autoindex4.test @@ -0,0 +1,83 @@ +# 2014-10-24 +# +# 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 automatic index creation logic, +# and specifically creation of automatic partial indexes. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test autoindex4-1.0 { + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(123,'abc'),(234,'def'),(234,'ghi'),(345,'jkl'); + CREATE TABLE t2(x,y); + INSERT INTO t2 VALUES(987,'zyx'),(654,'wvu'),(987,'rqp'); + + SELECT *, '|' FROM t1, t2 WHERE a=234 AND x=987 ORDER BY +b; +} {234 def 987 rqp | 234 def 987 zyx | 234 ghi 987 rqp | 234 ghi 987 zyx |} +do_execsql_test autoindex4-1.1 { + SELECT *, '|' FROM t1, t2 WHERE a=234 AND x=555; +} {} + +do_execsql_test autoindex4-1.2 { + SELECT *, '|' FROM t1 LEFT JOIN t2 ON a=234 AND x=555; +} {123 abc {} {} | 234 def {} {} | 234 ghi {} {} | 345 jkl {} {} |} +do_execsql_test autoindex4-1.3 { + SELECT *, '|' FROM t1 LEFT JOIN t2 ON x=555 WHERE a=234; +} {234 def {} {} | 234 ghi {} {} |} +do_execsql_test autoindex4-1.4 { + SELECT *, '|' FROM t1 LEFT JOIN t2 WHERE a=234 AND x=555; +} {} + + +do_execsql_test autoindex4-2.0 { + CREATE TABLE t3(e,f); + INSERT INTO t3 VALUES(123,654),(555,444),(234,987); + + SELECT (SELECT count(*) FROM t1, t2 WHERE a=e AND x=f), e, f, '|' + FROM t3 + ORDER BY rowid; +} {1 123 654 | 0 555 444 | 4 234 987 |} + +# Ticket [2326c258d02ead33d] +# Two joins, one with and the other without an ORDER BY clause. +# The one without ORDER BY correctly returns two rows of result. +# The one with ORDER BY returns no rows. +# +do_execsql_test autoindex4-3.0 { + CREATE TABLE A(Name text); + CREATE TABLE Items(ItemName text , Name text); + INSERT INTO Items VALUES('Item1','Parent'); + INSERT INTO Items VALUES('Item2','Parent'); + CREATE TABLE B(Name text); + + SELECT Items.ItemName + FROM Items + LEFT JOIN A ON (A.Name = Items.ItemName and Items.ItemName = 'dummy') + LEFT JOIN B ON (B.Name = Items.ItemName) + WHERE Items.Name = 'Parent' + ORDER BY Items.ItemName; +} {Item1 Item2} +do_execsql_test autoindex4-3.1 { + CREATE INDEX Items_x1 ON Items(ItemName,Name) WHERE ItemName = 'dummy'; + + SELECT Items.ItemName + FROM Items + LEFT JOIN A ON (A.Name = Items.ItemName and Items.ItemName = 'dummy') + LEFT JOIN B ON (B.Name = Items.ItemName) + WHERE Items.Name = 'Parent' + ORDER BY Items.ItemName; +} {Item1 Item2} + + +finish_test diff --git a/test/backup.test b/test/backup.test index 444619c..3b1e1db 100644 --- a/test/backup.test +++ b/test/backup.test @@ -217,6 +217,7 @@ foreach nPagePerStep {1 200} { INSERT INTO ${file_dest}.t1 VALUES(1, randstr(1000,1000)) " $db_dest } + execsql COMMIT $db_dest } # Backup the source database. diff --git a/test/backup5.test b/test/backup5.test new file mode 100644 index 0000000..c789adf --- /dev/null +++ b/test/backup5.test @@ -0,0 +1,65 @@ +# 2014 November 13 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix backup5 + +forcedelete test2.db + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b); + CREATE TABLE t2(a, b); + INSERT INTO t2 VALUES(1, 1); + INSERT INTO t2 VALUES(2, 2); + INSERT INTO t2 VALUES(3, 3); +} + +do_test 1.1 { + forcecopy test.db test.db2 + db eval { + DROP TABLE t2; + INSERT INTO t1 VALUES(zeroblob(1000), zeroblob(1000)); + INSERT INTO t1 VALUES(randomblob(1000), randomblob(1000)); + } +} {} + +do_test 1.2 { + sqlite3 db2 test.db2 + set stmt [sqlite3_prepare_v2 db2 "SELECT * FROM t2" -1 dummy] + sqlite3_step $stmt +} {SQLITE_ROW} + +do_test 1.3 { + list [catch { sqlite3_backup B db2 main db main } msg] $msg +} {1 {sqlite3_backup_init() failed}} + +do_test 1.4 { + sqlite3_errmsg db2 +} {destination database is in use} + +do_test 1.5 { + sqlite3_reset $stmt + sqlite3_backup B db2 main db main + B step 200 + B finish +} {SQLITE_OK} + +do_test 1.6 { + list [sqlite3_step $stmt] [sqlite3_finalize $stmt] +} {SQLITE_ERROR SQLITE_ERROR} + +do_test 1.7 { + sqlite3_errmsg db2 +} {no such table: t2} + +finish_test diff --git a/test/bigsort.test b/test/bigsort.test new file mode 100644 index 0000000..c711515 --- /dev/null +++ b/test/bigsort.test @@ -0,0 +1,50 @@ +# 2014 November 26 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix bigsort + +#-------------------------------------------------------------------- +# At one point there was an overflow problem if the product of the +# cache-size and page-size was larger than 2^31. Causing an infinite +# loop if the product was also an integer multiple of 2^32, or +# inefficiency otherwise. +# +# This test causes thrashing on machines with smaller amounts of +# memory. Make sure the host has at least 8GB available before running +# this test. +# +if {[catch {exec free | grep Mem:} out] || [lindex $out 1]<8000000} { + finish_test + return +} + +do_execsql_test 1.0 { + PRAGMA page_size = 1024; + CREATE TABLE t1(a, b); + BEGIN; + WITH data(x,y) AS ( + SELECT 1, zeroblob(10000) + UNION ALL + SELECT x+1, y FROM data WHERE x < 300000 + ) + INSERT INTO t1 SELECT * FROM data; + COMMIT; +} +do_execsql_test 1.1 { + PRAGMA cache_size = 4194304; + CREATE INDEX i1 ON t1(a, b); +} + + +finish_test diff --git a/test/btree01.test b/test/btree01.test new file mode 100644 index 0000000..25f2c68 --- /dev/null +++ b/test/btree01.test @@ -0,0 +1,132 @@ +# 2014-11-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. +# +#*********************************************************************** +# +# This file contains test cases for b-tree logic. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix btree01 + +# The refactoring on the b-tree balance() routine in check-in +# http://www.sqlite.org/src/info/face33bea1ba3a (2014-10-27) +# caused the integrity_check on the following SQL to fail. +# +do_execsql_test btree01-1.1 { + PRAGMA page_size=65536; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB); + WITH RECURSIVE + c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30) + INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c; + UPDATE t1 SET b=zeroblob(3000); + UPDATE t1 SET b=zeroblob(64000) WHERE a=2; + PRAGMA integrity_check; +} {ok} + +# The previous test is sufficient to prevent a regression. But we +# add a number of additional tests to stress the balancer in similar +# ways, looking for related problems. +# +for {set i 1} {$i<=30} {incr i} { + do_test btree01-1.2.$i { + db eval { + DELETE FROM t1; + WITH RECURSIVE + c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30) + INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c; + UPDATE t1 SET b=zeroblob(3000); + UPDATE t1 SET b=zeroblob(64000) WHERE a=$::i; + PRAGMA integrity_check; + } + } {ok} +} +for {set i 1} {$i<=30} {incr i} { + do_test btree01-1.3.$i { + db eval { + DELETE FROM t1; + WITH RECURSIVE + c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30) + INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c; + UPDATE t1 SET b=zeroblob(2000); + UPDATE t1 SET b=zeroblob(64000) WHERE a=$::i; + PRAGMA integrity_check; + } + } {ok} +} +for {set i 1} {$i<=30} {incr i} { + do_test btree01-1.4.$i { + db eval { + DELETE FROM t1; + WITH RECURSIVE + c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30) + INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c; + UPDATE t1 SET b=zeroblob(6499) WHERE (a%3)==0; + UPDATE t1 SET b=zeroblob(6499) WHERE (a%3)==1; + UPDATE t1 SET b=zeroblob(6499) WHERE (a%3)==2; + UPDATE t1 SET b=zeroblob(64000) WHERE a=$::i; + PRAGMA integrity_check; + } + } {ok} +} +for {set i 1} {$i<=30} {incr i} { + do_test btree01-1.5.$i { + db eval { + DELETE FROM t1; + WITH RECURSIVE + c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30) + INSERT INTO t1(a,b) SELECT i, zeroblob(6542) FROM c; + UPDATE t1 SET b=zeroblob(2331); + UPDATE t1 SET b=zeroblob(65496) WHERE a=$::i; + PRAGMA integrity_check; + } + } {ok} +} +for {set i 1} {$i<=30} {incr i} { + do_test btree01-1.6.$i { + db eval { + DELETE FROM t1; + WITH RECURSIVE + c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30) + INSERT INTO t1(a,b) SELECT i, zeroblob(6542) FROM c; + UPDATE t1 SET b=zeroblob(2332); + UPDATE t1 SET b=zeroblob(65496) WHERE a=$::i; + PRAGMA integrity_check; + } + } {ok} +} +for {set i 1} {$i<=30} {incr i} { + do_test btree01-1.7.$i { + db eval { + DELETE FROM t1; + WITH RECURSIVE + c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30) + INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c; + UPDATE t1 SET b=zeroblob(1); + UPDATE t1 SET b=zeroblob(65000) WHERE a=$::i; + PRAGMA integrity_check; + } + } {ok} +} +for {set i 1} {$i<=31} {incr i} { + do_test btree01-1.8.$i { + db eval { + DELETE FROM t1; + WITH RECURSIVE + c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<31) + INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c; + UPDATE t1 SET b=zeroblob(4000); + UPDATE t1 SET b=zeroblob(65000) WHERE a=$::i; + PRAGMA integrity_check; + } + } {ok} +} + +finish_test diff --git a/test/capi3.test b/test/capi3.test index cbaa5c5..9f3d6f6 100644 --- a/test/capi3.test +++ b/test/capi3.test @@ -912,7 +912,7 @@ do_test capi3-11.9.3 { } 1 do_test capi3-11.10 { sqlite3_step $STMT -} {SQLITE_ERROR} +} {SQLITE_ROW} ifcapable !autoreset { # If SQLITE_OMIT_AUTORESET is defined, then the statement must be # reset() before it can be passed to step() again. @@ -921,11 +921,11 @@ ifcapable !autoreset { } do_test capi3-11.11 { sqlite3_step $STMT -} {SQLITE_ROW} +} {SQLITE_DONE} do_test capi3-11.12 { sqlite3_step $STMT sqlite3_step $STMT -} {SQLITE_DONE} +} {SQLITE_ROW} do_test capi3-11.13 { sqlite3_finalize $STMT } {SQLITE_OK} diff --git a/test/capi3c.test b/test/capi3c.test index 6388717..6ab3bc2 100644 --- a/test/capi3c.test +++ b/test/capi3c.test @@ -863,7 +863,7 @@ do_test capi3c-11.9.3 { } 1 do_test capi3c-11.10 { sqlite3_step $STMT -} {SQLITE_ABORT} +} {SQLITE_ROW} ifcapable !autoreset { # If SQLITE_OMIT_AUTORESET is defined, then the statement must be # reset() before it can be passed to step() again. @@ -872,11 +872,11 @@ ifcapable !autoreset { } do_test capi3c-11.11 { sqlite3_step $STMT -} {SQLITE_ROW} +} {SQLITE_DONE} do_test capi3c-11.12 { sqlite3_step $STMT sqlite3_step $STMT -} {SQLITE_DONE} +} {SQLITE_ROW} do_test capi3c-11.13 { sqlite3_finalize $STMT } {SQLITE_OK} diff --git a/test/capi3d.test b/test/capi3d.test index fb8abe8..1459c5a 100644 --- a/test/capi3d.test +++ b/test/capi3d.test @@ -155,7 +155,6 @@ do_execsql_test capi3d-4.1 { } do_test capi3d-4.2.1 { - breakpoint set ::s1 [sqlite3_prepare_v2 db "ROLLBACK" -1 notused] sqlite3_step $::s1 } {SQLITE_DONE} diff --git a/test/colmeta.test b/test/colmeta.test index 3939f82..21b0e0f 100644 --- a/test/colmeta.test +++ b/test/colmeta.test @@ -17,17 +17,14 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !columnmetadata { - finish_test - return -} - # Set up a schema in the main and temp test databases. do_test colmeta-0 { execsql { CREATE TABLE abc(a, b, c); CREATE TABLE abc2(a PRIMARY KEY COLLATE NOCASE, b VARCHAR(32), c); CREATE TABLE abc3(a NOT NULL, b INTEGER PRIMARY KEY, c); + CREATE TABLE abc5(w,x,y,z,PRIMARY KEY(x,z)) WITHOUT ROWID; + CREATE TABLE abc6(rowid TEXT COLLATE rtrim, oid REAL, _rowid_ BLOB); } ifcapable autoinc { execsql { @@ -57,19 +54,27 @@ set tests { 13 {main abc rowid} {0 {INTEGER BINARY 0 1 0}} 14 {main abc3 rowid} {0 {INTEGER BINARY 0 1 0}} 16 {main abc d} {1 {no such table column: abc.d}} + 20 {main abc5 w} {0 {{} BINARY 0 0 0}} + 21 {main abc5 x} {0 {{} BINARY 1 1 0}} + 22 {main abc5 y} {0 {{} BINARY 0 0 0}} + 23 {main abc5 z} {0 {{} BINARY 1 1 0}} + 24 {main abc5 rowid} {1 {no such table column: abc5.rowid}} + 30 {main abc6 rowid} {0 {TEXT rtrim 0 0 0}} + 31 {main abc6 oid} {0 {REAL BINARY 0 0 0}} + 32 {main abc6 _rowid_} {0 {BLOB BINARY 0 0 0}} } -ifcapable view { +ifcapable autoinc { set tests [concat $tests { - 8 {{} abc4 b} {0 {INTEGER BINARY 0 1 1}} - 15 {main abc4 rowid} {0 {INTEGER BINARY 0 1 1}} + 100 {{} abc4 b} {0 {INTEGER BINARY 0 1 1}} + 101 {main abc4 rowid} {0 {INTEGER BINARY 0 1 1}} }] } ifcapable view { set tests [concat $tests { - 9 {{} v1 a} {1 {no such table column: v1.a}} - 10 {main v1 b} {1 {no such table column: v1.b}} - 11 {main v1 badname} {1 {no such table column: v1.badname}} - 12 {main v1 rowid} {1 {no such table column: v1.rowid}} + 200 {{} v1 a} {1 {no such table column: v1.a}} + 201 {main v1 b} {1 {no such table column: v1.b}} + 202 {main v1 badname} {1 {no such table column: v1.badname}} + 203 {main v1 rowid} {1 {no such table column: v1.rowid}} }] } @@ -91,4 +96,15 @@ foreach {tn params results} $tests { } $results } +# Calling sqlite3_table_column_metadata with a NULL column name merely +# checks for the existance of the table. +# +do_test colmeta-300 { + catch {sqlite3_table_column_metadata $::DB main xyzzy} res +} {1} +do_test colmeta-301 { + catch {sqlite3_table_column_metadata $::DB main abc} res +} {0} + + finish_test diff --git a/test/corruptH.test b/test/corruptH.test index ee2bb1e..5c83cb3 100644 --- a/test/corruptH.test +++ b/test/corruptH.test @@ -64,7 +64,6 @@ do_test 1.2 { } {} do_test 1.3 { -breakpoint db eval { PRAGMA secure_delete=1 } list [catch { db eval { SELECT * FROM t1 WHERE a IN (1, 2) } { diff --git a/test/corruptI.test b/test/corruptI.test index 41200c5..c8d0176 100644 --- a/test/corruptI.test +++ b/test/corruptI.test @@ -75,31 +75,34 @@ do_test 2.2 { catchsql { SELECT * FROM r WHERE x >= 10 } } {1 {database disk image is malformed}} -reset_db - -do_execsql_test 3.1 { - PRAGMA page_size = 512; - CREATE TABLE t1(a INTEGER PRIMARY KEY, b); - WITH s(a, b) AS ( - SELECT 2, 'abcdefghij' - UNION ALL - SELECT a+2, b FROM s WHERe a < 40 - ) - INSERT INTO t1 SELECT * FROM s; -} {} - -do_test 3.2 { - hexio_write test.db [expr 512+3] 0054 - db close - sqlite3 db test.db - execsql { INSERT INTO t1 VALUES(5, 'klmnopqrst') } - execsql { INSERT INTO t1 VALUES(7, 'klmnopqrst') } -} {} - -db close -sqlite3 db test.db -do_catchsql_test 3.2 { - INSERT INTO t1 VALUES(9, 'klmnopqrst'); -} {1 {database disk image is malformed}} - +if {[db one {SELECT sqlite_compileoption_used('ENABLE_OVERSIZE_CELL_CHECK')}]} { + # The following tests only work if OVERSIZE_CELL_CHECK is disabled +} else { + reset_db + do_execsql_test 3.1 { + PRAGMA auto_vacuum=0; + PRAGMA page_size = 512; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + WITH s(a, b) AS ( + SELECT 2, 'abcdefghij' + UNION ALL + SELECT a+2, b FROM s WHERe a < 40 + ) + INSERT INTO t1 SELECT * FROM s; + } {} + + do_test 3.2 { + hexio_write test.db [expr 512+3] 0054 + db close + sqlite3 db test.db + execsql { INSERT INTO t1 VALUES(5, 'klmnopqrst') } + execsql { INSERT INTO t1 VALUES(7, 'klmnopqrst') } + } {} + + db close + sqlite3 db test.db + do_catchsql_test 3.3 { + INSERT INTO t1 VALUES(9, 'klmnopqrst'); + } {1 {database disk image is malformed}} +} ;# end-if !defined(ENABLE_OVERSIZE_CELL_CHECK) finish_test diff --git a/test/default.test b/test/default.test index d6b6f97..406eb53 100644 --- a/test/default.test +++ b/test/default.test @@ -99,4 +99,32 @@ do_execsql_test default-3.3 { SELECT * FROM t300; } {2147483647 2147483648 9223372036854775807 -2147483647 -2147483648 -9223372036854775808 9.22337203685478e+18 9223372036854775807} +# Do now allow bound parameters in new DEFAULT values. +# Silently convert bound parameters to NULL in DEFAULT causes +# in the sqlite_master table, for backwards compatibility. +# +db close +forcedelete test.db +sqlite3 db test.db +do_execsql_test default-4.0 { + CREATE TABLE t1(a TEXT, b TEXT DEFAULT(99)); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE TABLE t1(a TEXT, b TEXT DEFAULT(:xyz))'; +} {} +db close +sqlite3 db test.db +do_execsql_test default-4.1 { + INSERT INTO t1(a) VALUES('xyzzy'); + SELECT a, quote(b) FROM t1; +} {xyzzy NULL} +do_catchsql_test default-4.2 { + CREATE TABLE t2(a TEXT, b TEXT DEFAULT(:xyz)); +} {1 {default value of column [b] is not constant}} +do_catchsql_test default-4.3 { + CREATE TABLE t2(a TEXT, b TEXT DEFAULT(abs(:xyz))); +} {1 {default value of column [b] is not constant}} +do_catchsql_test default-4.4 { + CREATE TABLE t2(a TEXT, b TEXT DEFAULT(98+coalesce(5,:xyz))); +} {1 {default value of column [b] is not constant}} + finish_test diff --git a/test/distinct.test b/test/distinct.test index 78c2c1d..2fb90dc 100644 --- a/test/distinct.test +++ b/test/distinct.test @@ -222,4 +222,34 @@ do_execsql_test 4.1 { SELECT quote(x) FROM t2 ORDER BY 1; } {'xyzzy' X'0000000000'} +#---------------------------------------------------------------------------- +# Ticket [c5ea805691bfc4204b1cb9e9aa0103bd48bc7d34] (2014-12-04) +# Make sure that DISTINCT works together with ORDER BY and descending +# indexes. +# +do_execsql_test 5.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(x); + INSERT INTO t1(x) VALUES(3),(1),(5),(2),(6),(4),(5),(1),(3); + CREATE INDEX t1x ON t1(x DESC); + SELECT DISTINCT x FROM t1 ORDER BY x ASC; +} {1 2 3 4 5 6} +do_execsql_test 5.2 { + SELECT DISTINCT x FROM t1 ORDER BY x DESC; +} {6 5 4 3 2 1} +do_execsql_test 5.3 { + SELECT DISTINCT x FROM t1 ORDER BY x; +} {1 2 3 4 5 6} +do_execsql_test 5.4 { + DROP INDEX t1x; + CREATE INDEX t1x ON t1(x ASC); + SELECT DISTINCT x FROM t1 ORDER BY x ASC; +} {1 2 3 4 5 6} +do_execsql_test 5.5 { + SELECT DISTINCT x FROM t1 ORDER BY x DESC; +} {6 5 4 3 2 1} +do_execsql_test 5.6 { + SELECT DISTINCT x FROM t1 ORDER BY x; +} {1 2 3 4 5 6} + finish_test diff --git a/test/e_blobbytes.test b/test/e_blobbytes.test new file mode 100644 index 0000000..a6283ab --- /dev/null +++ b/test/e_blobbytes.test @@ -0,0 +1,76 @@ +# 2014 October 30 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix e_blobbytes + +do_execsql_test 1.0 { + CREATE TABLE q1(r INTEGER PRIMARY KEY, s TEXT); + WITH d(a, b) AS ( + SELECT 0, '' + UNION ALL + SELECT a+1, b||'.' FROM d WHERE a<10000 + ) + INSERT INTO q1 SELECT * FROM d; +} + + +# EVIDENCE-OF: R-07796-55423 Returns the size in bytes of the BLOB +# accessible via the successfully opened BLOB handle in its only +# argument. +# +proc check_blob_size {tn rowid bytes} { + uplevel [list do_test $tn [subst -nocommands { + sqlite3_blob_open db main q1 s $rowid 0 B + set res [sqlite3_blob_bytes [set B]] + sqlite3_blob_close [set B] + set res + }] $bytes] +} +check_blob_size 1.1 43 43 +check_blob_size 1.2 391 391 +check_blob_size 1.3 6349 6349 +check_blob_size 1.4 2621 2621 +check_blob_size 1.5 7771 7771 +check_blob_size 1.6 7949 7949 +check_blob_size 1.7 4374 4374 +check_blob_size 1.8 2578 2578 +check_blob_size 1.9 7004 7004 +check_blob_size 1.10 2180 2180 +check_blob_size 1.11 3796 3796 +check_blob_size 1.12 7101 7101 +check_blob_size 1.13 7449 7449 +check_blob_size 1.14 7224 7224 +check_blob_size 1.15 3038 3038 +check_blob_size 1.16 1083 1083 +check_blob_size 1.17 5157 5157 +check_blob_size 1.18 6686 6686 +check_blob_size 1.19 6592 6592 +check_blob_size 1.20 0 0 + + +# EVIDENCE-OF: R-53088-19343 The incremental blob I/O routines can only +# read or overwriting existing blob content; they cannot change the size +# of a blob. +# +# Also demonstrated in other e_blobXXX.test files. +# +do_test 2.1 { + sqlite3_blob_open db main q1 s 86 1 B + list [catch { sqlite3_blob_write $B 86 "1" 1 } msg] $msg +} {1 SQLITE_ERROR} +sqlite3_blob_close $B + +finish_test + + diff --git a/test/e_blobclose.test b/test/e_blobclose.test new file mode 100644 index 0000000..a5d432d --- /dev/null +++ b/test/e_blobclose.test @@ -0,0 +1,171 @@ +# 2014 October 30 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix e_blobclose + +set dots [string repeat . 40] +do_execsql_test 1.0 { + CREATE TABLE x1(a INTEGER PRIMARY KEY, b DOTS); + INSERT INTO x1 VALUES(-1, $dots); + INSERT INTO x1 VALUES(-10, $dots); + INSERT INTO x1 VALUES(-100, $dots); + INSERT INTO x1 VALUES(-1000, $dots); + INSERT INTO x1 VALUES(-10000, $dots); +} + +# EVIDENCE-OF: R-03145-46390 This function closes an open BLOB handle. +# +# It's not clear how to test that a blob handle really is closed. +# Attempting to use a closed blob handle will likely crash the process. +# Assume here that if the SHARED lock on the db file is released, +# the blob handle has been closed. +# +do_execsql_test 1.1 { PRAGMA lock_status } {main unlocked temp closed} +sqlite3_blob_open db main x1 b -1 0 B +do_execsql_test 1.2 { PRAGMA lock_status } {main shared temp closed} +sqlite3_blob_close $B +do_execsql_test 1.3 { PRAGMA lock_status } {main unlocked temp closed} + + +# EVIDENCE-OF: R-34027-00617 If the blob handle being closed was opened +# for read-write access, and if the database is in auto-commit mode and +# there are no other open read-write blob handles or active write +# statements, the current transaction is committed. +# +# 2.1.*: Transaction is not committed if there are other open +# read-write blob handles. +# +# 2.2.*: Transaction is not committed if not in auto-commit mode. +# +# 2.3.*: Active write statements. +# +do_test 2.1.1 { + sqlite3_blob_open db main x1 b -100 1 B1 + sqlite3_blob_open db main x1 b -1000 1 B2 + sqlite3_blob_open db main x1 b -10000 1 B3 + sqlite3_blob_open db main x1 b -10000 0 B4 ;# B4 is read-only! + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.1.2 { + sqlite3_blob_close $B1 + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.1.3 { + sqlite3_blob_close $B2 + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.1.4 { + sqlite3_blob_close $B3 + execsql { PRAGMA lock_status } +} {main shared temp closed} +do_test 2.1.5 { + sqlite3_blob_close $B4 + execsql { PRAGMA lock_status } +} {main unlocked temp closed} + +do_test 2.2.1 { + sqlite3_blob_open db main x1 b -100 1 B1 + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.2.2 { + execsql { BEGIN } + sqlite3_blob_close $B1 + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.2.3 { + execsql { COMMIT } + execsql { PRAGMA lock_status } +} {main unlocked temp closed} + +proc val {} { + sqlite3_blob_close $::B + db eval { PRAGMA lock_status } +} +db func val val +do_test 2.3.1 { + sqlite3_blob_open db main x1 b -100 1 B + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.3.2 { + execsql { INSERT INTO x1 VALUES(15, val()) } + execsql { PRAGMA lock_status } +} {main unlocked temp closed} +do_test 2.3.3 { + execsql { SELECT * FROM x1 WHERE a = 15 } +} {15 {main reserved temp closed}} + +# A reader does not inhibit commit. +do_test 2.3.4 { + sqlite3_blob_open db main x1 b -100 1 B + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.3.5 { + execsql { SELECT a, val() FROM x1 LIMIT 1 } +} {-10000 {main shared temp closed}} + + +do_test 3.1 { + sqlite3_blob_open db main x1 b -10 1 B + execsql { + INSERT INTO x1 VALUES(1, 'abc'); + SELECT * FROM x1 WHERE a=1; + } +} {1 abc} +do_test 3.2 { + sqlite3_blob_write $B 0 "abcdefghij" 10 + execsql { SELECT * FROM x1 WHERE a=-10 } +} {-10 abcdefghij..............................} + +do_test 3.3 { + sqlite3 db2 test.db + execsql { BEGIN ; SELECT * FROM x1 } db2 + sqlite3_blob_close $B +} {SQLITE_BUSY} + +# EVIDENCE-OF: R-41959-38737 Otherwise, if this function is passed a +# valid open blob handle, the values returned by the sqlite3_errcode() +# and sqlite3_errmsg() functions are set before returning. +# +do_test 3.4 { + list [sqlite3_errcode db] [sqlite3_errmsg db] +} {SQLITE_BUSY {database is locked}} + +# EVIDENCE-OF: R-37801-37633 The BLOB handle is closed unconditionally. +# Even if this routine returns an error code, the handle is still +# closed. +# +# Test that the lock has been released. Assume this means the handle +# is closed, even though blob_close() returned SQLITE_BUSY. +# +do_execsql_test 3.4 { PRAGMA lock_status } {main unlocked temp closed} + +# EVIDENCE-OF: R-35111-05628 If an error occurs while committing the +# transaction, an error code is returned and the transaction rolled +# back. +# +# Row 1 is removed (it was inserted this transaction) and row -10 +# is restored to its original state. Transaction has been rolled back. +# +do_execsql_test 3.5 { + SELECT * FROM x1 WHERE a IN (1, -10); +} {-10 ........................................} + +# EVIDENCE-OF: R-25894-51060 Calling this routine with a null pointer +# (such as would be returned by a failed call to sqlite3_blob_open()) is +# a harmless no-op. +# +do_test 4.0 { sqlite3_blob_close 0 } {} + +finish_test + diff --git a/test/e_blobopen.test b/test/e_blobopen.test new file mode 100644 index 0000000..01f62cd --- /dev/null +++ b/test/e_blobopen.test @@ -0,0 +1,549 @@ +# 2014 October 30 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix e_blobopen + +forcedelete test.db2 + +do_execsql_test 1.0 { + ATTACH 'test.db2' AS aux; + + CREATE TABLE main.t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + CREATE TEMP TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + + CREATE TABLE main.x1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + CREATE TEMP TABLE x2(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + CREATE TABLE aux.x3(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + + INSERT INTO main.t1 VALUES(1, 'main one', X'0101'); + INSERT INTO main.t1 VALUES(2, 'main two', X'0102'); + INSERT INTO main.t1 VALUES(3, 'main three', X'0103'); + INSERT INTO main.t1 VALUES(4, 'main four', X'0104'); + INSERT INTO main.t1 VALUES(5, 'main five', X'0105'); + + INSERT INTO main.x1 VALUES(1, 'x main one', X'000101'); + INSERT INTO main.x1 VALUES(2, 'x main two', X'000102'); + INSERT INTO main.x1 VALUES(3, 'x main three', X'000103'); + INSERT INTO main.x1 VALUES(4, 'x main four', X'000104'); + INSERT INTO main.x1 VALUES(5, 'x main five', X'000105'); + + INSERT INTO temp.t1 VALUES(1, 'temp one', X'0201'); + INSERT INTO temp.t1 VALUES(2, 'temp two', X'0202'); + INSERT INTO temp.t1 VALUES(3, 'temp three', X'0203'); + INSERT INTO temp.t1 VALUES(4, 'temp four', X'0204'); + INSERT INTO temp.t1 VALUES(5, 'temp five', X'0205'); + + INSERT INTO temp.x2 VALUES(1, 'x temp one', X'000201'); + INSERT INTO temp.x2 VALUES(2, 'x temp two', X'000202'); + INSERT INTO temp.x2 VALUES(3, 'x temp three', X'000203'); + INSERT INTO temp.x2 VALUES(4, 'x temp four', X'000204'); + INSERT INTO temp.x2 VALUES(5, 'x temp five', X'000205'); + + INSERT INTO aux.t1 VALUES(1, 'aux one', X'0301'); + INSERT INTO aux.t1 VALUES(2, 'aux two', X'0302'); + INSERT INTO aux.t1 VALUES(3, 'aux three', X'0303'); + INSERT INTO aux.t1 VALUES(4, 'aux four', X'0304'); + INSERT INTO aux.t1 VALUES(5, 'aux five', X'0305'); + + INSERT INTO aux.x3 VALUES(1, 'x aux one', X'000301'); + INSERT INTO aux.x3 VALUES(2, 'x aux two', X'000302'); + INSERT INTO aux.x3 VALUES(3, 'x aux three', X'000303'); + INSERT INTO aux.x3 VALUES(4, 'x aux four', X'000304'); + INSERT INTO aux.x3 VALUES(5, 'x aux five', X'000305'); +} + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-37639-55938 This interfaces opens a handle to the BLOB +# located in row iRow, column zColumn, table zTable in database zDb; in +# other words, the same BLOB that would be selected by: SELECT zColumn +# FROM zDb.zTable WHERE rowid = iRow; +# +proc read_blob {zDb zTab zCol iRow} { + sqlite3_blob_open db $zDb $zTab $zCol $iRow 0 B + set nByte [sqlite3_blob_bytes $B] + set data [sqlite3_blob_read $B 0 $nByte] + sqlite3_blob_close $B + return $data +} + +do_test 1.1.1 { read_blob main t1 b 1 } "main one" +do_test 1.1.2 { read_blob main t1 c 1 } "\01\01" +do_test 1.1.3 { read_blob temp t1 b 1 } "temp one" +do_test 1.1.4 { read_blob temp t1 c 1 } "\02\01" +do_test 1.1.6 { read_blob aux t1 b 1 } "aux one" +do_test 1.1.7 { read_blob aux t1 c 1 } "\03\01" + +do_test 1.2.1 { read_blob main t1 b 4 } "main four" +do_test 1.2.2 { read_blob main t1 c 4 } "\01\04" +do_test 1.2.3 { read_blob temp t1 b 4 } "temp four" +do_test 1.2.4 { read_blob temp t1 c 4 } "\02\04" +do_test 1.2.6 { read_blob aux t1 b 4 } "aux four" +do_test 1.2.7 { read_blob aux t1 c 4 } "\03\04" + +do_test 1.3.1 { read_blob main x1 b 2 } "x main two" +do_test 1.3.2 { read_blob main x1 c 2 } "\00\01\02" +do_test 1.3.3 { read_blob temp x2 b 2 } "x temp two" +do_test 1.3.4 { read_blob temp x2 c 2 } "\00\02\02" +do_test 1.3.6 { read_blob aux x3 b 2 } "x aux two" +do_test 1.3.7 { read_blob aux x3 c 2 } "\00\03\02" + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-27234-05761 Parameter zDb is not the filename that +# contains the database, but rather the symbolic name of the database. +# For attached databases, this is the name that appears after the AS +# keyword in the ATTACH statement. For the main database file, the +# database name is "main". For TEMP tables, the database name is "temp". +# +# The test cases immediately above demonstrate that the database name +# for the main db, for TEMP tables and for those in attached databases +# is correct. The following tests check that filenames cannot be +# used as well. +# +do_test 2.1 { + list [catch { sqlite3_blob_open db "test.db" t1 b 1 0 B } msg] $msg +} {1 SQLITE_ERROR} +do_test 2.2 { + list [catch { sqlite3_blob_open db "test.db2" t1 b 1 0 B } msg] $msg +} {1 SQLITE_ERROR} + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-50854-53979 If the flags parameter is non-zero, then +# the BLOB is opened for read and write access. +# +# EVIDENCE-OF: R-03922-41160 If the flags parameter is zero, the BLOB is +# opened for read-only access. +# +foreach {tn iRow flags} { + 1 1 0 + 2 2 1 + 3 3 -1 + 4 4 2147483647 + 5 5 -2147483648 +} { + do_test 3.$tn.1 { + sqlite3_blob_open db main x1 c $iRow $flags B + set n [sqlite3_blob_bytes $B] + sqlite3_blob_read $B 0 $n + } [binary format ccc 0 1 $iRow] + + if {$flags==0} { + # Blob was opened for read-only access - writing returns an error. + do_test 3.$tn.2 { + list [catch { sqlite3_blob_write $B 0 xxx 3 } msg] $msg + } {1 SQLITE_READONLY} + + do_execsql_test 3.$tn.3 { + SELECT c FROM x1 WHERE a=$iRow; + } [binary format ccc 0 1 $iRow] + } else { + # Blob was opened for read/write access - writing succeeds + do_test 3.$tn.4 { + list [catch { sqlite3_blob_write $B 0 xxx 3 } msg] $msg + } {0 {}} + + do_execsql_test 3.$tn.5 { + SELECT c FROM x1 WHERE a=$iRow; + } {xxx} + } + + sqlite3_blob_close $B +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 4.0 { + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES('abcd', 152); + INSERT INTO t1 VALUES(NULL, X'00010203'); + INSERT INTO t1 VALUES('', 154.2); + + CREATE TABLE t2(x PRIMARY KEY, y) WITHOUT ROWID; + INSERT INTO t2 VALUES(1, 'blob'); + + CREATE TABLE t3(a PRIMARY KEY, b, c, d, e, f, UNIQUE(e, f)); + INSERT INTO t3 VALUES('aaaa', 'bbbb', 'cccc', 'dddd', 'eeee', 'ffff'); + CREATE INDEX t3b ON t3(b); + + CREATE TABLE p1(x PRIMARY KEY); + INSERT INTO p1 VALUES('abc'); + + CREATE TABLE c1(a INTEGER PRIMARY KEY, b REFERENCES p1); + INSERT INTO c1 VALUES(45, 'abc'); +} + +proc test_blob_open {tn zDb zTab zCol iRow flags errcode errmsg} { + global B + set B "0x1234" + + if {$errcode=="SQLITE_OK"} { + set expected "0 {}" + } else { + set expected "1 $errcode" + } + + set ::res [list [ + catch { sqlite3_blob_open db $zDb $zTab $zCol $iRow $flags B } msg + ] $msg] + do_test 4.$tn.1 { set ::res } $expected + + # EVIDENCE-OF: R-08940-21305 Unless it returns SQLITE_MISUSE, this + # function sets the database connection error code and message + # accessible via sqlite3_errcode() and sqlite3_errmsg() and related + # functions. + # + # This proc (test_blob_open) is used below to test various error and + # non-error conditions. But never SQLITE_MISUSE conditions. So these + # test cases are considered as partly verifying the requirement above. + # See below for a test of the SQLITE_MISUSE case. + # + do_test 4.$tn.2 { + sqlite3_errcode db + } $errcode + do_test 4.$tn.3 { + sqlite3_errmsg db + } $errmsg + + # EVIDENCE-OF: R-31086-35521 On success, SQLITE_OK is returned and the + # new BLOB handle is stored in *ppBlob. Otherwise an error code is + # returned and, unless the error code is SQLITE_MISUSE, *ppBlob is set + # to NULL. + # + do_test 4.$tn.4 { + expr {$B == "0"} + } [expr {$errcode != "SQLITE_OK"}] + + # EVIDENCE-OF: R-63421-15521 This means that, provided the API is not + # misused, it is always safe to call sqlite3_blob_close() on *ppBlob + # after this function it returns. + do_test 4.$tn.5 { + sqlite3_blob_close $B + } {} +} + +# EVIDENCE-OF: R-31204-44780 Database zDb does not exist +test_blob_open 1 nosuchdb t1 x 1 0 SQLITE_ERROR "no such table: nosuchdb.t1" + +# EVIDENCE-OF: R-28676-08005 Table zTable does not exist within database zDb +test_blob_open 2 main tt1 x 1 0 SQLITE_ERROR "no such table: main.tt1" + +# EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table +test_blob_open 3 main t2 y 1 0 SQLITE_ERROR \ + "cannot open table without rowid: t2" + +# EVIDENCE-OF: R-56376-21261 Column zColumn does not exist +test_blob_open 4 main t1 z 2 0 SQLITE_ERROR "no such column: \"z\"" + +# EVIDENCE-OF: R-28258-23166 Row iRow is not present in the table +test_blob_open 5 main t1 y 6 0 SQLITE_ERROR "no such rowid: 6" + +# EVIDENCE-OF: R-11683-62380 The specified column of row iRow contains a +# value that is not a TEXT or BLOB value +test_blob_open 6 main t1 x 2 0 SQLITE_ERROR "cannot open value of type null" +test_blob_open 7 main t1 y 1 0 SQLITE_ERROR "cannot open value of type integer" +test_blob_open 8 main t1 y 3 0 SQLITE_ERROR "cannot open value of type real" + +# EVIDENCE-OF: R-34146-30782 Column zColumn is part of an index, PRIMARY +# KEY or UNIQUE constraint and the blob is being opened for read/write +# access +# +# Test cases 8.1.* show that such columns can be opened for read-access. +# Tests 8.2.* show that read-write access is different. Columns "c" and "c" +# are not part of an index, PK or UNIQUE constraint, so they work in both +# cases. +# +test_blob_open 8.1.1 main t3 a 1 0 SQLITE_OK "not an error" +test_blob_open 8.1.2 main t3 b 1 0 SQLITE_OK "not an error" +test_blob_open 8.1.3 main t3 c 1 0 SQLITE_OK "not an error" +test_blob_open 8.1.4 main t3 d 1 0 SQLITE_OK "not an error" +test_blob_open 8.1.5 main t3 e 1 0 SQLITE_OK "not an error" +test_blob_open 8.1.6 main t3 f 1 0 SQLITE_OK "not an error" + +set cannot "cannot open indexed column for writing" +test_blob_open 8.2.1 main t3 a 1 8 SQLITE_ERROR $cannot +test_blob_open 8.2.2 main t3 b 1 8 SQLITE_ERROR $cannot +test_blob_open 8.2.3 main t3 c 1 8 SQLITE_OK "not an error" +test_blob_open 8.2.4 main t3 d 1 8 SQLITE_OK "not an error" +test_blob_open 8.2.5 main t3 e 1 8 SQLITE_ERROR $cannot +test_blob_open 8.2.6 main t3 f 1 8 SQLITE_ERROR $cannot + +# EVIDENCE-OF: R-50117-55204 Foreign key constraints are enabled, column +# zColumn is part of a child key definition and the blob is being opened +# for read/write access +# +# 9.1: FK disabled, read-only access. +# 9.2: FK disabled, read-only access. +# 9.3: FK enabled, read/write access. +# 9.4: FK enabled, read/write access. +# +test_blob_open 9.1 main c1 b 45 0 SQLITE_OK "not an error" +test_blob_open 9.2 main c1 b 45 1 SQLITE_OK "not an error" +execsql { PRAGMA foreign_keys = ON } +test_blob_open 9.3 main c1 b 45 0 SQLITE_OK "not an error" +test_blob_open 9.4 main c1 b 45 1 SQLITE_ERROR \ + "cannot open foreign key column for writing" + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-08940-21305 Unless it returns SQLITE_MISUSE, this +# function sets the database connection error code and message +# accessible via sqlite3_errcode() and sqlite3_errmsg() and related +# functions. +# +# This requirement is partially verified by the many uses of test +# command [test_blob_open] above. All that is left is to verify the +# SQLITE_MISUSE case. +# +# SQLITE_MISUSE is only returned if SQLITE_ENABLE_API_ARMOR is defined +# during compilation. +# +ifcapable api_armor { + sqlite3_blob_open db main t1 x 1 0 B + + do_test 10.1.1 { + list [catch {sqlite3_blob_open $B main t1 x 1 0 B2} msg] $msg + } {1 SQLITE_MISUSE} + do_test 10.1.2 { + list [sqlite3_errcode db] [sqlite3_errmsg db] + } {SQLITE_OK {not an error}} + sqlite3_blob_close $B + + do_test 10.2.1 { + list [catch {sqlite3_blob_open db main {} x 1 0 B} msg] $msg + } {1 SQLITE_MISUSE} + do_test 10.2.2 { + list [sqlite3_errcode db] [sqlite3_errmsg db] + } {SQLITE_OK {not an error}} +} + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-50542-62589 If the row that a BLOB handle points to is +# modified by an UPDATE, DELETE, or by ON CONFLICT side-effects then the +# BLOB handle is marked as "expired". This is true if any column of the +# row is changed, even a column other than the one the BLOB handle is +# open on. +# +# EVIDENCE-OF: R-48367-20048 Calls to sqlite3_blob_read() and +# sqlite3_blob_write() for an expired BLOB handle fail with a return +# code of SQLITE_ABORT. +# +# 11.2: read-only handle, DELETE. +# 11.3: read-only handle, UPDATE. +# 11.4: read-only handle, REPLACE. +# 11.5: read/write handle, DELETE. +# 11.6: read/write handle, UPDATE. +# 11.7: read/write handle, REPLACE. +# +do_execsql_test 11.1 { + CREATE TABLE b1(a INTEGER PRIMARY KEY, b, c UNIQUE); + INSERT INTO b1 VALUES(1, '1234567890', 1); + INSERT INTO b1 VALUES(2, '1234567890', 2); + INSERT INTO b1 VALUES(3, '1234567890', 3); + INSERT INTO b1 VALUES(4, '1234567890', 4); + INSERT INTO b1 VALUES(5, '1234567890', 5); + INSERT INTO b1 VALUES(6, '1234567890', 6); + + CREATE TABLE b2(a INTEGER PRIMARY KEY, b, c UNIQUE); + INSERT INTO b2 VALUES(1, '1234567890', 1); + INSERT INTO b2 VALUES(2, '1234567890', 2); + INSERT INTO b2 VALUES(3, '1234567890', 3); + INSERT INTO b2 VALUES(4, '1234567890', 4); + INSERT INTO b2 VALUES(5, '1234567890', 5); + INSERT INTO b2 VALUES(6, '1234567890', 6); +} + +do_test 11.2.1 { + sqlite3_blob_open db main b1 b 2 0 B + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.2.2 { + # Deleting a different row does not invalidate the blob handle. + execsql { DELETE FROM b1 WHERE a = 1 } + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.2.3 { + execsql { DELETE FROM b1 WHERE a = 2 } + list [catch { sqlite3_blob_read $B 0 10 } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.2.4 { + sqlite3_blob_close $B +} {} + +do_test 11.3.1 { + sqlite3_blob_open db main b1 b 3 0 B + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.3.2 { + # Updating a different row + execsql { UPDATE b1 SET c = 42 WHERE a=4 } + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.3.3 { + execsql { UPDATE b1 SET c = 43 WHERE a=3 } + list [catch { sqlite3_blob_read $B 0 10 } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.3.4 { + sqlite3_blob_close $B +} {} + +do_test 11.4.1 { + sqlite3_blob_open db main b1 b 6 0 B + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.4.2 { + # Replace a different row + execsql { INSERT OR REPLACE INTO b1 VALUES(10, 'abcdefghij', 5) } + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.4.3 { + execsql { INSERT OR REPLACE INTO b1 VALUES(11, 'abcdefghij', 6) } + list [catch { sqlite3_blob_read $B 0 10 } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.4.4 { + sqlite3_blob_close $B +} {} + +do_test 11.4.1 { + sqlite3_blob_open db main b2 b 2 1 B + sqlite3_blob_write $B 0 "abcdefghij" +} {} +do_test 11.4.2 { + # Deleting a different row does not invalidate the blob handle. + execsql { DELETE FROM b2 WHERE a = 1 } + sqlite3_blob_write $B 0 "ABCDEFGHIJ" +} {} +do_test 11.4.3 { + execsql { DELETE FROM b2 WHERE a = 2 } + list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.4.4 { + sqlite3_blob_close $B +} {} + +do_test 11.5.1 { + sqlite3_blob_open db main b2 b 3 1 B + sqlite3_blob_write $B 0 "abcdefghij" +} {} +do_test 11.5.2 { + # Updating a different row + execsql { UPDATE b2 SET c = 42 WHERE a=4 } + sqlite3_blob_write $B 0 "ABCDEFGHIJ" +} {} +do_test 11.5.3 { + execsql { UPDATE b2 SET c = 43 WHERE a=3 } + list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.5.4 { + sqlite3_blob_close $B +} {} + +do_test 11.6.1 { + sqlite3_blob_open db main b2 b 6 1 B + sqlite3_blob_write $B 0 "abcdefghij" +} {} +do_test 11.6.2 { + # Replace a different row + execsql { INSERT OR REPLACE INTO b2 VALUES(10, 'abcdefghij', 5) } + sqlite3_blob_write $B 0 "ABCDEFGHIJ" +} {} +do_test 11.6.3 { + execsql { INSERT OR REPLACE INTO b2 VALUES(11, 'abcdefghij', 6) } + list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.6.4 { + sqlite3_blob_close $B +} {} + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-45408-40694 Changes written into a BLOB prior to the +# BLOB expiring are not rolled back by the expiration of the BLOB. Such +# changes will eventually commit if the transaction continues to +# completion. +# +do_execsql_test 12.1 { + CREATE TABLE b3(x INTEGER PRIMARY KEY, y TEXT, z INTEGER); + INSERT INTO b3 VALUES(22, '..........', NULL); +} +do_test 12.2 { + sqlite3_blob_open db main b3 y 22 1 B + sqlite3_blob_write $B 0 "xxxxx" 5 +} {} +do_execsql_test 12.3 { + UPDATE b3 SET z = 'not null'; +} +do_test 12.4 { + list [catch {sqlite3_blob_write $B 5 "xxxxx" 5} msg] $msg +} {1 SQLITE_ABORT} +do_execsql_test 12.5 { + SELECT * FROM b3; +} {22 xxxxx..... {not null}} +do_test 12.5 { + sqlite3_blob_close $B +} {} +do_execsql_test 12.6 { + SELECT * FROM b3; +} {22 xxxxx..... {not null}} + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-58813-55036 The sqlite3_bind_zeroblob() and +# sqlite3_result_zeroblob() interfaces and the built-in zeroblob SQL +# function may be used to create a zero-filled blob to read or write +# using the incremental-blob interface. +# +do_execsql_test 13.1 { + CREATE TABLE c2(i INTEGER PRIMARY KEY, j); + INSERT INTO c2 VALUES(10, zeroblob(24)); +} + +do_test 13.2 { + set stmt [sqlite3_prepare_v2 db "INSERT INTO c2 VALUES(11, ?)" -1] + sqlite3_bind_zeroblob $stmt 1 45 + sqlite3_step $stmt + sqlite3_finalize $stmt +} {SQLITE_OK} + +# The blobs can be read: +# +do_test 13.3.1 { + sqlite3_blob_open db main c2 j 10 1 B + sqlite3_blob_open db main c2 j 11 1 B2 + list [sqlite3_blob_bytes $B] [sqlite3_blob_bytes $B2] +} {24 45} +do_test 13.3.2 { + sqlite3_blob_read $B 0 24 +} [string repeat [binary format c 0] 24] +do_test 13.3.3 { + sqlite3_blob_read $B2 0 45 +} [string repeat [binary format c 0] 45] + +# And also written: +# +do_test 13.4.1 { + sqlite3_blob_write $B 0 [string repeat [binary format c 1] 24] +} {} +do_test 13.4.2 { + sqlite3_blob_write $B2 0 [string repeat [binary format c 1] 45] +} {} +do_test 13.5 { + sqlite3_blob_close $B + sqlite3_blob_close $B2 + execsql { SELECT j FROM c2 } +} [list \ + [string repeat [binary format c 1] 24] \ + [string repeat [binary format c 1] 45] \ +] + + +finish_test + diff --git a/test/e_blobwrite.test b/test/e_blobwrite.test new file mode 100644 index 0000000..a0d3333 --- /dev/null +++ b/test/e_blobwrite.test @@ -0,0 +1,204 @@ +# 2014 October 30 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix e_blobwrite + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-62898-22698 This function is used to write data into an +# open BLOB handle from a caller-supplied buffer. N bytes of data are +# copied from the buffer Z into the open BLOB, starting at offset +# iOffset. +# +set dots [string repeat . 40] +do_execsql_test 1.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, t TEXT); + INSERT INTO t1 VALUES(-1, $dots); + INSERT INTO t1 VALUES(-2, $dots); + INSERT INTO t1 VALUES(-3, $dots); + INSERT INTO t1 VALUES(-4, $dots); + INSERT INTO t1 VALUES(-5, $dots); + INSERT INTO t1 VALUES(-6, $dots); +} + +proc blob_write_test {tn id iOffset blob nData final} { + sqlite3_blob_open db main t1 t $id 1 B + + # EVIDENCE-OF: R-45864-01884 On success, sqlite3_blob_write() returns + # SQLITE_OK. Otherwise, an error code or an extended error code is + # returned. + # + # This block tests the SQLITE_OK case in the requirement above (the + # Tcl sqlite3_blob_write() wrapper uses an empty string in place of + # "SQLITE_OK"). The error cases are tested by the "blob_write_error_test" + # tests below. + # + set res [sqlite3_blob_write $B $iOffset $blob $nData] + uplevel [list do_test $tn.1 [list set {} $res] {}] + + sqlite3_blob_close $B + uplevel [list do_execsql_test $tn.3 "SELECT t FROM t1 WHERE a=$id" $final] +} + +set blob "0123456789012345678901234567890123456789" +blob_write_test 1.1 -1 0 $blob 10 { 0123456789.............................. } +blob_write_test 1.2 -2 8 $blob 10 { ........0123456789...................... } +blob_write_test 1.3 -3 8 $blob 1 { ........0............................... } +blob_write_test 1.4 -4 18 $blob 22 { ..................0123456789012345678901 } +blob_write_test 1.5 -5 18 $blob 0 { ........................................ } +blob_write_test 1.6 -6 0 $blob 40 { 0123456789012345678901234567890123456789 } + + +proc blob_write_error_test {tn B iOffset blob nData errcode errmsg} { + + # In cases where the underlying sqlite3_blob_write() function returns + # SQLITE_OK, the Tcl wrapper returns an empty string. If the underlying + # function returns an error, the Tcl wrapper throws an exception with + # the error code as the Tcl exception message. + # + if {$errcode=="SQLITE_OK"} { + set ret "" + set isError 0 + } else { + set ret $errcode + set isError 1 + } + + set cmd [list sqlite3_blob_write $B $iOffset $blob $nData] + uplevel [list do_test $tn.1 [subst -nocommands { + list [catch {$cmd} msg] [set msg] + }] [list $isError $ret]] + + # EVIDENCE-OF: R-34782-18311 Unless SQLITE_MISUSE is returned, this + # function sets the database connection error code and message + # accessible via sqlite3_errcode() and sqlite3_errmsg() and related + # functions. + # + if {$errcode == "SQLITE_MISUSE"} { error "test proc misuse!" } + uplevel [list do_test $tn.2 [list sqlite3_errcode db] $errcode] + uplevel [list do_test $tn.3 [list sqlite3_errmsg db] $errmsg] +} + +do_execsql_test 2.0 { + CREATE TABLE t2(a TEXT, b INTEGER PRIMARY KEY); + INSERT INTO t2 VALUES($dots, 43); + INSERT INTO t2 VALUES($dots, 44); + INSERT INTO t2 VALUES($dots, 45); +} + +# EVIDENCE-OF: R-63341-57517 If the BLOB handle passed as the first +# argument was not opened for writing (the flags parameter to +# sqlite3_blob_open() was zero), this function returns SQLITE_READONLY. +# +sqlite3_blob_open db main t2 a 43 0 B +blob_write_error_test 2.1 $B 0 $blob 10 \ + SQLITE_READONLY {attempt to write a readonly database} +sqlite3_blob_close $B + +# EVIDENCE-OF: R-29804-27366 If offset iOffset is less than N bytes from +# the end of the BLOB, SQLITE_ERROR is returned and no data is written. +# +sqlite3_blob_open db main t2 a 44 3 B +blob_write_error_test 2.2.1 $B 31 $blob 10 \ + SQLITE_ERROR {SQL logic error or missing database} + +# Make a successful write to the blob handle. This shows that the +# sqlite3_errcode() and sqlite3_errmsg() values are set even if the +# blob_write() call succeeds (see requirement in the [blob_write_error_test] +# proc). +blob_write_error_test 2.2.1 $B 30 $blob 10 SQLITE_OK {not an error} + +# EVIDENCE-OF: R-58570-38916 If N or iOffset are less than zero +# SQLITE_ERROR is returned and no data is written. +# +blob_write_error_test 2.2.2 $B 31 $blob -1 \ + SQLITE_ERROR {SQL logic error or missing database} +blob_write_error_test 2.2.3 $B 20 $blob 10 SQLITE_OK {not an error} +blob_write_error_test 2.2.4 $B -1 $blob 10 \ + SQLITE_ERROR {SQL logic error or missing database} +sqlite3_blob_close $B + +# EVIDENCE-OF: R-20958-54138 An attempt to write to an expired BLOB +# handle fails with an error code of SQLITE_ABORT. +# +do_test 2.3 { + sqlite3_blob_open db main t2 a 43 0 B + execsql { DELETE FROM t2 WHERE b=43 } +} {} +blob_write_error_test 2.3.1 $B 5 $blob 5 \ + SQLITE_ABORT {callback requested query abort} +do_test 2.3.2 { + execsql { SELECT 1, 2, 3 } + sqlite3_errcode db +} {SQLITE_OK} +blob_write_error_test 2.3.3 $B 5 $blob 5 \ + SQLITE_ABORT {callback requested query abort} +sqlite3_blob_close $B + +# EVIDENCE-OF: R-08382-59936 Writes to the BLOB that occurred before the +# BLOB handle expired are not rolled back by the expiration of the +# handle, though of course those changes might have been overwritten by +# the statement that expired the BLOB handle or by other independent +# statements. +# +# 3.1.*: not rolled back, +# 3.2.*: overwritten. +# +do_execsql_test 3.0 { + CREATE TABLE t3(i INTEGER PRIMARY KEY, j TEXT, k TEXT); + INSERT INTO t3 VALUES(1, $dots, $dots); + INSERT INTO t3 VALUES(2, $dots, $dots); + SELECT * FROM t3 WHERE i=1; +} { + 1 + ........................................ + ........................................ +} +sqlite3_blob_open db main t3 j 1 1 B +blob_write_error_test 3.1.1 $B 5 $blob 10 SQLITE_OK {not an error} +do_execsql_test 3.1.2 { + UPDATE t3 SET k = 'xyz' WHERE i=1; + SELECT * FROM t3 WHERE i=1; +} { + 1 .....0123456789......................... xyz +} +blob_write_error_test 3.1.3 $B 15 $blob 10 \ + SQLITE_ABORT {callback requested query abort} +sqlite3_blob_close $B +do_execsql_test 3.1.4 { + SELECT * FROM t3 WHERE i=1; +} { + 1 .....0123456789......................... xyz +} + +sqlite3_blob_open db main t3 j 2 1 B +blob_write_error_test 3.2.1 $B 5 $blob 10 SQLITE_OK {not an error} +do_execsql_test 3.2.2 { + UPDATE t3 SET j = 'xyz' WHERE i=2; + SELECT * FROM t3 WHERE i=2; +} { + 2 xyz ........................................ +} +blob_write_error_test 3.2.3 $B 15 $blob 10 \ + SQLITE_ABORT {callback requested query abort} +sqlite3_blob_close $B +do_execsql_test 3.2.4 { + SELECT * FROM t3 WHERE i=2; +} { + 2 xyz ........................................ +} + + + +finish_test + diff --git a/test/e_changes.test b/test/e_changes.test new file mode 100644 index 0000000..a77e22a --- /dev/null +++ b/test/e_changes.test @@ -0,0 +1,441 @@ +# 2011 October 28 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix e_changes + +# Like [do_execsql_test], except it appends the value returned by +# [db changes] to the result of executing the SQL script. +# +proc do_changes_test {tn sql res} { + uplevel [list \ + do_test $tn "concat \[execsql {$sql}\] \[db changes\]" $res + ] +} + + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-15996-49369 This function returns the number of rows +# modified, inserted or deleted by the most recently completed INSERT, +# UPDATE or DELETE statement on the database connection specified by the +# only parameter. +# +do_execsql_test 1.0 { + CREATE TABLE t1(a, b); + CREATE TABLE t2(x, y, PRIMARY KEY(x, y)) WITHOUT ROWID; + CREATE INDEX i1 ON t1(a); + CREATE INDEX i2 ON t2(y); +} +foreach {tn schema} { + 1 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(b); + } + 2 { + CREATE TABLE t1(a, b, PRIMARY KEY(a, b)) WITHOUT ROWID; + CREATE INDEX i1 ON t1(b); + } +} { + reset_db + execsql $schema + + # Insert 1 row. + do_changes_test 1.$tn.1 { INSERT INTO t1 VALUES(0, 0) } 1 + + # Insert 10 rows. + do_changes_test 1.$tn.2 { + WITH rows(i, j) AS ( + SELECT 1, 1 UNION ALL SELECT i+1, j+i FROM rows WHERE i<10 + ) + INSERT INTO t1 SELECT * FROM rows + } 10 + + # Modify 5 rows. + do_changes_test 1.$tn.3 { + UPDATE t1 SET b=b+1 WHERE a<5; + } 5 + + # Delete 4 rows + do_changes_test 1.$tn.4 { + DELETE FROM t1 WHERE a>6 + } 4 + + # Check the "on the database connecton specified" part of hte + # requirement - changes made by other connections do not show up in + # the return value of sqlite3_changes(). + do_test 1.$tn.5 { + sqlite3 db2 test.db + execsql { INSERT INTO t1 VALUES(-1, -1) } db2 + db2 changes + } 1 + do_test 1.$tn.6 { + db changes + } 4 + db2 close + + # Test that statements that modify no rows because they hit UNIQUE + # constraints set the sqlite3_changes() value to 0. Regardless of + # whether or not they are executed inside an explicit transaction. + # + # 1.$tn.8-9: outside of a transaction + # 1.$tn.10-12: inside a transaction + # + do_changes_test 1.$tn.7 { + CREATE UNIQUE INDEX i2 ON t1(a); + } 4 + do_catchsql_test 1.$tn.8 { + INSERT INTO t1 VALUES('a', 0), ('b', 0), ('c', 0), (0, 11); + } {1 {UNIQUE constraint failed: t1.a}} + do_test 1.$tn.9 { db changes } 0 + do_catchsql_test 1.$tn.10 { + BEGIN; + INSERT INTO t1 VALUES('a', 0), ('b', 0), ('c', 0), (0, 11); + } {1 {UNIQUE constraint failed: t1.a}} + do_test 1.$tn.11 { db changes } 0 + do_changes_test 1.$tn.12 COMMIT 0 + +} + + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-44877-05564 Executing any other type of SQL statement +# does not modify the value returned by this function. +# +reset_db +do_changes_test 2.1 { CREATE TABLE t1(x) } 0 +do_changes_test 2.2 { + WITH d(y) AS (SELECT 1 UNION ALL SELECT y+1 FROM d WHERE y<47) + INSERT INTO t1 SELECT y FROM d; +} 47 + +# The statement above set changes() to 47. Check that none of the following +# modify this. +do_changes_test 2.3 { SELECT count(x) FROM t1 } {47 47} +do_changes_test 2.4 { DROP TABLE t1 } 47 +do_changes_test 2.5 { CREATE TABLE t1(x) } 47 +do_changes_test 2.6 { ALTER TABLE t1 ADD COLUMN b } 47 + + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-53938-27527 Only changes made directly by the INSERT, +# UPDATE or DELETE statement are considered - auxiliary changes caused +# by triggers, foreign key actions or REPLACE constraint resolution are +# not counted. +# +# 3.1.*: triggers +# 3.2.*: foreign key actions +# 3.3.*: replace constraints +# +reset_db +do_execsql_test 3.1.0 { + CREATE TABLE log(x); + CREATE TABLE p1(one PRIMARY KEY, two); + + CREATE TRIGGER tr_ai AFTER INSERT ON p1 BEGIN + INSERT INTO log VALUES('insert'); + END; + CREATE TRIGGER tr_bd BEFORE DELETE ON p1 BEGIN + INSERT INTO log VALUES('delete'); + END; + CREATE TRIGGER tr_au AFTER UPDATE ON p1 BEGIN + INSERT INTO log VALUES('update'); + END; + +} + +do_changes_test 3.1.1 { + INSERT INTO p1 VALUES('a', 'A'), ('b', 'B'), ('c', 'C'); +} 3 +do_changes_test 3.1.2 { + UPDATE p1 SET two = two||two; +} 3 +do_changes_test 3.1.3 { + DELETE FROM p1 WHERE one IN ('a', 'c'); +} 2 +do_execsql_test 3.1.4 { + -- None of the inserts on table log were counted. + SELECT count(*) FROM log +} 8 + +do_execsql_test 3.2.0 { + DELETE FROM p1; + INSERT INTO p1 VALUES('a', 'A'), ('b', 'B'), ('c', 'C'); + + CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET NULL); + CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET DEFAULT); + CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE CASCADE); + INSERT INTO c1 VALUES('a', 'aaa'); + INSERT INTO c2 VALUES('b', 'bbb'); + INSERT INTO c3 VALUES('c', 'ccc'); + + INSERT INTO p1 VALUES('d', 'D'), ('e', 'E'), ('f', 'F'); + CREATE TABLE c4(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET NULL); + CREATE TABLE c5(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET DEFAULT); + CREATE TABLE c6(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE CASCADE); + INSERT INTO c4 VALUES('d', 'aaa'); + INSERT INTO c5 VALUES('e', 'bbb'); + INSERT INTO c6 VALUES('f', 'ccc'); + + PRAGMA foreign_keys = ON; +} + +do_changes_test 3.2.1 { DELETE FROM p1 WHERE one = 'a' } 1 +do_changes_test 3.2.2 { DELETE FROM p1 WHERE one = 'b' } 1 +do_changes_test 3.2.3 { DELETE FROM p1 WHERE one = 'c' } 1 +do_execsql_test 3.2.4 { + SELECT * FROM c1; + SELECT * FROM c2; + SELECT * FROM c3; +} {{} aaa {} bbb} + +do_changes_test 3.2.5 { UPDATE p1 SET one = 'g' WHERE one = 'd' } 1 +do_changes_test 3.2.6 { UPDATE p1 SET one = 'h' WHERE one = 'e' } 1 +do_changes_test 3.2.7 { UPDATE p1 SET one = 'i' WHERE one = 'f' } 1 +do_execsql_test 3.2.8 { + SELECT * FROM c4; + SELECT * FROM c5; + SELECT * FROM c6; +} {{} aaa {} bbb i ccc} + +do_execsql_test 3.3.0 { + CREATE TABLE r1(a UNIQUE, b UNIQUE); + INSERT INTO r1 VALUES('i', 'i'); + INSERT INTO r1 VALUES('ii', 'ii'); + INSERT INTO r1 VALUES('iii', 'iii'); + INSERT INTO r1 VALUES('iv', 'iv'); + INSERT INTO r1 VALUES('v', 'v'); + INSERT INTO r1 VALUES('vi', 'vi'); + INSERT INTO r1 VALUES('vii', 'vii'); +} + +do_changes_test 3.3.1 { INSERT OR REPLACE INTO r1 VALUES('i', 1) } 1 +do_changes_test 3.3.2 { INSERT OR REPLACE INTO r1 VALUES('iv', 'v') } 1 +do_changes_test 3.3.3 { UPDATE OR REPLACE r1 SET b='v' WHERE a='iii' } 1 +do_changes_test 3.3.4 { UPDATE OR REPLACE r1 SET b='vi',a='vii' WHERE a='ii' } 1 +do_execsql_test 3.3.5 { + SELECT * FROM r1 ORDER BY a; +} {i 1 iii v vii vi} + + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-09813-48563 The value returned by sqlite3_changes() +# immediately after an INSERT, UPDATE or DELETE statement run on a view +# is always zero. +# +reset_db +do_execsql_test 4.1 { + CREATE TABLE log(log); + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + INSERT INTO t1 VALUES(5, 6); + + CREATE VIEW v1 AS SELECT * FROM t1; + CREATE TRIGGER v1_i INSTEAD OF INSERT ON v1 BEGIN + INSERT INTO log VALUES('insert'); + END; + CREATE TRIGGER v1_u INSTEAD OF UPDATE ON v1 BEGIN + INSERT INTO log VALUES('update'), ('update'); + END; + CREATE TRIGGER v1_d INSTEAD OF DELETE ON v1 BEGIN + INSERT INTO log VALUES('delete'), ('delete'), ('delete'); + END; +} + +do_changes_test 4.2.1 { INSERT INTO t1 SELECT * FROM t1 } 3 +do_changes_test 4.2.2 { INSERT INTO v1 VALUES(1, 2) } 0 + +do_changes_test 4.3.1 { INSERT INTO t1 SELECT * FROM t1 } 6 +do_changes_test 4.3.2 { UPDATE v1 SET y='xyz' WHERE x=1 } 0 + +do_changes_test 4.4.1 { INSERT INTO t1 SELECT * FROM t1 } 12 +do_changes_test 4.4.2 { DELETE FROM v1 WHERE x=5 } 0 + + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-32918-61474 Before entering a trigger program the value +# returned by sqlite3_changes() function is saved. After the trigger +# program has finished, the original value is restored. +# +reset_db +db func my_changes my_changes +set ::changes [list] +proc my_changes {x} { + set res [db changes] + lappend ::changes $x $res + return $res +} + +do_execsql_test 5.1.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + CREATE TABLE t2(x); + INSERT INTO t1 VALUES(1, NULL); + INSERT INTO t1 VALUES(2, NULL); + INSERT INTO t1 VALUES(3, NULL); + CREATE TRIGGER AFTER UPDATE ON t1 BEGIN + INSERT INTO t2 VALUES('a'), ('b'), ('c'); + SELECT my_changes('trigger'); + END; +} + +do_execsql_test 5.1.1 { + INSERT INTO t2 VALUES('a'), ('b'); + UPDATE t1 SET b = my_changes('update'); + SELECT * FROM t1; +} {1 2 2 2 3 2} + +# Value is being restored to "2" when the trigger program exits. +do_test 5.1.2 { + set ::changes +} {update 2 trigger 3 update 2 trigger 3 update 2 trigger 3} + + +reset_db +do_execsql_test 5.2.0 { + CREATE TABLE t1(a, b); + CREATE TABLE log(x); + INSERT INTO t1 VALUES(1, 0); + INSERT INTO t1 VALUES(2, 0); + INSERT INTO t1 VALUES(3, 0); + CREATE TRIGGER t1_a_u AFTER UPDATE ON t1 BEGIN + INSERT INTO log VALUES(old.b || ' -> ' || new.b || ' c = ' || changes() ); + END; + CREATE TABLE t2(a); + INSERT INTO t2 VALUES(1), (2), (3); + UPDATE t1 SET b = changes(); +} +do_execsql_test 5.2.1 { + SELECT * FROM t1; +} {1 3 2 3 3 3} +do_execsql_test 5.2.2 { + SELECT * FROM log; +} {{0 -> 3 c = 3} {0 -> 3 c = 3} {0 -> 3 c = 3}} + + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-17146-37073 Within a trigger program each INSERT, +# UPDATE and DELETE statement sets the value returned by +# sqlite3_changes() upon completion as normal. Of course, this value +# will not include any changes performed by sub-triggers, as the +# sqlite3_changes() value will be saved and restored after each +# sub-trigger has run. +reset_db +do_execsql_test 6.0 { + + CREATE TABLE t1(a, b); + CREATE TABLE t2(a, b); + CREATE TABLE t3(a, b); + CREATE TABLE log(x); + + CREATE TRIGGER t1_i BEFORE INSERT ON t1 BEGIN + INSERT INTO t2 VALUES(new.a, new.b), (new.a, new.b); + INSERT INTO log VALUES('t2->' || changes()); + END; + + CREATE TRIGGER t2_i AFTER INSERT ON t2 BEGIN + INSERT INTO t3 VALUES(new.a, new.b), (new.a, new.b), (new.a, new.b); + INSERT INTO log VALUES('t3->' || changes()); + END; + + CREATE TRIGGER t1_u AFTER UPDATE ON t1 BEGIN + UPDATE t2 SET b=new.b WHERE a=old.a; + INSERT INTO log VALUES('t2->' || changes()); + END; + + CREATE TRIGGER t2_u BEFORE UPDATE ON t2 BEGIN + UPDATE t3 SET b=new.b WHERE a=old.a; + INSERT INTO log VALUES('t3->' || changes()); + END; + + CREATE TRIGGER t1_d AFTER DELETE ON t1 BEGIN + DELETE FROM t2 WHERE a=old.a AND b=old.b; + INSERT INTO log VALUES('t2->' || changes()); + END; + + CREATE TRIGGER t2_d BEFORE DELETE ON t2 BEGIN + DELETE FROM t3 WHERE a=old.a AND b=old.b; + INSERT INTO log VALUES('t3->' || changes()); + END; +} + +do_changes_test 6.1 { + INSERT INTO t1 VALUES('+', 'o'); + SELECT * FROM log; +} {t3->3 t3->3 t2->2 1} + +do_changes_test 6.2 { + DELETE FROM log; + UPDATE t1 SET b='*'; + SELECT * FROM log; +} {t3->6 t3->6 t2->2 1} + +do_changes_test 6.3 { + DELETE FROM log; + DELETE FROM t1; + SELECT * FROM log; +} {t3->6 t3->0 t2->2 1} + + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-43399-09409 This means that if the changes() SQL +# function (or similar) is used by the first INSERT, UPDATE or DELETE +# statement within a trigger, it returns the value as set when the +# calling statement began executing. +# +# EVIDENCE-OF: R-53215-27584 If it is used by the second or subsequent +# such statement within a trigger program, the value returned reflects +# the number of rows modified by the previous INSERT, UPDATE or DELETE +# statement within the same trigger. +# +reset_db +do_execsql_test 7.1 { + CREATE TABLE q1(t); + CREATE TABLE q2(u, v); + CREATE TABLE q3(w); + + CREATE TRIGGER q2_insert BEFORE INSERT ON q2 BEGIN + + /* changes() returns value from previous I/U/D in callers context */ + INSERT INTO q1 VALUES('1:' || changes()); + + /* changes() returns value of previous I/U/D in this context */ + INSERT INTO q3 VALUES(changes()), (2), (3); + INSERT INTO q1 VALUES('2:' || changes()); + INSERT INTO q3 VALUES(changes() + 3), (changes()+4); + SELECT 'this does not affect things!'; + INSERT INTO q1 VALUES('3:' || changes()); + UPDATE q3 SET w = w+10 WHERE w%2; + INSERT INTO q1 VALUES('4:' || changes()); + DELETE FROM q3; + INSERT INTO q1 VALUES('5:' || changes()); + END; +} + +do_execsql_test 7.2 { + INSERT INTO q2 VALUES('x', 'y'); + SELECT * FROM q1; +} { + 1:0 2:3 3:2 4:3 5:5 +} + +do_execsql_test 7.3 { + DELETE FROM q1; + INSERT INTO q2 VALUES('x', 'y'); + SELECT * FROM q1; +} { + 1:5 2:3 3:2 4:3 5:5 +} + + + +finish_test diff --git a/test/e_createtable.test b/test/e_createtable.test index 08f606f..2921d86 100644 --- a/test/e_createtable.test +++ b/test/e_createtable.test @@ -862,11 +862,11 @@ do_createtable_tests 3.2.3 -query { 3 "INSERT INTO t1 DEFAULT VALUES" {NULL NULL NULL} } -# EVIDENCE-OF: R-62940-43005 An explicit DEFAULT clause may specify that +# EVIDENCE-OF: R-07343-35026 An explicit DEFAULT clause may specify that # the default value is NULL, a string constant, a blob constant, a -# signed-number, or any constant expression enclosed in parentheses. An -# explicit default value may also be one of the special case-independent -# keywords CURRENT_TIME, CURRENT_DATE or CURRENT_TIMESTAMP. +# signed-number, or any constant expression enclosed in parentheses. A +# default value may also be one of the special case-independent keywords +# CURRENT_TIME, CURRENT_DATE or CURRENT_TIMESTAMP. # do_execsql_test e_createtable-3.3.1 { CREATE TABLE t4( @@ -884,9 +884,9 @@ do_execsql_test e_createtable-3.3.1 { ); } {} -# EVIDENCE-OF: R-36381-62919 For the purposes of the DEFAULT clause, an -# expression is considered constant provided that it does not contain -# any sub-queries, column or table references, or string literals +# EVIDENCE-OF: R-18415-27776 For the purposes of the DEFAULT clause, an +# expression is considered constant if it does contains no sub-queries, +# column or table references, bound parameters, or string literals # enclosed in double-quotes instead of single-quotes. # do_createtable_tests 3.4.1 -error { @@ -896,6 +896,7 @@ do_createtable_tests 3.4.1 -error { 2 {CREATE TABLE t5(x DEFAULT ( "abc" ))} {} 3 {CREATE TABLE t5(x DEFAULT ( 1 IN (SELECT 1) ))} {} 4 {CREATE TABLE t5(x DEFAULT ( EXISTS (SELECT 1) ))} {} + 5 {CREATE TABLE t5(x DEFAULT ( x!=?1 ))} {} } do_createtable_tests 3.4.2 -repair { catchsql { DROP TABLE t5 } diff --git a/test/e_totalchanges.test b/test/e_totalchanges.test new file mode 100644 index 0000000..ee163c9 --- /dev/null +++ b/test/e_totalchanges.test @@ -0,0 +1,213 @@ +# 2011 May 06 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix e_totalchanges + +# Like [do_execsql_test], except it appends the value returned by +# [db total_changes] to the result of executing the SQL script. +# +proc do_tc_test {tn sql res} { + uplevel [list \ + do_test $tn "concat \[execsql {$sql}\] \[db total_changes\]" $res + ] +} + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b); + CREATE INDEX t1_b ON t1(b); + CREATE TABLE t2(x, y, PRIMARY KEY(x, y)) WITHOUT ROWID; + CREATE INDEX t2_y ON t2(y); +} + + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-65438-26258 This function returns the total number of +# rows inserted, modified or deleted by all INSERT, UPDATE or DELETE +# statements completed since the database connection was opened, +# including those executed as part of trigger programs. +# +# 1.1.*: different types of I/U/D statements, +# 1.2.*: trigger programs. +# +do_tc_test 1.1.1 { + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + UPDATE t1 SET a = a+1; + DELETE FROM t1; +} {6} +do_tc_test 1.1.2 { + DELETE FROM t1 +} {6} + +do_tc_test 1.1.3 { + WITH data(a,b) AS ( + SELECT 0, 0 UNION ALL SELECT a+1, b+1 FROM data WHERE a<99 + ) + INSERT INTO t1 SELECT * FROM data; +} {106} + +do_tc_test 1.1.4 { + INSERT INTO t2 SELECT * FROM t1 WHERE a<50; + UPDATE t2 SET y=y+1; +} {206} + +do_tc_test 1.1.5 { + DELETE FROM t2 WHERE y<=25 +} {231} + +do_execsql_test 1.2.1 { + DELETE FROM t1; + DELETE FROM t2; +} +sqlite3 db test.db ; # To reset total_changes +do_tc_test 1.2.2 { + CREATE TABLE log(detail); + CREATE TRIGGER t1_after_insert AFTER INSERT ON t1 BEGIN + INSERT INTO log VALUES('inserted into t1'); + END; + + CREATE TRIGGER t1_before_delete BEFORE DELETE ON t1 BEGIN + INSERT INTO log VALUES('deleting from t1'); + INSERT INTO log VALUES('here we go!'); + END; + + CREATE TRIGGER t1_after_update AFTER UPDATE ON t1 BEGIN + INSERT INTO log VALUES('update'); + DELETE FROM log; + END; + + INSERT INTO t1 VALUES('a', 'b'); -- 1 + 1 + UPDATE t1 SET b='c'; -- 1 + 1 + 2 + DELETE FROM t1; -- 1 + 1 + 1 +} {9} + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-61766-15253 Executing any other type of SQL statement +# does not affect the value returned by sqlite3_total_changes(). +do_tc_test 2.1 { + INSERT INTO t1 VALUES(1, 2), (3, 4); + INSERT INTO t2 VALUES(1, 2), (3, 4); +} {15} +do_tc_test 2.2 { + SELECT count(*) FROM t1; +} {2 15} +do_tc_test 2.3 { + CREATE TABLE t4(a, b); + ALTER TABLE t4 ADD COLUMN c; + CREATE INDEX i4 ON t4(c); + ALTER TABLE t4 RENAME TO t5; + ANALYZE; + BEGIN; + DROP TABLE t2; + ROLLBACK; + VACUUM; +} {15} + + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-36043-10590 Changes made as part of foreign key +# actions are included in the count, but those made as part of REPLACE +# constraint resolution are not. +# +# 3.1.*: foreign key actions +# 3.2.*: REPLACE constraints. +# +sqlite3 db test.db ; # To reset total_changes +do_tc_test 3.1.1 { + CREATE TABLE p1(c PRIMARY KEY, d); + CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET NULL); + CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE CASCADE); + CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET DEFAULT); + + INSERT INTO p1 VALUES(1, 'one'); + INSERT INTO p1 VALUES(2, 'two'); + INSERT INTO p1 VALUES(3, 'three'); + INSERT INTO p1 VALUES(4, 'four'); + + INSERT INTO c1 VALUES(1, 'i'); + INSERT INTO c2 VALUES(2, 'ii'); + INSERT INTO c3 VALUES(3, 'iii'); + PRAGMA foreign_keys = ON; +} {7} + +do_tc_test 3.1.2 { DELETE FROM p1 WHERE c=1; } {9} +do_tc_test 3.1.3 { DELETE FROM p1 WHERE c=2; } {11} +do_tc_test 3.1.4 { DELETE FROM p1 WHERE c=3; } {13} +do_tc_test 3.1.5 { DELETE FROM p1 WHERE c=4; } {14} ; # only 1 this time. + +sqlite3 db test.db ; # To reset total_changes +do_tc_test 3.1.6 { + DROP TABLE c1; + DROP TABLE c2; + DROP TABLE c3; + CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET NULL); + CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE CASCADE); + CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET DEFAULT); + + INSERT INTO p1 VALUES(1, 'one'); + INSERT INTO p1 VALUES(2, 'two'); + INSERT INTO p1 VALUES(3, 'three'); + INSERT INTO p1 VALUES(4, 'four'); + + INSERT INTO c1 VALUES(1, 'i'); + INSERT INTO c2 VALUES(2, 'ii'); + INSERT INTO c3 VALUES(3, 'iii'); + PRAGMA foreign_keys = ON; +} {7} + +do_tc_test 3.1.7 { UPDATE p1 SET c=c+4 WHERE c=1; } {9} +do_tc_test 3.1.8 { UPDATE p1 SET c=c+4 WHERE c=2; } {11} +do_tc_test 3.1.9 { UPDATE p1 SET c=c+4 WHERE c=3; } {13} +do_tc_test 3.1.10 { UPDATE p1 SET c=c+4 WHERE c=4; } {14} ; # only 1 this time. + +sqlite3 db test.db ; # To reset total_changes +do_tc_test 3.2.1 { + CREATE TABLE t3(a UNIQUE, b UNIQUE); + INSERT INTO t3 VALUES('one', 'one'); + INSERT INTO t3 VALUES('two', 'two'); + INSERT OR REPLACE INTO t3 VALUES('one', 'two'); +} {3} + +do_tc_test 3.2.2 { + INSERT INTO t3 VALUES('three', 'one'); + UPDATE OR REPLACE t3 SET b='two' WHERE b='one'; + SELECT * FROM t3; +} {three two 5} + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-54872-08741 Changes to a view that are intercepted by +# INSTEAD OF triggers are not counted. +# +sqlite3 db test.db ; # To reset total_changes +do_tc_test 4.1 { + CREATE TABLE t6(x); + CREATE VIEW v1 AS SELECT * FROM t6; + CREATE TRIGGER v1_tr1 INSTEAD OF INSERT ON v1 BEGIN + SELECT 'no-op'; + END; + + INSERT INTO v1 VALUES('a'); + INSERT INTO v1 VALUES('b'); +} {0} +do_tc_test 4.2 { + CREATE TRIGGER v1_tr2 INSTEAD OF INSERT ON v1 BEGIN + INSERT INTO t6 VALUES(new.x); + END; + + INSERT INTO v1 VALUES('c'); + INSERT INTO v1 VALUES('d'); +} {2} + + +finish_test diff --git a/test/e_uri.test b/test/e_uri.test index a8865ca..d1590e4 100644 --- a/test/e_uri.test +++ b/test/e_uri.test @@ -125,6 +125,9 @@ if {$tcl_platform(platform) == "unix"} { sqlite3_shutdown sqlite3_config_uri 1 +# EVIDENCE-OF: R-06842-00595 If the URI contains an authority, then it +# must be either an empty string or the string "localhost". +# # EVIDENCE-OF: R-17482-00398 If the authority is not an empty string or # "localhost", an error is returned to the caller. # diff --git a/test/e_wal.test b/test/e_wal.test new file mode 100644 index 0000000..a5e074f --- /dev/null +++ b/test/e_wal.test @@ -0,0 +1,229 @@ +# 2011 May 06 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix e_wal + +db close +testvfs oldvfs -iversion 1 + + +# EVIDENCE-OF: R-58297-14483 WAL databases can be created, read, and +# written even if shared memory is unavailable as long as the +# locking_mode is set to EXCLUSIVE before the first attempted access. +# +# EVIDENCE-OF: R-00449-33772 This feature allows WAL databases to be +# created, read, and written by legacy VFSes that lack the "version 2" +# shared-memory methods xShmMap, xShmLock, xShmBarrier, and xShmUnmap on +# the sqlite3_io_methods object. +# +# 1.1: "create" tests. +# 1.2: "read" tests. +# 1.3: "write" tests. +# +# All three done with VFS "oldvfs", which has iVersion==1 and so does +# not support shared memory. +# +sqlite3 db test.db -vfs oldvfs +do_execsql_test 1.1.1 { + PRAGMA journal_mode = WAL; +} {delete} +do_execsql_test 1.1.2 { + PRAGMA locking_mode = EXCLUSIVE; + PRAGMA journal_mode = WAL; +} {exclusive wal} +do_execsql_test 1.1.3 { + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES(1, 2); +} {} +do_test 1.1.4 { + list [file exists test.db-shm] [file exists test.db-wal] +} {0 1} + +do_test 1.2.1 { + db close + sqlite3 db test.db -vfs oldvfs + catchsql { SELECT * FROM t1 } +} {1 {unable to open database file}} +do_test 1.2.2 { + execsql { PRAGMA locking_mode = EXCLUSIVE } + execsql { SELECT * FROM t1 } +} {1 2} +do_test 1.2.3 { + list [file exists test.db-shm] [file exists test.db-wal] +} {0 1} + +do_test 1.3.1 { + db close + sqlite3 db test.db -vfs oldvfs + catchsql { INSERT INTO t1 VALUES(3, 4) } +} {1 {unable to open database file}} +do_test 1.3.2 { + execsql { PRAGMA locking_mode = EXCLUSIVE } + execsql { INSERT INTO t1 VALUES(3, 4) } + execsql { SELECT * FROM t1 } +} {1 2 3 4} +do_test 1.3.3 { + list [file exists test.db-shm] [file exists test.db-wal] +} {0 1} + +# EVIDENCE-OF: R-31969-57825 If EXCLUSIVE locking mode is set prior to +# the first WAL-mode database access, then SQLite never attempts to call +# any of the shared-memory methods and hence no shared-memory wal-index +# is ever created. +# +db close +sqlite3 db test.db +do_execsql_test 2.1.1 { + PRAGMA locking_mode = EXCLUSIVE; + SELECT * FROM t1; +} {exclusive 1 2 3 4} +do_test 2.1.2 { + list [file exists test.db-shm] [file exists test.db-wal] +} {0 1} + +# EVIDENCE-OF: R-36328-16367 In that case, the database connection +# remains in EXCLUSIVE mode as long as the journal mode is WAL; attempts +# to change the locking mode using "PRAGMA locking_mode=NORMAL;" are +# no-ops. +# +do_execsql_test 2.2.1 { + PRAGMA locking_mode = NORMAL; + SELECT * FROM t1; +} {exclusive 1 2 3 4} +do_test 2.2.2 { + sqlite3 db2 test.db + catchsql {SELECT * FROM t1} db2 +} {1 {database is locked}} +db2 close + +# EVIDENCE-OF: R-63522-46088 The only way to change out of EXCLUSIVE +# locking mode is to first change out of WAL journal mode. +# +do_execsql_test 2.3.1 { + PRAGMA journal_mode = DELETE; + SELECT * FROM t1; +} {delete 1 2 3 4} +do_test 2.3.2 { + sqlite3 db2 test.db + catchsql {SELECT * FROM t1} db2 +} {1 {database is locked}} +do_execsql_test 2.3.3 { + PRAGMA locking_mode = NORMAL; + SELECT * FROM t1; +} {normal 1 2 3 4} +do_test 2.3.4 { + sqlite3 db2 test.db + catchsql {SELECT * FROM t1} db2 +} {0 {1 2 3 4}} +db2 close +db close + + +# EVIDENCE-OF: R-57239-11845 If NORMAL locking mode is in effect for the +# first WAL-mode database access, then the shared-memory wal-index is +# created. +# +do_test 3.0 { + sqlite3 db test.db + execsql { PRAGMA journal_mode = WAL } + db close +} {} +do_test 3.1 { + sqlite3 db test.db + execsql { SELECT * FROM t1 } + list [file exists test.db-shm] [file exists test.db-wal] +} {1 1} + +# EVIDENCE-OF: R-13779-07711 As long as exactly one connection is using +# a shared-memory wal-index, the locking mode can be changed freely +# between NORMAL and EXCLUSIVE. +# +do_execsql_test 3.2.1 { + PRAGMA locking_mode = EXCLUSIVE; + PRAGMA locking_mode = NORMAL; + PRAGMA locking_mode = EXCLUSIVE; + INSERT INTO t1 VALUES(5, 6); +} {exclusive normal exclusive} +do_test 3.2.2 { + sqlite3 db2 test.db + catchsql { SELECT * FROM t1 } db2 +} {1 {database is locked}} + +# EVIDENCE-OF: R-10993-11647 It is only when the shared-memory wal-index +# is omitted, when the locking mode is EXCLUSIVE prior to the first +# WAL-mode database access, that the locking mode is stuck in EXCLUSIVE. +# +do_execsql_test 3.2.3 { + PRAGMA locking_mode = NORMAL; + SELECT * FROM t1; +} {normal 1 2 3 4 5 6} +do_test 3.2.4 { + catchsql { SELECT * FROM t1 } db2 +} {0 {1 2 3 4 5 6}} + +do_catchsql_test 3.2.5 { + PRAGMA locking_mode = EXCLUSIVE; + INSERT INTO t1 VALUES(7, 8); +} {1 {database is locked}} + +db2 close + +# EVIDENCE-OF: R-46197-42811 This means that the underlying VFS must +# support the "version 2" shared-memory. +# +# EVIDENCE-OF: R-55316-21772 If the VFS does not support shared-memory +# methods, then the attempt to open a database that is already in WAL +# mode, or the attempt convert a database into WAL mode, will fail. +# +db close +do_test 3.4.1 { + sqlite3 db test.db -vfs oldvfs + catchsql { SELECT * FROM t1 } +} {1 {unable to open database file}} +db close +do_test 3.4.2 { + forcedelete test.db2 + sqlite3 db test.db2 -vfs oldvfs + catchsql { PRAGMA journal_mode = WAL } +} {0 delete} +db close + + +# EVIDENCE-OF: R-22428-28959 To prevent older versions of SQLite from +# trying to recover a WAL-mode database (and making matters worse) the +# database file format version numbers (bytes 18 and 19 in the database +# header) are increased from 1 to 2 in WAL mode. +# +reset_db +do_execsql_test 4.1.1 { CREATE TABLE t1(x, y) } +do_test 4.1.2 { hexio_read test.db 18 2 } {0101} +do_execsql_test 4.1.3 { PRAGMA journal_mode = wAL } {wal} +do_test 4.1.4 { hexio_read test.db 18 2 } {0202} + + +# EVIDENCE-OF: R-02535-05811 One can explicitly change out of WAL mode +# using a pragma such as this: PRAGMA journal_mode=DELETE; +# +do_execsql_test 4.2.1 { INSERT INTO t1 VALUES(1, 1); } {} +do_test 4.2.2 { file exists test.db-wal } {1} +do_execsql_test 4.2.3 { PRAGMA journal_mode = delete } {delete} +do_test 4.2.4 { file exists test.db-wal } {0} + +# EVIDENCE-OF: R-60175-02388 Deliberately changing out of WAL mode +# changes the database file format version numbers back to 1 so that +# older versions of SQLite can once again access the database file. +# +do_test 4.3 { hexio_read test.db 18 2 } {0101} + +finish_test diff --git a/test/e_walauto.test b/test/e_walauto.test new file mode 100644 index 0000000..b624b24 --- /dev/null +++ b/test/e_walauto.test @@ -0,0 +1,202 @@ +# 2014 December 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/wal_common.tcl +set testprefix e_walauto + + +proc read_nbackfill {} { + seek $::shmfd 96 + binary scan [read $::shmfd 4] n nBackfill + set nBackfill +} +proc read_mxframe {} { + seek $::shmfd 16 + binary scan [read $::shmfd 4] n mxFrame + set mxFrame +} + +# Assuming that the main db for database handle +# +proc do_autocommit_threshold_test {tn value} { + + set nBackfillSaved [read_nbackfill] + while {1} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + if {[read_mxframe] >= $value} break + } + + set nBackfillNew [read_nbackfill] + uplevel [list do_test $tn "expr $nBackfillNew > $nBackfillSaved" 1] +} + +# EVIDENCE-OF: R-30135-06439 The wal_autocheckpoint pragma can be used +# to invoke this interface from SQL. +# +# All tests in this file are run twice - once using the +# sqlite3_wal_autocheckpoint() API, and once using "PRAGMA +# wal_autocheckpoint". +# +foreach {tn code} { + 1 { + proc autocheckpoint {db value} { + uplevel [list $db eval "PRAGMA wal_autocheckpoint = $value"] + } + } + + 2 { + proc autocheckpoint {db value} { + uplevel [list sqlite3_wal_autocheckpoint $db $value] + return $value + } + } +} { + + eval $code + + reset_db + execsql { PRAGMA auto_vacuum = 0 } + do_execsql_test 1.$tn.0 { PRAGMA journal_mode = WAL } {wal} + do_execsql_test 1.$tn.1 { CREATE TABLE t1(a, b) } + set shmfd [open "test.db-shm" rb] + + # EVIDENCE-OF: R-41531-51083 Every new database connection defaults to + # having the auto-checkpoint enabled with a threshold of 1000 or + # SQLITE_DEFAULT_WAL_AUTOCHECKPOINT pages. + # + do_autocommit_threshold_test 1.$tn.2 1000 + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + do_autocommit_threshold_test 1.$tn.3 1000 + + # EVIDENCE-OF: R-38128-34102 The sqlite3_wal_autocheckpoint(D,N) is a + # wrapper around sqlite3_wal_hook() that causes any database on database + # connection D to automatically checkpoint after committing a + # transaction if there are N or more frames in the write-ahead log file. + # + do_test 1.$tn.4 { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + autocheckpoint db 100 + } {100} + do_autocommit_threshold_test 1.$tn.5 100 + + do_test 1.$tn.6 { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + autocheckpoint db 500 + } {500} + do_autocommit_threshold_test 1.$tn.7 500 + + # EVIDENCE-OF: R-26993-43540 Passing zero or a negative value as the + # nFrame parameter disables automatic checkpoints entirely. + # + do_test 1.$tn.7 { + autocheckpoint db 0 ;# Set to zero + for {set i 0} {$i < 10000} {incr i} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } + expr {[file size test.db-wal] > (5 * 1024 * 1024)} + } 1 + do_test 1.$tn.8 { + sqlite3_wal_checkpoint_v2 db truncate + file size test.db-wal + } 0 + do_test 1.$tn.9 { + autocheckpoint db -4 ;# Set to a negative value + for {set i 0} {$i < 10000} {incr i} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } + expr {[file size test.db-wal] > (5 * 1024 * 1024)} + } 1 + + # EVIDENCE-OF: R-10203-42688 The callback registered by this function + # replaces any existing callback registered using sqlite3_wal_hook(). + # + set ::wal_hook_callback 0 + proc wal_hook_callback {args} { incr ::wal_hook_callback ; return 0 } + do_test 1.$tn.10.1 { + db wal_hook wal_hook_callback + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + set ::wal_hook_callback + } 2 + do_test 1.$tn.10.2 { + autocheckpoint db 100 + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + set ::wal_hook_callback + } 2 + + # EVIDENCE-OF: R-17497-43474 Likewise, registering a callback using + # sqlite3_wal_hook() disables the automatic checkpoint mechanism + # configured by this function. + do_test 1.$tn.11.1 { + sqlite3_wal_checkpoint_v2 db truncate + file size test.db-wal + } 0 + do_test 1.$tn.11.2 { + autocheckpoint db 100 + for {set i 0} {$i < 1000} {incr i} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } + expr {[file size test.db-wal] < (1 * 1024 * 1024)} + } 1 + do_test 1.$tn.11.3 { + db wal_hook wal_hook_callback + for {set i 0} {$i < 1000} {incr i} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } + expr {[file size test.db-wal] < (1 * 1024 * 1024)} + } 0 + + # EVIDENCE-OF: R-33080-59193 Checkpoints initiated by this mechanism + # are PASSIVE. + # + set ::busy_callback_count 0 + proc busy_callback {args} { + puts Hello + incr ::busy_callback_count + return 0 + } + do_test 1.$tn.12.1 { + sqlite3_wal_checkpoint_v2 db truncate + autocheckpoint db 100 + db busy busy_callback + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } {} + do_test 1.$tn.12.2 { + sqlite3 db2 test.db + db2 eval { BEGIN; SELECT * FROM t1 LIMIT 10; } + read_nbackfill + } {0} + do_test 1.$tn.12.3 { + for {set i 0} {$i < 1000} {incr i} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } + read_nbackfill + } {2} + do_test 1.$tn.12.4 { + set ::busy_callback_count + } {0} + db2 close + + do_test 1.$tn.12.5 { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + read_nbackfill + } {1559} + + db close + close $shmfd +} + +finish_test diff --git a/test/e_walckpt.test b/test/e_walckpt.test new file mode 100644 index 0000000..e022f84 --- /dev/null +++ b/test/e_walckpt.test @@ -0,0 +1,754 @@ +# 2014 December 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/lock_common.tcl +source $testdir/wal_common.tcl +set testprefix e_walckpt + +# The following two commands are used to determine if any of the files +# "test.db", "test.db2" and "test.db3" are modified by a test case. +# +# The [save_db_hashes] command saves a hash of the current contents of +# all three files in global variables. The [compare_db_hashes] compares +# the current contents with the saved hashes and returns a list of the +# files that have changed. +# +proc save_db_hashes {} { + global H + foreach f {test.db test.db2 test.db3} { + set H($f) 0 + catch { set H($f) [md5file $f] } + } +} +proc compare_db_hashes {} { + global H + set ret [list] + foreach f {test.db test.db2 test.db3} { + set expect 0 + catch { set expect [md5file $f] } + if {$H($f) != $expect} { lappend ret $f } + } + set ret +} + +#------------------------------------------------------------------------- +# All calls to the [sqlite3_wal_checkpoint_v2] command made within this +# file use this wrapper. It's sole purpose is to throw an error if the +# following requirement is violated: +# +# EVIDENCE-OF: R-60567-47780 Unless it returns SQLITE_MISUSE, the +# sqlite3_wal_checkpoint_v2() interface sets the error information that +# is queried by sqlite3_errcode() and sqlite3_errmsg(). +# +proc wal_checkpoint_v2 {db args} { + set rc [catch { + uplevel sqlite3_wal_checkpoint_v2 $db $args + } msg] + + set errcode "SQLITE_OK" + if {$rc} { + set errcode [lindex [split $msg " "] 0] + } elseif { [lindex $msg 0] } { + set errcode "SQLITE_BUSY" + } + + if {$errcode != "SQLITE_MISUSE" && [sqlite3_errcode $db] != $errcode} { + error "sqlite3_errcode mismatch! (1) $errcode!=[sqlite3_errcode $db]" + } + + if {$rc==0} { + return $msg + } else { + error $msg + } +} + + +# The following tests are run 3 times, each using a different method of +# invoking a checkpoint: +# +# 1) Using sqlite3_wal_checkpoint_v2() +# 2) Using "PRAGMA wal_checkpoint" +# 3) Using sqlite3_wal_checkpoint() in place of checkpoint_v2(PASSIVE) +# +# Cases (2) and (3) are to show that the following statements are +# correct, respectively: +# +# EVIDENCE-OF: R-36706-10507 The PRAGMA wal_checkpoint command can be +# used to invoke this interface from SQL. +# +# EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is +# equivalent to +# sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). +# +foreach {tn script} { + 1 { + proc checkpoint {db mode args} { + eval wal_checkpoint_v2 [list $db] [list $mode] $args + } + } + + 2 { + proc checkpoint {db mode args} { + set sql "PRAGMA wal_checkpoint = $mode" + if {[llength $args] && [lindex $args 0]!=""} { + set sql "PRAGMA [lindex $args 0].wal_checkpoint = $mode" + } + set rc [catch { $db eval $sql } msg] + if {$rc} { + regsub {database} $msg {database:} msg + error "[sqlite3_errcode $db] - $msg" + } + set msg + } + } + + 3 { + proc checkpoint {db mode args} { + if {$mode == "passive"} { + set rc [eval sqlite3_wal_checkpoint [list $db] $args] + if {$rc != "SQLITE_OK"} { + error "$rc - [sqlite3_errmsg $db]" + } + } else { + eval wal_checkpoint_v2 [list $db] [list $mode] $args + } + } + } + +} { + + eval $script + + reset_db + forcedelete test.db2 test.db3 test.db4 + execsql { + ATTACH 'test.db2' AS aux; + ATTACH 'test.db3' AS aux2; + ATTACH 'test.db4' AS aux3; + CREATE TABLE t1(x); + CREATE TABLE aux.t2(x); + CREATE TABLE aux2.t3(x); + CREATE TABLE aux3.t4(x); + PRAGMA main.journal_mode = WAL; + PRAGMA aux.journal_mode = WAL; + PRAGMA aux2.journal_mode = WAL; + /* Leave aux4 in rollback mode */ + } + + # EVIDENCE-OF: R-49787-09095 The sqlite3_wal_checkpoint_v2(D,X,M,L,C) + # interface runs a checkpoint operation on database X of database + # connection D in mode M. Status information is written back into + # integers pointed to by L and C. + # + # Tests 1, 2 and 3 below verify the "on database X" part of the + # above. Other parts of this requirement are tested below. + # + # EVIDENCE-OF: R-00653-06026 If parameter zDb is NULL or points to a + # zero length string, then the specified operation is attempted on all + # WAL databases attached to database connection db. + # + # Tests 4 and 5 below test this. + # + foreach {tn2 zDb dblist} { + 1 main test.db + 2 aux test.db2 + 3 aux2 test.db3 + 4 "" {test.db test.db2 test.db3} + 5 - {test.db test.db2 test.db3} + 6 temp {} + } { + do_test $tn.1.$tn2 { + execsql { + INSERT INTO t1 VALUES(1); + INSERT INTO t2 VALUES(2); + INSERT INTO t3 VALUES(3); + } + save_db_hashes + + if {$zDb == "-"} { + checkpoint db passive + } else { + checkpoint db passive $zDb + } + + compare_db_hashes + } $dblist + } + + # EVIDENCE-OF: R-38207-48996 If zDb is not NULL (or a zero length + # string) and is not the name of any attached database, SQLITE_ERROR is + # returned to the caller. + do_test $tn.2.1 { + list [catch { checkpoint db passive notadb } msg] $msg + } {1 {SQLITE_ERROR - unknown database: notadb}} + + # EVIDENCE-OF: R-14303-42483 If database zDb is the name of an attached + # database that is not in WAL mode, SQLITE_OK is returned and both + # *pnLog and *pnCkpt set to -1. + # + if {$tn==3} { + # With sqlite3_wal_checkpoint() the two output variables cannot be + # tested. So just test that no error is returned when attempting to + # checkpoint a db in rollback mode. + do_test $tn.2.2.a { checkpoint db passive aux3 } {} + } else { + do_test $tn.2.2.b { checkpoint db passive aux3 } {0 -1 -1} + } + + # EVIDENCE-OF: R-62028-47212 All calls obtain an exclusive "checkpoint" + # lock on the database file. + db close + testvfs tvfs + tvfs filter xShmLock + tvfs script filelock + proc filelock {method file handle details} { + # Test for an exclusive checkpoint lock. A checkpoint lock locks a + # single byte starting at offset 1. + if {$details == "1 1 lock exclusive"} { set ::seen_checkpoint_lock 1 } + } + sqlite3 db test.db -vfs tvfs + do_test $tn.3.1 { + execsql { INSERT INTO t1 VALUES('xyz') } + unset -nocomplain ::seen_checkpoint_lock + checkpoint db passive + set ::seen_checkpoint_lock + } {1} + db close + tvfs delete + reset_db + + + + + #----------------------------------------------------------------------- + # EVIDENCE-OF: R-10421-19736 If any other process is running a + # checkpoint operation at the same time, the lock cannot be obtained and + # SQLITE_BUSY is returned. + # + # EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured, + # it will not be invoked in this case. + # + testvfs tvfs + tvfs filter xWrite + sqlite3 db test.db -vfs tvfs + sqlite3 db2 test.db -vfs tvfs + + do_test $tn.3.2.1 { + db2 eval { + PRAGMA auto_vacuum = 0; + PRAGMA journal_mode = WAL; + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES(1,2); + INSERT INTO t1 VALUES(3,4); + INSERT INTO t1 VALUES(5,6); + } + file size test.db-wal + } [wal_file_size 5 1024] + + + # Connection [db] runs a checkpoint. During this checkpoint, each + # time it calls xWrite() to write a page into the database file, we + # attempt to start a checkpoint using [db2]. According to the + # first requirement being tested, this should return SQLITE_BUSY. According + # to the second, the busy-handler belonging to [db2] should not be + # invoked. + # + set ::write_count 0 + set ::write_errors [list] + proc busy_callback {args} { + lappend ::write_errors "busy handler called!" + } + proc write_callback {args} { + set rc [catch {checkpoint db2 passive} msg] + if {0==[regexp "database is locked" $msg] && $msg!="1 -1 -1"} { + lappend ::write_errors "$rc $msg" + } + incr ::write_count + } + db2 busy busy_callback + tvfs script write_callback + + do_test $tn.3.2.2 { + db eval {SELECT * FROM sqlite_master} + checkpoint db full + set ::write_count + } {2} + + do_test $tn.3.2.3 { + set ::write_errors + } {} + + db close + db2 close + tvfs delete + + proc busy_handler {mode busy_handler_mode n} { + incr ::busy_handler_counter + switch -- $busy_handler_mode { + 1 { + # Do nothing. Do not block. + return 1 + } + + 2 { + # Close first the reader, then later the writer. Give up before + # closing the [db6] reader. + if {$n==5} { catch {db2 eval commit} } + if {$n==10} { catch {db3 eval commit} } + if {$n==15} { return 1 } + return 0 + } + + 3 { + # Close first the writer, then later the reader. And finally the + # [db6] reader. + if {$n==5} { catch {db2 eval commit} } + if {$n==10} { catch {db3 eval commit} } + if {$n==15} { catch {db6 eval commit} } + return 0 + } + } + } + + foreach {mode busy_handler_mode} { + passive 1 + full 1 full 2 full 3 + restart 1 restart 2 restart 3 + truncate 1 truncate 2 truncate 3 + } { + set tp "$tn.$mode.$busy_handler_mode" + + set ::sync_counter 0 + + # Set up a callback function for xSync and xWrite calls made during + # the checkpoint. + # + set ::checkpoint_ongoing 0 + proc tvfs_callback {method args} { + if {$::checkpoint_ongoing==0} return + + set tail [file tail [lindex $args 0]] + if {$method == "xSync" && $tail == "test.db"} { + incr ::sync_counter + } + if {$method == "xWrite" && $tail=="test.db"} { + if {$::write_ok < 0} { + set ::write_ok [expr ![catch {db5 eval { BEGIN IMMEDIATE }}]] + catch { db5 eval ROLLBACK } + } + if {$::read_ok < 0} { + set ::read_ok [expr ![catch {db5 eval { SELECT * FROM t1 }}]] + } + + # If one has not already been opened, open a read-transaction using + # connection [db6] + catch { db6 eval { BEGIN ; SELECT * FROM sqlite_master } } msg + } + if {$method == "xShmLock" } { + set details [lindex $args 2] + if {$details == "0 1 lock exclusive"} { set ::seen_writer_lock 1 } + } + } + + catch { db close } + forcedelete test.db + testvfs tvfs + sqlite3 db test.db -vfs tvfs + #tvfs filter xSync + tvfs script tvfs_callback + + do_execsql_test $tp.0 { + CREATE TABLE t1(a, b); + CREATE TABLE t2(a, b); + PRAGMA journal_mode = wal; + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + INSERT INTO t1 VALUES(5, 6); + } {wal} + + # Open a reader on the current database snapshot. + do_test $tp.1 { + sqlite3 db2 test.db -vfs tvfs + execsql { + BEGIN; + SELECT * FROM t1 UNION ALL SELECT * FROM t2; + } db2 + } {1 2 3 4 5 6} + + # Open a writer. Write a transaction. Then begin, but do not commit, + # a second transaction. + do_test $tp.2 { + sqlite3 db3 test.db -vfs tvfs + execsql { + INSERT INTO t2 VALUES(7, 8); + BEGIN; + INSERT INTO t2 VALUES(9, 10); + SELECT * FROM t1 UNION ALL SELECT * FROM t2; + } db3 + } {1 2 3 4 5 6 7 8 9 10} + + sqlite3 db5 test.db -vfs tvfs + sqlite3 db6 test.db -vfs tvfs + + # Register a busy-handler with connection [db]. + # + db busy [list busy_handler $mode $busy_handler_mode] + set ::sync_counter 0 + set ::busy_handler_counter 0 + set ::read_ok -1 + set ::write_ok -1 + set ::seen_writer_lock 0 + + set ::checkpoint_ongoing 1 + do_test $tp.3 { + checkpoint db $mode main + set {} {} + } {} + set ::checkpoint_ongoing 0 + set ::did_restart_blocking [expr {[catch {db6 eval commit}]}] + + if { $mode=="passive" } { + # EVIDENCE-OF: R-16333-64433 Checkpoint as many frames as possible + # without waiting for any database readers or writers to finish, then + # sync the database file if all frames in the log were checkpointed. + # + # "As many frames as possible" means all but the last two transactions + # (the two that write to table t2, of which the scond is unfinished). + # So copying the db file only we see the t1 change, but not the t2 + # modifications. + # + # The busy handler is not invoked (see below) and the db reader and + # writer are still active - so the checkpointer did not wait for either + # readers or writers. As a result the checkpoint was not finished and + # so the db file is not synced. + # + # EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked + # in the SQLITE_CHECKPOINT_PASSIVE mode. + # + # It's not. Test case "$tp.6". + # + do_test $tp.4 { + forcecopy test.db abc.db + sqlite3 db4 abc.db + db4 eval { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } + } {1 2 3 4 5 6} + do_test $tp.5 { set ::sync_counter } 0 + do_test $tp.6 { set ::busy_handler_counter } 0 + db4 close + + db2 eval COMMIT + db3 eval COMMIT + + # EVIDENCE-OF: R-65499-53765 On the other hand, passive mode might leave + # the checkpoint unfinished if there are concurrent readers or writers. + # + # The reader and writer have now dropped their locks. And so a + # checkpoint now is able to checkpoint more frames. Showing that the + # attempt above was left "unfinished". + # + # Also, because the checkpoint finishes this time, the db is synced. + # Which is part of R-16333-64433 above. + # + set ::checkpoint_ongoing 1 + do_test $tp.7 { + checkpoint db $mode main + forcecopy test.db abc.db + sqlite3 db4 abc.db + db4 eval { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } + } {1 2 3 4 5 6 7 8 9 10} + set ::checkpoint_ongoing 0 + do_test $tp.7 { set ::sync_counter } 1 + do_test $tp.8 { set ::busy_handler_counter } 0 + db4 close + } + + if { $mode=="full" || $mode=="restart" || $mode=="truncate" } { + + # EVIDENCE-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and + # TRUNCATE modes also obtain the exclusive "writer" lock on the + # database file. + # + # Or at least attempts to obtain. + # + do_test $tp.9 { + set ::seen_writer_lock + } {1} + + if {$busy_handler_mode==2 || $busy_handler_mode==3} { + # EVIDENCE-OF: R-59171-47567 This mode blocks (it invokes the + # busy-handler callback) until there is no database writer and all + # readers are reading from the most recent database snapshot. + # + # The test below shows that both the reader and writer have + # finished: + # + # Also restated by the following two. That both busy_handler_mode + # values 2 and 3 work show that both of the following are true - as + # they release the reader and writer transactions in different + # orders. + # + # EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained + # immediately, and a busy-handler is configured, it is invoked and the + # writer lock retried until either the busy-handler returns 0 or the + # lock is successfully obtained. + # + # EVIDENCE-OF: R-48107-00250 The busy-handler is also invoked while + # waiting for database readers as described above. + # + do_test $tp.7 { + list [catchsql COMMIT db2] [catchsql COMMIT db3] + } [list \ + {1 {cannot commit - no transaction is active}} \ + {1 {cannot commit - no transaction is active}} \ + ] + + # EVIDENCE-OF: R-29177-48281 It then checkpoints all frames in the log + # file and syncs the database file. + # + do_test $tp.8 { + forcecopy test.db abc.db + sqlite3 db4 abc.db + db4 eval { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } + } {1 2 3 4 5 6 7 8 9 10} + do_test $tp.9 { set ::sync_counter } 1 + db4 close + + # EVIDENCE-OF: R-51867-44713 This mode blocks new database writers + # while it is pending, but new database readers are allowed to continue + # unimpeded. + # + # EVIDENCE-OF: R-47276-58266 Like SQLITE_CHECKPOINT_FULL, this mode + # blocks new database writer attempts while it is pending, but does not + # impede readers. + # + # The first of the above two refers to "full" mode. The second + # to "restart". + # + do_test $tp.10.1 { + list $::write_ok $::read_ok + } {0 1} + + # EVIDENCE-OF: R-12410-31217 This mode works the same way as + # SQLITE_CHECKPOINT_FULL with the addition that after checkpointing the + # log file it blocks (calls the busy-handler callback) until all + # readers are reading from the database file only. + # + # The stuff above passed, so the first part of this requirement + # is met. The second part is tested below. If the checkpoint mode + # was "restart" or "truncate", then the busy-handler will have + # been called to block on wal-file readers. + # + do_test $tp.11 { + set ::did_restart_blocking + } [expr {($mode=="restart"||$mode=="truncate")&&$busy_handler_mode==3}] + + # EVIDENCE-OF: R-44699-57140 This mode works the same way as + # SQLITE_CHECKPOINT_RESTART with the addition that it also truncates + # the log file to zero bytes just prior to a successful return. + if {$mode=="truncate" && $busy_handler_mode==3} { + do_test $tp.12 { + file size test.db-wal + } 0 + } + } elseif {$busy_handler_mode==1} { + + # EVIDENCE-OF: R-34519-06271 SQLITE_BUSY is returned in this case. + if {$tn!=2} { + # ($tn==2) is the loop that uses "PRAGMA wal_checkpoint" + do_test $tp.13 { sqlite3_errcode db } {SQLITE_BUSY} + } + + # EVIDENCE-OF: R-49155-63541 If the busy-handler returns 0 before the + # writer lock is obtained or while waiting for database readers, the + # checkpoint operation proceeds from that point in the same way as + # SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible + # without blocking any further. + do_test $tp.14 { + forcecopy test.db abc.db + sqlite3 db4 abc.db + db4 eval { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } + } {1 2 3 4 5 6} + do_test $tp.15 { set ::sync_counter } 0 + do_test $tp.16 { set ::busy_handler_counter } 1 + db4 close + } + } + + db2 close + db3 close + db5 close + db6 close + } + + db close + tvfs delete +} + +#----------------------------------------------------------------------- +# EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint +# mode: +# +# Valid checkpoint modes are 0, 1, 2 and 3. +# +sqlite3 db test.db +foreach {tn mode res} { + 0 -1001 {1 {SQLITE_MISUSE - not an error}} + 1 -1 {1 {SQLITE_MISUSE - not an error}} + 2 0 {0 {0 -1 -1}} + 3 1 {0 {0 -1 -1}} + 4 2 {0 {0 -1 -1}} + 5 3 {0 {0 -1 -1}} + 6 4 {1 {SQLITE_MISUSE - not an error}} + 7 114 {1 {SQLITE_MISUSE - not an error}} + 8 1000000 {1 {SQLITE_MISUSE - not an error}} +} { + do_test 4.$tn { + list [catch "wal_checkpoint_v2 db $mode" msg] $msg + } $res +} +db close + +foreach tn {1 2 3} { + forcedelete test.db test.db2 test.db3 + testvfs tvfs + + sqlite3 db test.db -vfs tvfs + execsql { + ATTACH 'test.db2' AS aux2; + ATTACH 'test.db3' AS aux3; + PRAGMA main.journal_mode = WAL; + PRAGMA aux2.journal_mode = WAL; + PRAGMA aux3.journal_mode = WAL; + + CREATE TABLE main.t1(x,y); + CREATE TABLE aux2.t2(x,y); + CREATE TABLE aux3.t3(x,y); + + INSERT INTO t1 VALUES('a', 'b'); + INSERT INTO t2 VALUES('a', 'b'); + INSERT INTO t3 VALUES('a', 'b'); + } + sqlite3 db2 test.db2 -vfs tvfs + + switch -- $tn { + 1 { + # EVIDENCE-OF: R-41299-52117 If no error (SQLITE_BUSY or otherwise) is + # encountered while processing the attached databases, SQLITE_OK is + # returned. + do_test 5.$tn.1 { + lindex [wal_checkpoint_v2 db truncate] 0 + } {0} ;# 0 -> SQLITE_OK + do_test 5.$tn.2 { + list [expr [file size test.db-wal]==0] \ + [expr [file size test.db2-wal]==0] \ + [expr [file size test.db3-wal]==0] + } {1 1 1} + } + + 2 { + # EVIDENCE-OF: R-38578-34175 If an SQLITE_BUSY error is encountered when + # processing one or more of the attached WAL databases, the operation is + # still attempted on any remaining attached databases and SQLITE_BUSY is + # returned at the end. + db2 eval { BEGIN; INSERT INTO t2 VALUES('d', 'e'); } + do_test 5.$tn.1 { + lindex [wal_checkpoint_v2 db truncate] 0 + } {1} ;# 1 -> SQLITE_BUSY + do_test 5.$tn.2 { + list [expr [file size test.db-wal]==0] \ + [expr [file size test.db2-wal]==0] \ + [expr [file size test.db3-wal]==0] + } {1 0 1} + db2 eval ROLLBACK + } + + 3 { + # EVIDENCE-OF: R-38049-07913 If any other error occurs while processing + # an attached database, processing is abandoned and the error code is + # returned to the caller immediately. + tvfs filter xWrite + tvfs script inject_ioerr + proc inject_ioerr {method file args} { + if {[file tail $file]=="test.db2"} { + return "SQLITE_IOERR" + } + return 0 + } + do_test 5.$tn.1 { + list [catch { wal_checkpoint_v2 db truncate } msg] $msg + } {1 {SQLITE_IOERR - disk I/O error}} + do_test 5.$tn.2 { + list [expr [file size test.db-wal]==0] \ + [expr [file size test.db2-wal]==0] \ + [expr [file size test.db3-wal]==0] + } {1 0 0} + tvfs script "" + } + } + + db close + db2 close +} + +reset_db +sqlite3 db2 test.db + +do_test 6.1 { + execsql { + PRAGMA auto_vacuum = 0; + PRAGMA journal_mode = WAL; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + } + file size test.db-wal +} [wal_file_size 3 1024] + +do_test 6.2 { + db2 eval { BEGIN; SELECT * FROM t1; } + db eval { INSERT INTO t1 VALUES(3, 4) } + file size test.db-wal +} [wal_file_size 4 1024] + +# At this point the log file contains 4 frames. 3 of which it should +# be possible to checkpoint. +# +# EVIDENCE-OF: R-16642-42503 If pnLog is not NULL, then *pnLog is set to +# the total number of frames in the log file or to -1 if the checkpoint +# could not run because of an error or because the database is not in +# WAL mode. +# +# EVIDENCE-OF: R-10514-25250 If pnCkpt is not NULL,then *pnCkpt is set +# to the total number of checkpointed frames in the log file (including +# any that were already checkpointed before the function was called) or +# to -1 if the checkpoint could not run due to an error or because the +# database is not in WAL mode. +# +do_test 6.4 { + lrange [wal_checkpoint_v2 db passive] 1 2 +} {4 3} + +# EVIDENCE-OF: R-37257-17813 Note that upon successful completion of an +# SQLITE_CHECKPOINT_TRUNCATE, the log file will have been truncated to +# zero bytes and so both *pnLog and *pnCkpt will be set to zero. +# +do_test 6.5 { + db2 eval COMMIT + wal_checkpoint_v2 db truncate +} {0 0 0} + + + +finish_test + diff --git a/test/e_walhook.test b/test/e_walhook.test new file mode 100644 index 0000000..c8c8819 --- /dev/null +++ b/test/e_walhook.test @@ -0,0 +1,200 @@ +# 2014 December 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/wal_common.tcl +set testprefix e_walhook + + +# EVIDENCE-OF: R-00752-43975 The sqlite3_wal_hook() function is used to +# register a callback that is invoked each time data is committed to a +# database in wal mode. +# +# 1.1: shows that the wal-hook is not invoked in rollback mode. +# 1.2: but is invoked in wal mode. +# +set ::wal_hook_count 0 +proc my_wal_hook {args} { + incr ::wal_hook_count + return 0 +} + +do_test 1.1.1 { + db wal_hook my_wal_hook + execsql { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1); + } + set ::wal_hook_count +} 0 +do_test 1.1.2 { + execsql { PRAGMA journal_mode = wal } + set ::wal_hook_count +} 0 + +do_test 1.3 { + execsql { INSERT INTO t1 VALUES(2) } + set wal_hook_count +} 1 + +do_test 1.4 { + execsql { + BEGIN; + INSERT INTO t1 VALUES(3); + INSERT INTO t1 VALUES(4); + COMMIT; + } + set wal_hook_count +} 2 + +# EVIDENCE-OF: R-65366-15139 The callback is invoked by SQLite after the +# commit has taken place and the associated write-lock on the database +# released +# +set ::read_ok 0 +proc my_wal_hook {args} { + sqlite3 db2 test.db + if {[db2 eval { SELECT * FROM t1 }] == "1 2 3 4 5"} { + set ::read_ok 1 + } + db2 close +} +do_test 2.1 { + execsql { INSERT INTO t1 VALUES(5) } + set ::read_ok +} 1 + +# EVIDENCE-OF: R-44294-52863 The third parameter is the name of the +# database that was written to - either "main" or the name of an +# ATTACH-ed database. +# +# EVIDENCE-OF: R-18913-19355 The fourth parameter is the number of pages +# currently in the write-ahead log file, including those that were just +# committed. +# +set ::wal_hook_args [list] +proc my_wal_hook {dbname nEntry} { + set ::wal_hook_args [list $dbname $nEntry] +} +forcedelete test.db2 +do_test 3.0 { + execsql { + ATTACH 'test.db2' AS aux; + CREATE TABLE aux.t2(x); + PRAGMA aux.journal_mode = wal; + } +} {wal} + +# Database "aux" +do_test 3.1.1 { + set wal_hook_args [list] + execsql { INSERT INTO t2 VALUES('a') } +} {} +do_test 3.1.2 { + set wal_hook_args +} [list aux [wal_frame_count test.db2-wal 1024]] + +# Database "main" +do_test 3.2.1 { + set wal_hook_args [list] + execsql { INSERT INTO t1 VALUES(6) } +} {} +do_test 3.1.2 { + set wal_hook_args +} [list main [wal_frame_count test.db-wal 1024]] + +# EVIDENCE-OF: R-14034-00929 If an error code is returned, that error +# will propagate back up through the SQLite code base to cause the +# statement that provoked the callback to report an error, though the +# commit will have still occurred. +# +proc my_wal_hook {args} { return 1 ;# SQLITE_ERROR } +do_catchsql_test 4.1 { + INSERT INTO t1 VALUES(7) +} {1 {SQL logic error or missing database}} + +proc my_wal_hook {args} { return 5 ;# SQLITE_BUSY } +do_catchsql_test 4.2 { + INSERT INTO t1 VALUES(8) +} {1 {database is locked}} + +proc my_wal_hook {args} { return 14 ;# SQLITE_CANTOPEN } +do_catchsql_test 4.3 { + INSERT INTO t1 VALUES(9) +} {1 {unable to open database file}} + +do_execsql_test 4.4 { + SELECT * FROM t1 +} {1 2 3 4 5 6 7 8 9} + +# EVIDENCE-OF: R-10466-53920 Calling sqlite3_wal_hook() replaces any +# previously registered write-ahead log callback. +set ::old_wal_hook 0 +proc my_old_wal_hook {args} { + incr ::old_wal_hook + return 0 +} +db wal_hook my_old_wal_hook +do_test 5.1 { + execsql { INSERT INTO t1 VALUES(10) } + set ::old_wal_hook +} {1} + +# Replace old_wal_hook. Observe that it is not invoked after it has +# been replaced. +proc my_new_wal_hook {args} { return 0 } +db wal_hook my_new_wal_hook +do_test 5.2 { + execsql { INSERT INTO t1 VALUES(11) } + set ::old_wal_hook +} {1} + + + +# EVIDENCE-OF: R-42842-27162 Note that the sqlite3_wal_autocheckpoint() +# interface and the wal_autocheckpoint pragma both invoke +# sqlite3_wal_hook() and will those overwrite any prior +# sqlite3_wal_hook() settings. +# +set ::old_wal_hook 0 +proc my_old_wal_hook {args} { incr ::old_wal_hook ; return 0 } +db wal_hook my_old_wal_hook +do_test 6.1.1 { + execsql { INSERT INTO t1 VALUES(12) } + set ::old_wal_hook +} {1} +do_test 6.1.2 { + execsql { PRAGMA wal_autocheckpoint = 1000 } + execsql { INSERT INTO t1 VALUES(12) } + set ::old_wal_hook +} {1} + +# EVIDENCE-OF: R-52629-38967 The first parameter passed to the callback +# function when it is invoked is a copy of the third parameter passed to +# sqlite3_wal_hook() when registering the callback. +# +# This is tricky to test using the tcl interface. However, the +# mechanism used to invoke the tcl script registered as a wal-hook +# depends on the context pointer being correctly passed through. And +# since multiple different wal-hook scripts have been successfully +# invoked by this test script, consider this tested. +# +# EVIDENCE-OF: R-23378-42536 The second is a copy of the database +# handle. +# +# There is an assert() in the C wal-hook used by tclsqlite.c to +# prove this. And that hook has been invoked multiple times when +# running this script. So consider this requirement tested as well. +# + +finish_test diff --git a/test/eval.test b/test/eval.test index 912dc82..360d158 100644 --- a/test/eval.test +++ b/test/eval.test @@ -58,6 +58,18 @@ do_test eval-2.2 { SELECT * FROM t2 } } {} +do_test eval-2.3 { + execsql { + INSERT INTO t2 SELECT x, x+1 FROM t1 WHERE x<5; + SELECT x, test_eval('DELETE FROM t2 WHERE x='||x), y FROM t2 + ORDER BY rowid DESC; + } +} {4 {} {} 3 {} {} 2 {} {} 1 {} {}} +do_test eval-2.4 { + execsql { + SELECT * FROM t2 + } +} {} # Modify a row while it is being read. # diff --git a/test/expr.test b/test/expr.test index cc4c9c6..8d913d2 100644 --- a/test/expr.test +++ b/test/expr.test @@ -205,6 +205,10 @@ test_expr expr-1.125 {i1=6, i2=NULL} \ test_expr expr-1.126 {i1=8, i2=8} \ {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} no +do_catchsql_test expr-1.127 { + SELECT 1 IS #1; +} {1 {near "#1": syntax error}} + ifcapable floatingpoint {if {[working_64bit_int]} { test_expr expr-1.200\ {i1=9223372036854775806, i2=1} {i1+i2} 9223372036854775807 diff --git a/test/fkey2.test b/test/fkey2.test index 4c8daa0..53b90dc 100644 --- a/test/fkey2.test +++ b/test/fkey2.test @@ -1554,7 +1554,7 @@ ifcapable auth { } } {} - proc auth {args} {eval lappend ::authargs $args ; return SQLITE_OK} + proc auth {args} {eval lappend ::authargs [lrange $args 0 4]; return SQLITE_OK} db auth auth # An insert on the parent table must read the child key of any deferred diff --git a/test/fkey5.test b/test/fkey5.test index 5aa8b1d..dc866cb 100644 --- a/test/fkey5.test +++ b/test/fkey5.test @@ -252,13 +252,17 @@ do_test fkey5-6.5 { } {c12 1 p4 0 c12 3 p4 0 c12 6 p4 0} do_test fkey5-7.1 { + set res {} db eval { INSERT OR IGNORE INTO c13 SELECT * FROM c12; INSERT OR IGNORE INTO C14 SELECT * FROM c12; DELETE FROM c12; PRAGMA foreign_key_check; + } { + lappend res [list $table $rowid $fkid $parent] } -} {c14 1 p4 0 c14 3 p4 0 c14 6 p4 0 c13 1 p3 0 c13 2 p3 0 c13 3 p3 0 c13 4 p3 0 c13 5 p3 0 c13 6 p3 0} + lsort $res +} {{c13 1 0 p3} {c13 2 0 p3} {c13 3 0 p3} {c13 4 0 p3} {c13 5 0 p3} {c13 6 0 p3} {c14 1 0 p4} {c14 3 0 p4} {c14 6 0 p4}} do_test fkey5-7.2 { db eval { PRAGMA foreign_key_check(c14); diff --git a/test/fkey7.test b/test/fkey7.test index c2682ed..6c646a9 100644 --- a/test/fkey7.test +++ b/test/fkey7.test @@ -50,5 +50,22 @@ do_tblsread_test 1.3 { UPDATE par SET a=? WHERE b=? } {c1 c2 par} do_tblsread_test 1.4 { UPDATE par SET c=? WHERE b=? } {c3 par} do_tblsread_test 1.5 { UPDATE par SET a=?,b=?,c=? WHERE b=? } {c1 c2 c3 par s1} +ifcapable incrblob { + do_execsql_test 2.0 { + CREATE TABLE pX(x PRIMARY KEY); + CREATE TABLE cX(a INTEGER PRIMARY KEY, b REFERENCES pX); + } + + do_catchsql_test 2.1 { + INSERT INTO cX VALUES(11, zeroblob(40)); + } {1 {FOREIGN KEY constraint failed}} + + do_test 2.2 { + set stmt [sqlite3_prepare_v2 db "INSERT INTO cX VALUES(11, ?)" -1] + sqlite3_bind_zeroblob $stmt 1 45 + sqlite3_step $stmt + sqlite3_finalize $stmt + } {SQLITE_CONSTRAINT} +} finish_test diff --git a/test/fkey8.test b/test/fkey8.test new file mode 100644 index 0000000..60bb8e4 --- /dev/null +++ b/test/fkey8.test @@ -0,0 +1,106 @@ +# 2001 September 15 +# +# 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. +# +# This file implements tests for foreign keys. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fkey8 + +ifcapable {!foreignkey} { + finish_test + return +} +do_execsql_test 1.0 { PRAGMA foreign_keys = 1; } + + +foreach {tn use_stmt sql schema} { + 1 1 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1); + } + + 2.1 0 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE); + } + 2.2 0 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE SET NULL); + } + 2.3 1 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE SET DEFAULT); + } + + 3 1 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE); + CREATE TRIGGER ct1 AFTER DELETE ON c1 BEGIN + INSERT INTO p1 VALUES('x'); + END; + } + + 4 1 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE, c PRIMARY KEY); + CREATE TABLE cc1(d REFERENCES c1); + } + + 5.1 0 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE, c PRIMARY KEY); + CREATE TABLE cc1(d REFERENCES c1 ON DELETE CASCADE); + } + 5.2 0 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE, c PRIMARY KEY); + CREATE TABLE cc1(d REFERENCES c1 ON DELETE SET NULL); + } + 5.3 1 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE, c PRIMARY KEY); + CREATE TABLE cc1(d REFERENCES c1 ON DELETE SET DEFAULT); + } + + 6.1 1 "UPDATE p1 SET a = ?" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON UPDATE SET NULL, c); + } + 6.2 0 "UPDATE OR IGNORE p1 SET a = ?" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON UPDATE SET NULL, c); + } + 6.3 1 "UPDATE OR IGNORE p1 SET a = ?" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON UPDATE CASCADE, c); + } + 6.4 1 "UPDATE OR IGNORE p1 SET a = ?" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b NOT NULL REFERENCES p1 ON UPDATE SET NULL, c); + } + +} { + drop_all_tables + do_test 1.$tn { + execsql $schema + set stmt [sqlite3_prepare_v2 db $sql -1 dummy] + set ret [uses_stmt_journal $stmt] + sqlite3_finalize $stmt + set ret + } $use_stmt +} + + +finish_test + diff --git a/test/fts3expr4.test b/test/fts3expr4.test index 9473797..4bc6203 100644 --- a/test/fts3expr4.test +++ b/test/fts3expr4.test @@ -24,12 +24,16 @@ ifcapable !fts3||!icu { set sqlite_fts3_enable_parentheses 1 -proc test_icu_fts3expr {expr} { - db one {SELECT fts3_exprtest('icu', $expr, 'a', 'b', 'c')} +proc test_fts3expr {tokenizer expr} { + db one {SELECT fts3_exprtest($tokenizer, $expr, 'a', 'b', 'c')} } proc do_icu_expr_test {tn expr res} { - uplevel [list do_test $tn [list test_icu_fts3expr $expr] $res] + uplevel [list do_test $tn [list test_fts3expr icu $expr] [list {*}$res]] +} + +proc do_simple_expr_test {tn expr res} { + uplevel [list do_test $tn [list test_fts3expr simple $expr] [list {*}$res]] } #------------------------------------------------------------------------- @@ -53,5 +57,26 @@ do_icu_expr_test 2.1 { f (e NEAR/2 a) } {AND {AND {AND {PHRASE 3 0 f} {PHRASE 3 0 (}} {NEAR/2 {PHRASE 3 0 e} {PHRASE 3 0 a}}} {PHRASE 3 0 )}} +#------------------------------------------------------------------------- +# +do_simple_expr_test 3.1 {*lOl* *h4h*} { + AND {PHRASE 3 0 lol+} {PHRASE 3 0 h4h+} +} + +do_icu_expr_test 3.2 {*lOl* *h4h*} { + AND {AND {AND {PHRASE 3 0 *} {PHRASE 3 0 lol+}} {PHRASE 3 0 *}} {PHRASE 3 0 h4h+} +} + +do_simple_expr_test 3.3 { * } { } +do_simple_expr_test 3.4 { *a } { PHRASE 3 0 a } +do_simple_expr_test 3.5 { a*b } { AND {PHRASE 3 0 a+} {PHRASE 3 0 b} } +do_simple_expr_test 3.6 { *a*b } { AND {PHRASE 3 0 a+} {PHRASE 3 0 b} } +do_simple_expr_test 3.7 { *"abc" } { PHRASE 3 0 abc } +do_simple_expr_test 3.8 { "abc"* } { PHRASE 3 0 abc } +do_simple_expr_test 3.8 { "ab*c" } { PHRASE 3 0 ab+ c } + +do_icu_expr_test 3.9 { "ab*c" } { PHRASE 3 0 ab+ * c } +do_icu_expr_test 3.10 { ab*c } { AND {PHRASE 3 0 ab+} {PHRASE 3 0 c}} + finish_test diff --git a/test/fts3matchinfo.test b/test/fts3matchinfo.test index fd475af..36c9121 100644 --- a/test/fts3matchinfo.test +++ b/test/fts3matchinfo.test @@ -433,4 +433,21 @@ do_execsql_test 9.1 { SELECT snippet(ft2, '[', ']', '', -1, 1) FROM ft2 WHERE ft2 MATCH 'c'; } {{[c]} {[c]}} +#--------------------------------------------------------------------------- +# Test for a memory leak +# +do_execsql_test 10.1 { + DROP TABLE t10; + CREATE VIRTUAL TABLE t10 USING fts4(idx, value); + INSERT INTO t10 values (1, 'one'),(2, 'two'),(3, 'three'); + SELECT docId, t10.* + FROM t10 + JOIN (SELECT 1 AS idx UNION SELECT 2 UNION SELECT 3) AS x + WHERE t10 MATCH x.idx + AND matchinfo(t10) not null + GROUP BY docId + ORDER BY 1; +} {1 1 one 2 2 two 3 3 three} + + finish_test diff --git a/test/fts4aa.test b/test/fts4aa.test index 88550c9..e6c7f93 100644 --- a/test/fts4aa.test +++ b/test/fts4aa.test @@ -170,7 +170,7 @@ foreach {q r} [array get fts4aa_res] { # Should get the same search results when an authorizer prevents # all PRAGMA statements. # -proc no_pragma_auth {code arg1 arg2 arg3 arg4} { +proc no_pragma_auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_PRAGMA"} {return SQLITE_DENY} return SQLITE_OK; } diff --git a/test/fuzz2.test b/test/fuzz2.test index 989b00f..4b3fb72 100644 --- a/test/fuzz2.test +++ b/test/fuzz2.test @@ -12,7 +12,6 @@ # # This file checks error recovery from malformed SQL strings. # -# $Id: fuzz2.test,v 1.3 2007/05/15 16:51:37 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -105,4 +104,26 @@ do_test fuzz2-5.5 { fuzzcatch {SELECT ALL * GROUP BY EXISTS ( SELECT "AAAAAA" . * , AAAAAA ( * ) AS AAAAAA FROM "AAAAAA" . "AAAAAA" AS "AAAAAA" USING ( AAAAAA , "AAAAAA" , "AAAAAA" ) WHERE AAAAAA ( DISTINCT ) - RAISE ( FAIL , "AAAAAA" ) HAVING "AAAAAA" . "AAAAAA" . AAAAAA ORDER BY #182 , #55 ) BETWEEN EXISTS ( SELECT ALL * FROM ( ( } } {1} +# Test cases discovered by Michal Zalewski on 2015-01-03 and reported on the +# sqlite-users mailing list. All of these cases cause segfaults in +# SQLite 3.8.7.4 and earlier. +# +do_test fuzz2-6.1 { + catchsql {SELECT n()AND+#0;} +} {1 {near "#0": syntax error}} +do_test fuzz2-6.2 { + catchsql {SELECT strftime()} +} {0 {{}}} +do_test fuzz2-6.3 { + catchsql {DETACH(SELECT group_concat(q));} +} {1 {no such column: q}} +do_test fuzz2-6.4a { + db eval {DROP TABLE IF EXISTS t0; CREATE TABLE t0(t);} + catchsql {INSERT INTO t0 SELECT strftime();} +} {0 {}} +do_test fuzz2-6.4b { + db eval {SELECT quote(t) FROM t0} +} {NULL} + + finish_test diff --git a/test/in5.test b/test/in5.test index 8a43b8d..67d2125 100644 --- a/test/in5.test +++ b/test/in5.test @@ -12,6 +12,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix in5 do_test in5-1.1 { execsql { @@ -135,4 +136,51 @@ do_test in5-5.3 { }] } {0} +#------------------------------------------------------------------------- +# At one point SQLite was removing the DISTINCT keyword from expressions +# similar to: +# +# IN (SELECT DISTINCT FROM...) +# +# However, there are a few obscure cases where this is incorrect. For +# example, if the SELECT features a LIMIT clause, or if the collation +# sequence or affinity used by the DISTINCT does not match the one used +# by the IN(...) expression. +# +do_execsql_test 6.1.1 { + CREATE TABLE t1(a COLLATE nocase); + INSERT INTO t1 VALUES('one'); + INSERT INTO t1 VALUES('ONE'); +} +do_execsql_test 6.1.2 { + SELECT count(*) FROM t1 WHERE a COLLATE BINARY IN (SELECT DISTINCT a FROM t1) +} {1} + +do_execsql_test 6.2.1 { + CREATE TABLE t3(a, b); + INSERT INTO t3 VALUES(1, 1); + INSERT INTO t3 VALUES(1, 2); + INSERT INTO t3 VALUES(1, 3); + INSERT INTO t3 VALUES(2, 4); + INSERT INTO t3 VALUES(2, 5); + INSERT INTO t3 VALUES(2, 6); + INSERT INTO t3 VALUES(3, 7); + INSERT INTO t3 VALUES(3, 8); + INSERT INTO t3 VALUES(3, 9); +} +do_execsql_test 6.2.2 { + SELECT count(*) FROM t3 WHERE b IN (SELECT DISTINCT a FROM t3 LIMIT 5); +} {3} +do_execsql_test 6.2.3 { + SELECT count(*) FROM t3 WHERE b IN (SELECT a FROM t3 LIMIT 5); +} {2} + +do_execsql_test 6.3.1 { + CREATE TABLE x1(a); + CREATE TABLE x2(b); + INSERT INTO x1 VALUES(1), (1), (2); + INSERT INTO x2 VALUES(1), (2); + SELECT count(*) FROM x2 WHERE b IN (SELECT DISTINCT a FROM x1 LIMIT 2); +} {2} + finish_test diff --git a/test/index5.test b/test/index5.test index 7895391..e369d75 100644 --- a/test/index5.test +++ b/test/index5.test @@ -16,6 +16,9 @@ source $testdir/tester.tcl set ::testprefix index5 do_test 1.1 { + if {[permutation]=="memsubsys1"} { + execsql { PRAGMA auto_vacuum = 0; } + } execsql { PRAGMA page_size = 1024; CREATE TABLE t1(x); @@ -38,7 +41,7 @@ tvfs filter xWrite tvfs script write_cb proc write_cb {xCall file handle iOfst args} { if {[file tail $file]=="test.db"} { - lappend ::write_list [expr $iOfst/1024] + lappend ::write_list [expr $iOfst/1024 + 1] } } diff --git a/test/index6.test b/test/index6.test index 68bdd06..8414b11 100644 --- a/test/index6.test +++ b/test/index6.test @@ -267,5 +267,33 @@ do_execsql_test index6-6.2 { PRAGMA integrity_check; } {ok} +# Test case for ticket [2326c258d02ead33d69faa63de8f4686b9b1b9d9] on +# 2015-02-24. Any use of a partial index qualifying constraint inside +# the ON clause of a LEFT JOIN was causing incorrect results for all +# versions of SQLite 3.8.0 through 3.8.8. +# +do_execsql_test index6-7.0 { + CREATE TABLE t7a(x); + CREATE TABLE t7b(y); + INSERT INTO t7a(x) VALUES(1); + CREATE INDEX t7ax ON t7a(x) WHERE x=99; + PRAGMA automatic_index=OFF; + SELECT * FROM t7a LEFT JOIN t7b ON (x=99) ORDER BY x; +} {1 {}} +do_execsql_test index6-7.1 { + INSERT INTO t7b(y) VALUES(2); + SELECT * FROM t7a JOIN t7b ON (x=99) ORDER BY x; +} {} +do_execsql_test index6-7.2 { + INSERT INTO t7a(x) VALUES(99); + SELECT * FROM t7a LEFT JOIN t7b ON (x=99) ORDER BY x; +} {1 {} 99 2} +do_execsql_test index6-7.3 { + SELECT * FROM t7a JOIN t7b ON (x=99) ORDER BY x; +} {99 2} +do_execsql_test index6-7.4 { + EXPLAIN QUERY PLAN + SELECT * FROM t7a JOIN t7b ON (x=99) ORDER BY x; +} {/USING COVERING INDEX t7ax/} finish_test diff --git a/test/index7.test b/test/index7.test index 1c81f60..0f341a3 100644 --- a/test/index7.test +++ b/test/index7.test @@ -248,4 +248,34 @@ do_execsql_test index7-5.0 { SELECT stat+0 FROM sqlite_stat1 WHERE idx='t3b'; } {6 6} +# Verify that the problem identified by ticket [98d973b8f5] has been fixed. +# +do_execsql_test index7-6.1 { + CREATE TABLE t5(a, b); + CREATE TABLE t4(c, d); + INSERT INTO t5 VALUES(1, 'xyz'); + INSERT INTO t4 VALUES('abc', 'not xyz'); + SELECT * FROM (SELECT * FROM t5 WHERE a=1 AND b='xyz'), t4 WHERE c='abc'; +} { + 1 xyz abc {not xyz} +} +do_execsql_test index7-6.2 { + CREATE INDEX i4 ON t4(c) WHERE d='xyz'; + SELECT * FROM (SELECT * FROM t5 WHERE a=1 AND b='xyz'), t4 WHERE c='abc'; +} { + 1 xyz abc {not xyz} +} +do_execsql_test index7-6.3 { + CREATE VIEW v4 AS SELECT * FROM t4; + INSERT INTO t4 VALUES('def', 'xyz'); + SELECT * FROM v4 WHERE d='xyz' AND c='def' +} { + def xyz +} +do_eqp_test index7-6.4 { + SELECT * FROM v4 WHERE d='xyz' AND c='def' +} { + 0 0 0 {SEARCH TABLE t4 USING INDEX i4 (c=?)} +} + finish_test diff --git a/test/ioerr2.test b/test/ioerr2.test index 5150ace..c08c345 100644 --- a/test/ioerr2.test +++ b/test/ioerr2.test @@ -112,6 +112,12 @@ foreach bPersist [list 0 1] { } } +# When this test was written, an IO error within the UPDATE statement caused +# a rollback, which tripped all read-cursors, causing the outer SELECT to +# fail with "abort due to ROLLBACK". Now, the loop continues until the UPDATE +# is run successfully. At this point the next IO error occurs within the +# SELECT - throwing the "disk I/O error" that the test case now expects. +# do_test ioerr2-5 { execsql { CREATE TABLE t2 AS SELECT * FROM t1; @@ -130,7 +136,7 @@ do_test ioerr2-5 { } } msg] list $rc $msg -} {1 {abort due to ROLLBACK}} +} {1 {disk I/O error}} ;# used to be "{1 {abort due to ROLLBACK}}" if {$::tcl_platform(platform) == "unix"} { # Cause the call to xAccess used by [pragma temp_store_directory] to diff --git a/test/join5.test b/test/join5.test index 45d8a31..b0b0df4 100644 --- a/test/join5.test +++ b/test/join5.test @@ -106,5 +106,59 @@ do_test join5-2.12 { execsql {SELECT * FROM xy LEFT JOIN ab ON NULL WHERE NULL} } {} +# Ticket https://www.sqlite.org/src/tktview/6f2222d550f5b0ee7ed37601 +# Incorrect output on a LEFT JOIN. +# +do_execsql_test join5-3.1 { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + DROP TABLE IF EXISTS t3; + CREATE TABLE x1(a); + INSERT INTO x1 VALUES(1); + CREATE TABLE x2(b NOT NULL); + CREATE TABLE x3(c, d); + INSERT INTO x3 VALUES('a', NULL); + INSERT INTO x3 VALUES('b', NULL); + INSERT INTO x3 VALUES('c', NULL); + SELECT * FROM x1 LEFT JOIN x2 LEFT JOIN x3 ON x3.d = x2.b; +} {1 {} {} {}} +do_execsql_test join5-3.2 { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + DROP TABLE IF EXISTS t3; + DROP TABLE IF EXISTS t4; + DROP TABLE IF EXISTS t5; + CREATE TABLE t1(x text NOT NULL, y text); + CREATE TABLE t2(u text NOT NULL, x text NOT NULL); + CREATE TABLE t3(w text NOT NULL, v text); + CREATE TABLE t4(w text NOT NULL, z text NOT NULL); + CREATE TABLE t5(z text NOT NULL, m text); + INSERT INTO t1 VALUES('f6d7661f-4efe-4c90-87b5-858e61cd178b',NULL); + INSERT INTO t1 VALUES('f6ea82c3-2cad-45ce-ae8f-3ddca4fb2f48',NULL); + INSERT INTO t1 VALUES('f6f47499-ecb4-474b-9a02-35be73c235e5',NULL); + INSERT INTO t1 VALUES('56f47499-ecb4-474b-9a02-35be73c235e5',NULL); + INSERT INTO t3 VALUES('007f2033-cb20-494c-b135-a1e4eb66130c', + 'f6d7661f-4efe-4c90-87b5-858e61cd178b'); + SELECT * + FROM t3 + INNER JOIN t1 ON t1.x= t3.v AND t1.y IS NULL + LEFT JOIN t4 ON t4.w = t3.w + LEFT JOIN t5 ON t5.z = t4.z + LEFT JOIN t2 ON t2.u = t5.m + LEFT JOIN t1 xyz ON xyz.y = t2.x; +} {007f2033-cb20-494c-b135-a1e4eb66130c f6d7661f-4efe-4c90-87b5-858e61cd178b f6d7661f-4efe-4c90-87b5-858e61cd178b {} {} {} {} {} {} {} {} {}} +do_execsql_test join5-3.3 { + DROP TABLE IF EXISTS x1; + DROP TABLE IF EXISTS x2; + DROP TABLE IF EXISTS x3; + CREATE TABLE x1(a); + INSERT INTO x1 VALUES(1); + CREATE TABLE x2(b NOT NULL); + CREATE TABLE x3(c, d); + INSERT INTO x3 VALUES('a', NULL); + INSERT INTO x3 VALUES('b', NULL); + INSERT INTO x3 VALUES('c', NULL); + SELECT * FROM x1 LEFT JOIN x2 JOIN x3 WHERE x3.d = x2.b; +} {} finish_test diff --git a/test/lock5.test b/test/lock5.test index f0d4955..99214af 100644 --- a/test/lock5.test +++ b/test/lock5.test @@ -154,6 +154,7 @@ do_test lock5-flock.8 { do_test lock5-none.1 { sqlite3 db test.db -vfs unix-none sqlite3 db2 test.db -vfs unix-none + execsql { PRAGMA mmap_size = 0 } db2 execsql { BEGIN; INSERT INTO t1 VALUES(3, 4); @@ -162,8 +163,8 @@ do_test lock5-none.1 { do_test lock5-none.2 { execsql { SELECT * FROM t1 } } {1 2 3 4} -do_test lock5-flock.3 { - execsql { SELECT * FROM t1 } db2 +do_test lock5-none.3 { + execsql { SELECT * FROM t1; } db2 } {1 2} do_test lock5-none.4 { execsql { @@ -183,7 +184,7 @@ ifcapable memorymanage { } {1 2 3 4} } -do_test lock5-flock.X { +do_test lock5-none.X { db close db2 close } {} diff --git a/test/main.test b/test/main.test index 5bbc52b..3f35afe 100644 --- a/test/main.test +++ b/test/main.test @@ -514,5 +514,25 @@ if {$::tcl_platform(platform)=="unix" } {1 {no such vfs: async}} } } + +# Print the version number so that it can be picked up by releasetest.tcl. +# +puts [db one {SELECT 'VERSION: ' || + sqlite_version() || ' ' || + sqlite_source_id();}] + +# Do deliberate failures if the TEST_FAILURE environment variable is set. +# This is done to verify that failure notifications are detected by the +# releasetest.tcl script, or possibly by other scripts involved in automatic +# testing. +# +if {[info exists ::env(TEST_FAILURE)]} { + set res 123 + if {$::env(TEST_FAILURE)==0} {set res 234} + do_test main-99.1 { + bad_behavior $::env(TEST_FAILURE) + set x 123 + } $res +} finish_test diff --git a/test/malloc.test b/test/malloc.test index 4276b58..8614567 100644 --- a/test/malloc.test +++ b/test/malloc.test @@ -881,6 +881,48 @@ do_malloc_test 39 -tclprep { db close } +reset_db +add_test_utf16bin_collate db +do_execsql_test 40.1 { + CREATE TABLE t1(a); + INSERT INTO t1 VALUES('fghij'); + INSERT INTO t1 VALUES('pqrst'); + INSERT INTO t1 VALUES('abcde'); + INSERT INTO t1 VALUES('uvwxy'); + INSERT INTO t1 VALUES('klmno'); +} +do_execsql_test 40.2 { + SELECT * FROM t1 ORDER BY 1 COLLATE utf16bin; +} {abcde fghij klmno pqrst uvwxy} +do_faultsim_test 40.3 -faults oom-trans* -body { + execsql { + SELECT * FROM t1 ORDER BY 1 COLLATE utf16bin; + } +} -test { + faultsim_test_result {0 {abcde fghij klmno pqrst uvwxy}} + faultsim_integrity_check +} + +reset_db +add_test_utf16bin_collate db +set big [string repeat x 200] +do_execsql_test 41.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a COLLATE utf16bin); + INSERT INTO t1 VALUES('fghij' || $::big); + INSERT INTO t1 VALUES('pqrst' || $::big); + INSERT INTO t1 VALUES('abcde' || $::big); + INSERT INTO t1 VALUES('uvwxy' || $::big); + INSERT INTO t1 VALUES('klmno' || $::big); + CREATE INDEX i1 ON t1(a); +} +do_faultsim_test 41.2 -faults oom* -body { + execsql { SELECT * FROM t1 WHERE a = ('abcde' || $::big)} +} -test { + faultsim_test_result [list 0 "abcde$::big"] + faultsim_integrity_check +} + # Ensure that no file descriptors were leaked. do_test malloc-99.X { catch {db close} diff --git a/test/mallocA.test b/test/mallocA.test index 61e88a6..a78073d 100644 --- a/test/mallocA.test +++ b/test/mallocA.test @@ -25,7 +25,6 @@ if {!$MEMDEBUG} { return } - # Construct a test database # forcedelete test.db.bu @@ -116,6 +115,26 @@ ifcapable stat3 { } } +do_execsql_test 7.0 { + PRAGMA cache_size = 5; +} +do_faultsim_test 7 -faults oom-trans* -prep { +} -body { + execsql { + WITH r(x,y) AS ( + SELECT 1, randomblob(100) + UNION ALL + SELECT x+1, randomblob(100) FROM r + LIMIT 1000 + ) + SELECT count(x), length(y) FROM r GROUP BY (x%5) + } +} -test { + set res [list 200 100 200 100 200 100 200 100 200 100] + faultsim_test_result [list 0 $res] +} + + # Ensure that no file descriptors were leaked. do_test malloc-99.X { catch {db close} diff --git a/test/memsubsys1.test b/test/memsubsys1.test index 76b79d0..891558f 100644 --- a/test/memsubsys1.test +++ b/test/memsubsys1.test @@ -124,7 +124,13 @@ do_test memsubsys1-3.1.3 { } 0 do_test memsubsys1-3.1.4 { set overflow [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2] -} $max_pagecache + # Note: The measured PAGECACHE_OVERFLOW is amount malloc() returns, not what + # was requested. System malloc() implementations might (arbitrarily) return + # slightly different oversize buffers, which can result in slightly different + # PAGECACHE_OVERFLOW sizes between consecutive runs. So we cannot do an + # exact comparison. Simply verify that the amount is within 5%. + expr {$overflow>=$max_pagecache*0.95 && $overflow<=$max_pagecache*1.05} +} 1 do_test memsubsys1-3.1.5 { set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2] } 0 @@ -170,20 +176,20 @@ do_test memsubsys1-4.6 { set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2] } 1 -# Test 5: Activate both PAGECACHE and SCRATCH. But make the page size +# Test 5: Activate both PAGECACHE and SCRATCH. But make the page size is # such that the SCRATCH allocations are too small. # db close sqlite3_shutdown sqlite3_config_pagecache [expr 4096+$xtra_size] 24 -sqlite3_config_scratch 6000 2 +sqlite3_config_scratch 4000 2 sqlite3_initialize reset_highwater_marks build_test_db memsubsys1-5 {PRAGMA page_size=4096} #show_memstats do_test memsubsys1-5.3 { set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2] -} 24 +} {/^2[34]$/} do_test memsubsys1-5.4 { set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2] expr {$maxreq>4096} @@ -209,7 +215,7 @@ build_test_db memsubsys1-6 {PRAGMA page_size=4096} #show_memstats do_test memsubsys1-6.3 { set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2] -} 24 +} {/^2[34]$/} #do_test memsubsys1-6.4 { # set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2] # expr {$maxreq>4096 && $maxreq<=(4096+$xtra_size)} diff --git a/test/minmax4.test b/test/minmax4.test index 0d8305b..8063538 100644 --- a/test/minmax4.test +++ b/test/minmax4.test @@ -56,14 +56,16 @@ do_test minmax4-1.5 { do_test minmax4-1.6 { db eval { SELECT p, min(q) FROM t1; + SELECT p FROM (SELECT p, min(q) FROM t1); } -} {1 2} +} {1 2 1} do_test minmax4-1.7 { db eval { INSERT INTO t1 VALUES(5,0); SELECT p, max(q) FROM t1; + SELECT p FROM (SELECT max(q), p FROM t1); } -} {3 4} +} {3 4 3} do_test minmax4-1.8 { db eval { SELECT p, min(q) FROM t1; @@ -73,8 +75,9 @@ do_test minmax4-1.9 { db eval { INSERT INTO t1 VALUES(6,1); SELECT p, max(q) FROM t1; + SELECT p FROM (SELECT max(q), p FROM t1); } -} {3 4} +} {3 4 3} do_test minmax4-1.10 { db eval { SELECT p, min(q) FROM t1; diff --git a/test/misc8.test b/test/misc8.test new file mode 100644 index 0000000..3ff52e5 --- /dev/null +++ b/test/misc8.test @@ -0,0 +1,98 @@ +# 2014-11-10 +# +# 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 "eval.c" loadable extension. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +load_static_extension db eval +do_execsql_test misc8-1.0 { + CREATE TABLE t1(a,b,c); + INSERT INTO t1 VALUES(1,2,3),(4,5,6); + SELECT quote(eval('SELECT * FROM t1 ORDER BY a','-abc-')); +} {'1-abc-2-abc-3-abc-4-abc-5-abc-6'} +do_execsql_test misc8-1.1 { + SELECT quote(eval('SELECT * FROM t1 ORDER BY a')); +} {{'1 2 3 4 5 6'}} +do_catchsql_test misc8-1.2 { + SELECT quote(eval('SELECT d FROM t1 ORDER BY a')); +} {1 {no such column: d}} +do_execsql_test misc8-1.3 { + INSERT INTO t1 VALUES(7,null,9); + SELECT eval('SELECT * FROM t1 ORDER BY a',','); +} {1,2,3,4,5,6,7,,9} +do_catchsql_test misc8-1.4 { + BEGIN; + INSERT INTO t1 VALUES(10,11,12); + SELECT a, coalesce(b, eval('ROLLBACK; SELECT ''bam'';')), c + FROM t1 ORDER BY a; +} {0 {1 2 3 4 5 6 7 bam 9}} +do_catchsql_test misc8-1.5 { + INSERT INTO t1 VALUES(10,11,12); + SELECT a, coalesce(b, eval('SELECT ''bam''')), c + FROM t1 + ORDER BY rowid; +} {0 {1 2 3 4 5 6 7 bam 9 10 11 12}} +do_catchsql_test misc8-1.6 { + SELECT a, coalesce(b, eval('DELETE FROM t1; SELECT ''bam''')), c + FROM t1 + ORDER BY rowid; +} {0 {1 2 3 4 5 6 7 bam {}}} +do_catchsql_test misc8-1.7 { + INSERT INTO t1 VALUES(1,2,3),(4,5,6),(7,null,9); + BEGIN; + CREATE TABLE t2(x); + SELECT a, coalesce(b, eval('ROLLBACK; SELECT ''bam''')), c + FROM t1 + ORDER BY rowid; +} {1 {abort due to ROLLBACK}} + + +reset_db + +proc dbeval {sql} { db eval $sql } +db func eval dbeval + +do_execsql_test misc8-2.1 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER) WITHOUT ROWID; + CREATE TABLE t2(c INTEGER PRIMARY KEY, d INTEGER, x BLOB); + INSERT INTO t1 VALUES(0,0); + INSERT INTO t1 VALUES(10,10); + INSERT INTO t2 VALUES(1,1,zeroblob(200)); + INSERT INTO t2 VALUES(2,2,zeroblob(200)); + INSERT INTO t2 VALUES(3,3,zeroblob(200)); + INSERT INTO t2 VALUES(4,4,zeroblob(200)); + INSERT INTO t2 VALUES(5,5,zeroblob(200)); + INSERT INTO t2 VALUES(6,6,zeroblob(200)); + INSERT INTO t2 VALUES(7,7,zeroblob(200)); + INSERT INTO t2 VALUES(8,8,zeroblob(200)); + INSERT INTO t2 VALUES(9,9,zeroblob(200)); + INSERT INTO t2 VALUES(10,10,zeroblob(200)); + SELECT a, c, eval( + printf('DELETE FROM t2 WHERE c=%d AND %d>5', a+c, a+c) + ) FROM t1, t2; +} { + 0 1 {} 10 1 {} + 0 2 {} 10 2 {} + 0 3 {} 10 3 {} + 0 4 {} 10 4 {} + 0 5 {} 10 5 {} + 0 6 {} 10 {} {} + 0 7 {} 10 {} {} + 0 8 {} 10 {} {} + 0 9 {} 10 {} {} + 0 10 {} 10 {} {} +} + + +finish_test diff --git a/test/mmap1.test b/test/mmap1.test index ece3e02..18aec9f 100644 --- a/test/mmap1.test +++ b/test/mmap1.test @@ -33,7 +33,7 @@ proc register_rblob_code {dbname seed} { set ::rcnt $seed proc rblob {n} { set ::rcnt [expr (([set ::rcnt] << 3) + [set ::rcnt] + 456) & 0xFFFFFFFF] - set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]] + set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]] string range [string repeat [set str] [expr [set n]/4]] 1 [set n] } $dbname func rblob rblob @@ -42,7 +42,7 @@ proc register_rblob_code {dbname seed} { # For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on # unix and 9 on windows. The difference is that windows only ever maps -# an integer number of OS pages (i.e. creates mappings that are a multiple +# an integer number of OS pages (i.e. creates mappings that are a multiple # of 4KB in size). Whereas on unix any sized mapping may be created. # foreach {t mmap_size nRead c2init} { @@ -106,50 +106,52 @@ foreach {t mmap_size nRead c2init} { set ::rcnt 0 proc rblob {n} { set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF] - set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]] + set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]] string range [string repeat $str [expr $n/4]] 1 $n } reset_db db func rblob rblob -do_execsql_test 2.1 { - PRAGMA auto_vacuum = 1; - PRAGMA mmap_size = 67108864; - PRAGMA journal_mode = wal; - CREATE TABLE t1(a, b, UNIQUE(a, b)); - INSERT INTO t1 VALUES(rblob(500), rblob(500)); - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 - PRAGMA wal_checkpoint; -} {67108864 wal 0 103 103} - -do_execsql_test 2.2 { - PRAGMA auto_vacuum; - SELECT count(*) FROM t1; -} {1 32} - -if {[permutation] != "inmemory_journal"} { - do_test 2.3 { - sqlite3 db2 test.db - db2 func rblob rblob - db2 eval { - DELETE FROM t1 WHERE (rowid%4); - PRAGMA wal_checkpoint; - } - db2 eval { - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 - SELECT count(*) FROM t1; - } - } {16} - - do_execsql_test 2.4 { +ifcapable wal { + do_execsql_test 2.1 { + PRAGMA auto_vacuum = 1; + PRAGMA mmap_size = 67108864; + PRAGMA journal_mode = wal; + CREATE TABLE t1(a, b, UNIQUE(a, b)); + INSERT INTO t1 VALUES(rblob(500), rblob(500)); + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 PRAGMA wal_checkpoint; - } {0 24 24} - db2 close + } {67108864 wal 0 103 103} + + do_execsql_test 2.2 { + PRAGMA auto_vacuum; + SELECT count(*) FROM t1; + } {1 32} + + if {[permutation] != "inmemory_journal"} { + do_test 2.3 { + sqlite3 db2 test.db + db2 func rblob rblob + db2 eval { + DELETE FROM t1 WHERE (rowid%4); + PRAGMA wal_checkpoint; + } + db2 eval { + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 + SELECT count(*) FROM t1; + } + } {16} + + do_execsql_test 2.4 { + PRAGMA wal_checkpoint; + } {0 24 24} + db2 close + } } reset_db @@ -227,7 +229,7 @@ do_test 4.4 { do_execsql_test 4.5 { COMMIT } #------------------------------------------------------------------------- -# Ensure that existing cursors holding xFetch() references are not +# Ensure that existing cursors holding xFetch() references are not # confused if those pages are moved to make way for the root page of a # new table or index. # @@ -296,7 +298,7 @@ foreach {tn1 mmap1 mmap2} { sql1 "PRAGMA mmap_size = $mmap1" sql2 "PRAGMA mmap_size = $mmap2" - do_test $tn1.$tn { + do_test $tn1.$tn { for {set i 1} {$i <= 100} {incr i} { if {$i % 2} { set c1 sql1 @@ -311,7 +313,7 @@ foreach {tn1 mmap1 mmap2} { UPDATE t2 SET x = (SELECT md5sum(a) FROM t1); } - set res [$c2 { + set res [$c2 { SELECT count(*) FROM t1; SELECT x == (SELECT md5sum(a) FROM t1) FROM t2; PRAGMA integrity_check; diff --git a/test/multiplex4.test b/test/multiplex4.test new file mode 100644 index 0000000..9c304c3 --- /dev/null +++ b/test/multiplex4.test @@ -0,0 +1,114 @@ +# 2014-09-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 contains tests for the "truncate" option in the multiplexor. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix multiplex4 + +db close +sqlite3_shutdown +sqlite3_multiplex_initialize {} 0 + +# delete all filesl with the base name of $basename +# +proc multiplex_delete_db {basename} { + foreach file [glob -nocomplain $basename.*] { + forcedelete $file + } +} + +# Return a sorted list of all files with the base name of $basename. +# Except, delete all text from the end of $basename through the NNN +# suffix on the end of the filename. +# +proc multiplex_file_list {basename} { + set x {} + foreach file [glob -nocomplain $basename.*] { + regsub "^$basename\\..*(\\d\\d\\d)\$" $file $basename.\\1 file + lappend x $file + } + return [lsort $x] +} + +do_test multiplex4-1.0 { + multiplex_delete_db mx4test + sqlite3 db {file:mx4test.db?chunksize=10&truncate=1} -uri 1 -vfs multiplex + db eval { + CREATE TABLE t1(x); + INSERT INTO t1(x) VALUES(randomblob(250000)); + } + multiplex_file_list mx4test +} {mx4test.001 mx4test.db} + +do_test multiplex4-1.1 { + db eval { + DELETE FROM t1; + VACUUM; + } + multiplex_file_list mx4test +} {mx4test.db} + +do_test multiplex4-1.2 { + db eval {PRAGMA multiplex_truncate} +} {on} +do_test multiplex4-1.3 { + db eval {PRAGMA multiplex_truncate=off} +} {off} +do_test multiplex4-1.4 { + db eval {PRAGMA multiplex_truncate} +} {off} +do_test multiplex4-1.5 { + db eval {PRAGMA multiplex_truncate=on} +} {on} +do_test multiplex4-1.6 { + db eval {PRAGMA multiplex_truncate} +} {on} +do_test multiplex4-1.7 { + db eval {PRAGMA multiplex_truncate=0} +} {off} +do_test multiplex4-1.8 { + db eval {PRAGMA multiplex_truncate=1} +} {on} +do_test multiplex4-1.9 { + db eval {PRAGMA multiplex_truncate=0} +} {off} + +do_test multiplex4-1.10 { + db eval { + INSERT INTO t1(x) VALUES(randomblob(250000)); + } + multiplex_file_list mx4test +} {mx4test.001 mx4test.db} + +do_test multiplex4-1.11 { + db eval { + DELETE FROM t1; + VACUUM; + } + multiplex_file_list mx4test +} {mx4test.001 mx4test.db} + +do_test multiplex4-1.12 { + db eval { + PRAGMA multiplex_truncate=ON; + DROP TABLE t1; + VACUUM; + } + multiplex_file_list mx4test +} {mx4test.db} + +catch { db close } +forcedelete mx4test.db +sqlite3_multiplex_shutdown +finish_test diff --git a/test/notify2.test b/test/notify2.test index 9e40ed6..12c6a53 100644 --- a/test/notify2.test +++ b/test/notify2.test @@ -101,6 +101,8 @@ set sql $zSql # This loop runs for ~20 seconds. # set iStart [clock_seconds] + set nOp 0 + set nAttempt 0 while { ([clock_seconds]-$iStart) < $nSecond } { # Each transaction does 3 operations. Each operation is either a read @@ -128,6 +130,7 @@ set sql $zSql # Execute the SQL transaction. # + incr nAttempt set rc [catch { execsql_blocking $::DB " BEGIN; $SQL(1); @@ -154,13 +157,14 @@ set sql $zSql # returned "1". Otherwise, the invariant was false, indicating that # some malfunction has occurred. foreach r $msg { if {$r != 1} { puts "Invariant check failed: $msg" } } + incr nOp } } # Close the database connection and return 0. # sqlite3_close $::DB - expr 0 + list $nOp $nAttempt } foreach {iTest xStep xPrepare} { @@ -204,7 +208,9 @@ foreach {iTest xStep xPrepare} { for {set ii 0} {$ii < $nThread} {incr ii} { do_test notify2-$iTest.2.$ii { if {![info exists finished($ii)]} { vwait finished($ii) } - set finished($ii) + incr anSuccess($xStep) [lindex $finished($ii) 0] + incr anAttempt($xStep) [lindex $finished($ii) 1] + expr 0 } {0} } @@ -225,17 +231,36 @@ foreach {iTest xStep xPrepare} { } # The following tests checks to make sure sqlite3_blocking_step() is -# faster than sqlite3_step(). blocking_step() is always faster on -# multi-core and is usually faster on single-core. But sometimes, by -# chance, step() will be faster on a single core, in which case the +# faster than sqlite3_step(). "Faster" in this case means uses fewer +# CPU cycles. This is not always the same as faster in wall-clock time +# for this type of test. The number of CPU cycles per transaction is +# roughly proportional to the number of attempts made (i.e. one plus the +# number of SQLITE_BUSY or SQLITE_LOCKED errors that require the transaction +# to be retried). So this test just measures that a greater percentage of +# transactions attempted using blocking_step() succeed. +# +# The blocking_step() function is almost always faster on multi-core and is +# usually faster on single-core. But sometimes, by chance, step() will be +# faster on a single core, in which case the # following test will fail. # puts "The following test seeks to demonstrate that the sqlite3_unlock_notify()" -puts "interface helps multi-core systems to run faster. This test sometimes" -puts "fails on single-core machines." +puts "interface helps multi-core systems to run more efficiently. This test" +puts "sometimes fails on single-core machines." puts [array get anWrite] do_test notify2-3 { - expr {$anWrite(sqlite3_blocking_step) > $anWrite(sqlite3_step)} + set blocking [expr { + double($anSuccess(sqlite3_blocking_step)) / + double($anAttempt(sqlite3_blocking_step)) + }] + set non [expr { + double($anSuccess(sqlite3_step)) / + double($anAttempt(sqlite3_step)) + }] + puts -nonewline [format " blocking: %.1f%% non-blocking %.1f%% ..." \ + [expr $blocking*100.0] [expr $non*100.0]] + + expr {$blocking > $non} } {1} sqlite3_enable_shared_cache $::enable_shared_cache diff --git a/test/orderby1.test b/test/orderby1.test index e06c9f1..6674e32 100644 --- a/test/orderby1.test +++ b/test/orderby1.test @@ -481,5 +481,19 @@ do_execsql_test 6.0 { FROM abc; } {hardware hardware hardware} +# Here is a test for a query-planner problem reported on the SQLite +# mailing list on 2014-09-18 by "Merike". Beginning with version 3.8.0, +# a separate sort was being used rather than using the single-column +# index. This was due to an oversight in the indexMightHelpWithOrderby() +# routine in where.c. +# +do_execsql_test 7.0 { + CREATE TABLE t7(a,b); + CREATE INDEX t7a ON t7(a); + CREATE INDEX t7ab ON t7(a,b); + EXPLAIN QUERY PLAN + SELECT * FROM t7 WHERE a=?1 ORDER BY rowid; +} {~/ORDER BY/} + finish_test diff --git a/test/orderby8.test b/test/orderby8.test new file mode 100644 index 0000000..53da971 --- /dev/null +++ b/test/orderby8.test @@ -0,0 +1,41 @@ +# 2015-01-19 +# +# 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 file is testing ORDER BY and LIMIT on tables with +# many columns. +# +# These tests verify that ticket [f97c4637102a3ae72b7911167e1d4da12ce60722] +# from 2015-01-19 has been fixed. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix orderby8 + +do_test 1.0 { + db eval { + CREATE TABLE t1(x); + INSERT INTO t1(x) VALUES(1),(5),(9),(7),(3),(2),(4),(6),(8); + } + set ::result_set "x" +} {x} +for {set i 1} {$i<200} {incr i} { + append ::result_set ", x+$i" + do_test 1.$i { + set res {} + db eval "SELECT $::result_set FROM t1 ORDER BY x LIMIT -1" { + lappend res $x + } + set res + } {1 2 3 4 5 6 7 8 9} +} + +finish_test diff --git a/test/oserror.test b/test/oserror.test index 40d2966..1bfa37c 100644 --- a/test/oserror.test +++ b/test/oserror.test @@ -51,19 +51,20 @@ proc do_re_test {tn script expression} { # a call to getcwd() may fail if there are no free file descriptors. So # an error may be reported for either open() or getcwd() here. # -puts "Possible valgrind error about invalid file descriptor follows:" -do_test 1.1.1 { - set ::log [list] - list [catch { - for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 } - } msg] $msg -} {1 {unable to open database file}} -do_test 1.1.2 { - catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } } -} {1} -do_re_test 1.1.3 { - lindex $::log 0 -} {^os_unix.c:\d+: \(\d+\) (open|getcwd)\(.*test.db\) - } +if {![clang_sanitize_address]} { + do_test 1.1.1 { + set ::log [list] + list [catch { + for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 } + } msg] $msg + } {1 {unable to open database file}} + do_test 1.1.2 { + catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } } + } {1} + do_re_test 1.1.3 { + lindex $::log 0 + } {^os_unix.c:\d+: \(\d+\) (open|getcwd)\(.*test.db\) - } +} # Test a failure in open() due to the path being a directory. diff --git a/test/ovfl.test b/test/ovfl.test new file mode 100644 index 0000000..075b1e4 --- /dev/null +++ b/test/ovfl.test @@ -0,0 +1,49 @@ +# 2014 October 01 +# +# 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 file is testing the SQLITE_DIRECT_OVERFLOW_READ logic. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix ovfl + +# Populate table t2: +# +# CREATE TABLE t1(c1 TEXT, c2 TEXT); +# +# with 2000 rows. In each row, c2 spans multiple overflow pages. The text +# value of c1 ranges in size from 1 to 2000 bytes. The idea is to create +# at least one row where the first byte of c2 is also the first byte of +# an overflow page. This was at one point exposing an obscure bug in the +# SQLITE_DIRECT_OVERFLOW_READ logic. +# +do_test 1.1 { + set c2 [string repeat abcdefghij 200] + execsql { + PRAGMA cache_size = 10; + CREATE TABLE t1(c1 TEXT, c2 TEXT); + BEGIN; + } + for {set i 1} {$i <= 2000} {incr i} { + set c1 [string repeat . $i] + execsql { INSERT INTO t1 VALUES($c1, $c2) } + } + execsql COMMIT +} {} + +do_execsql_test 1.2 { + SELECT sum(length(c2)) FROM t1; +} [expr 2000 * 2000] + +finish_test + + diff --git a/test/percentile.test b/test/percentile.test index 9d471df..b2bd061 100644 --- a/test/percentile.test +++ b/test/percentile.test @@ -200,7 +200,7 @@ ifcapable vtab { } { do_test percentile-2.1.$in { execsql { - SELECT percentile(x, $in) from t3; + SELECT round(percentile(x, $in),1) from t3; } } $out } diff --git a/test/permutations.test b/test/permutations.test index c3f4ddf..44f62e8 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -112,11 +112,25 @@ set allquicktests [test_set $alltests -exclude { incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test vtab_err.test walslow.test walcrash.test walcrash3.test walthread.test rtree3.test indexfault.test securedel2.test - fts4growth.test fts4growth2.test + sort3.test sort4.test fts4growth.test fts4growth2.test + bigsort.test }] if {[info exists ::env(QUICKTEST_INCLUDE)]} { set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)] } +if {[info exists ::env(QUICKTEST_OMIT)]} { + foreach x [split $::env(QUICKTEST_OMIT) ,] { + regsub -all \\y$x\\y $allquicktests {} allquicktests + } +} + +# If the TEST_FAILURE environment variable is set, it means that we what to +# deliberately provoke test failures in order to test the test infrastructure. +# Only the main.test module is needed for this. +# +if {[info exists ::env(TEST_FAILURE)]} { + set allquicktests main.test +} ############################################################################# # Start of tests @@ -140,7 +154,7 @@ test_suite "veryquick" -prefix "" -description { ] test_suite "mmap" -prefix "mm-" -description { - Similar to veryquick. Except with memory mapping disabled. + Similar to veryquick. Except with memory mapping enabled. } -presql { pragma mmap_size = 268435456; } -files [ @@ -151,7 +165,9 @@ test_suite "valgrind" -prefix "" -description { Run the "veryquick" test suite with a couple of multi-process tests (that fail under valgrind) omitted. } -files [ - test_set $allquicktests -exclude *malloc* *ioerr* *fault* wal.test atof1.test + test_set $allquicktests -exclude *malloc* *ioerr* *fault* wal.test \ + shell*.test crash8.test atof1.test selectG.test \ + tkt-fc62af4523.test ] -initialize { set ::G(valgrind) 1 } -shutdown { @@ -355,6 +371,12 @@ test_suite "coverage-analyze" -description { analyze.test analyzeB.test mallocA.test } +test_suite "coverage-sorter" -description { + Coverage tests for file vdbesort.c. +} -files { + sort.test sortfault.test +} + lappend ::testsuitelist xxx #------------------------------------------------------------------------- @@ -486,7 +508,7 @@ test_suite "multithread" -description { } -files { delete.test delete2.test insert.test rollback.test select1.test select2.test trans.test update.test vacuum.test types.test - types2.test types3.test + types2.test types3.test sort4.test } -shutdown { catch {db close} sqlite3_shutdown @@ -683,7 +705,7 @@ test_suite "inmemory_journal" -description { zerodamage.test # WAL mode is different. - wal* tkt-2d1a5c67d.test backcompat.test + wal* tkt-2d1a5c67d.test backcompat.test e_wal* }] ifcapable mem3 { diff --git a/test/pragma.test b/test/pragma.test index 539d867..09b9b6c 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -454,10 +454,34 @@ do_execsql_test pragma-3.21 { do_execsql_test pragma-3.22 { PRAGMA integrity_check(2); } {{non-unique entry in index t1a} {NULL value in t1x.a}} -do_execsql_test pragma-3.21 { +do_execsql_test pragma-3.23 { PRAGMA integrity_check(1); } {{non-unique entry in index t1a}} +# PRAGMA integrity check (or more specifically the sqlite3BtreeCount() +# interface) used to leave index cursors in an inconsistent state +# which could result in an assertion fault in sqlite3BtreeKey() +# called from saveCursorPosition() if content is removed from the +# index while the integrity_check is still running. This test verifies +# that problem has been fixed. +# +do_test pragma-3.30 { + db close + delete_file test.db + sqlite3 db test.db + db eval { + CREATE TABLE t1(a,b,c); + WITH RECURSIVE + c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<100) + INSERT INTO t1(a,b,c) SELECT i, printf('xyz%08x',i), 2000-i FROM c; + CREATE INDEX t1a ON t1(a); + CREATE INDEX t1bc ON t1(b,c); + } + db eval {PRAGMA integrity_check} { + db eval {DELETE FROM t1} + } +} {} + # Test modifying the cache_size of an attached database. ifcapable pager_pragmas&&attach { do_test pragma-4.1 { @@ -1190,13 +1214,13 @@ ifcapable schema_pragmas { execsql2 { pragma collation_list; } - } {seq 0 name NOCASE seq 1 name RTRIM seq 2 name BINARY} + } {seq 0 name RTRIM seq 1 name NOCASE seq 2 name BINARY} do_test pragma-11.2 { db collate New_Collation blah... execsql { pragma collation_list; } - } {0 New_Collation 1 NOCASE 2 RTRIM 3 BINARY} + } {0 New_Collation 1 RTRIM 2 NOCASE 3 BINARY} } ifcapable schema_pragmas&&tempdb { diff --git a/test/pragma3.test b/test/pragma3.test new file mode 100644 index 0000000..b7ea4d3 --- /dev/null +++ b/test/pragma3.test @@ -0,0 +1,253 @@ +# 2014-12-19 +# +# 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. +# +# This file implements tests for PRAGMA data_version command. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test pragma3-100 { + PRAGMA data_version; +} {1} +do_execsql_test pragma3-101 { + PRAGMA temp.data_version; +} {1} + +# Writing to the pragma is a no-op +do_execsql_test pragma3-102 { + PRAGMA main.data_version=1234; + PRAGMA main.data_version; +} {1 1} + +# EVIDENCE-OF: R-27726-60934 The "PRAGMA data_version" command provides +# an indication that the database file has been modified. +# +# EVIDENCE-OF: R-47505-58569 The "PRAGMA data_version" value is +# unchanged for commits made on the same database connection. +# +do_execsql_test pragma3-110 { + PRAGMA data_version; + BEGIN IMMEDIATE; + PRAGMA data_version; + CREATE TABLE t1(a); + INSERT INTO t1 VALUES(100),(200),(300); + PRAGMA data_version; + COMMIT; + SELECT * FROM t1; + PRAGMA data_version; +} {1 1 1 100 200 300 1} + +sqlite3 db2 test.db +do_test pragma3-120 { + db2 eval { + SELECT * FROM t1; + PRAGMA data_version; + } +} {100 200 300 1} + +do_execsql_test pragma3-130 { + PRAGMA data_version; + BEGIN IMMEDIATE; + PRAGMA data_version; + INSERT INTO t1 VALUES(400),(500); + PRAGMA data_version; + COMMIT; + SELECT * FROM t1; + PRAGMA data_version; + PRAGMA shrink_memory; +} {1 1 1 100 200 300 400 500 1} + +# EVIDENCE-OF: R-63005-41812 The integer values returned by two +# invocations of "PRAGMA data_version" from the same connection will be +# different if changes were committed to the database by any other +# connection in the interim. +# +# Value went from 1 in pragma3-120 to 2 here. +# +do_test pragma3-140 { + db2 eval { + SELECT * FROM t1; + PRAGMA data_version; + BEGIN IMMEDIATE; + PRAGMA data_version; + UPDATE t1 SET a=a+1; + COMMIT; + SELECT * FROM t1; + PRAGMA data_version; + } +} {100 200 300 400 500 2 2 101 201 301 401 501 2} +do_execsql_test pragma3-150 { + SELECT * FROM t1; + PRAGMA data_version; +} {101 201 301 401 501 2} + +# +do_test pragma3-160 { + db eval { + BEGIN; + PRAGMA data_version; + UPDATE t1 SET a=555 WHERE a=501; + PRAGMA data_version; + SELECT * FROM t1 ORDER BY a; + PRAGMA data_version; + } +} {2 2 101 201 301 401 555 2} +do_test pragma3-170 { + db2 eval { + PRAGMA data_version; + } +} {2} +do_test pragma3-180 { + db eval { + COMMIT; + PRAGMA data_version; + } +} {2} +do_test pragma3-190 { + db2 eval { + PRAGMA data_version; + } +} {3} + +# EVIDENCE-OF: R-19326-44825 The "PRAGMA data_version" value is a local +# property of each database connection and so values returned by two +# concurrent invocations of "PRAGMA data_version" on separate database +# connections are often different even though the underlying database is +# identical. +# +do_test pragma3-195 { + expr {[db eval {PRAGMA data_version}]!=[db2 eval {PRAGMA data_version}]} +} {1} + +# EVIDENCE-OF: R-54562-06892 The behavior of "PRAGMA data_version" is +# the same for all database connections, including database connections +# in separate processes and shared cache database connections. +# +# The next block checks the behavior for separate processes. +# +do_test pragma3-200 { + db eval {PRAGMA data_version; SELECT * FROM t1;} +} {2 101 201 301 401 555} +do_test pragma3-201 { + set fd [open pragma3.txt wb] + puts $fd { + sqlite3 db test.db; + db eval {DELETE FROM t1 WHERE a>300}; + db close; + exit; + } + close $fd + exec [info nameofexec] pragma3.txt + forcedelete pragma3.txt + db eval { + PRAGMA data_version; + SELECT * FROM t1; + } +} {3 101 201} +db2 close +db close + +# EVIDENCE-OF: R-54562-06892 The behavior of "PRAGMA data_version" is +# the same for all database connections, including database connections +# in separate processes and shared cache database connections. +# +# The next block checks that behavior is the same for shared-cache. +# +ifcapable shared_cache { + set ::enable_shared_cache [sqlite3_enable_shared_cache 1] + sqlite3 db test.db + sqlite3 db2 test.db + do_test pragma3-300 { + db eval { + PRAGMA data_version; + BEGIN; + CREATE TABLE t3(a,b,c); + CREATE TABLE t4(x,y,z); + INSERT INTO t4 VALUES(123,456,789); + PRAGMA data_version; + COMMIT; + PRAGMA data_version; + } + } {1 1 1} + do_test pragma3-310 { + db2 eval { + PRAGMA data_version; + BEGIN; + INSERT INTO t3(a,b,c) VALUES('abc','def','ghi'); + SELECT * FROM t3; + PRAGMA data_version; + } + } {2 abc def ghi 2} + # The transaction in db2 has not yet committed, so the data_version in + # db is unchanged. + do_test pragma3-320 { + db eval { + PRAGMA data_version; + SELECT * FROM t4; + } + } {1 123 456 789} + do_test pragma3-330 { + db2 eval { + COMMIT; + PRAGMA data_version; + SELECT * FROM t4; + } + } {2 123 456 789} + do_test pragma3-340 { + db eval { + PRAGMA data_version; + SELECT * FROM t3; + SELECT * FROM t4; + } + } {2 abc def ghi 123 456 789} + db2 close + db close + sqlite3_enable_shared_cache $::enable_shared_cache +} + +# Make sure this also works in WAL mode +# +# This will not work with the in-memory journal permutation, as opening +# [db2] switches the journal mode back to "memory" +# +ifcapable wal { +if {[permutation]!="inmemory_journal"} { + + sqlite3 db test.db + db eval {PRAGMA journal_mode=WAL} + sqlite3 db2 test.db + do_test pragma3-400 { + db eval { + PRAGMA data_version; + PRAGMA journal_mode; + SELECT * FROM t1; + } + } {2 wal 101 201} + do_test pragma3-410 { + db2 eval { + PRAGMA data_version; + PRAGMA journal_mode; + SELECT * FROM t1; + } + } {2 wal 101 201} + do_test pragma3-420 { + db eval {UPDATE t1 SET a=111*(a/100); PRAGMA data_version; SELECT * FROM t1} + } {2 111 222} + do_test pragma3-430 { + db2 eval {PRAGMA data_version; SELECT * FROM t1;} + } {3 111 222} + db2 close +} +} + +finish_test diff --git a/test/printf2.test b/test/printf2.test index 4cb1783..21deeb7 100644 --- a/test/printf2.test +++ b/test/printf2.test @@ -95,5 +95,25 @@ do_execsql_test printf2-2.3 { SELECT printf('%s=(%d/%g/%s)',a) FROM t1 ORDER BY a; } {-1=(0/0/) 1=(0/0/) 1.5=(0/0/) abc=(0/0/)} +# The precision of the %c conversion causes the character to repeat. +# +do_execsql_test printf2-3.1 { + SELECT printf('|%110.100c|','*'); +} {{| ****************************************************************************************************|}} +do_execsql_test printf2-3.2 { + SELECT printf('|%-110.100c|','*'); +} {{|**************************************************************************************************** |}} +do_execsql_test printf2-3.3 { + SELECT printf('|%9.8c|%-9.8c|','*','*'); +} {{| ********|******** |}} +do_execsql_test printf2-3.4 { + SELECT printf('|%8.8c|%-8.8c|','*','*'); +} {|********|********|} +do_execsql_test printf2-3.5 { + SELECT printf('|%7.8c|%-7.8c|','*','*'); +} {|********|********|} + + + finish_test diff --git a/test/releasetest.mk b/test/releasetest.mk deleted file mode 100644 index 5d217c6..0000000 --- a/test/releasetest.mk +++ /dev/null @@ -1,14 +0,0 @@ -######################################################## -TOP=/home/drh/sqlite/sqlite - -TCL_FLAGS=-I/home/drh/tcltk/86linux -LIBTCL=/home/drh/tcltk/86linux/libtcl8.6.a -lm -ldl -lpthread - -BCC = gcc -TCC = gcc -ansi -g $(CFLAGS) -NAWK = awk -AR = ar cr -RANLIB = ranlib -THREADLIB = -lpthread -ldl -lz -include $(TOP)/main.mk -######################################################## diff --git a/test/releasetest.tcl b/test/releasetest.tcl index eb2e440..746fc9b 100644 --- a/test/releasetest.tcl +++ b/test/releasetest.tcl @@ -1,69 +1,63 @@ - -set rcsid {$Id: $} - +#!/usr/bin/tclsh +# # Documentation for this script. This may be output to stderr # if the script is invoked incorrectly. See the [process_options] # proc below. # set ::USAGE_MESSAGE { This Tcl script is used to test the various configurations required -before releasing a new version. Supported command line options (all +before releasing a new version. Supported command line options (all optional) are: - -makefile PATH-TO-MAKEFILE (default "releasetest.mk") - -platform PLATFORM (see below) - -quick BOOLEAN (default "0") + --srcdir TOP-OF-SQLITE-TREE (see below) + --platform PLATFORM (see below) + --config CONFIGNAME (Run only CONFIGNAME) + --quick (Run "veryquick.test" only) + --veryquick (Run "make smoketest" only) + --buildonly (Just build testfixture - do not run) + --dryrun (Print what would have happened) + --info (Show diagnostic info) -The default value for -makefile is "./releasetest.mk". +The default value for --srcdir is the parent of the directory holding +this script. -The script determines the default value for -platform using the -$tcl_platform(os) and $tcl_platform(machine) variables. Supported +The script determines the default value for --platform using the +$tcl_platform(os) and $tcl_platform(machine) variables. Supported platforms are "Linux-x86", "Linux-x86_64" and "Darwin-i386". -If the -quick option is set to true, then the "veryquick.test" script -is run for all compilation configurations. Otherwise, sometimes "all.test" -is run, sometimes "veryquick.test". - -Almost any SQLite makefile (except those generated by configure - see below) -should work. The following properties are required: - - * The makefile should support the "fulltest" target. - * The makefile should support the variable "OPTS" as a way to pass - options from the make command line to lemon and the C compiler. - -More precisely, the following invocation must be supported: - - make -f $::MAKEFILE fulltest OPTS="-DSQLITE_SECURE_DELETE=1 -DSQLITE_DEBUG=1" - -Makefiles generated by the sqlite configure program cannot be used as -they do not respect the OPTS variable. - -Example Makefile contents: - - ######################################################## - TOP=/home/dan/work/sqlite/sqlite - - TCL_FLAGS=-I/home/dan/tcl/include - LIBTCL=-L/home/dan/tcl/lib -ltcl - - BCC = gcc - TCC = gcc -ansi -g $(CFLAGS) - NAWK = awk - AR = ar cr - RANLIB = ranlib - THREADLIB = -lpthread -ldl - include $(TOP)/main.mk - ######################################################## +Every test begins with a fresh run of the configure script at the top +of the SQLite source tree. } -array set ::Configs { +# Omit comments (text between # and \n) in a long multi-line string. +# +proc strip_comments {in} { + regsub -all {#[^\n]*\n} $in {} out + return $out +} + +array set ::Configs [strip_comments { "Default" { -O2 + --disable-amalgamation --disable-shared } - "Ftrapv" { - -O2 -ftrapv - -DSQLITE_MAX_ATTACHED=55 - -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 + "Sanitize" { + CC=clang -fsanitize=undefined + -DSQLITE_ENABLE_STAT4 + } + "Have-Not" { + # The "Have-Not" configuration sets all possible -UHAVE_feature options + # in order to verify that the code works even on platforms that lack + # these support services. + -DHAVE_FDATASYNC=0 + -DHAVE_GMTIME_R=0 + -DHAVE_ISNAN=0 + -DHAVE_LOCALTIME_R=0 + -DHAVE_LOCALTIME_S=0 + -DHAVE_MALLOC_USABLE_SIZE=0 + -DHAVE_STRCHRNUL=0 + -DHAVE_USLEEP=0 + -DHAVE_UTIME=0 } "Unlock-Notify" { -O2 @@ -80,6 +74,7 @@ array set ::Configs { -O2 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 + -DSQLITE_ENABLE_STMT_SCANSTATUS } "Check-Symbols" { -DSQLITE_MEMDEBUG=1 @@ -93,11 +88,13 @@ array set ::Configs { -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_ATOMIC_WRITE=1 - -DSQLITE_ENABLE_IOTRACE=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 + -DSQLITE_ENABLE_STAT4 + -DSQLITE_ENABLE_STMT_SCANSTATUS } "Debug-One" { + --disable-shared -O2 -DSQLITE_DEBUG=1 -DSQLITE_MEMDEBUG=1 @@ -108,6 +105,8 @@ array set ::Configs { -DSQLITE_ENABLE_MEMSYS5=1 -DSQLITE_ENABLE_MEMSYS3=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 + -DSQLITE_ENABLE_STAT4 + -DSQLITE_MAX_ATTACHED=125 } "Device-One" { -O2 @@ -148,6 +147,7 @@ array set ::Configs { -DSQLITE_ENABLE_LOCKING_STYLE=1 } "OS-X" { + -O1 # Avoid a compiler bug in gcc 4.2.1 build 5658 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_THREADSAFE=2 @@ -160,8 +160,9 @@ array set ::Configs { -DSQLITE_DEFAULT_CACHE_SIZE=1000 -DSQLITE_MAX_LENGTH=2147483645 -DSQLITE_MAX_VARIABLE_NUMBER=500000 - -DSQLITE_DEBUG=1 + -DSQLITE_DEBUG=1 -DSQLITE_PREFER_PROXY_LOCKING=1 + -DSQLITE_ENABLE_API_ARMOR=1 } "Extra-Robustness" { -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 @@ -176,40 +177,80 @@ array set ::Configs { -DSQLITE_DISABLE_FTS4_DEFERRED -DSQLITE_ENABLE_RTREE } - "No-lookaside" { -DSQLITE_TEST_REALLOC_STRESS=1 -DSQLITE_OMIT_LOOKASIDE=1 -DHAVE_USLEEP=1 } -} + "Valgrind" { + -DSQLITE_ENABLE_STAT4 + -DSQLITE_ENABLE_FTS4 + -DSQLITE_ENABLE_RTREE + } -array set ::Platforms { + # The next group of configurations are used only by the + # Failure-Detection platform. They are all the same, but we need + # different names for them all so that they results appear in separate + # subdirectories. + # + Fail0 {-O0} + Fail2 {-O0} + Fail3 {-O0} + Fail4 {-O0} +}] + +array set ::Platforms [strip_comments { Linux-x86_64 { "Check-Symbols" checksymbols - "Debug-One" test + "Debug-One" "mptest test" + "Have-Not" test "Secure-Delete" test "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" "Update-Delete-Limit" test "Extra-Robustness" test "Device-Two" test - "Ftrapv" test "No-lookaside" test - "Default" "threadtest test" + "Devkit" test + "Sanitize" {QUICKTEST_OMIT=func4.test,nan.test test} + "Valgrind" valgrindtest + "Default" "threadtest fulltest" "Device-One" fulltest } Linux-i686 { "Devkit" test + "Have-Not" test "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" "Device-One" test "Device-Two" test "Default" "threadtest fulltest" } Darwin-i386 { - "Locking-Style" test + "Locking-Style" "mptest test" + "Have-Not" test "OS-X" "threadtest fulltest" } -} + Darwin-x86_64 { + "Locking-Style" "mptest test" + "Have-Not" test + "OS-X" "threadtest fulltest" + } + "Windows NT-intel" { + "Default" "mptest fulltestonly" + "Have-Not" test + } + + # The Failure-Detection platform runs various tests that deliberately + # fail. This is used as a test of this script to verify that this script + # correctly identifies failures. + # + Failure-Detection { + Fail0 "TEST_FAILURE=0 test" + Sanitize "TEST_FAILURE=1 test" + Fail2 "TEST_FAILURE=2 valgrindtest" + Fail3 "TEST_FAILURE=3 valgrindtest" + Fail4 "TEST_FAILURE=4 test" + } +}] # End of configuration section. @@ -225,18 +266,82 @@ foreach {key value} [array get ::Platforms] { } } +# Open the file $logfile and look for a report on the number of errors +# and the number of test cases run. Add these values to the global +# $::NERRCASE and $::NTESTCASE variables. +# +# If any errors occur, then write into $errmsgVar the text of an appropriate +# one-line error message to show on the output. +# +proc count_tests_and_errors {logfile rcVar errmsgVar} { + if {$::DRYRUN} return + upvar 1 $rcVar rc $errmsgVar errmsg + set fd [open $logfile rb] + set seen 0 + while {![eof $fd]} { + set line [gets $fd] + if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} { + incr ::NERRCASE $nerr + incr ::NTESTCASE $ntest + set seen 1 + if {$nerr>0} { + set rc 1 + set errmsg $line + } + } + if {[regexp {runtime error: +(.*)} $line all msg]} { + incr ::NERRCASE + if {$rc==0} { + set rc 1 + set errmsg $msg + } + } + if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} { + incr ::NERRCASE + if {$rc==0} { + set rc 1 + set errmsg $all + } + } + if {[regexp {^VERSION: 3\.\d+.\d+} $line]} { + set v [string range $line 9 end] + if {$::SQLITE_VERSION eq ""} { + set ::SQLITE_VERSION $v + } elseif {$::SQLITE_VERSION ne $v} { + set rc 1 + set errmsg "version conflict: {$::SQLITE_VERSION} vs. {$v}" + } + } + } + close $fd + if {!$seen} { + set rc 1 + set errmsg "Test did not complete" + if {[file readable core]} { + append errmsg " - core file exists" + } + } +} + proc run_test_suite {name testtarget config} { - - # Tcl variable $opts is used to build up the value used to set the + # Tcl variable $opts is used to build up the value used to set the # OPTS Makefile variable. Variable $cflags holds the value for # CFLAGS. The makefile will pass OPTS to both gcc and lemon, but # CFLAGS is only passed to gcc. # - set cflags "" + set cflags "-g" set opts "" + set title ${name}($testtarget) + set configOpts "" + + regsub -all {#[^\n]*\n} $config \n config foreach arg $config { - if {[string match -D* $arg]} { + if {[regexp {^-[UD]} $arg]} { lappend opts $arg + } elseif {[regexp {^[A-Z]+=} $arg]} { + lappend testtarget $arg + } elseif {[regexp {^--(enable|disable)-} $arg]} { + lappend configOpts $arg } else { lappend cflags $arg } @@ -256,30 +361,76 @@ proc run_test_suite {name testtarget config} { append opts " -DSQLITE_OS_UNIX=1" } - # Run the test. - # - set makefile [file normalize $::MAKEFILE] - file mkdir $dir - puts -nonewline "Testing configuration \"$name\" (logfile=$dir/test.log)..." - flush stdout + if {!$::TRACE} { + set n [string length $title] + puts -nonewline "${title}[string repeat . [expr {63-$n}]]" + flush stdout + } - set makecmd [concat \ - [list exec make -C $dir -f $makefile clean] \ - $testtarget \ - [list CFLAGS=$cflags OPTS=$opts >& $dir/test.log] \ - ] - - set tm1 [clock seconds] - set rc [catch $makecmd] + set rc 0 + set tm1 [clock seconds] + set origdir [pwd] + trace_cmd file mkdir $dir + trace_cmd cd $dir + set errmsg {} + catch {file delete core} + set rc [catch [configureCommand $configOpts]] + if {!$rc} { + set rc [catch [makeCommand $testtarget $cflags $opts]] + count_tests_and_errors test.log rc errmsg + } + trace_cmd cd $origdir set tm2 [clock seconds] - set minutes [expr {($tm2-$tm1)/60}] - set seconds [expr {($tm2-$tm1)%60}] - puts -nonewline [format " (%d:%.2d) " $minutes $seconds] - if {$rc} { - puts "FAILED." - } else { - puts "Ok." + if {!$::TRACE} { + set hours [expr {($tm2-$tm1)/3600}] + set minutes [expr {(($tm2-$tm1)/60)%60}] + set seconds [expr {($tm2-$tm1)%60}] + set tm [format (%02d:%02d:%02d) $hours $minutes $seconds] + if {$rc} { + puts " FAIL $tm" + incr ::NERR + if {$errmsg!=""} {puts " $errmsg"} + } else { + puts " Ok $tm" + } + } +} + +# The following procedure returns the "configure" command to be exectued for +# the current platform, which may be Windows (via MinGW, etc). +# +proc configureCommand {opts} { + set result [list trace_cmd exec] + if {$::tcl_platform(platform)=="windows"} { + lappend result sh + } + lappend result $::SRCDIR/configure --enable-load-extension + foreach x $opts {lappend result $x} + lappend result >& test.log +} + +# The following procedure returns the "make" command to be executed for the +# specified targets, compiler flags, and options. +# +proc makeCommand { targets cflags opts } { + set result [list trace_cmd exec make clean] + foreach target $targets { + lappend result $target + } + lappend result CFLAGS=$cflags OPTS=$opts >>& test.log +} + +# The following procedure prints its arguments if ::TRACE is true. +# And it executes the command of its arguments in the calling context +# if ::DRYRUN is false. +# +proc trace_cmd {args} { + if {$::TRACE} { + puts $args + } + if {!$::DRYRUN} { + uplevel 1 $args } } @@ -290,15 +441,22 @@ proc run_test_suite {name testtarget config} { # option. # proc process_options {argv} { - set ::MAKEFILE releasetest.mk ;# Default value - set ::QUICK 0 ;# Default value + set ::SRCDIR [file normalize [file dirname [file dirname $::argv0]]] + set ::QUICK 0 + set ::BUILDONLY 0 + set ::DRYRUN 0 + set ::EXEC exec + set ::TRACE 0 + set config {} set platform $::tcl_platform(os)-$::tcl_platform(machine) for {set i 0} {$i < [llength $argv]} {incr i} { - switch -- [lindex $argv $i] { - -makefile { + set x [lindex $argv $i] + if {[regexp {^--[a-z]} $x]} {set x [string range $x 1 end]} + switch -glob -- $x { + -srcdir { incr i - set ::MAKEFILE [lindex $argv $i] + set ::SRCDIR [file normalize [lindex $argv $i]] } -platform { @@ -307,10 +465,57 @@ proc process_options {argv} { } -quick { - incr i - set ::QUICK [lindex $argv $i] + set ::QUICK 1 } - + -veryquick { + set ::QUICK 2 + } + + -config { + incr i + set config [lindex $argv $i] + } + + -buildonly { + set ::BUILDONLY 1 + } + + -dryrun { + set ::DRYRUN 1 + } + + -trace { + set ::TRACE 1 + } + + -info { + puts "Command-line Options:" + puts " --srcdir $::SRCDIR" + puts " --platform [list $platform]" + puts " --config [list $config]" + if {$::QUICK} {puts " --quick"} + if {$::BUILDONLY} {puts " --buildonly"} + if {$::DRYRUN} {puts " --dryrun"} + if {$::TRACE} {puts " --trace"} + puts "\nAvailable --platform options:" + foreach y [lsort [array names ::Platforms]] { + puts " [list $y]" + } + puts "\nAvailable --config options:" + foreach y [lsort [array names ::Configs]] { + puts " [list $y]" + } + exit + } + -g - + -D* - + -O* - + -enable-* - + -disable-* - + *=* { + lappend ::EXTRACONFIG [lindex $argv $i] + } + default { puts stderr "" puts stderr [string trim $::USAGE_MESSAGE] @@ -319,8 +524,6 @@ proc process_options {argv} { } } - set ::MAKEFILE [file normalize $::MAKEFILE] - if {0==[info exists ::Platforms($platform)]} { puts "Unknown platform: $platform" puts -nonewline "Set the -platform option to " @@ -333,9 +536,22 @@ proc process_options {argv} { exit } - set ::CONFIGLIST $::Platforms($platform) - puts "Running the following configurations for $platform:" + if {$config!=""} { + if {[llength $config]==1} {lappend config fulltest} + set ::CONFIGLIST $config + } else { + set ::CONFIGLIST $::Platforms($platform) + } + puts "Running the following test configurations for $platform:" puts " [string trim $::CONFIGLIST]" + puts -nonewline "Flags:" + if {$::DRYRUN} {puts -nonewline " --dryrun"} + if {$::BUILDONLY} {puts -nonewline " --buildonly"} + switch -- $::QUICK { + 1 {puts -nonewline " --quick"} + 2 {puts -nonewline " --veryquick"} + } + puts "" } # Main routine. @@ -343,30 +559,59 @@ proc process_options {argv} { proc main {argv} { # Process any command line options. + set ::EXTRACONFIG {} process_options $argv + puts [string repeat * 79] + set ::NERR 0 + set ::NTEST 0 + set ::NTESTCASE 0 + set ::NERRCASE 0 + set ::SQLITE_VERSION {} + set STARTTIME [clock seconds] foreach {zConfig target} $::CONFIGLIST { - if {$::QUICK} {set target test} - set config_options $::Configs($zConfig) + if {$target ne "checksymbols"} { + switch -- $::QUICK { + 1 {set target test} + 2 {set target smoketest} + } + if {$::BUILDONLY} {set target testfixture} + } + set config_options [concat $::Configs($zConfig) $::EXTRACONFIG] + incr NTEST run_test_suite $zConfig $target $config_options # If the configuration included the SQLITE_DEBUG option, then remove # it and run veryquick.test. If it did not include the SQLITE_DEBUG option # add it and run veryquick.test. - if {$target!="checksymbols"} { + if {$target!="checksymbols" && $target!="valgrindtest" + && !$::BUILDONLY && $::QUICK<2} { set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*] + set xtarget $target + regsub -all {fulltest[a-z]*} $xtarget test xtarget if {$debug_idx < 0} { - run_test_suite "${zConfig}_debug" test [ - concat $config_options -DSQLITE_DEBUG=1 - ] + incr NTEST + append config_options " -DSQLITE_DEBUG=1" + run_test_suite "${zConfig}_debug" $xtarget $config_options } else { - run_test_suite "${zConfig}_ndebug" test [ - lreplace $config_options $debug_idx $debug_idx - ] + incr NTEST + regsub { *-DSQLITE_MEMDEBUG[^ ]* *} $config_options { } config_options + regsub { *-DSQLITE_DEBUG[^ ]* *} $config_options { } config_options + run_test_suite "${zConfig}_ndebug" $xtarget $config_options } } + } + set elapsetime [expr {[clock seconds]-$STARTTIME}] + set hr [expr {$elapsetime/3600}] + set min [expr {($elapsetime/60)%60}] + set sec [expr {$elapsetime%60}] + set etime [format (%02d:%02d:%02d) $hr $min $sec] + puts [string repeat * 79] + puts "$::NERRCASE failures out of $::NTESTCASE tests in $etime" + if {$::SQLITE_VERSION ne ""} { + puts "SQLite $::SQLITE_VERSION" } } diff --git a/test/rollback.test b/test/rollback.test index c339c5d..7abafec 100644 --- a/test/rollback.test +++ b/test/rollback.test @@ -60,11 +60,11 @@ ifcapable conflict { # do_test rollback-1.5 { sqlite3_step $STMT - } {SQLITE_ERROR} + } {SQLITE_ROW} # Restart the SELECT statement # - do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_ABORT} + do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK} } else { do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK} } diff --git a/test/rollback2.test b/test/rollback2.test new file mode 100644 index 0000000..4d42dda --- /dev/null +++ b/test/rollback2.test @@ -0,0 +1,157 @@ +# 2014 November 12 +# +# 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 containst tests to verify that ROLLBACK or ROLLBACK TO +# operations interact correctly with ongoing SELECT statements. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix rollback2 + +proc int2hex {i} { format %.2X $i } +db func int2hex int2hex +do_execsql_test 1.0 { + SELECT int2hex(0), int2hex(100), int2hex(255) +} {00 64 FF} +do_execsql_test 1.1 { + CREATE TABLE t1(i, h); + CREATE INDEX i1 ON t1(h); + WITH data(a, b) AS ( + SELECT 1, int2hex(1) + UNION ALL + SELECT a+1, int2hex(a+1) FROM data WHERE a<40 + ) + INSERT INTO t1 SELECT * FROM data; +} {} + + +# do_rollback_test ID SWITCHES +# +# where SWITCHES are: +# +# -setup SQL script to open transaction and begin writing. +# -select SELECT to execute after -setup script +# -result Expected result of -select statement +# -rollback Use this SQL command ("ROLLBACK" or "ROLLBACK TO ...") to +# rollback the transaction in the middle of the -select statment +# execution. +# +proc do_rollback_test {tn args} { + set A(-setup) "" + set A(-select) "" + set A(-result) "" + set A(-rollback) ROLLBACK + + array set O $args + foreach k [array names O] { + if {[info exists A($k)]==0} { error "unknown option: $k" } + set A($k) $O($k) + } + + for {set iRollback 0} 1 {incr iRollback} { + catch { db eval ROLLBACK } + set res [list] + db eval $A(-setup) + + set i 0 + db eval $A(-select) x { + if {$i==$iRollback} { db eval $A(-rollback) } + foreach k $x(*) { lappend res $x($k) } + incr i + } + + do_test $tn.$iRollback [list set {} $res] [list {*}$A(-result)] + if {$i < $iRollback} break + } +} + +do_rollback_test 2.1 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%2)==1; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 +} -result { + 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 +} + +do_rollback_test 2.2 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%4)==1; + SAVEPOINT one; + DELETE FROM t1 WHERE (i%2)==1; +} -rollback { + ROLLBACK TO one; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 +} -result { + 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 +} + +#-------------------------------------------------------------------- +# Try with some index scans +# +do_eqp_test 3.1 { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; +} {0 0 0 {SCAN TABLE t1 USING INDEX i1}} +do_rollback_test 3.2 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%2)==1; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; +} -result { + 40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2 +} +do_rollback_test 3.3 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%4)==1; + SAVEPOINT one; + DELETE FROM t1 WHERE (i%2)==1; +} -rollback { + ROLLBACK TO one; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; +} -result { + 40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2 +} + +#-------------------------------------------------------------------- +# Now with some index scans that feature overflow keys. +# +set leader [string repeat "abcdefghij" 70] +do_execsql_test 4.1 { UPDATE t1 SET h = $leader || h; } + +do_eqp_test 4.2 { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; +} {0 0 0 {SCAN TABLE t1 USING INDEX i1}} +do_rollback_test 4.3 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%2)==1; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; +} -result { + 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 +} +do_rollback_test 4.4 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%4)==1; + SAVEPOINT one; + DELETE FROM t1 WHERE (i%2)==1; +} -rollback { + ROLLBACK TO one; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; +} -result { + 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 +} + +finish_test + diff --git a/test/rollbackfault.test b/test/rollbackfault.test new file mode 100644 index 0000000..f248d07 --- /dev/null +++ b/test/rollbackfault.test @@ -0,0 +1,84 @@ +# 2014-11-12 +# +# 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. +# +#*********************************************************************** +# +# Test that errors encountered during a ROLLBACK operation correctly +# affect ongoing SQL statements. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl +set testprefix rollbackfault + + +proc int2hex {i} { format %.2X $i } +db func int2hex int2hex +do_execsql_test 1.0 { + SELECT int2hex(0), int2hex(100), int2hex(255) +} {00 64 FF} +do_execsql_test 1.1 { + CREATE TABLE t1(i, h); + CREATE INDEX i1 ON t1(h); + WITH data(a, b) AS ( + SELECT 1, int2hex(1) + UNION ALL + SELECT a+1, int2hex(a+1) FROM data WHERE a<40 + ) + INSERT INTO t1 SELECT * FROM data; +} {} + +foreach f {oom ioerr} { + do_faultsim_test 1.2 -faults $f* -prep { + set sql1 { SELECT i FROM t1 WHERE (i%2)==0 } + set sql2 { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h } + set ::s1 [sqlite3_prepare db $sql1 -1 dummy] + set ::s2 [sqlite3_prepare db $sql2 -1 dummy] + + for {set i 0} {$i < 10} {incr i} { sqlite3_step $::s1 } + for {set i 0} {$i < 3} {incr i} { sqlite3_step $::s2 } + + execsql { + BEGIN; DELETE FROM t1 WHERE (i%2) + } + } -body { + execsql { ROLLBACK } + } -test { + + set res1 [list] + set res2 [list] + while {"SQLITE_ROW" == [sqlite3_step $::s1]} { + lappend res1 [sqlite3_column_text $::s1 0] + } + while {"SQLITE_ROW" == [sqlite3_step $::s2]} { + lappend res2 [sqlite3_column_text $::s2 0] + } + set rc1 [sqlite3_finalize $::s1] + set rc2 [sqlite3_finalize $::s2] + + catchsql { ROLLBACK } + + if {$rc1=="SQLITE_OK" && $rc2=="SQLITE_OK" + && $res1=="22 24 26 28 30 32 34 36 38 40" + && $res2=="8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40" + } { + # This is Ok. + } elseif {$rc1!="SQLITE_OK" && $rc2!="SQLITE_OK" && $res1=="" &&$res2==""} { + # Also Ok. + } else { + error "statements don't look right" + } + } +} + + +finish_test + + diff --git a/test/rowid.test b/test/rowid.test index 6d068d7..b00b528 100644 --- a/test/rowid.test +++ b/test/rowid.test @@ -679,9 +679,9 @@ do_test rowid-12.2 { save_prng_state execsql { INSERT INTO t7 VALUES(NULL,'b'); - SELECT x, y FROM t7; + SELECT x, y FROM t7 ORDER BY x; } -} {1 b 9223372036854775807 a} +} {/\d+ b 9223372036854775807 a/} execsql {INSERT INTO t7 VALUES(2,'y');} for {set i 1} {$i<100} {incr i} { do_test rowid-12.3.$i { @@ -701,5 +701,19 @@ do_test rowid-12.4 { } } {1 {database or disk is full}} +# INSERTs that happen inside of nested function calls are recorded +# by last_insert_rowid. +# +proc rowid_addrow_func {n} { + db eval {INSERT INTO t13(rowid,x) VALUES($n,$n*$n)} + return [db last_insert_rowid] +} +db function addrow rowid_addrow_func +do_execsql_test rowid-13.1 { + CREATE TABLE t13(x); + INSERT INTO t13(rowid,x) VALUES(1234,5); + SELECT rowid, x, addrow(rowid+1000), '|' FROM t13 LIMIT 3; + SELECT last_insert_rowid(); +} {1234 5 2234 | 2234 4990756 3234 | 3234 10458756 4234 | 4234} finish_test diff --git a/test/savepoint.test b/test/savepoint.test index 9f4571a..8055e61 100644 --- a/test/savepoint.test +++ b/test/savepoint.test @@ -315,7 +315,7 @@ ifcapable incrblob { do_test savepoint-5.3.2.3 { set rc [catch {seek $fd 0; read $fd} res] set rc - } {1} + } {0} do_test savepoint-5.3.3 { catchsql {RELEASE def} } {0 {}} @@ -561,7 +561,7 @@ do_test savepoint-8-2 { # ifcapable auth { proc auth {args} { - eval lappend ::authdata $args + eval lappend ::authdata [lrange $args 0 4] return SQLITE_OK } db auth auth @@ -583,7 +583,7 @@ ifcapable auth { } {SQLITE_SAVEPOINT RELEASE sp1 {} {}} proc auth {args} { - eval lappend ::authdata $args + eval lappend ::authdata [lrange $args 0 4] return SQLITE_DENY } db auth auth diff --git a/test/savepoint7.test b/test/savepoint7.test index bc99187..d8a02f1 100644 --- a/test/savepoint7.test +++ b/test/savepoint7.test @@ -30,6 +30,7 @@ do_test savepoint7-1.1 { db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; + CREATE TABLE IF NOT EXISTS t3(xyz); INSERT INTO t2 VALUES($a,$b,$c); RELEASE x2; } @@ -46,7 +47,7 @@ do_test savepoint7-1.2 { RELEASE x2; } } - db eval {SELECT * FROM t2} + db eval {SELECT * FROM t2;} } {1 2 3 4 5 6 7 8 9} do_test savepoint7-1.3 { @@ -65,7 +66,7 @@ do_test savepoint7-1.3 { # queries in outer contexts. # do_test savepoint7-2.1 { - db eval {DELETE FROM t2; SAVEPOINT x1;} + db eval {DELETE FROM t2; SAVEPOINT x1; CREATE TABLE t4(abc);} set rc [catch { db eval {SELECT * FROM t1} { db eval { @@ -77,7 +78,7 @@ do_test savepoint7-2.1 { } msg] db eval {RELEASE x1} list $rc $msg [db eval {SELECT * FROM t2}] -} {1 {callback requested query abort} {}} +} {1 {abort due to ROLLBACK} {}} do_test savepoint7-2.2 { db eval {DELETE FROM t2;} @@ -85,12 +86,13 @@ do_test savepoint7-2.2 { db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; + CREATE TABLE t5(pqr); INSERT INTO t2 VALUES($a,$b,$c); ROLLBACK TO x2; } } } msg] list $rc $msg [db eval {SELECT * FROM t2}] -} {1 {callback requested query abort} {}} +} {1 {abort due to ROLLBACK} {}} finish_test diff --git a/test/scanstatus.test b/test/scanstatus.test new file mode 100644 index 0000000..ed24d97 --- /dev/null +++ b/test/scanstatus.test @@ -0,0 +1,398 @@ +# 2014 November 1 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix scanstatus + +ifcapable !scanstatus { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b); + CREATE TABLE t2(x, y); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + INSERT INTO t2 VALUES('a', 'b'); + INSERT INTO t2 VALUES('c', 'd'); + INSERT INTO t2 VALUES('e', 'f'); +} + +proc do_scanstatus_test {tn res} { + set stmt [db_last_stmt_ptr db] + set idx 0 + set ret [list] + while {1} { + set r [sqlite3_stmt_scanstatus $stmt $idx] + if {[llength $r]==0} break + lappend ret {*}$r + incr idx + } + + uplevel [list do_test $tn [list set {} $ret] [list {*}$res]] +} + +do_execsql_test 1.1 { SELECT count(*) FROM t1, t2; } 6 +do_scanstatus_test 1.2 { + nLoop 1 nVisit 2 nEst 1048576.0 zName t1 zExplain {SCAN TABLE t1} + nLoop 2 nVisit 6 nEst 1048576.0 zName t2 zExplain {SCAN TABLE t2} +} + +do_execsql_test 1.3 { + ANALYZE; + SELECT count(*) FROM t1, t2; +} 6 +do_scanstatus_test 1.4 { + nLoop 1 nVisit 2 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} + nLoop 2 nVisit 6 nEst 3.0 zName t2 zExplain {SCAN TABLE t2} +} + +do_execsql_test 1.5 { ANALYZE } +do_execsql_test 1.6 { + SELECT count(*) FROM t1, t2 WHERE t2.rowid>1; +} 4 +do_scanstatus_test 1.7 { + nLoop 1 nVisit 2 nEst 2.0 zName t2 zExplain + {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} + nLoop 2 nVisit 4 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} +} + +do_execsql_test 1.8 { + SELECT count(*) FROM t1, t2 WHERE t2.rowid>1; +} 4 + +do_scanstatus_test 1.9 { + nLoop 2 nVisit 4 nEst 2.0 zName t2 zExplain + {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} + nLoop 4 nVisit 8 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} +} + +do_test 1.9 { + sqlite3_stmt_scanstatus_reset [db_last_stmt_ptr db] +} {} + +do_scanstatus_test 1.10 { + nLoop 0 nVisit 0 nEst 2.0 zName t2 zExplain + {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} + nLoop 0 nVisit 0 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} +} + +#------------------------------------------------------------------------- +# Try a few different types of scans. +# +reset_db +do_execsql_test 2.1 { + CREATE TABLE x1(i INTEGER PRIMARY KEY, j); + INSERT INTO x1 VALUES(1, 'one'); + INSERT INTO x1 VALUES(2, 'two'); + INSERT INTO x1 VALUES(3, 'three'); + INSERT INTO x1 VALUES(4, 'four'); + CREATE INDEX x1j ON x1(j); + + SELECT * FROM x1 WHERE i=2; +} {2 two} + +do_scanstatus_test 2.2 { + nLoop 1 nVisit 1 nEst 1.0 zName x1 + zExplain {SEARCH TABLE x1 USING INTEGER PRIMARY KEY (rowid=?)} +} + +do_execsql_test 2.3.1 { + SELECT * FROM x1 WHERE j='two' +} {2 two} +do_scanstatus_test 2.3.2 { + nLoop 1 nVisit 1 nEst 10.0 zName x1j + zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j=?)} +} + +do_execsql_test 2.4.1 { + SELECT * FROM x1 WHERE j<'two' +} {4 four 1 one 3 three} +do_scanstatus_test 2.4.2 { + nLoop 1 nVisit 3 nEst 262144.0 zName x1j + zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j='two' +} {2 two} +do_scanstatus_test 2.5.2 { + nLoop 1 nVisit 1 nEst 262144.0 zName x1j + zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>?)} +} + +do_execsql_test 2.6.1 { + SELECT * FROM x1 WHERE j BETWEEN 'three' AND 'two' +} {3 three 2 two} +do_scanstatus_test 2.6.2 { + nLoop 1 nVisit 2 nEst 16384.0 zName x1j + zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>? AND j? AND j? AND a? AND b? AND b? AND a=1 + # expr $::aborted>=1 + expr $::aborted==0 } {1} # This test is designed to catch a specific bug that was present during diff --git a/test/shell1.test b/test/shell1.test index ab382e7..f24b00d 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -45,20 +45,21 @@ do_test shell1-1.1.1 { list $rc \ [regexp {Error: unknown option: -bad} $res] } {1 1} +do_test shell1-1.1.1b { + set res [catchcmd "test.db -bad" ""] + set rc [lindex $res 0] + list $rc \ + [regexp {Error: unknown option: -bad} $res] +} {1 1} # error on extra options do_test shell1-1.1.2 { - set res [catchcmd "-bad test.db \"select 3\" \"select 4\"" ""] - set rc [lindex $res 0] - list $rc \ - [regexp {Error: too many options: "select 4"} $res] -} {1 1} + catchcmd "test.db \"select 3\" \"select 4\"" "" +} {0 {3 +4}} # error on extra options do_test shell1-1.1.3 { - set res [catchcmd "-bad FOO test.db BAD" ".quit"] - set rc [lindex $res 0] - list $rc \ - [regexp {Error: too many options: "BAD"} $res] -} {1 1} + catchcmd "test.db FOO test.db BAD" ".quit" +} {1 {Error: near "FOO": syntax error}} # -help do_test shell1-1.2.1 { @@ -75,11 +76,11 @@ do_test shell1-1.3.1 { catchcmd "-init FOO test.db" "" } {0 {}} do_test shell1-1.3.2 { - set res [catchcmd "-init FOO test.db .quit BAD" ""] - set rc [lindex $res 0] - list $rc \ - [regexp {Error: too many options: "BAD"} $res] -} {1 1} + catchcmd "-init FOO test.db .quit BAD" "" +} {0 {}} +do_test shell1-1.3.3 { + catchcmd "-init FOO test.db BAD .quit" "" +} {1 {Error: near "BAD": syntax error}} # -echo print commands before execution do_test shell1-1.4.1 { @@ -206,10 +207,10 @@ do_test shell1-2.2.4 { } {0 {}} do_test shell1-2.2.5 { catchcmd "test.db" ".mode \"insert FOO" -} {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} +} {1 {Error: mode should be one of: ascii column csv html insert line list tabs tcl}} do_test shell1-2.2.6 { catchcmd "test.db" ".mode \'insert FOO" -} {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} +} {1 {Error: mode should be one of: ascii column csv html insert line list tabs tcl}} # check multiple tokens, and quoted tokens do_test shell1-2.3.1 { @@ -237,7 +238,7 @@ do_test shell1-2.3.7 { # check quoted args are unquoted do_test shell1-2.4.1 { catchcmd "test.db" ".mode FOO" -} {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} +} {1 {Error: mode should be one of: ascii column csv html insert line list tabs tcl}} do_test shell1-2.4.2 { catchcmd "test.db" ".mode csv" } {0 {}} @@ -420,20 +421,21 @@ do_test shell1-3.12.3 { } {1 {Usage: .indices ?LIKE-PATTERN?}} # .mode MODE ?TABLE? Set output mode where MODE is one of: +# ascii Columns/rows delimited by 0x1F and 0x1E # csv Comma-separated values # column Left-aligned columns. (See .width) # html HTML
  • code # insert SQL insert statements for TABLE # line One value per line -# list Values delimited by .separator string +# list Values delimited by .separator strings # tabs Tab-separated values # tcl TCL list elements do_test shell1-3.13.1 { catchcmd "test.db" ".mode" -} {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} +} {1 {Error: mode should be one of: ascii column csv html insert line list tabs tcl}} do_test shell1-3.13.2 { catchcmd "test.db" ".mode FOO" -} {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} +} {1 {Error: mode should be one of: ascii column csv html insert line list tabs tcl}} do_test shell1-3.13.3 { catchcmd "test.db" ".mode csv" } {0 {}} @@ -466,10 +468,10 @@ do_test shell1-3.13.11 { # don't allow partial mode type matches do_test shell1-3.13.12 { catchcmd "test.db" ".mode l" -} {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} +} {1 {Error: mode should be one of: ascii column csv html insert line list tabs tcl}} do_test shell1-3.13.13 { catchcmd "test.db" ".mode li" -} {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} +} {1 {Error: mode should be one of: ascii column csv html insert line list tabs tcl}} do_test shell1-3.13.14 { catchcmd "test.db" ".mode lin" } {0 {}} @@ -585,10 +587,10 @@ CREATE VIEW v2 AS SELECT x+1 AS y FROM t1; CREATE VIEW v1 AS SELECT y+1 FROM v2;}} db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;} -# .separator STRING Change separator used by output mode and .import +# .separator STRING Change column separator used by output and .import do_test shell1-3.22.1 { catchcmd "test.db" ".separator" -} {1 {Usage: .separator SEPARATOR ?NEWLINE?}} +} {1 {Usage: .separator COL ?ROW?}} do_test shell1-3.22.2 { catchcmd "test.db" ".separator FOO" } {0 {}} @@ -598,7 +600,7 @@ do_test shell1-3.22.3 { do_test shell1-3.22.4 { # too many arguments catchcmd "test.db" ".separator FOO BAD BAD2" -} {1 {Usage: .separator SEPARATOR ?NEWLINE?}} +} {1 {Usage: .separator COL ?ROW?}} # .show Show the current values for various settings do_test shell1-3.23.1 { @@ -609,10 +611,11 @@ do_test shell1-3.23.1 { [regexp {mode:} $res] \ [regexp {nullvalue:} $res] \ [regexp {output:} $res] \ - [regexp {separator:} $res] \ + [regexp {colseparator:} $res] \ + [regexp {rowseparator:} $res] \ [regexp {stats:} $res] \ [regexp {width:} $res] -} {1 1 1 1 1 1 1 1 1} +} {1 1 1 1 1 1 1 1 1 1} do_test shell1-3.23.2 { # too many arguments catchcmd "test.db" ".show BAD" diff --git a/test/shell2.test b/test/shell2.test index def574c..616610b 100644 --- a/test/shell2.test +++ b/test/shell2.test @@ -52,9 +52,9 @@ do_test shell2-1.1.1 { # Ticket [f5cb008a65]. do_test shell2-1.2.1 { set rc [catch { eval exec $CLI \":memory:\" \"select 3\" \"select 4\" } msg] - list $rc \ - [regexp {Error: too many options: "select 4"} $msg] -} {1 1} + list $rc $msg +} {0 {3 +4}} # Test a problem reported on the mailing list. The shell was at one point # returning the generic SQLITE_ERROR message ("SQL error or missing database") diff --git a/test/shell5.test b/test/shell5.test index 8d740cb..e22db04 100644 --- a/test/shell5.test +++ b/test/shell5.test @@ -55,7 +55,7 @@ do_test shell5-1.1.3 { # .separator STRING Change separator used by output mode and .import do_test shell5-1.2.1 { catchcmd "test.db" ".separator" -} {1 {Usage: .separator SEPARATOR ?NEWLINE?}} +} {1 {Usage: .separator COL ?ROW?}} do_test shell5-1.2.2 { catchcmd "test.db" ".separator ONE" } {0 {}} @@ -65,12 +65,18 @@ do_test shell5-1.2.3 { do_test shell5-1.2.4 { # too many arguments catchcmd "test.db" ".separator ONE TWO THREE" -} {1 {Usage: .separator SEPARATOR ?NEWLINE?}} +} {1 {Usage: .separator COL ?ROW?}} -# separator should default to "|" -do_test shell5-1.3.1 { +# column separator should default to "|" +do_test shell5-1.3.1.1 { set res [catchcmd "test.db" ".show"] - list [regexp {separator: \"\|\"} $res] + list [regexp {colseparator: \"\|\"} $res] +} {1} + +# row separator should default to "\n" +do_test shell5-1.3.1.2 { + set res [catchcmd "test.db" ".show"] + list [regexp {rowseparator: \"\\n\"} $res] } {1} # set separator to different value. @@ -372,5 +378,31 @@ CREATE TABLE t4(a, b); db eval { SELECT * FROM t4 } } {xy\" hello one 2 {} {}} +#---------------------------------------------------------------------------- +# Tests for the shell "ascii" import/export mode. +# +do_test shell5-3.1 { + set fd [open shell5.csv w] + fconfigure $fd -encoding binary -translation binary + puts -nonewline $fd "\"test 1\"\x1F,test 2\r\n\x1E" + puts -nonewline $fd "test 3\x1Ftest 4\n" + close $fd + catchcmd test.db { +.mode ascii +CREATE TABLE t5(a, b); +.import shell5.csv t5 + } + db eval { SELECT * FROM t5 } +} "\{\"test 1\"} \{,test 2\r\n\} \{test 3\} \{test 4\n\}" + +do_test shell5-3.2 { + set x [catchcmd test.db { +.mode ascii +SELECT * FROM t5; + }] + # Handle platform end-of-line differences + regsub -all {[\n\r]?\n} $x x + set x +} "0 \{\"test 1\"\x1F,test 2\x1Etest 3\x1Ftest 4\x1E\}" finish_test diff --git a/test/skipscan1.test b/test/skipscan1.test index 8150b01..4f996df 100644 --- a/test/skipscan1.test +++ b/test/skipscan1.test @@ -245,6 +245,51 @@ do_execsql_test skipscan1-5.3 { SELECT xh, loc FROM t5 WHERE loc >= 'M' AND loc < 'N'; } {/.*COVERING INDEX t5i1 .*/} +# The column used by the skip-scan needs to be sufficiently selective. +# See the private email from Adi Zaimi to drh@sqlite.org on 2014-09-22. +# +db close +forcedelete test.db +sqlite3 db test.db +do_execsql_test skipscan1-6.1 { + CREATE TABLE t1(a,b,c,d,e,f,g,h varchar(300)); + CREATE INDEX t1ab ON t1(a,b); + ANALYZE sqlite_master; + -- Only two distinct values for the skip-scan column. Skip-scan is not used. + INSERT INTO sqlite_stat1 VALUES('t1','t1ab','500000 250000 125000'); + ANALYZE sqlite_master; + EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=1; +} {~/ANY/} +do_execsql_test skipscan1-6.2 { + -- Four distinct values for the skip-scan column. Skip-scan is used. + UPDATE sqlite_stat1 SET stat='500000 250000 62500'; + ANALYZE sqlite_master; + EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=1; +} {/ANY.a. AND b=/} +do_execsql_test skipscan1-6.3 { + -- Two distinct values for the skip-scan column again. Skip-scan is not used. + UPDATE sqlite_stat1 SET stat='500000 125000 62500'; + ANALYZE sqlite_master; + EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=1; +} {~/ANY/} +# If the sqlite_stat1 entry includes the "noskipscan" token, then never use +# skipscan with that index. +# +do_execsql_test skipscan1-7.1 { + UPDATE sqlite_stat1 SET stat='500000 125000 1 sz=100'; + ANALYZE sqlite_master; + EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=1; +} {/ANY/} +do_execsql_test skipscan1-7.2 { + UPDATE sqlite_stat1 SET stat='500000 125000 1 noskipscan sz=100'; + ANALYZE sqlite_master; + EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=1; +} {~/ANY/} +do_execsql_test skipscan1-7.3 { + UPDATE sqlite_stat1 SET stat='500000 125000 1 sz=100 noskipscan'; + ANALYZE sqlite_master; + EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=1; +} {~/ANY/} finish_test diff --git a/test/skipscan3.test b/test/skipscan3.test new file mode 100644 index 0000000..260d11c --- /dev/null +++ b/test/skipscan3.test @@ -0,0 +1,73 @@ +# 2014-08-20 +# +# 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 tests of the "skip-scan" query strategy. +# In particular, this file looks at skipping intermediate terms +# in an index. For example, if (a,b,c) are indexed, and we have +# "WHERE a=?1 AND c=?2" - verify that skip-scan can still be used. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test skipscan3-1.1 { + CREATE TABLE t1(a,b,c,d,PRIMARY KEY(a,b,c)); + WITH RECURSIVE + c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) + INSERT INTO t1(a,b,c,d) + SELECT 1, 1, x, printf('x%04d',x) FROM c; + ANALYZE; +} {} + +# This version has long used skip-scan because of the "+a" +# +do_execsql_test skipscan3-1.2eqp { + EXPLAIN QUERY PLAN SELECT d FROM t1 WHERE +a=1 AND c=32; +} {/*ANY(a) AND ANY(b)*/} +do_execsql_test skipscan3-1.2 { + SELECT d FROM t1 WHERE +a=1 AND c=32; +} {x0032} + +# This version (with "a" instead of "+a") should use skip-scan but +# did not prior to changes implemented on 2014-08-20 +# +do_execsql_test skipscan3-1.3eqp { + EXPLAIN QUERY PLAN SELECT d FROM t1 WHERE a=1 AND c=32; +} {/*ANY(a) AND ANY(b)*/} +do_execsql_test skipscan3-1.3 { + SELECT d FROM t1 WHERE a=1 AND c=32; +} {x0032} + +# Repeat the test on a WITHOUT ROWID table +# +do_execsql_test skipscan3-2.1 { + CREATE TABLE t2(a,b,c,d,PRIMARY KEY(a,b,c)) WITHOUT ROWID; + WITH RECURSIVE + c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) + INSERT INTO t2(a,b,c,d) + SELECT 1, 1, x, printf('x%04d',x) FROM c; + ANALYZE; +} {} +do_execsql_test skipscan3-2.2eqp { + EXPLAIN QUERY PLAN SELECT d FROM t2 WHERE +a=1 AND c=32; +} {/*ANY(a) AND ANY(b)*/} +do_execsql_test skipscan3-2.2 { + SELECT d FROM t2 WHERE +a=1 AND c=32; +} {x0032} +do_execsql_test skipscan3-2.3eqp { + EXPLAIN QUERY PLAN SELECT d FROM t2 WHERE a=1 AND c=32; +} {/*ANY(a) AND ANY(b)*/} +do_execsql_test skipscan3-2.3 { + SELECT d FROM t2 WHERE a=1 AND c=32; +} {x0032} + + +finish_test diff --git a/test/skipscan5.test b/test/skipscan5.test index 5d6d392..7c3b166 100644 --- a/test/skipscan5.test +++ b/test/skipscan5.test @@ -108,7 +108,7 @@ foreach {tn dbenc coll} { 3 { c > 'q' } {/*ANY(a) AND ANY(b) AND c>?*/} 4 { c > 'e' } {/*SCAN TABLE t2*/} 5 { c < 'q' } {/*SCAN TABLE t2*/} - 4 { c < 'e' } {/*ANY(a) AND ANY(b) AND c. AND dd<../} + + +# Create a table containing 100 rows. Column "a" contains a copy of the +# rowid value - sequentially increasing integers from 1 to 100. Column +# "b" contains the value of (a % 5). Columns "c" and "d" both contain +# constant values (i.e. the same for every row). +# +# Then create a second table t2. t2 is the same as t3 except for the +# order in which the indexes are created. +# +do_execsql_test 3.0 { + CREATE TABLE t3(a, b, c, d); + CREATE INDEX t3_ba ON t3(b, a, c); + CREATE INDEX t3_a ON t3(a); + + WITH d(a, b) AS ( + SELECT 1, 1 + UNION ALL + SELECT a+1, (a+1) % 5 FROM d WHERE a<100 + ) + INSERT INTO t3 SELECT a, b, 'c', 'd' FROM d; + + CREATE TABLE t2(a, b, c, d); + CREATE INDEX t2_a ON t2(a); + CREATE INDEX t2_ba ON t2(b, a, c); + INSERT INTO t2 SELECT * FROM t3; + + ANALYZE; + SELECT * FROM sqlite_stat1; +} { + t2 t2_ba {100 20 1 1} + t2 t2_a {100 1} + t3 t3_a {100 1} + t3 t3_ba {100 20 1 1} +} + +# Use index "t3_a", as (a=?) is expected to match only a single row. +# +do_eqp_test 3.1 { + SELECT * FROM t3 WHERE a = ? AND c = ? +} { + 0 0 0 {SEARCH TABLE t3 USING INDEX t3_a (a=?)} +} + +# The same query on table t2. This should use index "t2_a", for the +# same reason. At one point though, it was mistakenly using a skip-scan. +# +do_eqp_test 3.2 { + SELECT * FROM t2 WHERE a = ? AND c = ? +} { + 0 0 0 {SEARCH TABLE t2 USING INDEX t2_a (a=?)} +} + +finish_test + + + + +finish_test diff --git a/test/sort.test b/test/sort.test index 08d496b..21b11d6 100644 --- a/test/sort.test +++ b/test/sort.test @@ -8,13 +8,19 @@ # May you share freely, never taking more than you give. # #*********************************************************************** -# This file implements regression tests for SQLite library. The -# focus of this file is testing the CREATE TABLE statement. # -# $Id: sort.test,v 1.25 2005/11/14 22:29:06 drh Exp $ +# This file implements regression tests for SQLite library. The +# focus of this file is testing the sorter (code in vdbesort.c). +# set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix sort +db close +sqlite3_shutdown +sqlite3_config_pmasz 10 +sqlite3_initialize +sqlite3 db test.db # Create a bunch of data to sort against # @@ -464,4 +470,175 @@ do_test sort-12.1 { } } {1 2 xxx 1 3 yyy 1 1 zzz} +#------------------------------------------------------------------------- +# Check that the sorter in vdbesort.c sorts in a stable fashion. +# +do_execsql_test sort-13.0 { + CREATE TABLE t10(a, b); +} +do_test sort-13.1 { + db transaction { + for {set i 0} {$i < 100000} {incr i} { + execsql { INSERT INTO t10 VALUES( $i/10, $i%10 ) } + } + } +} {} +do_execsql_test sort-13.2 { + SELECT a, b FROM t10 ORDER BY a; +} [db eval {SELECT a, b FROM t10 ORDER BY a, b}] +do_execsql_test sort-13.3 { + PRAGMA cache_size = 5; + SELECT a, b FROM t10 ORDER BY a; +} [db eval {SELECT a, b FROM t10 ORDER BY a, b}] + +#------------------------------------------------------------------------- +# Sort some large ( > 4KiB) records. +# +proc cksum {x} { + set i1 1 + set i2 2 + binary scan $x c* L + foreach {a b} $L { + set i1 [expr (($i2<<3) + $a) & 0x7FFFFFFF] + set i2 [expr (($i1<<3) + $b) & 0x7FFFFFFF] + } + list $i1 $i2 +} +db func cksum cksum + +do_execsql_test sort-14.0 { + PRAGMA cache_size = 5; + CREATE TABLE t11(a, b); + INSERT INTO t11 VALUES(randomblob(5000), NULL); + INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --2 + INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --3 + INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --4 + INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --5 + INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --6 + INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --7 + INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --8 + INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --9 + UPDATE t11 SET b = cksum(a); +} + +foreach {tn mmap_limit} { + 1 0 + 2 1000000 +} { + do_test sort-14.$tn { + sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $mmap_limit + set prev "" + db eval { SELECT * FROM t11 ORDER BY b } { + if {$b != [cksum $a]} {error "checksum failed"} + if {[string compare $b $prev] < 0} {error "sort failed"} + set prev $b + } + set {} {} + } {} +} + +#------------------------------------------------------------------------- +# +foreach {tn mmap_limit nWorker tmpstore coremutex fakeheap softheaplimit} { + 1 0 3 file true false 0 + 2 0 3 file true true 0 + 3 0 0 file true false 0 + 4 1000000 3 file true false 0 + 5 0 0 memory false true 0 + 6 0 0 file false true 1000000 + 7 0 0 file false true 10000 +} { + db close + sqlite3_shutdown + if {$coremutex} { + sqlite3_config multithread + } else { + sqlite3_config singlethread + } + sqlite3_initialize + sorter_test_fakeheap $fakeheap + sqlite3_soft_heap_limit $softheaplimit + + reset_db + sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $mmap_limit + execsql "PRAGMA temp_store = $tmpstore; PRAGMA threads = $nWorker" + + + set ten [string repeat X 10300] + set one [string repeat y 200] + + if {$softheaplimit} { + execsql { PRAGMA cache_size = 20 }; + } else { + execsql { PRAGMA cache_size = 5 }; + } + + do_execsql_test 15.$tn.1 { + WITH rr AS ( + SELECT 4, $ten UNION ALL + SELECT 2, $one UNION ALL + SELECT 1, $ten UNION ALL + SELECT 3, $one + ) + SELECT * FROM rr ORDER BY 1; + } [list 1 $ten 2 $one 3 $one 4 $ten] + + do_execsql_test 15.$tn.2 { + CREATE TABLE t1(a); + INSERT INTO t1 VALUES(4); + INSERT INTO t1 VALUES(5); + INSERT INTO t1 VALUES(3); + INSERT INTO t1 VALUES(2); + INSERT INTO t1 VALUES(6); + INSERT INTO t1 VALUES(1); + CREATE INDEX i1 ON t1(a); + SELECT * FROM t1 ORDER BY a; + } {1 2 3 4 5 6} + + do_execsql_test 15.$tn.3 { + WITH rr AS ( + SELECT 4, $ten UNION ALL + SELECT 2, $one + ) + SELECT * FROM rr ORDER BY 1; + } [list 2 $one 4 $ten] + + sorter_test_fakeheap 0 +} + +db close +sqlite3_shutdown +set t(0) singlethread +set t(1) multithread +set t(2) serialized +sqlite3_config $t($sqlite_options(threadsafe)) +sqlite3_initialize +sqlite3_soft_heap_limit 0 + +reset_db +do_catchsql_test 16.1 { + CREATE TABLE t1(a, b, c); + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t1 VALUES(1, NULL, 3); + INSERT INTO t1 VALUES(NULL, 2, 3); + INSERT INTO t1 VALUES(1, 2, NULL); + INSERT INTO t1 VALUES(4, 5, 6); + CREATE UNIQUE INDEX i1 ON t1(b, a, c); +} {0 {}} +reset_db +do_catchsql_test 16.2 { + CREATE TABLE t1(a, b, c); + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t1 VALUES(1, NULL, 3); + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t1 VALUES(1, 2, NULL); + INSERT INTO t1 VALUES(4, 5, 6); + CREATE UNIQUE INDEX i1 ON t1(b, a, c); +} {1 {UNIQUE constraint failed: t1.b, t1.a, t1.c}} + +reset_db +do_execsql_test 17.1 { + SELECT * FROM sqlite_master ORDER BY sql; +} {} + finish_test diff --git a/test/sort2.test b/test/sort2.test new file mode 100644 index 0000000..890025a --- /dev/null +++ b/test/sort2.test @@ -0,0 +1,84 @@ +# 2014 March 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. +# +# Specifically, the tests in this file attempt to verify that +# multi-threaded sorting works. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix sort2 +db close +sqlite3_shutdown +sqlite3_config_pmasz 10 +sqlite3_initialize +sqlite3 db test.db + +foreach {tn script} { + 1 { } + 2 { + catch { db close } + reset_db + catch { db eval {PRAGMA threads=7} } + } +} { + + eval $script + + do_execsql_test $tn.1 { + PRAGMA cache_size = 5; + WITH r(x,y) AS ( + SELECT 1, randomblob(100) + UNION ALL + SELECT x+1, randomblob(100) FROM r + LIMIT 100000 + ) + SELECT count(x), length(y) FROM r GROUP BY (x%5) + } { + 20000 100 20000 100 20000 100 20000 100 20000 100 + } + + do_execsql_test $tn.2.1 { + CREATE TABLE t1(a, b); + WITH r(x,y) AS ( + SELECT 1, randomblob(100) + UNION ALL + SELECT x+1, randomblob(100) FROM r + LIMIT 10000 + ) INSERT INTO t1 SELECT * FROM r; + } + + do_execsql_test $tn.2.2 { + CREATE UNIQUE INDEX i1 ON t1(b, a); + } + + do_execsql_test $tn.2.3 { + CREATE UNIQUE INDEX i2 ON t1(a); + } + + do_execsql_test $tn.2.4 { PRAGMA integrity_check } {ok} + + do_execsql_test $tn.3 { + PRAGMA cache_size = 5; + WITH r(x,y) AS ( + SELECT 1, randomblob(100) + UNION ALL + SELECT x+1, randomblob(100) FROM r + LIMIT 1000000 + ) + SELECT count(x), length(y) FROM r GROUP BY (x%5) + } { + 200000 100 200000 100 200000 100 200000 100 200000 100 + } +} + +finish_test diff --git a/test/sort3.test b/test/sort3.test new file mode 100644 index 0000000..80d8bbc --- /dev/null +++ b/test/sort3.test @@ -0,0 +1,67 @@ +# 2014 March 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 tests in this file verify that sorting works when the library is +# configured to use mmap(), but the temporary files generated by the +# sorter are too large to be completely mapped. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix sort3 + +# Sort roughly 20MB of data. Once with a mmap limit of 5MB and once without. +# +foreach {itest limit} { + 1 5000000 + 2 0x7FFFFFFF +} { + sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $limit + do_execsql_test 1.$itest { + WITH r(x,y) AS ( + SELECT 1, randomblob(1000) + UNION ALL + SELECT x+1, randomblob(1000) FROM r + LIMIT 20000 + ) + SELECT count(*), sum(length(y)) FROM r GROUP BY (x%5); + } { + 4000 4000000 + 4000 4000000 + 4000 4000000 + 4000 4000000 + 4000 4000000 + } +} + +# Sort more than 2GB of data. At one point this was causing a problem. +# This test might take one minute or more to run. +# +do_execsql_test 2 { + PRAGMA cache_size = 20000; + WITH r(x,y) AS ( + SELECT 1, randomblob(1000) + UNION ALL + SELECT x+1, randomblob(1000) FROM r + LIMIT 2200000 + ) + SELECT count(*), sum(length(y)) FROM r GROUP BY (x%5); +} { + 440000 440000000 + 440000 440000000 + 440000 440000000 + 440000 440000000 + 440000 440000000 +} + +finish_test + diff --git a/test/sort4.test b/test/sort4.test new file mode 100644 index 0000000..7b91361 --- /dev/null +++ b/test/sort4.test @@ -0,0 +1,195 @@ +# 2014 May 6. +# +# 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 tests in this file are brute force tests of the multi-threaded +# sorter. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix sort4 +db close +sqlite3_shutdown +sqlite3_config_pmasz 10 +sqlite3_initialize +sqlite3 db test.db + + +# Configure the sorter to use 3 background threads. +db eval {PRAGMA threads=3} + +# Minimum number of seconds to run for. If the value is 0, each test +# is run exactly once. Otherwise, tests are repeated until the timeout +# expires. +set SORT4TIMEOUT 0 +if {[permutation] == "multithread"} { set SORT4TIMEOUT 300 } + +#-------------------------------------------------------------------- +# Set up a table "t1" containing $nRow rows. Each row contains also +# contains blob fields that collectively contain at least $nPayload +# bytes of content. The table schema is as follows: +# +# CREATE TABLE t1(a INTEGER, , b INTEGER); +# +# For each row, the values of columns "a" and "b" are set to the same +# pseudo-randomly selected integer. The "extra-columns", of which there +# are at most eight, are named c0, c1, c2 etc. Column c0 contains a 4 +# byte string. Column c1 an 8 byte string. Field c2 16 bytes, and so on. +# +# This table is intended to be used for testing queries of the form: +# +# SELECT a, , b FROM t1 ORDER BY a; +# +# The test code checks that rows are returned in order, and that the +# values of "a" and "b" are the same for each row (the idea being that +# if field "b" at the end of the sorter record has not been corrupted, +# the rest of the record is probably Ok as well). +# +proc populate_table {nRow nPayload} { + set nCol 0 + + set n 0 + for {set nCol 0} {$n < $nPayload} {incr nCol} { + incr n [expr (4 << $nCol)] + } + + set cols [lrange [list xxx c0 c1 c2 c3 c4 c5 c6 c7] 1 $nCol] + set data [lrange [list xxx \ + randomblob(4) randomblob(8) randomblob(16) randomblob(32) \ + randomblob(64) randomblob(128) randomblob(256) randomblob(512) \ + ] 1 $nCol] + + execsql { DROP TABLE IF EXISTS t1 } + + db transaction { + execsql "CREATE TABLE t1(a, [join $cols ,], b);" + set insert "INSERT INTO t1 VALUES(:k, [join $data ,], :k)" + for {set i 0} {$i < $nRow} {incr i} { + set k [expr int(rand()*1000000000)] + execsql $insert + } + } +} + +# Helper for [do_sorter_test] +# +proc sorter_test {nRow nRead nPayload} { + set res [list] + + set nLoad [expr ($nRow > $nRead) ? $nRead : $nRow] + + set nPayload [expr (($nPayload+3)/4) * 4] + set cols [list] + foreach {mask col} { + 0x04 c0 0x08 c1 0x10 c2 0x20 c3 + 0x40 c4 0x80 c5 0x100 c6 0x200 c7 + } { + if {$nPayload & $mask} { lappend cols $col } + } + + # Create two SELECT statements. Statement $sql1 uses the sorter to sort + # $nRow records of a bit over $nPayload bytes each read from the "t1" + # table created by [populate_table] proc above. Rows are sorted in order + # of the integer field in each "t1" record. + # + # The second SQL statement sorts the same set of rows as the first, but + # uses a LIMIT clause, causing SQLite to use a temp table instead of the + # sorter for sorting. + # + set sql1 "SELECT a, [join $cols ,], b FROM t1 WHERE rowid<=$nRow ORDER BY a" + set sql2 "SELECT a FROM t1 WHERE rowid<=$nRow ORDER BY a LIMIT $nRead" + + # Pass the two SQL statements to a helper command written in C. This + # command steps statement $sql1 $nRead times and compares the integer + # values in the rows returned with the results of executing $sql2. If + # the comparison fails (indicating some bug in the sorter), a Tcl + # exception is thrown. + # + sorter_test_sort4_helper db $sql1 $nRead $sql2 + set {} {} +} + +# Usage: +# +# do_sorter_test ... +# +# where are any of the following switches: +# +# -rows N (number of rows to have sorter sort) +# -read N (number of rows to read out of sorter) +# -payload N (bytes of payload to read with each row) +# -cachesize N (Value for "PRAGMA cache_size = ?") +# -repeats N (number of times to repeat test) +# -fakeheap BOOL (true to use separate allocations for in-memory records) +# +proc do_sorter_test {tn args} { + set a(-rows) 1000 + set a(-repeats) 1 + set a(-read) 100 + set a(-payload) 100 + set a(-cachesize) 100 + set a(-fakeheap) 0 + + foreach {s val} $args { + if {[info exists a($s)]==0} { + unset a(-cachesize) + set optlist "[join [array names a] ,] or -cachesize" + error "Unknown option $s, expected $optlist" + } + set a($s) $val + } + if {[permutation] == "memsys3" || [permutation] == "memsys5"} { + set a(-fakeheap) 0 + } + if {$a(-fakeheap)} { sorter_test_fakeheap 1 } + + + db eval "PRAGMA cache_size = $a(-cachesize)" + do_test $tn [subst -nocommands { + for {set i 0} {[set i] < $a(-repeats)} {incr i} { + sorter_test $a(-rows) $a(-read) $a(-payload) + } + }] {} + + if {$a(-fakeheap)} { sorter_test_fakeheap 0 } +} + +proc clock_seconds {} { + db one {SELECT strftime('%s')} +} + +#------------------------------------------------------------------------- +# Begin tests here. + +# Create a test database. +do_test 1 { + execsql "PRAGMA page_size = 4096" + populate_table 100000 500 +} {} + +set iTimeLimit [expr [clock_seconds] + $SORT4TIMEOUT] + +for {set t 2} {1} {incr tn} { + do_sorter_test $t.2 -repeats 10 -rows 1000 -read 100 + do_sorter_test $t.3 -repeats 10 -rows 100000 -read 1000 + do_sorter_test $t.4 -repeats 10 -rows 100000 -read 1000 -payload 500 + do_sorter_test $t.5 -repeats 10 -rows 100000 -read 100000 -payload 8 + do_sorter_test $t.6 -repeats 10 -rows 100000 -read 10 -payload 8 + do_sorter_test $t.7 -repeats 10 -rows 10000 -read 10000 -payload 8 -fakeheap 1 + do_sorter_test $t.8 -repeats 10 -rows 100000 -read 10000 -cachesize 250 + + set iNow [clock_seconds] + if {$iNow>=$iTimeLimit} break + do_test "$testprefix-([expr $iTimeLimit-$iNow] seconds remain)" {} {} +} + +finish_test diff --git a/test/sort5.test b/test/sort5.test new file mode 100644 index 0000000..a02b8f9 --- /dev/null +++ b/test/sort5.test @@ -0,0 +1,45 @@ +# 2014 September 15. +# +# 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. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix sort5 + + +#------------------------------------------------------------------------- +# Verify that sorting works with a version 1 sqlite3_io_methods structure. +# +testvfs tvfs -iversion 1 -default true +reset_db +do_execsql_test 1.0 { + PRAGMA mmap_size = 10000000; + PRAGMA cache_size = 10; + CREATE TABLE t1(a, b); +} {0} + +do_test 1.1 { + execsql BEGIN + for {set i 0} {$i < 2000} {incr i} { + execsql { INSERT INTO t1 VALUES($i, randomblob(2000)) } + } + execsql COMMIT +} {} + +do_execsql_test 1.2 { + CREATE INDEX i1 ON t1(b); +} + +db close +tvfs delete +finish_test + diff --git a/test/sortfault.test b/test/sortfault.test new file mode 100644 index 0000000..f9fe2be --- /dev/null +++ b/test/sortfault.test @@ -0,0 +1,171 @@ +# 2014 March 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. +# +# Specifically, it tests the effects of fault injection on the sorter +# module (code in vdbesort.c). +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix sortfault +db close +sqlite3_shutdown +sqlite3_config_pmasz 10 +sqlite3_initialize +sqlite3 db test.db + + +do_execsql_test 1.0 { + PRAGMA cache_size = 5; +} + +foreach {tn mmap_limit nWorker tmpstore threadsmode fakeheap lookaside} { + 1 0 0 file multithread false false + 2 100000 0 file multithread false false + 3 100000 1 file multithread false false + 4 2000000 0 file singlethread false true +} { + if {$sqlite_options(threadsafe)} { set threadsmode singlethread } + + db eval "PRAGMA threads=$nWorker" + sqlite3_config $threadsmode + if { $lookaside } { + sqlite3_config_lookaside 100 500 + } else { + sqlite3_config_lookaside 0 0 + } + sqlite3_initialize + sorter_test_fakeheap $fakeheap + + set str [string repeat a 1000] + puts $threadsmode + + do_faultsim_test 1.$tn -prep { + sqlite3 db test.db + sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $::mmap_limit + execsql { PRAGMA cache_size = 5 } + } -body { + execsql { + WITH r(x,y) AS ( + SELECT 1, $::str + UNION ALL + SELECT x+1, $::str FROM r + LIMIT 200 + ) + SELECT count(x), length(y) FROM r GROUP BY (x%5) + } + } -test { + faultsim_test_result {0 {40 1000 40 1000 40 1000 40 1000 40 1000}} + } + + do_faultsim_test 2.$tn -faults oom* -prep { + sqlite3 db test.db + sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $::mmap_limit + add_test_utf16bin_collate db + execsql { PRAGMA cache_size = 5 } + } -body { + execsql { + WITH r(x,y) AS ( + SELECT 100, $::str + UNION ALL + SELECT x-1, $::str FROM r + LIMIT 100 + ) + SELECT count(x), length(y) FROM r GROUP BY y COLLATE utf16bin, (x%5) + } + } -test { + faultsim_test_result {0 {20 1000 20 1000 20 1000 20 1000 20 1000}} + } + + if {$mmap_limit > 1000000} { + set str2 [string repeat $str 10] + + sqlite3_memdebug_vfs_oom_test 0 + sqlite3 db test.db + sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $::mmap_limit + execsql { PRAGMA cache_size = 5 } + + do_faultsim_test 3.$tn -faults oom-trans* -body { + execsql { + WITH r(x,y) AS ( + SELECT 300, $::str2 + UNION ALL + SELECT x-1, $::str2 FROM r + LIMIT 300 + ) + SELECT count(x), length(y) FROM r GROUP BY y, (x%5) + } + } -test { + faultsim_test_result {0 {60 10000 60 10000 60 10000 60 10000 60 10000}} + } + + sqlite3_memdebug_vfs_oom_test 1 + } +} + +catch { db close } +sqlite3_shutdown +set t(0) singlethread +set t(1) multithread +set t(2) serialized +sqlite3_config $t($sqlite_options(threadsafe)) +sqlite3_config_lookaside 100 500 +sqlite3_initialize + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 4.0 { + CREATE TABLE t1(a, b, c); + INSERT INTO t1 VALUES(1, 2, 3); +} +do_test 4.1 { + for {set i 0} {$i < 256} {incr i} { + execsql { + INSERT INTO t1 SELECT + ((a<<3) + b) & 2147483647, + ((b<<3) + c) & 2147483647, + ((c<<3) + a) & 2147483647 + FROM t1 ORDER BY rowid DESC LIMIT 1; + } + } +} {} + +faultsim_save_and_close + +do_faultsim_test 4.2 -faults oom* -prep { + faultsim_restore_and_reopen +} -body { + execsql { CREATE UNIQUE INDEX i1 ON t1(a,b,c) } +} -test { + faultsim_test_result {0 {}} +} + +#------------------------------------------------------------------------- +# +reset_db +set a [string repeat a 500] +set b [string repeat b 500] +set c [string repeat c 500] +do_execsql_test 5.0 { + CREATE TABLE t1(a, b, c); + INSERT INTO t1 VALUES($a, $b, $c); + INSERT INTO t1 VALUES($c, $b, $a); +} + +do_faultsim_test 5.1 -faults oom* -body { + execsql { SELECT * FROM t1 ORDER BY a } +} -test { + faultsim_test_result [list 0 [list $::a $::b $::c $::c $::b $::a]] +} + +finish_test diff --git a/test/speedtest1.c b/test/speedtest1.c index 383f580..8e5b74c 100644 --- a/test/speedtest1.c +++ b/test/speedtest1.c @@ -27,6 +27,7 @@ static const char zHelp[] = " --stats Show statistics at the end\n" " --testset T Run test-set T\n" " --trace Turn on SQL tracing\n" + " --threads N Use up to N threads for sorting\n" " --utf16be Set text encoding to UTF-16BE\n" " --utf16le Set text encoding to UTF-16LE\n" " --verify Run additional verification steps.\n" @@ -933,6 +934,7 @@ void testset_cte(void){ } +#ifdef SQLITE_ENABLE_RTREE /* Generate two numbers between 1 and mx. The first number is less than ** the second. Usually the numbers are near each other but can sometimes ** be far apart. @@ -953,7 +955,9 @@ static void twoCoords( *pX0 = x0; *pX1 = x1; } +#endif +#ifdef SQLITE_ENABLE_RTREE /* The following routine is an R-Tree geometry callback. It returns ** true if the object overlaps a slice on the Y coordinate between the ** two values given as arguments. In other words @@ -973,7 +977,9 @@ static int xsliceGeometryCallback( *pRes = aCoord[3]>=p->aParam[0] && aCoord[2]<=p->aParam[1]; return SQLITE_OK; } +#endif /* SQLITE_ENABLE_RTREE */ +#ifdef SQLITE_ENABLE_RTREE /* ** A testset for the R-Tree virtual table */ @@ -1109,6 +1115,7 @@ void testset_rtree(int p1, int p2){ } speedtest1_end_test(); } +#endif /* SQLITE_ENABLE_RTREE */ /* ** A testset used for debugging speedtest1 itself. @@ -1141,6 +1148,7 @@ int main(int argc, char **argv){ int nPCache = 0, szPCache = 0;/* --pcache configuration */ int nScratch = 0, szScratch=0;/* --scratch configuration */ int showStats = 0; /* True for --stats */ + int nThread = 0; /* --threads value */ const char *zTSet = "main"; /* Which --testset torun */ int doTrace = 0; /* True for --trace */ const char *zEncoding = 0; /* --utf16be or --utf16le */ @@ -1225,6 +1233,9 @@ int main(int argc, char **argv){ zTSet = argv[++i]; }else if( strcmp(z,"trace")==0 ){ doTrace = 1; + }else if( strcmp(z,"threads")==0 ){ + if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); + nThread = integerValue(argv[++i]); }else if( strcmp(z,"utf16le")==0 ){ zEncoding = "utf16le"; }else if( strcmp(z,"utf16be")==0 ){ @@ -1290,6 +1301,7 @@ int main(int argc, char **argv){ /* Set database connection options */ sqlite3_create_function(g.db, "random", 0, SQLITE_UTF8, 0, randomFunc, 0, 0); if( doTrace ) sqlite3_trace(g.db, traceCallback, 0); + speedtest1_exec("PRAGMA threads=%d", nThread); if( zKey ){ speedtest1_exec("PRAGMA key('%s')", zKey); } @@ -1323,7 +1335,12 @@ int main(int argc, char **argv){ }else if( strcmp(zTSet,"cte")==0 ){ testset_cte(); }else if( strcmp(zTSet,"rtree")==0 ){ +#ifdef SQLITE_ENABLE_RTREE testset_rtree(6, 147); +#else + fatal_error("compile with -DSQLITE_ENABLE_RTREE to enable " + "the R-Tree tests\n"); +#endif }else{ fatal_error("unknown testset: \"%s\"\nChoices: main debug1 cte rtree\n", zTSet); diff --git a/test/spellfix.test b/test/spellfix.test index 21383c2..954bdb2 100644 --- a/test/spellfix.test +++ b/test/spellfix.test @@ -124,6 +124,22 @@ do_execsql_test 1.23 { SELECT next_char('ab','vocab2','w',null,'binary'); } {c} +do_execsql_test 1.30 { + SELECT rowid FROM t1 WHERE word='rabbit'; +} {2} +do_execsql_test 1.31 { + UPDATE t1 SET rowid=2000 WHERE word='rabbit'; + SELECT rowid FROM t1 WHERE word='rabbit'; +} {2000} +do_execsql_test 1.32 { + INSERT INTO t1(rowid, word) VALUES(3000,'melody'); + SELECT rowid, word, matchlen FROM t1 WHERE word MATCH 'melotti' + ORDER BY score LIMIT 3; +} {3000 melody 6} +do_test 1.33 { + catchsql {INSERT INTO t1(rowid, word) VALUES(3000,'garden');} +} {1 {constraint failed}} + do_execsql_test 2.1 { CREATE VIRTUAL TABLE t2 USING spellfix1; INSERT INTO t2 (word, soundslike) VALUES('school', 'skuul'); diff --git a/test/sqllimits1.test b/test/sqllimits1.test index 2cbad3f..57fc931 100644 --- a/test/sqllimits1.test +++ b/test/sqllimits1.test @@ -51,6 +51,13 @@ do_test sqllimits1-1.9 { do_test sqllimits1-1.10 { sqlite3_limit db SQLITE_LIMIT_VARIABLE_NUMBER -1 } $SQLITE_MAX_VARIABLE_NUMBER +do_test sqllimits1-1.11 { + sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH -1 +} $SQLITE_MAX_TRIGGER_DEPTH +do_test sqllimits1-1.12 { + sqlite3_limit db SQLITE_LIMIT_WORKER_THREADS 99999 + sqlite3_limit db SQLITE_LIMIT_WORKER_THREADS -1 +} $SQLITE_MAX_WORKER_THREADS # Limit parameters out of range. # diff --git a/test/subquery2.test b/test/subquery2.test index 4406efc..de637d5 100644 --- a/test/subquery2.test +++ b/test/subquery2.test @@ -103,5 +103,50 @@ do_execsql_test 2.2 { LIMIT (SELECT a FROM t5) } {2 3 3 6 4 10} +############################################################################ +# Ticket http://www.sqlite.org/src/info/d11a6e908f (2014-09-20) +# Query planner fault on three-way nested join with compound inner SELECT +# +do_execsql_test 3.0 { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + CREATE TABLE t1 (id INTEGER PRIMARY KEY, data TEXT); + INSERT INTO t1(id,data) VALUES(9,'nine-a'); + INSERT INTO t1(id,data) VALUES(10,'ten-a'); + INSERT INTO t1(id,data) VALUES(11,'eleven-a'); + CREATE TABLE t2 (id INTEGER PRIMARY KEY, data TEXT); + INSERT INTO t2(id,data) VALUES(9,'nine-b'); + INSERT INTO t2(id,data) VALUES(10,'ten-b'); + INSERT INTO t2(id,data) VALUES(11,'eleven-b'); + + SELECT id FROM ( + SELECT id,data FROM ( + SELECT * FROM t1 UNION ALL SELECT * FROM t2 + ) + WHERE id=10 ORDER BY data + ); +} {10 10} +do_execsql_test 3.1 { + SELECT data FROM ( + SELECT 'dummy', data FROM ( + SELECT data FROM t1 UNION ALL SELECT data FROM t1 + ) ORDER BY data + ); +} {eleven-a eleven-a nine-a nine-a ten-a ten-a} +do_execsql_test 3.2 { + DROP TABLE IF EXISTS t3; + DROP TABLE IF EXISTS t4; + CREATE TABLE t3(id INTEGER, data TEXT); + CREATE TABLE t4(id INTEGER, data TEXT); + INSERT INTO t3 VALUES(4, 'a'),(2,'c'); + INSERT INTO t4 VALUES(3, 'b'),(1,'d'); + + SELECT data, id FROM ( + SELECT id, data FROM ( + SELECT * FROM t3 UNION ALL SELECT * FROM t4 + ) ORDER BY data + ); +} {a 4 b 3 c 2 d 1} + finish_test diff --git a/test/table.test b/test/table.test index 656884c..69f105a 100644 --- a/test/table.test +++ b/test/table.test @@ -11,7 +11,6 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # -# $Id: table.test,v 1.53 2009/06/05 17:09:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -773,4 +772,21 @@ do_catchsql_test table-16.7 { INSERT INTO t16 DEFAULT VALUES; } {1 {unknown function: group_concat()}} +# Ticket [https://www.sqlite.org/src/info/094d39a4c95ee4abbc417f04214617675ba15c63] +# describes a assertion fault that occurs on a CREATE TABLE .. AS SELECT statement. +# the following test verifies that the problem has been fixed. +# +do_execsql_test table-17.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a TEXT); + INSERT INTO t1(a) VALUES(1),(2); + DROP TABLE IF EXISTS t2; + CREATE TABLE t2(x TEXT, y TEXT); + INSERT INTO t2(x,y) VALUES(3,4); + DROP TABLE IF EXISTS t3; + CREATE TABLE t3 AS + SELECT a AS p, coalesce(y,a) AS q FROM t1 LEFT JOIN t2 ON a=x; + SELECT p, q, '|' FROM t3 ORDER BY p; +} {1 1 | 2 2 |} + finish_test diff --git a/test/tester.tcl b/test/tester.tcl index 3bf92f2..dad2266 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -1077,6 +1077,7 @@ proc explain_i {sql {db db}} { foreach opcode { Seek SeekGe SeekGt SeekLe SeekLt NotFound Last Rewind NoConflict Next Prev VNext VPrev VFilter + SorterSort SorterNext } { set color($opcode) $B } @@ -1099,6 +1100,7 @@ proc explain_i {sql {db db}} { if {$opcode=="Next" || $opcode=="Prev" || $opcode=="VNext" || $opcode=="VPrev" + || $opcode=="SorterNext" } { for {set i $p2} {$i<$addr} {incr i} { incr x($i) 2 diff --git a/test/threadtest3.c b/test/threadtest3.c index cb7e2fa..25caeb8 100644 --- a/test/threadtest3.c +++ b/test/threadtest3.c @@ -1,41 +1,41 @@ - /* +** 2010-07-22 +** +** 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. +** +************************************************************************* +** ** The code in this file runs a few multi-threaded test cases using the ** SQLite library. It can be compiled to an executable on unix using the ** following command: ** ** gcc -O2 threadtest3.c sqlite3.c -ldl -lpthread -lm ** -** Then run the compiled program. The exit status is non-zero if any tests -** failed (hopefully there is also some output to stdout to clarify what went -** wrong). +** Even though threadtest3.c is the only C source code file mentioned on +** the compiler command-line, #include macros are used to pull in additional +** C code files named "tt3_*.c". ** -** There are three parts to the code in this file, in the following order: +** After compiling, run this program with an optional argument telling +** which test to run. All tests are run if no argument is given. The +** argument can be a glob pattern to match multiple tests. Examples: ** -** 1. Code for the SQL aggregate function md5sum() copied from -** tclsqlite.c in the SQLite distribution. The names of all the -** types and functions in this section begin with "MD5" or "md5". +** ./a.out -- Run all tests +** ./a.out walthread3 -- Run the "walthread3" test +** ./a.out 'wal*' -- Run all of the wal* tests +** ./a.out --help -- List all available tests ** -** 2. A set of utility functions that may be used to implement -** multi-threaded test cases. These are all called by test code -** via macros that help with error reporting. The macros are defined -** immediately below this comment. -** -** 3. The test code itself. And a main() routine to drive the test -** code. +** The exit status is non-zero if any test fails. */ -/************************************************************************* -** Start of test code/infrastructure interface macros. -** -** The following macros constitute the interface between the test -** programs and the test infrastructure. Test infrastructure code -** does not itself use any of these macros. Test code should not -** call any of the macroname_x() functions directly. -** -** See the header comments above the corresponding macroname_x() -** function for a description of each interface. +/* +** The "Set Error Line" macro. */ +#define SEL(e) ((e)->iLine = ((e)->rc ? (e)->iLine : __LINE__)) /* Database functions */ #define opendb(w,x,y,z) (SEL(w), opendb_x(w,x,y,z)) @@ -47,10 +47,13 @@ #define execsql_i64(x,y,...) (SEL(x), execsql_i64_x(x,y,__VA_ARGS__)) #define execsql_text(x,y,z,...) (SEL(x), execsql_text_x(x,y,z,__VA_ARGS__)) #define execsql(x,y,...) (SEL(x), (void)execsql_i64_x(x,y,__VA_ARGS__)) +#define sql_script_printf(x,y,z,...) ( \ + SEL(x), sql_script_printf_x(x,y,z,__VA_ARGS__) \ +) /* Thread functions */ -#define launch_thread(w,x,y,z) (SEL(w), launch_thread_x(w,x,y,z)) -#define join_all_threads(y,z) (SEL(y), join_all_threads_x(y,z)) +#define launch_thread(w,x,y,z) (SEL(w), launch_thread_x(w,x,y,z)) +#define join_all_threads(y,z) (SEL(y), join_all_threads_x(y,z)) /* Timer functions */ #define setstoptime(y,z) (SEL(y), setstoptime_x(y,z)) @@ -64,6 +67,9 @@ #define filesize(y,z) (SEL(y), filesize_x(y,z)) #define filecopy(x,y,z) (SEL(x), filecopy_x(x,y,z)) +#define PTR2INT(x) ((int)((intptr_t)x)) +#define INT2PTR(x) ((void*)((intptr_t)x)) + /* ** End of test code/infrastructure interface macros. *************************************************************************/ @@ -115,7 +121,10 @@ struct MD5Context { int isInit; uint32 buf[4]; uint32 bits[2]; - unsigned char in[64]; + union { + unsigned char in[64]; + uint32 in32[16]; + } u; }; typedef struct MD5Context MD5Context; @@ -264,7 +273,7 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ /* Handle any leading odd-sized chunks */ if ( t ) { - unsigned char *p = (unsigned char *)ctx->in + t; + unsigned char *p = (unsigned char *)ctx->u.in + t; t = 64-t; if (len < t) { @@ -272,8 +281,8 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ return; } memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); + byteReverse(ctx->u.in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->u.in); buf += t; len -= t; } @@ -281,16 +290,16 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ /* Process data in 64-byte chunks */ while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); + memcpy(ctx->u.in, buf, 64); + byteReverse(ctx->u.in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->u.in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ - memcpy(ctx->in, buf, len); + memcpy(ctx->u.in, buf, len); } /* @@ -306,7 +315,7 @@ static void MD5Final(unsigned char digest[16], MD5Context *ctx){ /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ - p = ctx->in + count; + p = ctx->u.in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ @@ -316,25 +325,25 @@ static void MD5Final(unsigned char digest[16], MD5Context *ctx){ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); + byteReverse(ctx->u.in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->u.in); /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); + memset(ctx->u.in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count-8); } - byteReverse(ctx->in, 14); + byteReverse(ctx->u.in, 14); /* Append length in bits and transform */ - ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; - ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; + ctx->u.in32[14] = ctx->bits[0]; + ctx->u.in32[15] = ctx->bits[1]; - MD5Transform(ctx->buf, (uint32 *)ctx->in); + MD5Transform(ctx->buf, (uint32 *)ctx->u.in); byteReverse((unsigned char *)ctx->buf, 4); memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */ + memset(ctx, 0, sizeof(*ctx)); /* In case it is sensitive */ } /* @@ -382,9 +391,9 @@ static void md5finalize(sqlite3_context *context){ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } -/************************************************************************* +/* ** End of copied md5sum() code. -*/ +**************************************************************************/ typedef sqlite3_int64 i64; @@ -398,9 +407,6 @@ typedef struct Thread Thread; /* Total number of errors in this process so far. */ static int nGlobalErr = 0; -/* Set to true to run in "process" instead of "thread" mode. */ -static int bProcessMode = 0; - struct Error { int rc; int iLine; @@ -421,10 +427,10 @@ struct Statement { struct Thread { int iTid; /* Thread number within test */ - int iArg; /* Integer argument passed by caller */ + void* pArg; /* Pointer argument passed by caller */ pthread_t tid; /* Thread id */ - char *(*xProc)(int, int); /* Thread main proc */ + char *(*xProc)(int, void*); /* Thread main proc */ Thread *pNext; /* Next in this list of threads */ }; @@ -441,8 +447,13 @@ static void free_err(Error *p){ static void print_err(Error *p){ if( p->rc!=SQLITE_OK ){ - printf("Error: (%d) \"%s\" at line %d\n", p->rc, p->zErr, p->iLine); - nGlobalErr++; + int isWarn = 0; + if( p->rc==SQLITE_SCHEMA ) isWarn = 1; + if( sqlite3_strglob("* - no such table: *",p->zErr)==0 ) isWarn = 1; + printf("%s: (%d) \"%s\" at line %d\n", isWarn ? "Warning" : "Error", + p->rc, p->zErr, p->iLine); + if( !isWarn ) nGlobalErr++; + fflush(stdout); } } @@ -506,8 +517,9 @@ static void opendb_x( ){ if( pErr->rc==SQLITE_OK ){ int rc; + int flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI; if( bDelete ) unlink(zFile); - rc = sqlite3_open(zFile, &pDb->db); + rc = sqlite3_open_v2(zFile, &pDb->db, flags, 0); if( rc ){ sqlite_error(pErr, pDb, "open"); sqlite3_close(pDb->db); @@ -556,6 +568,22 @@ static void sql_script_x( } } +static void sql_script_printf_x( + Error *pErr, /* IN/OUT: Error code */ + Sqlite *pDb, /* Database handle */ + const char *zFormat, /* SQL printf format string */ + ... /* Printf args */ +){ + va_list ap; /* ... printf arguments */ + va_start(ap, zFormat); + if( pErr->rc==SQLITE_OK ){ + char *zSql = sqlite3_vmprintf(zFormat, ap); + pErr->rc = sqlite3_exec(pDb->db, zSql, 0, 0, &pErr->zErr); + sqlite3_free(zSql); + } + va_end(ap); +} + static Statement *getSqlStatement( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* Database handle */ @@ -624,11 +652,9 @@ static i64 execsql_i64_x( if( pErr->rc==SQLITE_OK ){ sqlite3_stmt *pStmt; /* SQL statement to execute */ va_list ap; /* ... arguments */ - int i; /* Used to iterate through parameters */ va_start(ap, pDb); pStmt = getAndBindSqlStatement(pErr, pDb, ap); if( pStmt ){ - int rc; int first = 1; while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( first && sqlite3_column_count(pStmt)>0 ){ @@ -663,11 +689,9 @@ static char * execsql_text_x( if( pErr->rc==SQLITE_OK ){ sqlite3_stmt *pStmt; /* SQL statement to execute */ va_list ap; /* ... arguments */ - int i; /* Used to iterate through parameters */ va_start(ap, iSlot); pStmt = getAndBindSqlStatement(pErr, pDb, ap); if( pStmt ){ - int rc; int first = 1; while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( first && sqlite3_column_count(pStmt)>0 ){ @@ -693,14 +717,13 @@ static void integrity_check_x( ){ if( pErr->rc==SQLITE_OK ){ Statement *pStatement; /* Statement to execute */ - int rc; /* Return code */ char *zErr = 0; /* Integrity check error */ pStatement = getSqlStatement(pErr, pDb, "PRAGMA integrity_check"); if( pStatement ){ sqlite3_stmt *pStmt = pStatement->pStmt; while( SQLITE_ROW==sqlite3_step(pStmt) ){ - const char *z = sqlite3_column_text(pStmt, 0); + const char *z = (const char*)sqlite3_column_text(pStmt, 0); if( strcmp(z, "ok") ){ if( zErr==0 ){ zErr = sqlite3_mprintf("%s", z); @@ -721,14 +744,14 @@ static void integrity_check_x( static void *launch_thread_main(void *pArg){ Thread *p = (Thread *)pArg; - return (void *)p->xProc(p->iTid, p->iArg); + return (void *)p->xProc(p->iTid, p->pArg); } static void launch_thread_x( Error *pErr, /* IN/OUT: Error code */ Threadset *pThreads, /* Thread set */ - char *(*xProc)(int, int), /* Proc to run */ - int iArg /* Argument passed to thread proc */ + char *(*xProc)(int, void*), /* Proc to run */ + void *pArg /* Argument passed to thread proc */ ){ if( pErr->rc==SQLITE_OK ){ int iTid = ++pThreads->iMaxTid; @@ -738,7 +761,7 @@ static void launch_thread_x( p = (Thread *)sqlite3_malloc(sizeof(Thread)); memset(p, 0, sizeof(Thread)); p->iTid = iTid; - p->iArg = iArg; + p->pArg = pArg; p->xProc = xProc; rc = pthread_create(&p->tid, NULL, launch_thread_main, (void *)p); @@ -767,6 +790,7 @@ static void join_all_threads_x( if( pErr->rc==SQLITE_OK ) system_error(pErr, rc); }else{ printf("Thread %d says: %s\n", p->iTid, (ret==0 ? "..." : (char *)ret)); + fflush(stdout); } sqlite3_free(p); } @@ -880,11 +904,6 @@ static int timetostop_x( return ret; } -/* -** The "Set Error Line" macro. -*/ -#define SEL(e) ((e)->iLine = ((e)->rc ? (e)->iLine : __LINE__)) - /************************************************************************* ************************************************************************** @@ -895,7 +914,7 @@ static int timetostop_x( #define WALTHREAD1_NTHREAD 10 #define WALTHREAD3_NTHREAD 6 -static char *walthread1_thread(int iTid, int iArg){ +static char *walthread1_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nIter = 0; /* Iterations so far */ @@ -934,7 +953,7 @@ static char *walthread1_thread(int iTid, int iArg){ return sqlite3_mprintf("%d iterations", nIter); } -static char *walthread1_ckpt_thread(int iTid, int iArg){ +static char *walthread1_ckpt_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nCkpt = 0; /* Checkpoints so far */ @@ -966,6 +985,7 @@ static void walthread1(int nMs){ "INSERT INTO t1 VALUES(randomblob(100));" "INSERT INTO t1 SELECT md5sum(x) FROM t1;" ); + closedb(&err, &db); setstoptime(&err, nMs); for(i=0; i2 ) goto usage; - if( argc==2 ){ - zTest = argv[1]; - nTest = strlen(zTest); - if( zTest[nTest-1]=='*' ){ - nTest--; - bPrefix = 1; - } - } + static char *substArgv[] = { 0, "*", 0 }; + int i, iArg; + int nTestfound = 0; sqlite3_config(SQLITE_CONFIG_MULTITHREAD); - - for(i=0; i=sizeof(aTest)/sizeof(aTest[0]) ) goto usage; + } + for(iArg=1; iArg0 ? 255 : 0); usage: - printf("Usage: %s [testname|testprefix*]\n", argv[0]); + printf("Usage: %s [testname|testprefix*]...\n", argv[0]); printf("Available tests are:\n"); for(i=0; i +#include +#include +#include +#include +#include +#include + +/* +** An instance of the following structure is passed into each worker +** thread. +*/ +typedef struct WorkerInfo WorkerInfo; +struct WorkerInfo { + int tid; /* Thread ID */ + int nWorker; /* Total number of workers */ + unsigned wkrFlags; /* Flags */ + sqlite3 *mainDb; /* Database connection of the main thread */ + sqlite3 *db; /* Database connection of this thread */ + int nErr; /* Number of errors seen by this thread */ + int nTest; /* Number of tests run by this thread */ + char *zMsg; /* Message returned by this thread */ + pthread_t id; /* Thread id */ + pthread_mutex_t *pWrMutex; /* Hold this mutex while writing */ +}; + +/* +** Allowed values for WorkerInfo.wkrFlags +*/ +#define TT4_SERIALIZED 0x0000001 /* The --serialized option is used */ +#define TT4_WAL 0x0000002 /* WAL mode in use */ +#define TT4_TRACE 0x0000004 /* Trace activity */ + + +/* +** Report an OOM error and die if the argument is NULL +*/ +static void check_oom(void *x){ + if( x==0 ){ + fprintf(stderr, "out of memory\n"); + exit(1); + } +} + +/* +** Allocate memory. If the allocation fails, print an error message and +** kill the process. +*/ +static void *safe_malloc(int sz){ + void *x = sqlite3_malloc(sz>0?sz:1); + check_oom(x); + return x; +} + +/* +** Print a trace message for a worker +*/ +static void worker_trace(WorkerInfo *p, const char *zFormat, ...){ + va_list ap; + char *zMsg; + if( (p->wkrFlags & TT4_TRACE)==0 ) return; + va_start(ap, zFormat); + zMsg = sqlite3_vmprintf(zFormat, ap); + check_oom(zMsg); + va_end(ap); + fprintf(stderr, "TRACE(%02d): %s\n", p->tid, zMsg); + sqlite3_free(zMsg); +} + +/* +** Prepare a single SQL query +*/ +static sqlite3_stmt *prep_sql(sqlite3 *db, const char *zFormat, ...){ + va_list ap; + char *zSql; + int rc; + sqlite3_stmt *pStmt = 0; + + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + check_oom(zSql); + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ){ + fprintf(stderr, "SQL error (%d,%d): %s\nWhile preparing: [%s]\n", + rc, sqlite3_extended_errcode(db), sqlite3_errmsg(db), zSql); + exit(1); + } + sqlite3_free(zSql); + return pStmt; +} + +/* +** Run a SQL statements. Panic if unable. +*/ +static void run_sql(WorkerInfo *p, const char *zFormat, ...){ + va_list ap; + char *zSql; + int rc; + sqlite3_stmt *pStmt = 0; + int nRetry = 0; + + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + check_oom(zSql); + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ){ + fprintf(stderr, "SQL error (%d,%d): %s\nWhile preparing: [%s]\n", + rc, sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zSql); + exit(1); + } + worker_trace(p, "running [%s]", zSql); + while( (rc = sqlite3_step(pStmt))!=SQLITE_DONE ){ + if( (rc&0xff)==SQLITE_BUSY || (rc&0xff)==SQLITE_LOCKED ){ + sqlite3_reset(pStmt); + nRetry++; + if( nRetry<10 ){ + worker_trace(p, "retry %d for [%s]", nRetry, zSql); + sched_yield(); + continue; + }else{ + fprintf(stderr, "Deadlock in thread %d while running [%s]\n", + p->tid, zSql); + exit(1); + } + } + if( rc!=SQLITE_ROW ){ + fprintf(stderr, "SQL error (%d,%d): %s\nWhile running [%s]\n", + rc, sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zSql); + exit(1); + } + } + sqlite3_free(zSql); + sqlite3_finalize(pStmt); +} + + +/* +** Open the database connection for WorkerInfo. The order in which +** the files are opened is a function of the tid value. +*/ +static void worker_open_connection(WorkerInfo *p, int iCnt){ + char *zFile; + int x; + int rc; + static const unsigned char aOrder[6][3] = { + { 1, 2, 3}, + { 1, 3, 2}, + { 2, 1, 3}, + { 2, 3, 1}, + { 3, 1, 2}, + { 3, 2, 1} + }; + x = (p->tid + iCnt) % 6; + zFile = sqlite3_mprintf("tt4-test%d.db", aOrder[x][0]); + check_oom(zFile); + worker_trace(p, "open %s", zFile); + rc = sqlite3_open_v2(zFile, &p->db, + SQLITE_OPEN_READWRITE|SQLITE_OPEN_SHAREDCACHE, 0); + if( rc!=SQLITE_OK ){ + fprintf(stderr, "sqlite_open_v2(%s) failed on thread %d\n", + zFile, p->tid); + exit(1); + } + sqlite3_free(zFile); + run_sql(p, "PRAGMA read_uncommitted=ON;"); + sqlite3_busy_timeout(p->db, 10000); + run_sql(p, "PRAGMA synchronous=OFF;"); + run_sql(p, "ATTACH 'tt4-test%d.db' AS aux1", aOrder[x][1]); + run_sql(p, "ATTACH 'tt4-test%d.db' AS aux2", aOrder[x][2]); +} + +/* +** Close the worker database connection +*/ +static void worker_close_connection(WorkerInfo *p){ + if( p->db ){ + worker_trace(p, "close"); + sqlite3_close(p->db); + p->db = 0; + } +} + +/* +** Delete all content in the three databases associated with a +** single thread. Make this happen all in a single transaction if +** inTrans is true, or separately for each database if inTrans is +** false. +*/ +static void worker_delete_all_content(WorkerInfo *p, int inTrans){ + if( inTrans ){ + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "BEGIN"); + run_sql(p, "DELETE FROM t1 WHERE tid=%d", p->tid); + run_sql(p, "DELETE FROM t2 WHERE tid=%d", p->tid); + run_sql(p, "DELETE FROM t3 WHERE tid=%d", p->tid); + run_sql(p, "COMMIT"); + pthread_mutex_unlock(p->pWrMutex); + p->nTest++; + }else{ + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "DELETE FROM t1 WHERE tid=%d", p->tid); + pthread_mutex_unlock(p->pWrMutex); + p->nTest++; + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "DELETE FROM t2 WHERE tid=%d", p->tid); + pthread_mutex_unlock(p->pWrMutex); + p->nTest++; + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "DELETE FROM t3 WHERE tid=%d", p->tid); + pthread_mutex_unlock(p->pWrMutex); + p->nTest++; + } +} + +/* +** Create rows mn through mx in table iTab for the given worker +*/ +static void worker_add_content(WorkerInfo *p, int mn, int mx, int iTab){ + char *zTabDef; + switch( iTab ){ + case 1: zTabDef = "t1(tid,sp,a,b,c)"; break; + case 2: zTabDef = "t2(tid,sp,d,e,f)"; break; + case 3: zTabDef = "t3(tid,sp,x,y,z)"; break; + } + pthread_mutex_lock(p->pWrMutex); + run_sql(p, + "WITH RECURSIVE\n" + " c(i) AS (VALUES(%d) UNION ALL SELECT i+1 FROM c WHERE i<%d)\n" + "INSERT INTO %s SELECT %d, zeroblob(3000), i, printf('%%d',i), i FROM c;", + mn, mx, zTabDef, p->tid + ); + pthread_mutex_unlock(p->pWrMutex); + p->nTest++; +} + +/* +** Set an error message on a worker +*/ +static void worker_error(WorkerInfo *p, const char *zFormat, ...){ + va_list ap; + p->nErr++; + sqlite3_free(p->zMsg); + va_start(ap, zFormat); + p->zMsg = sqlite3_vmprintf(zFormat, ap); + va_end(ap); +} + +/* +** Each thread runs the following function. +*/ +static void *worker_thread(void *pArg){ + WorkerInfo *p = (WorkerInfo*)pArg; + int iOuter; + int i; + int rc; + sqlite3_stmt *pStmt; + + printf("worker %d startup\n", p->tid); fflush(stdout); + for(iOuter=1; iOuter<=p->nWorker; iOuter++){ + worker_open_connection(p, iOuter); + for(i=0; i<4; i++){ + worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter)%3 + 1); + worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter+1)%3 + 1); + worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter+2)%3 + 1); + } + + pStmt = prep_sql(p->db, "SELECT count(a) FROM t1 WHERE tid=%d", p->tid); + worker_trace(p, "query [%s]", sqlite3_sql(pStmt)); + rc = sqlite3_step(pStmt); + if( rc!=SQLITE_ROW ){ + worker_error(p, "Failed to step: %s", sqlite3_sql(pStmt)); + }else if( sqlite3_column_int(pStmt, 0)!=400 ){ + worker_error(p, "Wrong result: %d", sqlite3_column_int(pStmt,0)); + } + sqlite3_finalize(pStmt); + if( p->nErr ) break; + + if( ((iOuter+p->tid)%3)==0 ){ + sqlite3_db_release_memory(p->db); + p->nTest++; + } + + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "BEGIN;"); + run_sql(p, "UPDATE t1 SET c=NULL WHERE a=55"); + run_sql(p, "UPDATE t2 SET f=NULL WHERE d=42"); + run_sql(p, "UPDATE t3 SET z=NULL WHERE x=31"); + run_sql(p, "ROLLBACK;"); + p->nTest++; + pthread_mutex_unlock(p->pWrMutex); + + + if( iOuter==p->tid ){ + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "VACUUM"); + pthread_mutex_unlock(p->pWrMutex); + } + + pStmt = prep_sql(p->db, + "SELECT t1.rowid, t2.rowid, t3.rowid" + " FROM t1, t2, t3" + " WHERE t1.tid=%d AND t2.tid=%d AND t3.tid=%d" + " AND t1.a<>t2.d AND t2.d<>t3.x" + " ORDER BY 1, 2, 3" + ,p->tid, p->tid, p->tid); + worker_trace(p, "query [%s]", sqlite3_sql(pStmt)); + for(i=0; inWorker; i++){ + rc = sqlite3_step(pStmt); + if( rc!=SQLITE_ROW ){ + worker_error(p, "Failed to step: %s", sqlite3_sql(pStmt)); + break; + } + sched_yield(); + } + sqlite3_finalize(pStmt); + if( p->nErr ) break; + + worker_delete_all_content(p, (p->tid+iOuter)%2); + worker_close_connection(p); + p->db = 0; + } + worker_close_connection(p); + printf("worker %d finished\n", p->tid); fflush(stdout); + return 0; +} + +int main(int argc, char **argv){ + int nWorker = 0; /* Number of worker threads */ + int i; /* Loop counter */ + WorkerInfo *aInfo; /* Information for each worker */ + unsigned wkrFlags = 0; /* Default worker flags */ + int nErr = 0; /* Number of errors */ + int nTest = 0; /* Number of tests */ + int rc; /* Return code */ + sqlite3 *db = 0; /* Main database connection */ + pthread_mutex_t wrMutex; /* The write serialization mutex */ + WorkerInfo infoTop; /* WorkerInfo for the main thread */ + WorkerInfo *p; /* Pointer to infoTop */ + + sqlite3_config(SQLITE_CONFIG_MULTITHREAD); + for(i=1; i='1' && z[0]<='9' && nWorker==0 ){ + nWorker = atoi(z); + if( nWorker<2 ){ + fprintf(stderr, "minimum of 2 threads\n"); + exit(1); + } + }else{ + fprintf(stderr, "extra command-line argument: \"%s\"\n", argv[i]); + exit(1); + } + } + if( nWorker==0 ){ + fprintf(stderr, + "usage: %s ?OPTIONS? N\n" + "N is the number of threads and must be at least 2.\n" + "Options:\n" + " --serialized\n" + " --multithread\n" + " --wal\n" + " --trace\n" + ,argv[0] + ); + exit(1); + } + if( !sqlite3_threadsafe() ){ + fprintf(stderr, "requires a threadsafe build of SQLite\n"); + exit(1); + } + sqlite3_initialize(); + sqlite3_enable_shared_cache(1); + pthread_mutex_init(&wrMutex, 0); + + /* Initialize the test database files */ + (void)unlink("tt4-test1.db"); + (void)unlink("tt4-test2.db"); + (void)unlink("tt4-test3.db"); + rc = sqlite3_open("tt4-test1.db", &db); + if( rc!=SQLITE_OK ){ + fprintf(stderr, "Unable to open test database: tt4-test2.db\n"); + exit(1); + } + memset(&infoTop, 0, sizeof(infoTop)); + infoTop.db = db; + infoTop.wkrFlags = wkrFlags; + p = &infoTop; + if( wkrFlags & TT4_WAL ){ + run_sql(p, "PRAGMA journal_mode=WAL"); + } + run_sql(p, "PRAGMA synchronous=OFF"); + run_sql(p, "CREATE TABLE IF NOT EXISTS t1(tid INTEGER, sp, a, b, c)"); + run_sql(p, "CREATE INDEX t1tid ON t1(tid)"); + run_sql(p, "CREATE INDEX t1ab ON t1(a,b)"); + run_sql(p, "ATTACH 'tt4-test2.db' AS 'test2'"); + run_sql(p, "CREATE TABLE IF NOT EXISTS test2.t2(tid INTEGER, sp, d, e, f)"); + run_sql(p, "CREATE INDEX test2.t2tid ON t2(tid)"); + run_sql(p, "CREATE INDEX test2.t2de ON t2(d,e)"); + run_sql(p, "ATTACH 'tt4-test3.db' AS 'test3'"); + run_sql(p, "CREATE TABLE IF NOT EXISTS test3.t3(tid INTEGER, sp, x, y, z)"); + run_sql(p, "CREATE INDEX test3.t3tid ON t3(tid)"); + run_sql(p, "CREATE INDEX test3.t3xy ON t3(x,y)"); + aInfo = safe_malloc( sizeof(*aInfo)*nWorker ); + memset(aInfo, 0, sizeof(*aInfo)*nWorker); + for(i=0; i=0} @@ -220,4 +221,36 @@ ifcapable compound { } {2} } +reset_db +do_execsql_test 4.1 { + CREATE TABLE t1(a, b); + CREATE TABLE log(x); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + CREATE VIEW v1 AS SELECT a, b FROM t1; + + CREATE TRIGGER tr1 INSTEAD OF DELETE ON v1 BEGIN + INSERT INTO log VALUES('delete'); + END; + + CREATE TRIGGER tr2 INSTEAD OF UPDATE ON v1 BEGIN + INSERT INTO log VALUES('update'); + END; + + CREATE TRIGGER tr3 INSTEAD OF INSERT ON v1 BEGIN + INSERT INTO log VALUES('insert'); + END; +} + +do_execsql_test 4.2 { + DELETE FROM v1 WHERE rowid=1; +} {} + +do_execsql_test 4.3 { + UPDATE v1 SET a=b WHERE rowid=2; +} {} + + + + finish_test diff --git a/test/tt3_checkpoint.c b/test/tt3_checkpoint.c index 3c28f0d..060a698 100644 --- a/test/tt3_checkpoint.c +++ b/test/tt3_checkpoint.c @@ -1,5 +1,5 @@ /* -** 2001 September 15 +** 2011-02-02 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -66,7 +66,7 @@ static int checkpoint_starvation_walhook( return SQLITE_OK; } -static char *checkpoint_starvation_reader(int iTid, int iArg){ +static char *checkpoint_starvation_reader(int iTid, void *pArg){ Error err = {0}; Sqlite db = {0}; @@ -146,5 +146,3 @@ static void checkpoint_starvation_2(int nMs){ } print_and_free_err(&err); } - - diff --git a/test/tt3_index.c b/test/tt3_index.c new file mode 100644 index 0000000..62f06ad --- /dev/null +++ b/test/tt3_index.c @@ -0,0 +1,74 @@ +/* +** 2014 December 9 +** +** 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. +** +************************************************************************* +** +** create_drop_index_1 +*/ + + +static char *create_drop_index_thread(int iTid, void *pArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + + while( !timetostop(&err) ){ + opendb(&err, &db, "test.db", 0); + + sql_script(&err, &db, + "DROP INDEX IF EXISTS i1;" + "DROP INDEX IF EXISTS i2;" + "DROP INDEX IF EXISTS i3;" + "DROP INDEX IF EXISTS i4;" + + "CREATE INDEX IF NOT EXISTS i1 ON t11(a);" + "CREATE INDEX IF NOT EXISTS i2 ON t11(b);" + "CREATE INDEX IF NOT EXISTS i3 ON t11(c);" + "CREATE INDEX IF NOT EXISTS i4 ON t11(d);" + + "SELECT * FROM t11 ORDER BY a;" + "SELECT * FROM t11 ORDER BY b;" + "SELECT * FROM t11 ORDER BY c;" + "SELECT * FROM t11 ORDER BY d;" + ); + clear_error(&err, SQLITE_LOCKED); + + closedb(&err, &db); + } + + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + +static void create_drop_index_1(int nMs){ + Error err = {0}; + Sqlite db = {0}; + Threadset threads = {0}; + + opendb(&err, &db, "test.db", 1); + sql_script(&err, &db, + "CREATE TABLE t11(a, b, c, d);" + "WITH data(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM data WHERE x<100) " + "INSERT INTO t11 SELECT x,x,x,x FROM data;" + ); + closedb(&err, &db); + + setstoptime(&err, nMs); + + sqlite3_enable_shared_cache(1); + launch_thread(&err, &threads, create_drop_index_thread, 0); + launch_thread(&err, &threads, create_drop_index_thread, 0); + launch_thread(&err, &threads, create_drop_index_thread, 0); + launch_thread(&err, &threads, create_drop_index_thread, 0); + launch_thread(&err, &threads, create_drop_index_thread, 0); + + join_all_threads(&err, &threads); + sqlite3_enable_shared_cache(0); + print_and_free_err(&err); +} diff --git a/test/tt3_lookaside1.c b/test/tt3_lookaside1.c new file mode 100644 index 0000000..e785e79 --- /dev/null +++ b/test/tt3_lookaside1.c @@ -0,0 +1,99 @@ +/* +** 2014 December 9 +** +** 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. +** +************************************************************************* +** +** lookaside1 +*/ + +/* +** The test in this file attempts to expose a specific race condition +** that is suspected to exist at time of writing. +*/ + +static char *lookaside1_thread_reader(int iTid, void *pArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + + opendb(&err, &db, "test.db", 0); + + while( !timetostop(&err) ){ + sqlite3_stmt *pStmt = 0; + int rc; + + sqlite3_prepare_v2(db.db, "SELECT 1 FROM t1", -1, &pStmt, 0); + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + execsql(&err, &db, "SELECT length(x||y||z) FROM t2"); + } + rc = sqlite3_finalize(pStmt); + if( err.rc==SQLITE_OK && rc!=SQLITE_OK ){ + sqlite_error(&err, &db, "finalize"); + } + } + + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + +static char *lookaside1_thread_writer(int iTid, void *pArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + + opendb(&err, &db, "test.db", 0); + + do{ + sql_script(&err, &db, + "BEGIN;" + "UPDATE t3 SET i=i+1 WHERE x=1;" + "ROLLBACK;" + ); + }while( !timetostop(&err) ); + + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + + +static void lookaside1(int nMs){ + Error err = {0}; + Sqlite db = {0}; + Threadset threads = {0}; + + opendb(&err, &db, "test.db", 1); + sql_script(&err, &db, + "CREATE TABLE t1(x PRIMARY KEY) WITHOUT ROWID;" + "WITH data(x,y) AS (" + " SELECT 1, quote(randomblob(750)) UNION ALL " + " SELECT x*2, y||y FROM data WHERE x<5) " + "INSERT INTO t1 SELECT y FROM data;" + + "CREATE TABLE t3(x PRIMARY KEY,i) WITHOUT ROWID;" + "INSERT INTO t3 VALUES(1, 1);" + + "CREATE TABLE t2(x,y,z);" + "INSERT INTO t2 VALUES(randomblob(50), randomblob(50), randomblob(50));" + ); + closedb(&err, &db); + + setstoptime(&err, nMs); + + sqlite3_enable_shared_cache(1); + launch_thread(&err, &threads, lookaside1_thread_reader, 0); + launch_thread(&err, &threads, lookaside1_thread_reader, 0); + launch_thread(&err, &threads, lookaside1_thread_reader, 0); + launch_thread(&err, &threads, lookaside1_thread_reader, 0); + launch_thread(&err, &threads, lookaside1_thread_reader, 0); + launch_thread(&err, &threads, lookaside1_thread_writer, 0); + join_all_threads(&err, &threads); + sqlite3_enable_shared_cache(0); + print_and_free_err(&err); +} diff --git a/test/tt3_stress.c b/test/tt3_stress.c new file mode 100644 index 0000000..cdfab9c --- /dev/null +++ b/test/tt3_stress.c @@ -0,0 +1,368 @@ +/* +** 2014 December 9 +** +** 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. +** +************************************************************************* +** +** +*/ + + +/* +** Thread 1. CREATE and DROP a table. +*/ +static char *stress_thread_1(int iTid, void *pArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + + opendb(&err, &db, "test.db", 0); + while( !timetostop(&err) ){ + sql_script(&err, &db, "CREATE TABLE IF NOT EXISTS t1(a PRIMARY KEY, b)"); + clear_error(&err, SQLITE_LOCKED); + sql_script(&err, &db, "DROP TABLE IF EXISTS t1"); + clear_error(&err, SQLITE_LOCKED); + } + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + +/* +** Thread 2. Open and close database connections. +*/ +static char *stress_thread_2(int iTid, void *pArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + while( !timetostop(&err) ){ + opendb(&err, &db, "test.db", 0); + sql_script(&err, &db, "SELECT * FROM sqlite_master;"); + clear_error(&err, SQLITE_LOCKED); + closedb(&err, &db); + } + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + +/* +** Thread 3. Attempt many small SELECT statements. +*/ +static char *stress_thread_3(int iTid, void *pArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + + int i1 = 0; + int i2 = 0; + + opendb(&err, &db, "test.db", 0); + while( !timetostop(&err) ){ + sql_script(&err, &db, "SELECT * FROM t1 ORDER BY a;"); + i1++; + if( err.rc ) i2++; + clear_error(&err, SQLITE_LOCKED); + clear_error(&err, SQLITE_ERROR); + } + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("read t1 %d/%d attempts", i2, i1); +} + +/* +** Thread 5. Attempt INSERT statements. +*/ +static char *stress_thread_4(int iTid, void *pArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + int i1 = 0; + int i2 = 0; + int iArg = PTR2INT(pArg); + + opendb(&err, &db, "test.db", 0); + while( !timetostop(&err) ){ + if( iArg ){ + closedb(&err, &db); + opendb(&err, &db, "test.db", 0); + } + sql_script(&err, &db, + "WITH loop(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM loop LIMIT 200) " + "INSERT INTO t1 VALUES(randomblob(60), randomblob(60));" + ); + i1++; + if( err.rc ) i2++; + clear_error(&err, SQLITE_LOCKED); + clear_error(&err, SQLITE_ERROR); + } + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("wrote t1 %d/%d attempts", i2, i1); +} + +/* +** Thread 6. Attempt DELETE operations. +*/ +static char *stress_thread_5(int iTid, void *pArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + int iArg = PTR2INT(pArg); + + int i1 = 0; + int i2 = 0; + + opendb(&err, &db, "test.db", 0); + while( !timetostop(&err) ){ + i64 i = (i1 % 4); + if( iArg ){ + closedb(&err, &db); + opendb(&err, &db, "test.db", 0); + } + execsql(&err, &db, "DELETE FROM t1 WHERE (rowid % 4)==:i", &i); + i1++; + if( err.rc ) i2++; + clear_error(&err, SQLITE_LOCKED); + } + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("deleted from t1 %d/%d attempts", i2, i1); +} + + +static void stress1(int nMs){ + Error err = {0}; + Threadset threads = {0}; + + setstoptime(&err, nMs); + sqlite3_enable_shared_cache(1); + + launch_thread(&err, &threads, stress_thread_1, 0); + launch_thread(&err, &threads, stress_thread_1, 0); + + launch_thread(&err, &threads, stress_thread_2, 0); + launch_thread(&err, &threads, stress_thread_2, 0); + + launch_thread(&err, &threads, stress_thread_3, 0); + launch_thread(&err, &threads, stress_thread_3, 0); + + launch_thread(&err, &threads, stress_thread_4, 0); + launch_thread(&err, &threads, stress_thread_4, 0); + + launch_thread(&err, &threads, stress_thread_5, 0); + launch_thread(&err, &threads, stress_thread_5, (void*)1); + + join_all_threads(&err, &threads); + sqlite3_enable_shared_cache(0); + + print_and_free_err(&err); +} + +/************************************************************************** +*************************************************************************** +** Start of test case "stress2" +*/ + + + +/* +** 1. CREATE TABLE statements. +** 2. DROP TABLE statements. +** 3. Small SELECT statements. +** 4. Big SELECT statements. +** 5. Small INSERT statements. +** 6. Big INSERT statements. +** 7. Small UPDATE statements. +** 8. Big UPDATE statements. +** 9. Small DELETE statements. +** 10. Big DELETE statements. +** 11. VACUUM. +** 14. Integrity-check. +** 17. Switch the journal mode from delete to wal and back again. +** 19. Open and close database connections rapidly. +*/ + +#define STRESS2_TABCNT 5 /* count1 in SDS test */ + +#define STRESS2_COUNT2 200 /* count2 in SDS test */ +#define STRESS2_COUNT3 57 /* count2 in SDS test */ + +static void stress2_workload1(Error *pErr, Sqlite *pDb, int i){ + int iTab = (i % (STRESS2_TABCNT-1)) + 1; + sql_script_printf(pErr, pDb, + "CREATE TABLE IF NOT EXISTS t%d(x PRIMARY KEY, y, z);", iTab + ); +} + +static void stress2_workload2(Error *pErr, Sqlite *pDb, int i){ + int iTab = (i % (STRESS2_TABCNT-1)) + 1; + sql_script_printf(pErr, pDb, "DROP TABLE IF EXISTS t%d;", iTab); +} + +static void stress2_workload3(Error *pErr, Sqlite *pDb, int i){ + sql_script(pErr, pDb, "SELECT * FROM t0 WHERE z = 'small'"); +} + +static void stress2_workload4(Error *pErr, Sqlite *pDb, int i){ + sql_script(pErr, pDb, "SELECT * FROM t0 WHERE z = 'big'"); +} + +static void stress2_workload5(Error *pErr, Sqlite *pDb, int i){ + sql_script(pErr, pDb, + "INSERT INTO t0 VALUES(hex(random()), hex(randomblob(200)), 'small');" + ); +} + +static void stress2_workload6(Error *pErr, Sqlite *pDb, int i){ + sql_script(pErr, pDb, + "INSERT INTO t0 VALUES(hex(random()), hex(randomblob(57)), 'big');" + ); +} + +static void stress2_workload7(Error *pErr, Sqlite *pDb, int i){ + sql_script_printf(pErr, pDb, + "UPDATE t0 SET y = hex(randomblob(200)) " + "WHERE x LIKE hex((%d %% 5)) AND z='small';" + ,i + ); +} +static void stress2_workload8(Error *pErr, Sqlite *pDb, int i){ + sql_script_printf(pErr, pDb, + "UPDATE t0 SET y = hex(randomblob(57)) " + "WHERE x LIKE hex(%d %% 5) AND z='big';" + ,i + ); +} + +static void stress2_workload9(Error *pErr, Sqlite *pDb, int i){ + sql_script_printf(pErr, pDb, + "DELETE FROM t0 WHERE x LIKE hex(%d %% 5) AND z='small';", i + ); +} +static void stress2_workload10(Error *pErr, Sqlite *pDb, int i){ + sql_script_printf(pErr, pDb, + "DELETE FROM t0 WHERE x LIKE hex(%d %% 5) AND z='big';", i + ); +} + +static void stress2_workload11(Error *pErr, Sqlite *pDb, int i){ + sql_script(pErr, pDb, "VACUUM"); +} + +static void stress2_workload14(Error *pErr, Sqlite *pDb, int i){ + sql_script(pErr, pDb, "PRAGMA integrity_check"); +} + +static void stress2_workload17(Error *pErr, Sqlite *pDb, int i){ + sql_script_printf(pErr, pDb, + "PRAGMA journal_mode = %q", (i%2) ? "delete" : "wal" + ); +} + +static char *stress2_workload19(int iTid, void *pArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + const char *zDb = (const char*)pArg; + while( !timetostop(&err) ){ + opendb(&err, &db, zDb, 0); + sql_script(&err, &db, "SELECT * FROM sqlite_master;"); + clear_error(&err, SQLITE_LOCKED); + closedb(&err, &db); + } + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + + +typedef struct Stress2Ctx Stress2Ctx; +struct Stress2Ctx { + const char *zDb; + void (*xProc)(Error*, Sqlite*, int); +}; + +static char *stress2_thread_wrapper(int iTid, void *pArg){ + Stress2Ctx *pCtx = (Stress2Ctx*)pArg; + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + int i1 = 0; + int i2 = 0; + + while( !timetostop(&err) ){ + int cnt; + opendb(&err, &db, pCtx->zDb, 0); + for(cnt=0; err.rc==SQLITE_OK && cntxProc(&err, &db, i1); + i2 += (err.rc==SQLITE_OK); + clear_error(&err, SQLITE_LOCKED); + i1++; + } + closedb(&err, &db); + } + + print_and_free_err(&err); + return sqlite3_mprintf("ok %d/%d", i2, i1); +} + +static void stress2_launch_thread_loop( + Error *pErr, /* IN/OUT: Error code */ + Threadset *pThreads, /* Thread set */ + const char *zDb, /* Database name */ + void (*x)(Error*,Sqlite*,int) /* Run this until error or timeout */ +){ + Stress2Ctx *pCtx = sqlite3_malloc(sizeof(Stress2Ctx)); + pCtx->zDb = zDb; + pCtx->xProc = x; + launch_thread(pErr, pThreads, stress2_thread_wrapper, (void*)pCtx); +} + +static void stress2(int nMs){ + struct Stress2Task { + void (*x)(Error*,Sqlite*,int); + } aTask[] = { + { stress2_workload1 }, + { stress2_workload2 }, + { stress2_workload3 }, + { stress2_workload4 }, + { stress2_workload5 }, + { stress2_workload6 }, + { stress2_workload7 }, + { stress2_workload8 }, + { stress2_workload9 }, + { stress2_workload10 }, + { stress2_workload11 }, + { stress2_workload14 }, + { stress2_workload17 }, + }; + const char *zDb = "test.db"; + + int i; + Error err = {0}; + Sqlite db = {0}; + Threadset threads = {0}; + + /* To make sure the db file is empty before commencing */ + opendb(&err, &db, zDb, 1); + sql_script(&err, &db, + "CREATE TABLE IF NOT EXISTS t0(x PRIMARY KEY, y, z);" + "CREATE INDEX IF NOT EXISTS i0 ON t0(y);" + ); + closedb(&err, &db); + + setstoptime(&err, nMs); + sqlite3_enable_shared_cache(1); + + for(i=0; i-1} { return SQLITE_OK } diff --git a/test/wal5.test b/test/wal5.test index 68750f1..2d3522b 100644 --- a/test/wal5.test +++ b/test/wal5.test @@ -55,7 +55,8 @@ foreach {testprefix do_wal_checkpoint} { if {[lsearch {-mode -db} $key]<0} { error "unknown switch: $key" } } - if {$a(-mode)!="restart" && $a(-mode)!="full"} { set a(-mode) passive } + set vals {restart full truncate} + if {[lsearch -exact $vals $a(-mode)]<0} { set a(-mode) passive } set cmd [list sqlite3_wal_checkpoint_v2 $dbhandle $a(-mode)] if {[info exists a(-db)]} { lappend sql $a(-db) } @@ -278,6 +279,11 @@ foreach {testprefix do_wal_checkpoint} { 9 RESTART 2 {1 4 3} 2 10 RESTART 3 {1 4 4} 3 + 11 TRUNCATE - {0 0 0} 3 + 12 TRUNCATE 1 {1 3 3} 1 + 13 TRUNCATE 2 {1 4 3} 2 + 14 TRUNCATE 3 {1 4 4} 3 + } { do_multiclient_test tn { setup_and_attach_aux @@ -348,6 +354,123 @@ foreach {testprefix do_wal_checkpoint} { do_test 3.$tn.6 { code3 { do_wal_checkpoint db3 } } {0 0 0} } + + # Test SQLITE_CHECKPOINT_TRUNCATE. + # + do_multiclient_test tn { + + code1 $do_wal_checkpoint + code2 $do_wal_checkpoint + code3 $do_wal_checkpoint + + do_test 4.$tn.1 { + sql1 { + PRAGMA page_size = 1024; + PRAGMA auto_vacuum = 0; + PRAGMA journal_mode = WAL; + PRAGMA synchronous = normal; + CREATE TABLE t1(x, y); + CREATE INDEX i1 ON t1(x, y); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + } + file size test.db-wal + } [wal_file_size 8 1024] + + do_test 4.$tn.2 { do_wal_checkpoint db -mode truncate } {0 0 0} + do_test 4.$tn.3 { file size test.db-wal } 0 + + do_test 4.$tn.4 { + sql2 { SELECT * FROM t1 } + } {1 2 3 4} + + do_test 4.$tn.5 { + sql2 { INSERT INTO t1 VALUES('a', 'b') } + file size test.db-wal + } [wal_file_size 2 1024] + + } + + # Test that FULL, RESTART and TRUNCATE callbacks block on other clients + # and truncate the wal file as required even if the entire wal file has + # already been checkpointed when they are invoked. + # + do_multiclient_test tn { + + code1 $do_wal_checkpoint + code2 $do_wal_checkpoint + code3 $do_wal_checkpoint + + do_test 5.$tn.1 { + sql1 { + PRAGMA page_size = 1024; + PRAGMA auto_vacuum = 0; + PRAGMA journal_mode = WAL; + PRAGMA synchronous = normal; + CREATE TABLE t1(x, y); + CREATE INDEX i1 ON t1(x, y); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + INSERT INTO t1 VALUES(5, 6); + } + file size test.db-wal + } [wal_file_size 10 1024] + + do_test 5.$tn.2 { + sql2 { BEGIN; SELECT * FROM t1 } + } {1 2 3 4 5 6} + + do_test 5.$tn.3 { do_wal_checkpoint db -mode passive } {0 10 10} + + do_test 5.$tn.4 { + sql3 { BEGIN; INSERT INTO t1 VALUES(7, 8); } + } {} + + do_test 5.$tn.5 { do_wal_checkpoint db -mode passive } {0 10 10} + do_test 5.$tn.6 { do_wal_checkpoint db -mode full } {1 10 10} + + do_test 5.$tn.7 { sql3 { ROLLBACK } } {} + + do_test 5.$tn.8 { do_wal_checkpoint db -mode full } {0 10 10} + do_test 5.$tn.9 { do_wal_checkpoint db -mode truncate } {1 10 10} + + do_test 5.$tn.10 { + file size test.db-wal + } [wal_file_size 10 1024] + + proc xBusyHandler {n} { sql2 { COMMIT } ; return 0 } + db busy xBusyHandler + + do_test 5.$tn.11 { do_wal_checkpoint db -mode truncate } {0 0 0} + do_test 5.$tn.12 { file size test.db-wal } 0 + + do_test 5.$tn.13 { + sql1 { + INSERT INTO t1 VALUES(7, 8); + INSERT INTO t1 VALUES(9, 10); + SELECT * FROM t1; + } + } {1 2 3 4 5 6 7 8 9 10} + + do_test 5.$tn.14 { + sql2 { BEGIN; SELECT * FROM t1 } + } {1 2 3 4 5 6 7 8 9 10} + + proc xBusyHandler {n} { return 1 } + do_test 5.$tn.14 { do_wal_checkpoint db -mode truncate } {1 4 4} + do_test 5.$tn.15 { file size test.db-wal } [wal_file_size 4 1024] + + do_test 5.$tn.16 { do_wal_checkpoint db -mode restart } {1 4 4} + + proc xBusyHandler {n} { sql2 { COMMIT } ; return 0 } + db busy xBusyHandler + do_test 5.$tn.17 { do_wal_checkpoint db -mode restart } {0 4 4} + do_test 5.$tn.18 { file size test.db-wal } [wal_file_size 4 1024] + + do_test 5.$tn.19 { do_wal_checkpoint db -mode truncate } {0 0 0} + do_test 5.$tn.20 { file size test.db-wal } 0 + } + } diff --git a/test/whereJ.test b/test/whereJ.test index 5209f16..48924d0 100644 --- a/test/whereJ.test +++ b/test/whereJ.test @@ -371,5 +371,308 @@ do_execsql_test whereJ-2.2 { ORDER BY t4.x; } {~/SCAN/} +############################################################################ + +# Create and populate table. +do_execsql_test 3.1 { CREATE TABLE t1(a, b, c) } +for {set i 0} {$i < 32} {incr i 2} { + for {set x 0} {$x < 100} {incr x} { + execsql { INSERT INTO t1 VALUES($i, $x, $c) } + incr c + } + execsql { INSERT INTO t1 VALUES($i+1, 5, $c) } + incr c +} + +do_execsql_test 3.2 { + SELECT a, count(*) FROM t1 GROUP BY a HAVING a < 8; +} { + 0 100 1 1 2 100 3 1 4 100 5 1 6 100 7 1 +} + +do_execsql_test 3.3 { + CREATE INDEX idx_ab ON t1(a, b); + CREATE INDEX idx_c ON t1(c); + ANALYZE; +} {} + +# This one should use index "idx_c". +do_eqp_test 3.4 { + SELECT * FROM t1 WHERE + a = 4 AND b BETWEEN 20 AND 80 -- Matches 80 rows + AND + c BETWEEN 150 AND 160 -- Matches 10 rows +} { + 0 0 0 {SEARCH TABLE t1 USING INDEX idx_c (c>? AND c? AND b=5 AND d<=5) + AND ((e>=7 AND e<=7) OR (f>=8 AND f<=8)) + AND g>0; + }] +} {~/ANY/} +do_test 5.2 {set res} {/USING INDEX t1abe/} +do_test 5.3 {set res} {/USING INDEX t1abf/} + + finish_test diff --git a/test/without_rowid3.test b/test/without_rowid3.test index c4c2d6f..a0dc76d 100644 --- a/test/without_rowid3.test +++ b/test/without_rowid3.test @@ -1621,7 +1621,7 @@ ifcapable auth { } } {} - proc auth {args} {eval lappend ::authargs $args ; return SQLITE_OK} + proc auth {args} {eval lappend ::authargs [lrange $args 0 4]; return SQLITE_OK} db auth auth # An insert on the parent table must read the child key of any deferred diff --git a/test/without_rowid5.test b/test/without_rowid5.test index 45e047b..d163d9c 100644 --- a/test/without_rowid5.test +++ b/test/without_rowid5.test @@ -185,8 +185,7 @@ do_execsql_test without_rowid5-5.9 { # EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not # work for WITHOUT ROWID tables. # -# EVIDENCE-OF: R-25760-33257 The sqlite3_blob_open() interface will fail -# for a WITHOUT ROWID table. +# EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table # do_execsql_test without_rowid5-6.1 { CREATE TABLE b1(a INTEGER PRIMARY KEY, b BLOB) WITHOUT ROWID; diff --git a/test/without_rowid6.test b/test/without_rowid6.test new file mode 100644 index 0000000..e827cca --- /dev/null +++ b/test/without_rowid6.test @@ -0,0 +1,41 @@ +# 2014-12-28 +# +# 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. +# +#*********************************************************************** +# +# Verify that WITHOUT ROWID tables work correctly when the PRIMARY KEY +# has redundant columns. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test without_rowid6-100 { + CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,a,b,c,d,a,b,c)) WITHOUT ROWID; + CREATE INDEX t1a ON t1(b, b); + WITH RECURSIVE + c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<1000) + INSERT INTO t1(a,b,c,d,e) SELECT i, i+1000, printf('x%dy',i), 0, 0 FROM c; + ANALYZE; +} {} +do_execsql_test without_rowid6-110 { + SELECT c FROM t1 WHERE a=123; +} {x123y} +do_execsql_test without_rowid6-120 { + SELECT c FROM t1 WHERE b=1123; +} {x123y} +do_execsql_test without_rowid6-130 { + SELECT c FROM t1 ORDER BY a DESC LIMIT 5; +} {x1000y x999y x998y x997y x996y} +do_execsql_test without_rowid6-140 { + SELECT c FROM t1 ORDER BY b LIMIT 5; +} {x1y x2y x3y x4y x5y} + + +finish_test diff --git a/tool/lemon.c b/tool/lemon.c index 85e94f7..4ada425 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -1497,10 +1497,12 @@ int main(int argc, char **argv) {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, - {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."}, + {OPT_FSTR, "f", 0, "Ignored. (Placeholder for -f compiler options.)"}, {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, + {OPT_FSTR, "I", 0, "Ignored. (Placeholder for '-I' compiler options.)"}, {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."}, {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."}, + {OPT_FSTR, "O", 0, "Ignored. (Placeholder for '-O' compiler options.)"}, {OPT_FLAG, "p", (char*)&showPrecedenceConflict, "Show conflicts resolved by precedence rules"}, {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, @@ -1508,6 +1510,8 @@ int main(int argc, char **argv) {OPT_FLAG, "s", (char*)&statistics, "Print parser stats to standard output."}, {OPT_FLAG, "x", (char*)&version, "Print the version number."}, + {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."}, + {OPT_FSTR, "W", 0, "Ignored. (Placeholder for '-W' compiler options.)"}, {OPT_FLAG,0,0,0} }; int i; @@ -1812,6 +1816,8 @@ static int handleflags(int i, FILE *err) errline(i,1,err); } errcnt++; + }else if( op[j].arg==0 ){ + /* Ignore this option */ }else if( op[j].type==OPT_FLAG ){ *((int*)op[j].arg) = v; }else if( op[j].type==OPT_FFLAG ){ @@ -2001,17 +2007,17 @@ void OptPrint(){ break; case OPT_INT: case OPT_FINT: - fprintf(errstream," %s=%*s %s\n",op[i].label, + fprintf(errstream," -%s%*s %s\n",op[i].label, (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message); break; case OPT_DBL: case OPT_FDBL: - fprintf(errstream," %s=%*s %s\n",op[i].label, + fprintf(errstream," -%s%*s %s\n",op[i].label, (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message); break; case OPT_STR: case OPT_FSTR: - fprintf(errstream," %s=%*s %s\n",op[i].label, + fprintf(errstream," -%s%*s %s\n",op[i].label, (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); break; } @@ -2436,7 +2442,7 @@ to follow the previous rule."); if( x[0]=='{' || x[0]=='\"' || isalnum(x[0]) ){ const char *zOld, *zNew; char *zBuf, *z; - int nOld, n, nLine, nNew, nBack; + int nOld, n, nLine = 0, nNew, nBack; int addLineMacro; char zLine[50]; zNew = x; @@ -2635,7 +2641,7 @@ void Parse(struct lemon *gp) struct pstate ps; FILE *fp; char *filebuf; - int filesize; + unsigned int filesize; int lineno; int c; char *cp, *nextcp; @@ -2769,7 +2775,7 @@ void Parse(struct lemon *gp) c = *cp; *cp = 0; /* Null terminate the token */ parseonetoken(&ps); /* Parse the token */ - *cp = c; /* Restore the buffer */ + *cp = (char)c; /* Restore the buffer */ cp = nextcp; } free(filebuf); /* Release the buffer after parsing */ @@ -3392,7 +3398,7 @@ PRIVATE char *append_str(const char *zText, int n, int p1, int p2){ zText++; n--; }else{ - z[used++] = c; + z[used++] = (char)c; } } z[used] = 0; diff --git a/tool/mkautoconfamal.sh b/tool/mkautoconfamal.sh index c13f7c9..0c2668c 100644 --- a/tool/mkautoconfamal.sh +++ b/tool/mkautoconfamal.sh @@ -62,13 +62,13 @@ mkdir -p tea/generic echo "#ifdef USE_SYSTEM_SQLITE" > tea/generic/tclsqlite3.c echo "# include " >> tea/generic/tclsqlite3.c echo "#else" >> tea/generic/tclsqlite3.c -echo "#include \"../../sqlite3.c\"" >> tea/generic/tclsqlite3.c +echo "#include \"sqlite3.c\"" >> tea/generic/tclsqlite3.c echo "#endif" >> tea/generic/tclsqlite3.c cat $TOP/src/tclsqlite.c >> tea/generic/tclsqlite3.c -cat tea/configure.in | +cat tea/configure.ac | sed "s/AC_INIT(\[sqlite\], .*)/AC_INIT([sqlite], [$VERSION])/" > tmp -mv tmp tea/configure.in +mv tmp tea/configure.ac cd tea autoconf @@ -80,4 +80,3 @@ tar -xzf sqlite-$VERSION.tar.gz mv sqlite-$VERSION sqlite-autoconf-$ARTIFACT tar -czf sqlite-autoconf-$ARTIFACT.tar.gz sqlite-autoconf-$ARTIFACT mv sqlite-autoconf-$ARTIFACT.tar.gz .. - diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index 28a1e46..21503d1 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -246,18 +246,29 @@ set pragma_def { NAME: schema_version TYPE: HEADER_VALUE + ARG: BTREE_SCHEMA_VERSION IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: user_version TYPE: HEADER_VALUE + ARG: BTREE_USER_VERSION + IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + + NAME: data_version + TYPE: HEADER_VALUE + ARG: BTREE_DATA_VERSION + FLAG: ReadOnly IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: freelist_count TYPE: HEADER_VALUE + ARG: BTREE_FREE_PAGE_COUNT + FLAG: ReadOnly IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: application_id TYPE: HEADER_VALUE + ARG: BTREE_APPLICATION_ID IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: compile_options @@ -294,6 +305,8 @@ set pragma_def { IF: defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) NAME: soft_heap_limit + + NAME: threads } fconfigure stdout -translation lf set name {} diff --git a/tool/mksqlite3c-noext.tcl b/tool/mksqlite3c-noext.tcl index ecb9cb0..2752226 100644 --- a/tool/mksqlite3c-noext.tcl +++ b/tool/mksqlite3c-noext.tcl @@ -96,6 +96,7 @@ foreach hdr { hash.h hwtime.h keywordhash.h + msvc.h mutex.h opcodes.h os_common.h @@ -239,6 +240,7 @@ foreach file { malloc.c printf.c random.c + threads.c utf.c util.c hash.c diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index 6420772..1d597a5 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -100,6 +100,7 @@ foreach hdr { hash.h hwtime.h keywordhash.h + msvc.h mutex.h opcodes.h os_common.h @@ -212,7 +213,7 @@ proc copy_file {filename} { } } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} { regsub {^SQLITE_EXTERN } $line {} line - puts $out "SQLITE_PRIVATE $line" + puts $out $line } elseif {[regexp {^void \(\*sqlite3Os} $line]} { puts $out "SQLITE_PRIVATE $line" } else { @@ -253,6 +254,7 @@ foreach file { malloc.c printf.c random.c + threads.c utf.c util.c hash.c diff --git a/tool/mksqlite3internalh.tcl b/tool/mksqlite3internalh.tcl index 7e92b3a..8db593f 100644 --- a/tool/mksqlite3internalh.tcl +++ b/tool/mksqlite3internalh.tcl @@ -58,6 +58,7 @@ foreach hdr { hash.h hwtime.h keywordhash.h + msvc.h opcodes.h os_common.h os_setup.h diff --git a/tool/showdb.c b/tool/showdb.c index 1a51e9d..82b8c9f 100644 --- a/tool/showdb.c +++ b/tool/showdb.c @@ -957,7 +957,7 @@ static void usage(const char *argv0){ " NNNbdCCC Decode cell CCC on btree page NNN\n" " NNNt Decode freelist trunk page NNN\n" " NNNtd Show leaf freelist pages on the decode\n" - " NNNtr Recurisvely decode freelist starting at NNN\n" + " NNNtr Recursively decode freelist starting at NNN\n" ); } diff --git a/tool/showstat4.c b/tool/showstat4.c index 668d210..2159629 100644 --- a/tool/showstat4.c +++ b/tool/showstat4.c @@ -39,6 +39,7 @@ int main(int argc, char **argv){ int nSample; i64 iVal; const char *zSep; + int iRow = 0; if( argc!=2 ){ fprintf(stderr, "Usage: %s DATABASE-FILE\n", argv[0]); @@ -60,13 +61,13 @@ int main(int argc, char **argv){ } while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( zIdx==0 || strcmp(zIdx, (const char*)sqlite3_column_text(pStmt,0))!=0 ){ - if( zIdx ) printf("\n"); + if( zIdx ) printf("\n**************************************" + "**************\n\n"); sqlite3_free(zIdx); zIdx = sqlite3_mprintf("%s", sqlite3_column_text(pStmt,0)); - printf("%s:\n", zIdx); - }else{ - printf(" -----------------------------------------------------------\n"); + iRow = 0; } + printf("%s sample %d ------------------------------------\n", zIdx, ++iRow); printf(" nEq = %s\n", sqlite3_column_text(pStmt,1)); printf(" nLt = %s\n", sqlite3_column_text(pStmt,2)); printf(" nDLt = %s\n", sqlite3_column_text(pStmt,3)); diff --git a/tool/showwal.c b/tool/showwal.c index 6dc1de1..35810c6 100644 --- a/tool/showwal.c +++ b/tool/showwal.c @@ -510,7 +510,7 @@ static void decode_btree_page( int main(int argc, char **argv){ struct stat sbuf; - unsigned char zPgSz[2]; + unsigned char zPgSz[4]; if( argc<2 ){ fprintf(stderr,"Usage: %s FILENAME ?PAGE? ...\n", argv[0]); exit(1); @@ -522,9 +522,9 @@ int main(int argc, char **argv){ } zPgSz[0] = 0; zPgSz[1] = 0; - lseek(fd, 10, SEEK_SET); - read(fd, zPgSz, 2); - pagesize = zPgSz[0]*256 + zPgSz[1]; + lseek(fd, 8, SEEK_SET); + read(fd, zPgSz, 4); + pagesize = zPgSz[1]*65536 + zPgSz[2]*256 + zPgSz[3]; if( pagesize==0 ) pagesize = 1024; printf("Pagesize: %d\n", pagesize); fstat(fd, &sbuf); diff --git a/tool/varint.c b/tool/varint.c new file mode 100644 index 0000000..f4a5111 --- /dev/null +++ b/tool/varint.c @@ -0,0 +1,123 @@ +/* +** A utility program to translate SQLite varints into decimal and decimal +** integers into varints. +*/ +#include +#include +#include + +#if defined(_MSC_VER) || defined(__BORLANDC__) + typedef __int64 i64; + typedef unsigned __int64 u64; +#else + typedef long long int i64; + typedef unsigned long long int u64; +#endif + +static int hexValue(char c){ + if( c>='0' && c<='9' ) return c - '0'; + if( c>='a' && c<='f' ) return c - 'a' + 10; + if( c>='A' && c<='F' ) return c - 'A' + 10; + return -1; +} + +static char toHex(unsigned char c){ + return "0123456789abcdef"[c&0xf]; +} + +static int putVarint(unsigned char *p, u64 v){ + int i, j, n; + unsigned char buf[10]; + if( v & (((u64)0xff000000)<<32) ){ + p[8] = (unsigned char)v; + v >>= 8; + for(i=7; i>=0; i--){ + p[i] = (unsigned char)((v & 0x7f) | 0x80); + v >>= 7; + } + return 9; + } + n = 0; + do{ + buf[n++] = (unsigned char)((v & 0x7f) | 0x80); + v >>= 7; + }while( v!=0 ); + buf[0] &= 0x7f; + for(i=0, j=n-1; j>=0; j--, i++){ + p[i] = buf[j]; + } + return n; +} + + +int main(int argc, char **argv){ + int i; + u64 x; + u64 uX = 0; + i64 iX; + int n; + unsigned char zHex[20]; + + if( argc==1 ){ + fprintf(stderr, + "Usage:\n" + " %s HH HH HH ... Convert varint to decimal\n" + " %s DDDDD Convert decimal to varint\n" + " Add '+' or '-' before DDDDD to disambiguate.\n", + argv[0], argv[0]); + exit(1); + } + if( argc>2 + || (strlen(argv[1])==2 && hexValue(argv[1][0])>=0 && hexValue(argv[1][1])>=0) + ){ + /* Hex to decimal */ + for(i=1; i'9' ){ + fprintf(stderr, "Not a decimal number: %s", argv[1]); + exit(1); + } + uX = uX*10 + z[0] - '0'; + z++; + } + if( sign<0 ){ + memcpy(&iX, &uX, 8); + iX = -iX; + memcpy(&uX, &iX, 8); + } + } + n = putVarint(zHex, uX); + printf("%lld =", (i64)uX); + for(i=0; i>4), toHex(zHex[i]&0x0f)); + } + printf("\n"); + return 0; +} diff --git a/tool/vdbe-compress.tcl b/tool/vdbe-compress.tcl index a349830..9477f4a 100644 --- a/tool/vdbe-compress.tcl +++ b/tool/vdbe-compress.tcl @@ -110,6 +110,11 @@ while {![eof stdin]} { foreach v $vlist { regsub -all "(\[^a-zA-Z0-9>.\])${v}(\\W)" $line "\\1u.$sname.$v\\2" line regsub -all "(\[^a-zA-Z0-9>.\])${v}(\\W)" $line "\\1u.$sname.$v\\2" line + + # The expressions above fail to catch instance of variable "abc" in + # expressions like (32>abc). The following expression makes those + # substitutions. + regsub -all "(\[^-\])>${v}(\\W)" $line "\\1>u.$sname.$v\\2" line } append afterUnion [string trimright $line]\n } elseif {$line=="" && [eof stdin]} { From eb94bb87474aa53e3ae82fb21a7baaf2846930c2 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 20 Mar 2015 10:03:51 -0500 Subject: [PATCH 22/59] set writeOnly to false when performing sqlite3BtreeRollback --- src/crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto.c b/src/crypto.c index 976e19d..c79e5c5 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -478,7 +478,7 @@ int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey) { sqlcipher_codec_key_copy(ctx, CIPHER_WRITE_CTX); } else { CODEC_TRACE(("sqlite3_rekey_v2: rollback\n")); - sqlite3BtreeRollback(pDb->pBt, SQLITE_ABORT_ROLLBACK); + sqlite3BtreeRollback(pDb->pBt, SQLITE_ABORT_ROLLBACK, 0); } sqlite3_mutex_leave(db->mutex); From e44ce2ccd5a31ed9e79bb252cce0fc00a2f2e480 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 20 Mar 2015 10:04:34 -0500 Subject: [PATCH 23/59] Only call FIPS_mode when compiled with SQLCIPHER_FIPS --- src/crypto_openssl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/crypto_openssl.c b/src/crypto_openssl.c index 7b82de0..66553a0 100644 --- a/src/crypto_openssl.c +++ b/src/crypto_openssl.c @@ -233,7 +233,11 @@ static int sqlcipher_openssl_ctx_free(void **ctx) { } static int sqlcipher_openssl_fips_status(void *ctx) { +#ifdef SQLCIPHER_FIPS return FIPS_mode(); +#else + return 0; +#endif } int sqlcipher_openssl_setup(sqlcipher_provider *p) { From f0cf4c5b252d12c84b9e10f771a1fbd6063449a9 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 20 Mar 2015 10:04:53 -0500 Subject: [PATCH 24/59] Rebuilt configure from autoconf --- configure | 181 +++++++++++------------------------------------------- 1 file changed, 35 insertions(+), 146 deletions(-) diff --git a/configure b/configure index 916ae02..ebb8e3a 100755 --- a/configure +++ b/configure @@ -1,6 +1,10 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.62 for sqlcipher 3.8.8.3. +# Generated by GNU Autoconf 2.69 for sqlcipher 3.8.8.3. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. @@ -763,116 +767,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL -PATH_SEPARATOR -PACKAGE_NAME -PACKAGE_TARNAME -PACKAGE_VERSION -PACKAGE_STRING -PACKAGE_BUGREPORT -exec_prefix -prefix -program_transform_name -bindir -sbindir -libexecdir -datarootdir -datadir -sysconfdir -sharedstatedir -localstatedir -includedir -oldincludedir -docdir -infodir -htmldir -dvidir -pdfdir -psdir -libdir -localedir -mandir -DEFS -ECHO_C -ECHO_N -ECHO_T -LIBS -build_alias -host_alias -target_alias -LIBTOOL -build -build_cpu -build_vendor -build_os -host -host_cpu -host_vendor -host_os -CC -CFLAGS -LDFLAGS -CPPFLAGS -ac_ct_CC -EXEEXT -OBJEXT -SED -GREP -EGREP -FGREP -LD -DUMPBIN -ac_ct_DUMPBIN -NM -LN_S -OBJDUMP -AR -STRIP -RANLIB -lt_ECHO -DSYMUTIL -NMEDIT -LIPO -OTOOL -OTOOL64 -CPP -INSTALL_PROGRAM -INSTALL_SCRIPT -INSTALL_DATA -AWK -TCLSH_CMD -TCLLIBDIR -program_prefix -VERSION -RELEASE -VERSION_NUMBER -BUILD_CC -SQLITE_THREADSAFE -ALLOWRELEASE -TEMP_STORE -BUILD_EXEEXT -SQLITE_OS_UNIX -SQLITE_OS_WIN -TARGET_EXEEXT -TCL_VERSION -TCL_BIN_DIR -TCL_SRC_DIR -TCL_INCLUDE_SPEC -TCL_LIB_FILE -TCL_LIB_FLAG -TCL_LIB_SPEC -TCL_STUB_LIB_FILE -TCL_STUB_LIB_FLAG -TCL_STUB_LIB_SPEC -HAVE_TCL -TARGET_READLINE_LIBS -TARGET_READLINE_INC -TARGET_HAVE_READLINE -TARGET_DEBUG -USE_AMALGAMATION -OPT_FEATURE_FLAGS -USE_GCOV -BUILD_CFLAGS +ac_subst_vars='LTLIBOBJS LIBOBJS BUILD_CFLAGS USE_GCOV @@ -1641,6 +1536,8 @@ Optional Features: --disable-libtool-lock avoid locking (might break parallel builds) --disable-largefile omit support for large files --disable-threadsafe Disable mutexing + --enable-cross-thread-connections + Allow connection sharing across threads --enable-releasemode Support libtool link to release mode --enable-tempstore Use an in-ram database for temporary tables (never,no,yes,always) @@ -1659,7 +1556,6 @@ Optional Packages: --with-pic try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] - --with-hints=FILE Read configuration options from FILE --with-crypto-lib Specify which crypto library to use --with-tcl=DIR directory containing tcl configuration (tclConfig.sh) @@ -1744,7 +1640,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF sqlcipher configure 3.8.8.3 -generated by GNU Autoconf 2.62 +generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation @@ -1753,6 +1649,10 @@ _ACEOF exit fi +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. @@ -2158,7 +2058,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 sqlcipher $as_me 3.8.4.3, which was +It was created by sqlcipher $as_me 3.8.8.3, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4016,13 +3916,13 @@ if ${lt_cv_nm_interface+:} false; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:3727: $ac_compile\"" >&5) + (eval echo "\"\$as_me:3919: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:3730: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:3922: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:3733: output\"" >&5) + (eval echo "\"\$as_me:3925: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -5228,8 +5128,8 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 4955 "configure"' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + echo '#line 5131 "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 @@ -6753,11 +6653,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6824: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6656: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6828: \$? = $ac_status" >&5 + echo "$as_me:6660: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7092,11 +6992,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7163: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6995: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7167: \$? = $ac_status" >&5 + echo "$as_me:6999: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7197,11 +7097,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7268: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7100: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7272: \$? = $ac_status" >&5 + echo "$as_me:7104: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -7252,11 +7152,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7323: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7155: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7327: \$? = $ac_status" >&5 + echo "$as_me:7159: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -9632,7 +9532,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10136 "configure" +#line 9535 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -9728,7 +9628,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10232 "configure" +#line 9631 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10372,18 +10272,8 @@ fi ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "$ac_includes_default" if test "x$ac_cv_type_uint64_t" = xyes; then : - - -for ac_func in fdatasync gmtime_r isnan localtime_r localtime_s malloc_usable_size strchrnul usleep utime -do -as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 -$as_echo_n "checking for $ac_func... " >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then - $as_echo_n "(cached) " >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ +cat >>confdefs.h <<_ACEOF +#define HAVE_UINT64_T 1 _ACEOF @@ -10418,7 +10308,7 @@ done ######### # Figure out whether or not we have these functions # -for ac_func in usleep fdatasync localtime_r gmtime_r localtime_s utime malloc_usable_size +for ac_func in fdatasync gmtime_r isnan localtime_r localtime_s malloc_usable_size strchrnul usleep utime do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -10527,7 +10417,6 @@ $as_echo "$as_me: Version number set to $VERSION_NUMBER" >&6;} ######### - # Locate a compiler for the build machine. This compiler should # generate command-line programs that run on the build machine. # @@ -12063,7 +11952,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by sqlcipher $as_me 3.8.8.3, which was -generated by GNU Autoconf 2.62. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -12129,8 +12018,8 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ sqlcipher config.status 3.8.8.3 -configured by $0, generated by GNU Autoconf 2.62, - with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation From 88be2c676d766f990ae40db971c1b561bc8f6664 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 20 Mar 2015 10:22:46 -0500 Subject: [PATCH 25/59] Bump cipher version to 3.3.0 --- src/crypto.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypto.h b/src/crypto.h index 0ce3737..a614ede 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -45,9 +45,9 @@ #ifndef CIPHER_VERSION #ifdef SQLCIPHER_FIPS -#define CIPHER_VERSION "3.2.0 FIPS" +#define CIPHER_VERSION "3.3.0 FIPS" #else -#define CIPHER_VERSION "3.2.0" +#define CIPHER_VERSION "3.3.0" #endif #endif From 4677f474b166bff33c843a265afc2b8e7862e55b Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 20 Mar 2015 10:49:35 -0500 Subject: [PATCH 26/59] Bump cipher_version value in test --- test/crypto.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/crypto.test b/test/crypto.test index 7d6d5a5..a55b474 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -1541,7 +1541,7 @@ do_test verify-pragma-cipher-version { execsql { PRAGMA cipher_version; } -} {3.2.0} +} {3.3.0} db close file delete -force test.db From fafb0d05bdae394037ac495fe7261573f5f675eb Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Wed, 25 Mar 2015 14:47:02 -0500 Subject: [PATCH 27/59] Update change log --- CHANGELOG.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2156daa..43d6fdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. ## [Unreleased][unreleased] +## [3.3.0] - 2015-03-25 +### Added +- Added FIPS API calls within the OpenSSL crpyto provider +- `PRAGMA cipher_default_page_size` - support for attaching non-default page sizes + +### Changed +- Merged upstream SQLite 3.8.8.3 + ## [3.2.0] - 2014-09-30 ### Added - Added PRAGMA cipher_store_pass @@ -13,22 +21,22 @@ All notable changes to this project will be documented in this file. ## [3.1.0] - 2014-04-23 ### Added -- Added PRAGMA cipher_profile +- Added `PRAGMA cipher_profile` ### Changed - Merged upstream SQLite 3.8.4.3 ## [3.0.1] - 2013-12-06 ### Added -- Add PRAGMA cipher_add_random to source external entropy +- Add `PRAGMA cipher_add_random` to source external entropy ### Changed -- Fix cipher_migrate to handle passphrases longer than 64 characters & raw keys +- Fix `PRAGMA cipher_migrate` to handle passphrases longer than 64 characters & raw keys - Improvements to the libtomcrypt provider ## [3.0.0] - 2013-11-05 ### Added -- Added PRAGMA cipher_migrate to migrate older database file formats +- Added `PRAGMA cipher_migrate` to migrate older database file formats ### Changed - Merged upstream SQLite 3.8.0.2 @@ -41,7 +49,8 @@ All notable changes to this project will be documented in this file. ### Security - Change KDF iteration length from 4,000 to 64,000 -[unreleased]: https://github.com/sqlcipher/sqlcipher/compare/v3.2.0...prerelease +[unreleased]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.0...prerelease +[3.3.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.2.0...v3.3.0 [3.2.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.1.0...v3.2.0 [3.1.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.1...v3.1.0 [3.0.1]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.0...v3.0.1 From 388970a669f244c771d9ebe24f976ad91a6ce7c8 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Wed, 25 Mar 2015 14:53:22 -0500 Subject: [PATCH 28/59] Fix spelling --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43d6fdb..c67f1fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. ## [3.3.0] - 2015-03-25 ### Added -- Added FIPS API calls within the OpenSSL crpyto provider +- Added FIPS API calls within the OpenSSL crypto provider - `PRAGMA cipher_default_page_size` - support for attaching non-default page sizes ### Changed From c14afcf742ac1e3b439e4939ae39f6003e272083 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Thu, 16 Apr 2015 08:55:44 -0500 Subject: [PATCH 29/59] Prevent segfault when invalid cipher name provided, identified by Nicholas Starke --- src/crypto_openssl.c | 7 +++++-- test/crypto.test | 12 ++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/crypto_openssl.c b/src/crypto_openssl.c index 66553a0..eaa2a17 100644 --- a/src/crypto_openssl.c +++ b/src/crypto_openssl.c @@ -186,8 +186,11 @@ static int sqlcipher_openssl_cipher(void *ctx, int mode, unsigned char *key, int static int sqlcipher_openssl_set_cipher(void *ctx, const char *cipher_name) { openssl_ctx *o_ctx = (openssl_ctx *)ctx; - o_ctx->evp_cipher = (EVP_CIPHER *) EVP_get_cipherbyname(cipher_name); - return SQLITE_OK; + EVP_CIPHER* cipher = (EVP_CIPHER *) EVP_get_cipherbyname(cipher_name); + if(cipher != NULL) { + o_ctx->evp_cipher = cipher; + } + return cipher != NULL ? SQLITE_OK : SQLITE_ERROR; } static const char* sqlcipher_openssl_get_cipher(void *ctx) { diff --git a/test/crypto.test b/test/crypto.test index a55b474..b7cbf7b 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -1922,6 +1922,18 @@ do_test verify-pragma-cipher-page-size-changed { db close file delete -force test.db +# verify invalid cipher does not cause segfault +if_built_with_openssl verify-invalid-cipher-does_not_segfault { + sqlite_orig db test.db + execsql { + PRAGMA key = 'test'; + PRAGMA cipher = 'junk'; + PRAGMA cipher; + } +} {AES-256-CBC} +db close +file delete -force test.db + # verify the pragma cipher # reports the default value if_built_with_openssl verify-pragma-cipher-default { From e26aa0db094c0c48978a93ccfff92786e9b7dfac Mon Sep 17 00:00:00 2001 From: Jan Berkel Date: Sat, 18 Apr 2015 22:43:52 +0100 Subject: [PATCH 30/59] Fix amalgamation output paths sqlite3.c gets generated as a result of this script --- sqlcipher.xcodeproj/project.pbxproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sqlcipher.xcodeproj/project.pbxproj b/sqlcipher.xcodeproj/project.pbxproj index 5c66f77..a3459bc 100644 --- a/sqlcipher.xcodeproj/project.pbxproj +++ b/sqlcipher.xcodeproj/project.pbxproj @@ -153,10 +153,9 @@ files = ( ); inputPaths = ( - "$(SRCROOT)/sqlite3.c", ); outputPaths = ( - "$(BUILT_PRODUCTS_DIR)/libsqlcipher.a", + "$(SRCROOT)/sqlite3.c", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; From 18f95ebbea977b6be7dd714044205843cbfe3346 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Tue, 21 Apr 2015 14:06:30 -0500 Subject: [PATCH 31/59] Check for valid context before using cipher_store_pass Identified by Nicholas Starke --- src/crypto.c | 12 ++++++++---- test/crypto.test | 14 +++++++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index c79e5c5..79451ae 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -97,12 +97,16 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef } } else if( sqlite3StrICmp(zLeft, "cipher_store_pass")==0 && zRight ) { - sqlcipher_codec_set_store_pass(ctx, sqlite3GetBoolean(zRight, 1)); + if(ctx) { + sqlcipher_codec_set_store_pass(ctx, sqlite3GetBoolean(zRight, 1)); + } } else if( sqlite3StrICmp(zLeft, "cipher_store_pass")==0 && !zRight ) { - char *store_pass_value = sqlite3_mprintf("%d", sqlcipher_codec_get_store_pass(ctx)); - codec_vdbe_return_static_string(pParse, "cipher_store_pass", store_pass_value); - sqlite3_free(store_pass_value); + if(ctx){ + char *store_pass_value = sqlite3_mprintf("%d", sqlcipher_codec_get_store_pass(ctx)); + codec_vdbe_return_static_string(pParse, "cipher_store_pass", store_pass_value); + sqlite3_free(store_pass_value); + } } if( sqlite3StrICmp(zLeft, "cipher_profile")== 0 && zRight ){ char *profile_status = sqlite3_mprintf("%d", sqlcipher_cipher_profile(db, zRight)); diff --git a/test/crypto.test b/test/crypto.test index b7cbf7b..84f8d57 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -1923,7 +1923,7 @@ db close file delete -force test.db # verify invalid cipher does not cause segfault -if_built_with_openssl verify-invalid-cipher-does_not_segfault { +if_built_with_openssl verify-invalid-cipher-does-not-segfault { sqlite_orig db test.db execsql { PRAGMA key = 'test'; @@ -1934,6 +1934,18 @@ if_built_with_openssl verify-invalid-cipher-does_not_segfault { db close file delete -force test.db +# verify setting cipher_store_pass before key +# does not cause segfault +do_test verify-cipher-store-pass-before-key-does-not-segfault { + sqlite_orig db test.db + execsql { + PRAGMA cipher_store_pass = 1; + PRAGMA key = 'test'; + } +} {} +db close +file delete -force test.db + # verify the pragma cipher # reports the default value if_built_with_openssl verify-pragma-cipher-default { From 4eeb4a0dc1fc03152866de50946d7fba97d45820 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Thu, 28 May 2015 11:41:52 -0500 Subject: [PATCH 32/59] Add contributions section to README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ab571b0..d30a16e 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ an iPhone data vault and password manager (http://getstrip.com). - Algorithms provided by the peer reviewed OpenSSL crypto library. - Configurable crypto providers +## Contributions + +We welcome contributions, to contribute to SQLCipher, a [contributor agreement](https://www.zetetic.net/contributions/) needs to be submitted. All submissions should be based on the =prerelease= branch. + ## Compiling Building SQLCipher is almost the same as compiling a regular version of From def3373d6f538059befdf2b1e43b777937dde258 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Thu, 28 May 2015 11:42:42 -0500 Subject: [PATCH 33/59] Fix format in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d30a16e..fc4547f 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ an iPhone data vault and password manager (http://getstrip.com). ## Contributions -We welcome contributions, to contribute to SQLCipher, a [contributor agreement](https://www.zetetic.net/contributions/) needs to be submitted. All submissions should be based on the =prerelease= branch. +We welcome contributions, to contribute to SQLCipher, a [contributor agreement](https://www.zetetic.net/contributions/) needs to be submitted. All submissions should be based on the `prerelease` branch. ## Compiling From 6e87d2db26fe48f77d0213df2d79dd7ed6648910 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Thu, 28 May 2015 11:41:52 -0500 Subject: [PATCH 34/59] Add contributions section to README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ab571b0..d30a16e 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ an iPhone data vault and password manager (http://getstrip.com). - Algorithms provided by the peer reviewed OpenSSL crypto library. - Configurable crypto providers +## Contributions + +We welcome contributions, to contribute to SQLCipher, a [contributor agreement](https://www.zetetic.net/contributions/) needs to be submitted. All submissions should be based on the =prerelease= branch. + ## Compiling Building SQLCipher is almost the same as compiling a regular version of From b5443984768236ea077fa2cf32c377dfef017e92 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Thu, 28 May 2015 11:42:42 -0500 Subject: [PATCH 35/59] Fix format in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d30a16e..fc4547f 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ an iPhone data vault and password manager (http://getstrip.com). ## Contributions -We welcome contributions, to contribute to SQLCipher, a [contributor agreement](https://www.zetetic.net/contributions/) needs to be submitted. All submissions should be based on the =prerelease= branch. +We welcome contributions, to contribute to SQLCipher, a [contributor agreement](https://www.zetetic.net/contributions/) needs to be submitted. All submissions should be based on the `prerelease` branch. ## Compiling From e451540b9c18faad0dfd6a3e708c274963483993 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Wed, 17 Jun 2015 11:57:00 -0500 Subject: [PATCH 36/59] Remove null check, assignment always occurs --- src/crypto_impl.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 8c891d5..12fefb8 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -1158,11 +1158,9 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { db->nTotalChange = saved_nTotalChange; db->xTrace = saved_xTrace; db->autoCommit = 1; - if( pDb ){ - sqlite3BtreeClose(pDb->pBt); - pDb->pBt = 0; - pDb->pSchema = 0; - } + sqlite3BtreeClose(pDb->pBt); + pDb->pBt = 0; + pDb->pSchema = 0; sqlite3ResetAllSchemasOfConnection(db); remove(migrated_db_filename); sqlite3_free(migrated_db_filename); From 724d1aac992d6d1af0992d703f00e0f3486dbfe9 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 10 Jul 2015 14:14:29 -0500 Subject: [PATCH 37/59] Snapshot of upstream SQLite 3.8.10.2 --- Makefile.in | 65 +- Makefile.msc | 561 ++- VERSION | 2 +- autoconf/Makefile.am | 3 +- configure | 6679 +++++++++++---------------------- configure.ac | 1 + ext/fts3/fts3.c | 171 +- ext/fts3/fts3Int.h | 6 + ext/fts3/fts3_aux.c | 2 +- ext/fts3/fts3_expr.c | 4 +- ext/fts3/fts3_snippet.c | 67 +- ext/fts3/fts3_term.c | 2 +- ext/fts3/fts3_tokenize_vtab.c | 2 +- ext/fts3/fts3_tokenizer.c | 20 +- ext/fts3/fts3_write.c | 18 +- ext/fts3/tool/fts3view.c | 4 +- ext/misc/amatch.c | 28 +- ext/misc/compress.c | 11 +- ext/misc/fuzzer.c | 2 +- ext/rtree/rtree.c | 16 +- ext/rtree/rtree9.test | 1 - main.mk | 56 +- manifest | 459 +-- manifest.uuid | 2 +- mkopcodeh.awk | 27 +- mptest/crash01.test | 4 + mptest/mptest.c | 56 +- mptest/multiwrite01.test | 10 + src/alter.c | 6 +- src/analyze.c | 15 +- src/attach.c | 5 +- src/backup.c | 2 +- src/bitvec.c | 2 +- src/btmutex.c | 1 + src/btree.c | 197 +- src/btree.h | 19 +- src/btreeInt.h | 4 + src/build.c | 42 +- src/complete.c | 2 +- src/ctime.c | 3 + src/{test_stat.c => dbstat.c} | 223 +- src/delete.c | 2 +- src/expr.c | 89 +- src/fkey.c | 28 +- src/func.c | 30 +- src/global.c | 10 +- src/insert.c | 84 +- src/loadext.c | 20 +- src/main.c | 124 +- src/malloc.c | 54 +- src/msvc.h | 1 + src/mutex_noop.c | 17 +- src/mutex_unix.c | 31 +- src/mutex_w32.c | 19 +- src/os_common.h | 10 - src/os_unix.c | 375 +- src/os_win.c | 164 +- src/os_win.h | 11 + src/pager.c | 6 +- src/parse.y | 70 +- src/pcache.c | 10 +- src/pcache1.c | 19 +- src/pragma.c | 569 +-- src/pragma.h | 459 +++ src/prepare.c | 6 +- src/printf.c | 106 +- src/resolve.c | 86 +- src/select.c | 99 +- src/shell.c | 496 ++- src/sqlite.h.in | 247 +- src/sqliteInt.h | 143 +- src/sqliteLimit.h | 12 +- src/status.c | 94 +- src/table.c | 6 +- src/tclsqlite.c | 101 +- src/test1.c | 60 +- src/test3.c | 15 +- src/test4.c | 2 +- src/test7.c | 2 +- src/test8.c | 4 +- src/test_backup.c | 2 +- src/test_blob.c | 5 +- src/test_config.c | 1 - src/test_demovfs.c | 2 +- src/test_func.c | 17 +- src/test_intarray.c | 8 +- src/test_malloc.c | 10 +- src/test_multiplex.c | 40 +- src/test_onefile.c | 6 +- src/test_osinst.c | 3 - src/test_rtree.c | 2 +- src/test_sqllog.c | 6 +- src/test_superlock.c | 2 +- src/test_thread.c | 2 +- src/test_vfs.c | 21 +- src/threads.c | 4 +- src/tokenize.c | 22 +- src/trigger.c | 20 +- src/util.c | 1 + src/vacuum.c | 6 +- src/vdbe.c | 543 +-- src/vdbe.h | 1 + src/vdbeInt.h | 12 +- src/vdbeapi.c | 46 +- src/vdbeaux.c | 48 +- src/vdbeblob.c | 11 +- src/vdbemem.c | 130 +- src/vdbesort.c | 399 +- src/vdbetrace.c | 9 +- src/vtab.c | 72 +- src/vxworks.h | 29 + src/wal.c | 33 +- src/where.c | 503 ++- src/whereInt.h | 7 +- test/alter.test | 9 + test/analyze.test | 2 +- test/analyze3.test | 54 +- test/analyze9.test | 112 + test/analyzeF.test | 127 + test/attach.test | 12 + test/autoindex1.test | 10 + test/btree02.test | 52 + test/capi3.test | 14 +- test/collate1.test | 72 +- test/collate3.test | 7 +- test/collate8.test | 34 +- test/corruptC.test | 2 +- test/corruptJ.test | 80 + test/count.test | 5 + test/crashM.test | 80 + test/e_insert.test | 6 +- test/e_reindex.test | 8 +- test/e_wal.test | 9 +- test/e_walauto.test | 8 + test/expr.test | 8 + test/fkey1.test | 30 + test/fkey2.test | 23 +- test/fkey5.test | 29 +- test/fts3aa.test | 22 + test/fts3atoken.test | 24 +- test/fts3expr5.test | 48 + test/fts3fault2.test | 19 + test/fts3matchinfo.test | 63 + test/fts3prefix.test | 82 + test/fts3query.test | 76 + test/fts3snippet.test | 38 + test/fts3tok1.test | 10 + test/fts4check.test | 30 + test/fts4content.test | 18 +- test/fuzz2.test | 10 + test/fuzzdata1.txt | Bin 0 -> 2966109 bytes test/fuzzdata2.txt | Bin 0 -> 15739506 bytes test/hexlit.test | 5 + test/imposter1.test | 141 + test/in.test | 6 + test/incrblob2.test | 32 + test/incrcorrupt.test | 127 + test/incrvacuum2.test | 4 +- test/index3.test | 2 +- test/index6.test | 31 + test/index7.test | 38 + test/indexedby.test | 49 +- test/insert2.test | 20 + test/insert4.test | 5 + test/jrnlmode.test | 14 + test/like.test | 4 +- test/like3.test | 112 + test/limit.test | 6 + test/lock.test | 3 + test/lock_common.tcl | 58 +- test/malloc.test | 21 + test/malloc5.test | 29 +- test/mallocK.test | 37 + test/misc1.test | 65 +- test/misc5.test | 18 + test/mkfuzzdata1.tcl | 113 + test/multiplex4.test | 18 + test/null.test | 17 + test/orderby1.test | 32 + test/pagesize.test | 18 + test/pragma.test | 203 +- test/pragma2.test | 4 + test/printf.test | 27 + test/printf2.test | 3 + test/rdonly.test | 5 + test/releasetest.tcl | 98 +- test/resolver01.test | 10 +- test/select1.test | 8 + test/select4.test | 50 + test/select6.test | 56 + test/selectA.test | 60 + test/selectE.test | 5 + test/shell1.test | 115 +- test/shell4.test | 24 +- test/shell5.test | 30 + test/shrink.test | 3 + test/softheap1.test | 8 + test/sort4.test | 15 +- test/speedtest1.c | 2 +- test/sqllimits1.test | 26 + test/stat.test | 10 +- test/statfault.test | 45 + test/subquery.test | 10 + test/table.test | 19 + test/tclsqlite.test | 2 +- test/tester.tcl | 33 + test/trace2.test | 2 +- test/trigger1.test | 16 + test/trigger7.test | 2 +- test/triggerC.test | 49 + test/vacuum2.test | 20 + test/vtab1.test | 91 + test/vtab2.test | 22 +- test/vtabA.test | 23 +- test/wal5.test | 14 +- test/walblock.test | 114 + test/where8.test | 4 +- test/whereD.test | 14 +- test/whereK.test | 72 + test/win32lock.test | 2 + test/with1.test | 21 + test/without_rowid6.test | 76 + test/zeroblob.test | 9 + tool/build-all-msvc.bat | 224 +- tool/fuzzershell.c | 846 +++++ tool/lemon.c | 78 +- tool/mkpragmatab.tcl | 67 +- tool/mksqlite3c-noext.tcl | 94 +- tool/mksqlite3c.tcl | 96 +- tool/mksqlite3h.tcl | 45 +- tool/mkvsix.tcl | 52 +- tool/showdb.c | 8 +- tool/showlocks.c | 64 + tool/spaceanal.tcl | 35 +- tool/sqldiff.c | 1242 ++++++ 235 files changed, 13690 insertions(+), 7345 deletions(-) rename src/{test_stat.c => dbstat.c} (81%) create mode 100644 src/pragma.h create mode 100644 src/vxworks.h create mode 100644 test/analyzeF.test create mode 100644 test/btree02.test create mode 100644 test/corruptJ.test create mode 100644 test/crashM.test create mode 100644 test/fts3expr5.test create mode 100644 test/fuzzdata1.txt create mode 100644 test/fuzzdata2.txt create mode 100644 test/imposter1.test create mode 100644 test/incrcorrupt.test create mode 100644 test/like3.test create mode 100644 test/mkfuzzdata1.tcl create mode 100644 test/statfault.test create mode 100644 test/walblock.test create mode 100644 test/whereK.test create mode 100644 tool/fuzzershell.c create mode 100644 tool/showlocks.c create mode 100644 tool/sqldiff.c diff --git a/Makefile.in b/Makefile.in index 3d6e0f2..0591150 100644 --- a/Makefile.in +++ b/Makefile.in @@ -167,7 +167,7 @@ USE_AMALGAMATION = @USE_AMALGAMATION@ # LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \ backup.lo bitvec.lo btmutex.lo btree.lo build.lo \ - callback.lo complete.lo ctime.lo date.lo delete.lo \ + callback.lo complete.lo ctime.lo date.lo dbstat.lo delete.lo \ expr.lo fault.lo fkey.lo \ fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \ fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \ @@ -213,6 +213,7 @@ SRC = \ $(TOP)/src/complete.c \ $(TOP)/src/ctime.c \ $(TOP)/src/date.c \ + $(TOP)/src/dbstat.c \ $(TOP)/src/delete.c \ $(TOP)/src/expr.c \ $(TOP)/src/fault.c \ @@ -255,6 +256,7 @@ SRC = \ $(TOP)/src/pcache.h \ $(TOP)/src/pcache1.c \ $(TOP)/src/pragma.c \ + $(TOP)/src/pragma.h \ $(TOP)/src/prepare.c \ $(TOP)/src/printf.c \ $(TOP)/src/random.c \ @@ -286,6 +288,7 @@ SRC = \ $(TOP)/src/vdbetrace.c \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/vtab.c \ + $(TOP)/src/vxworks.h \ $(TOP)/src/wal.c \ $(TOP)/src/wal.h \ $(TOP)/src/walker.c \ @@ -387,7 +390,6 @@ TESTSRC = \ $(TOP)/src/test_server.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ - $(TOP)/src/test_stat.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vfs.c \ @@ -421,6 +423,7 @@ TESTSRC2 = \ $(TOP)/src/build.c \ $(TOP)/src/ctime.c \ $(TOP)/src/date.c \ + $(TOP)/src/dbstat.c \ $(TOP)/src/expr.c \ $(TOP)/src/func.c \ $(TOP)/src/insert.c \ @@ -474,12 +477,14 @@ HDR = \ $(TOP)/src/pager.h \ $(TOP)/src/pcache.h \ parse.h \ + $(TOP)/src/pragma.h \ sqlite3.h \ $(TOP)/src/sqlite3ext.h \ $(TOP)/src/sqliteInt.h \ $(TOP)/src/sqliteLimit.h \ $(TOP)/src/vdbe.h \ $(TOP)/src/vdbeInt.h \ + $(TOP)/src/vxworks.h \ $(TOP)/src/whereInt.h \ config.h @@ -532,15 +537,29 @@ sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h -o $@ $(TOP)/src/shell.c libsqlite3.la \ $(LIBREADLINE) $(TLIBS) -rpath "$(libdir)" -mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c +sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h + $(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) + +fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h + $(LTLINK) -o $@ $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS) + +mptester$(TEXE): sqlite3.c $(TOP)/mptest/mptest.c $(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \ $(TLIBS) -rpath "$(libdir)" -mptest: mptester$(EXE) - rm -f mptest1.db - ./mptester$(EXE) mptest1.db $(TOP)/mptest/crash01.test - rm -f mptest2.db - ./mptester$(EXE) mptest2.db $(TOP)/mptest/multiwrite01.test +MPTEST1=./mptester$(TEXE) mptest.db $(TOP)/mptest/crash01.test --repeat 20 +MPTEST2=./mptester$(TEXE) mptest.db $(TOP)/mptest/multiwrite01.test --repeat 20 +mptest: mptester$(TEXE) + rm -f mptest.db + $(MPTEST1) --journalmode DELETE + $(MPTEST2) --journalmode WAL + $(MPTEST1) --journalmode WAL + $(MPTEST2) --journalmode PERSIST + $(MPTEST1) --journalmode PERSIST + $(MPTEST2) --journalmode TRUNCATE + $(MPTEST1) --journalmode TRUNCATE + $(MPTEST2) --journalmode DELETE + # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to @@ -634,6 +653,9 @@ ctime.lo: $(TOP)/src/ctime.c $(HDR) date.lo: $(TOP)/src/date.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/date.c +dbstat.lo: $(TOP)/src/dbstat.c $(HDR) + $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/dbstat.c + delete.lo: $(TOP)/src/delete.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/delete.c @@ -933,39 +955,48 @@ testfixture$(TEXE): $(TESTFIXTURE_SRC) -o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS) # A very detailed test running most or all test cases -fulltest: testfixture$(TEXE) sqlite3$(TEXE) +fulltest: testfixture$(TEXE) sqlite3$(TEXE) fuzztest ./testfixture$(TEXE) $(TOP)/test/all.test # Really really long testing -soaktest: testfixture$(TEXE) sqlite3$(TEXE) +soaktest: testfixture$(TEXE) sqlite3$(TEXE) fuzzoomtest ./testfixture$(TEXE) $(TOP)/test/all.test -soak=1 # Do extra testing but not aeverything. fulltestonly: testfixture$(TEXE) sqlite3$(TEXE) ./testfixture$(TEXE) $(TOP)/test/full.test +# Fuzz testing +fuzztest: fuzzershell$(TEXE) + ./fuzzershell$(TEXE) $(TOP)/test/fuzzdata1.txt $(TOP)/test/fuzzdata2.txt + +fuzzoomtest: fuzzershell$(TEXE) + ./fuzzershell$(TEXE) -f $(TOP)/test/fuzzdata1.txt --oom + # This is the common case. Run many tests but not those that take # a really long time. # -test: testfixture$(TEXE) sqlite3$(TEXE) +test: testfixture$(TEXE) sqlite3$(TEXE) fuzztest ./testfixture$(TEXE) $(TOP)/test/veryquick.test # Run a test using valgrind. This can take a really long time # because valgrind is so much slower than a native machine. # -valgrindtest: testfixture$(TEXE) sqlite3$(TEXE) +valgrindtest: testfixture$(TEXE) sqlite3$(TEXE) fuzzershell$(TEXE) + valgrind -v ./fuzzershell$(TEXE) -f $(TOP)/test/fuzzdata1.txt OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind # A very fast test that checks basic sanity. The name comes from # the 60s-era electronics testing: "Turn it on and see if smoke # comes out." # -smoketest: testfixture$(TEXE) +smoketest: testfixture$(TEXE) fuzzershell$(TEXE) ./testfixture$(TEXE) $(TOP)/test/main.test -sqlite3_analyzer.c: sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl +sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl echo "#define TCLSH 2" > $@ - cat sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c >> $@ + echo "#define SQLITE_ENABLE_DBSTAT_VTAB" >> $@ + cat sqlite3.c $(TOP)/src/tclsqlite.c >> $@ echo "static const char *tclsh_main_loop(void){" >> $@ echo "static const char *zMainloop = " >> $@ $(NAWK) -f $(TOP)/tool/tostr.awk $(TOP)/tool/spaceanal.tcl >> $@ @@ -995,7 +1026,7 @@ LogEst$(TEXE): $(TOP)/tool/logest.c sqlite3.h wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.c $(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.c $(TLIBS) -speedtest1$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo +speedtest1$(TEXE): $(TOP)/test/speedtest1.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/test/speedtest1.c sqlite3.lo $(TLIBS) # This target will fail if the SQLite amalgamation contains any exported @@ -1047,7 +1078,7 @@ install: sqlite3$(BEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_instal $(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(pkgconfigdir) pkgIndex.tcl: - echo 'package ifneeded sqlite3 $(RELEASE) [list load $(TCLLIBDIR)/libtclsqlite3.so sqlite3]' > $@ + echo 'package ifneeded sqlite3 $(RELEASE) [list load $(TCLLIBDIR)/libtclsqlite3$(SHLIB_SUFFIX) sqlite3]' > $@ tcl_install: lib_install libtclsqlite3.la pkgIndex.tcl $(INSTALL) -d $(DESTDIR)$(TCLLIBDIR) $(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR) diff --git a/Makefile.msc b/Makefile.msc index 4ebe9fd..df39851 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -22,14 +22,28 @@ USE_AMALGAMATION = 1 USE_FULLWARN = 0 !ENDIF +# Set this non-0 to use "stdcall" calling convention for the core library +# and shell executable. +# +!IFNDEF USE_STDCALL +USE_STDCALL = 0 +!ENDIF + +# Set this non-0 to have the shell executable link against the core dynamic +# link library. +# +!IFNDEF DYNAMIC_SHELL +DYNAMIC_SHELL = 0 +!ENDIF + # If necessary, create a list of harmless compiler warnings to disable when -# compiling the build tools. For the SQLite source code itself, warnings, +# compiling the various tools. For the SQLite source code itself, warnings, # if any, will be disabled from within it. # !IFNDEF NO_WARN !IF $(USE_FULLWARN)!=0 -NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4152 -wd4189 -wd4206 -wd4210 -NO_WARN = $(NO_WARN) -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706 +NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206 +NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706 !ENDIF !ENDIF @@ -59,6 +73,12 @@ USE_ICU = 0 USE_CRT_DLL = 0 !ENDIF +# Set this non-0 to link to the RPCRT4 library. +# +!IFNDEF USE_RPCRT4_LIB +USE_RPCRT4_LIB = 0 +!ENDIF + # Set this non-0 to generate assembly code listings for the source code # files. # @@ -95,6 +115,14 @@ USE_RC = 1 FOR_WINRT = 0 !ENDIF +# Set this non-0 to compile binaries suitable for the UAP environment. +# This setting does not apply to any binaries that require Tcl to operate +# properly (i.e. the text fixture, etc). +# +!IFNDEF FOR_UAP +FOR_UAP = 0 +!ENDIF + # Set this non-0 to skip attempting to look for and/or link with the Tcl # runtime library. # @@ -120,6 +148,13 @@ MEMDEBUG = 0 WIN32HEAP = 0 !ENDIF +# Set this to non-0 to enable OSTRACE() macros, which can be useful when +# debugging. +# +!IFNDEF OSTRACE +OSTRACE = 0 +!ENDIF + # Set this to one of the following values to enable various debugging # features. Each level includes the debugging options from the previous # levels. Currently, the recognized values for DEBUG are: @@ -250,9 +285,9 @@ NSDKLIBPATH = $(NSDKLIBPATH:\\=\) # will run on the platform that is doing the build. # !IF $(USE_FULLWARN)!=0 -BCC = $(NCC) -W4 +BCC = $(NCC) -nologo -W4 !ELSE -BCC = $(NCC) -W3 +BCC = $(NCC) -nologo -W3 !ENDIF # Check if assembly code listings should be generated for the source @@ -268,6 +303,11 @@ BCC = $(BCC) -FAcs # !IF $(USE_NATIVE_LIBPATHS)!=0 NLTLIBPATHS = "/LIBPATH:$(NCRTLIBPATH)" "/LIBPATH:$(NSDKLIBPATH)" + +!IFDEF NUCRTLIBPATH +NUCRTLIBPATH = $(NUCRTLIBPATH:\\=\) +NLTLIBPATHS = $(NLTLIBPATHS) "/LIBPATH:$(NUCRTLIBPATH)" +!ENDIF !ENDIF # C compiler and options for use in building executables that @@ -275,14 +315,106 @@ NLTLIBPATHS = "/LIBPATH:$(NCRTLIBPATH)" "/LIBPATH:$(NSDKLIBPATH)" # same unless your are cross-compiling.) # !IF $(USE_FULLWARN)!=0 -TCC = $(CC) -W4 -DINCLUDE_MSVC_H=1 +TCC = $(CC) -nologo -W4 -DINCLUDE_MSVC_H=1 !ELSE -TCC = $(CC) -W3 +TCC = $(CC) -nologo -W3 !ENDIF TCC = $(TCC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src -fp:precise RCC = $(RC) -DSQLITE_OS_WIN=1 -I$(TOP) -I$(TOP)\src +# Check if we want to use the "stdcall" calling convention when compiling. +# This is not supported by the compilers for non-x86 platforms. It should +# also be noted here that building any target with these "stdcall" options +# will most likely fail if the Tcl library is also required. This is due +# to how the Tcl library functions are declared and exported (i.e. without +# an explicit calling convention, which results in "cdecl"). +# +!IF $(USE_STDCALL)!=0 +!IF "$(PLATFORM)"=="x86" +CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +!ELSE +!IFNDEF PLATFORM +CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +!ELSE +CORE_CCONV_OPTS = +SHELL_CCONV_OPTS = +!ENDIF +!ENDIF +!ELSE +CORE_CCONV_OPTS = +SHELL_CCONV_OPTS = +!ENDIF + +# These are additional compiler options used for the core library. +# +!IFNDEF CORE_COMPILE_OPTS +!IF $(DYNAMIC_SHELL)!=0 +CORE_COMPILE_OPTS = $(CORE_CCONV_OPTS) -DSQLITE_API=__declspec(dllexport) +!ELSE +CORE_COMPILE_OPTS = $(CORE_CCONV_OPTS) +!ENDIF +!ENDIF + +# These are the additional targets that the core library should depend on +# when linking. +# +!IFNDEF CORE_LINK_DEP +!IF $(DYNAMIC_SHELL)!=0 +CORE_LINK_DEP = +!ELSE +CORE_LINK_DEP = sqlite3.def +!ENDIF +!ENDIF + +# These are additional linker options used for the core library. +# +!IFNDEF CORE_LINK_OPTS +!IF $(DYNAMIC_SHELL)!=0 +CORE_LINK_OPTS = +!ELSE +CORE_LINK_OPTS = /DEF:sqlite3.def +!ENDIF +!ENDIF + +# These are additional compiler options used for the shell executable. +# +!IFNDEF SHELL_COMPILE_OPTS +!IF $(DYNAMIC_SHELL)!=0 +SHELL_COMPILE_OPTS = $(SHELL_CCONV_OPTS) -DSQLITE_API=__declspec(dllimport) +!ELSE +SHELL_COMPILE_OPTS = $(SHELL_CCONV_OPTS) +!ENDIF +!ENDIF + +# This is the core library that the shell executable should depend on. +# +!IFNDEF SHELL_CORE_DEP +!IF $(DYNAMIC_SHELL)!=0 +SHELL_CORE_DEP = sqlite3.dll +!ELSE +SHELL_CORE_DEP = libsqlite3.lib +!ENDIF +!ENDIF + +# This is the core library that the shell executable should link with. +# +!IFNDEF SHELL_CORE_LIB +!IF $(DYNAMIC_SHELL)!=0 +SHELL_CORE_LIB = sqlite3.lib +!ELSE +SHELL_CORE_LIB = libsqlite3.lib +!ENDIF +!ENDIF + +# These are additional linker options used for the shell executable. +# +!IFNDEF SHELL_LINK_OPTS +SHELL_LINK_OPTS = $(SHELL_CORE_LIB) +!ENDIF + # Check if assembly code listings should be generated for the source # code files to be compiled. # @@ -341,11 +473,13 @@ RCC = $(RCC) -I$(TOP)\ext\rtree # options are necessary in order to allow debugging symbols to # work correctly with Visual Studio when using the amalgamation. # +!IFNDEF MKSQLITE3C_ARGS !IF $(DEBUG)>1 MKSQLITE3C_ARGS = --linemacros !ELSE MKSQLITE3C_ARGS = !ENDIF +!ENDIF # Define -DNDEBUG to compile without debugging (i.e., for production usage) # Omitting the define will cause extra debugging code to be inserted and @@ -367,9 +501,9 @@ TCC = $(TCC) -DSQLITE_DEBUG RCC = $(RCC) -DSQLITE_DEBUG !ENDIF -!IF $(DEBUG)>4 -TCC = $(TCC) -DSQLITE_DEBUG_OS_TRACE=1 -RCC = $(RCC) -DSQLITE_DEBUG_OS_TRACE=1 +!IF $(DEBUG)>4 || $(OSTRACE)!=0 +TCC = $(TCC) -DSQLITE_FORCE_OS_TRACE=1 -DSQLITE_DEBUG_OS_TRACE=1 +RCC = $(RCC) -DSQLITE_FORCE_OS_TRACE=1 -DSQLITE_DEBUG_OS_TRACE=1 !ENDIF !IF $(DEBUG)>5 @@ -501,6 +635,12 @@ RCC = $(RCC) -DSQLITE_TEMP_STORE=1 # REQ_FEATURE_FLAGS = $(REQ_FEATURE_FLAGS) -DSQLITE_MAX_TRIGGER_DEPTH=100 +# If we are linking to the RPCRT4 library, enable features that need it. +# +!IF $(USE_RPCRT4_LIB)!=0 +REQ_FEATURE_FLAGS = $(REQ_FEATURE_FLAGS) -DSQLITE_WIN32_USE_UUID=1 +!ENDIF + # Add the required and optional SQLite compilation options into the command # lines used to invoke the MSVC code and resource compilers. # @@ -564,13 +704,22 @@ LTRCOMPILE = $(RCC) -r LTLIB = lib.exe LTLINK = $(TCC) -Fe$@ +# If requested, link to the RPCRT4 library. +# +!IF $(USE_RPCRT4_LIB)!=0 +LTLINK = $(LTLINK) rpcrt4.lib +!ENDIF + # If a platform was set, force the linker to target that. # Note that the vcvars*.bat family of batch files typically # set this for you. Otherwise, the linker will attempt # to deduce the binary type based on the object files. !IFDEF PLATFORM -LTLINKOPTS = /MACHINE:$(PLATFORM) -LTLIBOPTS = /MACHINE:$(PLATFORM) +LTLINKOPTS = /NOLOGO /MACHINE:$(PLATFORM) +LTLIBOPTS = /NOLOGO /MACHINE:$(PLATFORM) +!ELSE +LTLINKOPTS = /NOLOGO +LTLIBOPTS = /NOLOGO !ENDIF # When compiling for use in the WinRT environment, the following @@ -579,7 +728,7 @@ LTLIBOPTS = /MACHINE:$(PLATFORM) # !IF $(FOR_WINRT)!=0 LTLINKOPTS = $(LTLINKOPTS) /APPCONTAINER -!IF "$(VISUALSTUDIOVERSION)"=="12.0" +!IF "$(VISUALSTUDIOVERSION)"=="12.0" || "$(VISUALSTUDIOVERSION)"=="14.0" !IFNDEF STORELIBPATH !IF "$(PLATFORM)"=="x86" STORELIBPATH = $(CRTLIBPATH)\store @@ -623,6 +772,16 @@ LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelH LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib !ENDIF +# When compiling for UAP, some extra linker options are also required. +# +!IF $(FOR_UAP)!=0 +LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE /NODEFAULTLIB:kernel32.lib +LTLINKOPTS = $(LTLINKOPTS) mincore.lib +!IFDEF PSDKLIBPATH +LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(PSDKLIBPATH)" +!ENDIF +!ENDIF + # If either debugging or symbols are enabled, enable PDBs. # !IF $(DEBUG)>1 || $(SYMBOLS)!=0 @@ -656,7 +815,7 @@ NAWK = gawk.exe # LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \ backup.lo bitvec.lo btmutex.lo btree.lo build.lo \ - callback.lo complete.lo ctime.lo date.lo delete.lo \ + callback.lo complete.lo ctime.lo date.lo dbstat.lo delete.lo \ expr.lo fault.lo fkey.lo \ fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \ fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \ @@ -696,7 +855,7 @@ LIBRESOBJS = # All of the source code files. # -SRC = \ +SRC1 = \ $(TOP)\src\alter.c \ $(TOP)\src\analyze.c \ $(TOP)\src\attach.c \ @@ -712,6 +871,7 @@ SRC = \ $(TOP)\src\complete.c \ $(TOP)\src\ctime.c \ $(TOP)\src\date.c \ + $(TOP)\src\dbstat.c \ $(TOP)\src\delete.c \ $(TOP)\src\expr.c \ $(TOP)\src\fault.c \ @@ -746,7 +906,8 @@ SRC = \ $(TOP)\src\os_setup.h \ $(TOP)\src\os_unix.c \ $(TOP)\src\os_win.c \ - $(TOP)\src\os_win.h \ + $(TOP)\src\os_win.h +SRC2 = \ $(TOP)\src\pager.c \ $(TOP)\src\pager.h \ $(TOP)\src\parse.y \ @@ -754,6 +915,7 @@ SRC = \ $(TOP)\src\pcache.h \ $(TOP)\src\pcache1.c \ $(TOP)\src\pragma.c \ + $(TOP)\src\pragma.h \ $(TOP)\src\prepare.c \ $(TOP)\src\printf.c \ $(TOP)\src\random.c \ @@ -785,6 +947,7 @@ SRC = \ $(TOP)\src\vdbetrace.c \ $(TOP)\src\vdbeInt.h \ $(TOP)\src\vtab.c \ + $(TOP)\src\vxworks.h \ $(TOP)\src\wal.c \ $(TOP)\src\wal.h \ $(TOP)\src\walker.c \ @@ -793,15 +956,14 @@ SRC = \ # Source code for extensions # -SRC = $(SRC) \ +SRC3 = \ $(TOP)\ext\fts1\fts1.c \ $(TOP)\ext\fts1\fts1.h \ $(TOP)\ext\fts1\fts1_hash.c \ $(TOP)\ext\fts1\fts1_hash.h \ $(TOP)\ext\fts1\fts1_porter.c \ $(TOP)\ext\fts1\fts1_tokenizer.h \ - $(TOP)\ext\fts1\fts1_tokenizer1.c -SRC = $(SRC) \ + $(TOP)\ext\fts1\fts1_tokenizer1.c \ $(TOP)\ext\fts2\fts2.c \ $(TOP)\ext\fts2\fts2.h \ $(TOP)\ext\fts2\fts2_hash.c \ @@ -811,7 +973,7 @@ SRC = $(SRC) \ $(TOP)\ext\fts2\fts2_tokenizer.h \ $(TOP)\ext\fts2\fts2_tokenizer.c \ $(TOP)\ext\fts2\fts2_tokenizer1.c -SRC = $(SRC) \ +SRC4 = \ $(TOP)\ext\fts3\fts3.c \ $(TOP)\ext\fts3\fts3.h \ $(TOP)\ext\fts3\fts3Int.h \ @@ -828,18 +990,16 @@ SRC = $(SRC) \ $(TOP)\ext\fts3\fts3_tokenize_vtab.c \ $(TOP)\ext\fts3\fts3_unicode.c \ $(TOP)\ext\fts3\fts3_unicode2.c \ - $(TOP)\ext\fts3\fts3_write.c -SRC = $(SRC) \ + $(TOP)\ext\fts3\fts3_write.c \ $(TOP)\ext\icu\sqliteicu.h \ - $(TOP)\ext\icu\icu.c -SRC = $(SRC) \ + $(TOP)\ext\icu\icu.c \ $(TOP)\ext\rtree\rtree.h \ $(TOP)\ext\rtree\rtree.c # Generated source code files # -SRC = $(SRC) \ +SRC5 = \ keywordhash.h \ opcodes.c \ opcodes.h \ @@ -847,6 +1007,10 @@ SRC = $(SRC) \ parse.h \ sqlite3.h +# All source code files. +# +SRC = $(SRC1) $(SRC2) $(SRC3) $(SRC4) $(SRC5) + # Source code to the test files. # TESTSRC = \ @@ -885,7 +1049,6 @@ TESTSRC = \ $(TOP)\src\test_server.c \ $(TOP)\src\test_superlock.c \ $(TOP)\src\test_syscall.c \ - $(TOP)\src\test_stat.c \ $(TOP)\src\test_tclvar.c \ $(TOP)\src\test_thread.c \ $(TOP)\src\test_vfs.c \ @@ -920,6 +1083,7 @@ TESTSRC2 = \ $(TOP)\src\build.c \ $(TOP)\src\ctime.c \ $(TOP)\src\date.c \ + $(TOP)\src\dbstat.c \ $(TOP)\src\expr.c \ $(TOP)\src\func.c \ $(TOP)\src\insert.c \ @@ -976,12 +1140,14 @@ HDR = \ $(TOP)\src\pager.h \ $(TOP)\src\pcache.h \ parse.h \ + $(TOP)\src\pragma.h \ sqlite3.h \ $(TOP)\src\sqlite3ext.h \ $(TOP)\src\sqliteInt.h \ $(TOP)\src\sqliteLimit.h \ $(TOP)\src\vdbe.h \ $(TOP)\src\vdbeInt.h \ + $(TOP)\src\vxworks.h \ $(TOP)\src\whereInt.h # Header files used by extensions @@ -1017,13 +1183,33 @@ libsqlite3.lib: $(LIBOBJ) libtclsqlite3.lib: tclsqlite.lo libsqlite3.lib $(LTLIB) $(LTLIBOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCL:tcl=tclstub) $(TLIBS) -sqlite3.exe: $(TOP)\src\shell.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h - $(LTLINK) $(READLINE_FLAGS) $(TOP)\src\shell.c \ - /link $(LTLINKOPTS) $(LTLIBPATHS) libsqlite3.lib $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) +sqlite3.exe: $(TOP)\src\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3.h + $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\shell.c \ + /link /pdb:sqlite3sh.pdb $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) -mptester.exe: $(TOP)\mptest\mptest.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h - $(LTLINK) $(TOP)\mptest\mptest.c \ - /link $(LTLINKOPTS) $(LTLIBPATHS) libsqlite3.lib $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) +sqldiff.exe: $(TOP)\tool\sqldiff.c sqlite3.c sqlite3.h + $(LTLINK) $(TOP)\tool\sqldiff.c sqlite3.c + +fuzzershell.exe: $(TOP)\tool\fuzzershell.c sqlite3.c sqlite3.h + $(LTLINK) $(TOP)\tool\fuzzershell.c sqlite3.c + +mptester.exe: $(TOP)\mptest\mptest.c $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3.h + $(LTLINK) $(SHELL_COMPILE_OPTS) $(TOP)\mptest\mptest.c \ + /link $(LTLINKOPTS) $(LTLIBPATHS) $(SHELL_LINK_OPTS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) + +MPTEST1 = mptester mptest.db $(TOP)\mptest\crash01.test --repeat 20 +MPTEST2 = mptester mptest.db $(TOP)\mptest\multiwrite01.test --repeat 20 + +mptest: mptester.exe + del /Q mptest.db 2>NUL + $(MPTEST1) --journalmode DELETE + $(MPTEST2) --journalmode WAL + $(MPTEST1) --journalmode WAL + $(MPTEST2) --journalmode PERSIST + $(MPTEST1) --journalmode PERSIST + $(MPTEST2) --journalmode TRUNCATE + $(MPTEST1) --journalmode TRUNCATE + $(MPTEST2) --journalmode DELETE # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to @@ -1032,10 +1218,14 @@ mptester.exe: $(TOP)\mptest\mptest.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h # all that automatic generation. # .target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl - -rmdir /S/Q tsrc + -rmdir /Q/S tsrc 2>NUL -mkdir tsrc - for %i in ($(SRC)) do copy /Y %i tsrc - del /Q tsrc\sqlite.h.in tsrc\parse.y + for %i in ($(SRC1)) do copy /Y %i tsrc + for %i in ($(SRC2)) do copy /Y %i tsrc + for %i in ($(SRC3)) do copy /Y %i tsrc + for %i in ($(SRC4)) do copy /Y %i tsrc + for %i in ($(SRC5)) do copy /Y %i tsrc + del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new move vdbe.new tsrc\vdbe.c echo > .target_source @@ -1060,7 +1250,7 @@ SQLITE3C = sqlite3.c # Rule to build the amalgamation # sqlite3.lo: $(SQLITE3C) - $(LTCOMPILE) -c $(SQLITE3C) + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(SQLITE3C) # Rules to build the LEMON compiler generator # @@ -1078,10 +1268,10 @@ lemon.exe: $(TOP)\tool\lemon.c lempar.c # opcodes.lo # parse.lo: parse.c $(HDR) - $(LTCOMPILE) -c parse.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c parse.c opcodes.lo: opcodes.c - $(LTCOMPILE) -c opcodes.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c opcodes.c # Rule to build the Win32 resources object file. # @@ -1099,223 +1289,226 @@ $(LIBRESOBJS): $(TOP)\src\sqlite3.rc $(HDR) # Rules to build individual *.lo files from files in the src directory. # alter.lo: $(TOP)\src\alter.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\alter.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\alter.c analyze.lo: $(TOP)\src\analyze.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\analyze.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\analyze.c attach.lo: $(TOP)\src\attach.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\attach.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\attach.c auth.lo: $(TOP)\src\auth.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\auth.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\auth.c backup.lo: $(TOP)\src\backup.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\backup.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\backup.c bitvec.lo: $(TOP)\src\bitvec.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\bitvec.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\bitvec.c btmutex.lo: $(TOP)\src\btmutex.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\btmutex.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\btmutex.c btree.lo: $(TOP)\src\btree.c $(HDR) $(TOP)\src\pager.h - $(LTCOMPILE) -c $(TOP)\src\btree.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\btree.c build.lo: $(TOP)\src\build.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\build.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\build.c callback.lo: $(TOP)\src\callback.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\callback.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\callback.c complete.lo: $(TOP)\src\complete.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\complete.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\complete.c ctime.lo: $(TOP)\src\ctime.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\ctime.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\ctime.c date.lo: $(TOP)\src\date.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\date.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\date.c + +dbstat.lo: $(TOP)\src\date.c $(HDR) + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\dbstat.c delete.lo: $(TOP)\src\delete.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\delete.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\delete.c expr.lo: $(TOP)\src\expr.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\expr.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\expr.c fault.lo: $(TOP)\src\fault.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\fault.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\fault.c fkey.lo: $(TOP)\src\fkey.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\fkey.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\fkey.c func.lo: $(TOP)\src\func.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\func.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\func.c global.lo: $(TOP)\src\global.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\global.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\global.c hash.lo: $(TOP)\src\hash.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\hash.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\hash.c insert.lo: $(TOP)\src\insert.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\insert.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\insert.c journal.lo: $(TOP)\src\journal.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\journal.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\journal.c legacy.lo: $(TOP)\src\legacy.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\legacy.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\legacy.c loadext.lo: $(TOP)\src\loadext.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\loadext.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\loadext.c main.lo: $(TOP)\src\main.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\main.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\main.c malloc.lo: $(TOP)\src\malloc.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\malloc.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\malloc.c mem0.lo: $(TOP)\src\mem0.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\mem0.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mem0.c mem1.lo: $(TOP)\src\mem1.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\mem1.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mem1.c mem2.lo: $(TOP)\src\mem2.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\mem2.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mem2.c mem3.lo: $(TOP)\src\mem3.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\mem3.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mem3.c mem5.lo: $(TOP)\src\mem5.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\mem5.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mem5.c memjournal.lo: $(TOP)\src\memjournal.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\memjournal.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\memjournal.c mutex.lo: $(TOP)\src\mutex.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\mutex.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mutex.c mutex_noop.lo: $(TOP)\src\mutex_noop.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\mutex_noop.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mutex_noop.c mutex_unix.lo: $(TOP)\src\mutex_unix.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\mutex_unix.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mutex_unix.c mutex_w32.lo: $(TOP)\src\mutex_w32.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\mutex_w32.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\mutex_w32.c notify.lo: $(TOP)\src\notify.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\notify.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\notify.c pager.lo: $(TOP)\src\pager.c $(HDR) $(TOP)\src\pager.h - $(LTCOMPILE) -c $(TOP)\src\pager.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\pager.c pcache.lo: $(TOP)\src\pcache.c $(HDR) $(TOP)\src\pcache.h - $(LTCOMPILE) -c $(TOP)\src\pcache.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\pcache.c pcache1.lo: $(TOP)\src\pcache1.c $(HDR) $(TOP)\src\pcache.h - $(LTCOMPILE) -c $(TOP)\src\pcache1.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\pcache1.c os.lo: $(TOP)\src\os.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\os.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\os.c os_unix.lo: $(TOP)\src\os_unix.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\os_unix.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\os_unix.c os_win.lo: $(TOP)\src\os_win.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\os_win.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\os_win.c pragma.lo: $(TOP)\src\pragma.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\pragma.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\pragma.c prepare.lo: $(TOP)\src\prepare.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\prepare.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\prepare.c printf.lo: $(TOP)\src\printf.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\printf.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\printf.c random.lo: $(TOP)\src\random.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\random.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\random.c resolve.lo: $(TOP)\src\resolve.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\resolve.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\resolve.c rowset.lo: $(TOP)\src\rowset.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\rowset.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\rowset.c select.lo: $(TOP)\src\select.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\select.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\select.c status.lo: $(TOP)\src\status.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\status.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\status.c table.lo: $(TOP)\src\table.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\table.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\table.c threads.lo: $(TOP)\src\threads.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\threads.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\threads.c tokenize.lo: $(TOP)\src\tokenize.c keywordhash.h $(HDR) - $(LTCOMPILE) -c $(TOP)\src\tokenize.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\tokenize.c trigger.lo: $(TOP)\src\trigger.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\trigger.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\trigger.c update.lo: $(TOP)\src\update.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\update.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\update.c utf.lo: $(TOP)\src\utf.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\utf.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\utf.c util.lo: $(TOP)\src\util.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\util.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\util.c vacuum.lo: $(TOP)\src\vacuum.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\vacuum.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vacuum.c vdbe.lo: $(TOP)\src\vdbe.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\vdbe.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbe.c vdbeapi.lo: $(TOP)\src\vdbeapi.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\vdbeapi.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbeapi.c vdbeaux.lo: $(TOP)\src\vdbeaux.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\vdbeaux.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbeaux.c vdbeblob.lo: $(TOP)\src\vdbeblob.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\vdbeblob.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbeblob.c vdbemem.lo: $(TOP)\src\vdbemem.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\vdbemem.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbemem.c vdbesort.lo: $(TOP)\src\vdbesort.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\vdbesort.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbesort.c vdbetrace.lo: $(TOP)\src\vdbetrace.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\vdbetrace.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbetrace.c vtab.lo: $(TOP)\src\vtab.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\vtab.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vtab.c wal.lo: $(TOP)\src\wal.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\wal.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\wal.c walker.lo: $(TOP)\src\walker.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\walker.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\walker.c where.lo: $(TOP)\src\where.c $(HDR) - $(LTCOMPILE) -c $(TOP)\src\where.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\where.c tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR) - $(LTCOMPILE) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c + $(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c tclsqlite-shell.lo: $(TOP)\src\tclsqlite.c $(HDR) - $(LTCOMPILE) -DTCLSH=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c + $(LTCOMPILE) $(NO_WARN) -DTCLSH=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c -tclsqlite3.exe: tclsqlite-shell.lo libsqlite3.lib $(LIBRESOBJS) - $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /OUT:$@ libsqlite3.lib tclsqlite-shell.lo $(LIBRESOBJS) $(LTLIBS) $(TLIBS) +tclsqlite3.exe: tclsqlite-shell.lo $(SQLITE3C) $(LIBRESOBJS) + $(LTLINK) $(SQLITE3C) /link $(LTLINKOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(LTLIBS) $(TLIBS) # Rules to build opcodes.c and opcodes.h # @@ -1330,7 +1523,7 @@ opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\mkopcodeh.awk parse.h: parse.c parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\addopcodes.awk - del /Q parse.y parse.h parse.h.temp + del /Q parse.y parse.h parse.h.temp 2>NUL copy $(TOP)\src\parse.y . .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(OPTS) parse.y move parse.h parse.h.temp @@ -1351,67 +1544,67 @@ keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe # Rules to build the extension objects. # icu.lo: $(TOP)\ext\icu\icu.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\icu\icu.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\icu\icu.c fts2.lo: $(TOP)\ext\fts2\fts2.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2.c fts2_hash.lo: $(TOP)\ext\fts2\fts2_hash.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_hash.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_hash.c fts2_icu.lo: $(TOP)\ext\fts2\fts2_icu.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_icu.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_icu.c fts2_porter.lo: $(TOP)\ext\fts2\fts2_porter.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_porter.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_porter.c fts2_tokenizer.lo: $(TOP)\ext\fts2\fts2_tokenizer.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_tokenizer.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_tokenizer.c fts2_tokenizer1.lo: $(TOP)\ext\fts2\fts2_tokenizer1.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_tokenizer1.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_tokenizer1.c fts3.lo: $(TOP)\ext\fts3\fts3.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3.c fts3_aux.lo: $(TOP)\ext\fts3\fts3_aux.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_aux.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_aux.c fts3_expr.lo: $(TOP)\ext\fts3\fts3_expr.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_expr.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_expr.c fts3_hash.lo: $(TOP)\ext\fts3\fts3_hash.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_hash.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_hash.c fts3_icu.lo: $(TOP)\ext\fts3\fts3_icu.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_icu.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_icu.c fts3_snippet.lo: $(TOP)\ext\fts3\fts3_snippet.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_snippet.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_snippet.c fts3_porter.lo: $(TOP)\ext\fts3\fts3_porter.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_porter.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_porter.c fts3_tokenizer.lo: $(TOP)\ext\fts3\fts3_tokenizer.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenizer.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenizer.c fts3_tokenizer1.lo: $(TOP)\ext\fts3\fts3_tokenizer1.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenizer1.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenizer1.c fts3_tokenize_vtab.lo: $(TOP)\ext\fts3\fts3_tokenize_vtab.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenize_vtab.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenize_vtab.c fts3_unicode.lo: $(TOP)\ext\fts3\fts3_unicode.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode.c fts3_unicode2.lo: $(TOP)\ext\fts3\fts3_unicode2.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode2.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode2.c fts3_write.lo: $(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_write.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_write.c rtree.lo: $(TOP)\ext\rtree\rtree.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\rtree\rtree.c + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\rtree\rtree.c # Rules to build the 'testfixture' application. @@ -1425,7 +1618,7 @@ TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN) -TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) libsqlite3.lib +TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) $(SHELL_CORE_DEP) TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C) !IF $(USE_AMALGAMATION)==0 TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0) @@ -1442,100 +1635,108 @@ testfixture.exe: $(TESTFIXTURE_SRC) $(LIBRESOBJS) $(HDR) extensiontest: testfixture.exe testloadext.dll .\testfixture.exe $(TOP)\test\loadext.test -fulltest: testfixture.exe sqlite3.exe +fulltest: testfixture.exe sqlite3.exe fuzztest .\testfixture.exe $(TOP)\test\all.test -soaktest: testfixture.exe sqlite3.exe +soaktest: testfixture.exe sqlite3.exe fuzzoomtest .\testfixture.exe $(TOP)\test\all.test -soak=1 -fulltestonly: testfixture.exe sqlite3.exe +fulltestonly: testfixture.exe sqlite3.exe fuzztest .\testfixture.exe $(TOP)\test\full.test queryplantest: testfixture.exe sqlite3.exe .\testfixture.exe $(TOP)\test\permutations.test queryplanner -test: testfixture.exe sqlite3.exe +fuzztest: fuzzershell.exe + .\fuzzershell.exe $(TOP)\test\fuzzdata1.txt $(TOP)\test\fuzzdata2.txt + +fuzzoomtest: fuzzershell.exe + .\fuzzershell.exe -f $(TOP)\test\fuzzdata1.txt --oom + +test: testfixture.exe sqlite3.exe fuzztest .\testfixture.exe $(TOP)\test\veryquick.test -sqlite3_analyzer.c: $(SQLITE3C) $(TOP)\src\test_stat.c $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl - copy $(SQLITE3C) + $(TOP)\src\test_stat.c + $(TOP)\src\tclsqlite.c $@ +smoketest: testfixture.exe + .\testfixture.exe $(TOP)\test\main.test + +sqlite3_analyzer.c: $(SQLITE3C) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl + copy $(SQLITE3C) + $(TOP)\src\tclsqlite.c $@ echo static const char *tclsh_main_loop(void){ >> $@ echo static const char *zMainloop = >> $@ $(NAWK) -f $(TOP)\tool\tostr.awk $(TOP)\tool\spaceanal.tcl >> $@ echo ; return zMainloop; } >> $@ sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS) - $(LTLINK) -DBUILD_sqlite -DTCLSH=2 -I$(TCLINCDIR) sqlite3_analyzer.c \ + $(LTLINK) $(NO_WARN) -DBUILD_sqlite -DSQLITE_ENABLE_DBSTAT_VTAB -DTCLSH=2 -I$(TCLINCDIR) sqlite3_analyzer.c \ /link $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) testloadext.lo: $(TOP)\src\test_loadext.c - $(LTCOMPILE) -c $(TOP)\src\test_loadext.c + $(LTCOMPILE) $(NO_WARN) -c $(TOP)\src\test_loadext.c testloadext.dll: testloadext.lo $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /OUT:$@ testloadext.lo showdb.exe: $(TOP)\tool\showdb.c $(SQLITE3C) - $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ $(TOP)\tool\showdb.c $(SQLITE3C) showstat4.exe: $(TOP)\tool\showstat4.c $(SQLITE3C) - $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ $(TOP)\tool\showstat4.c $(SQLITE3C) showjournal.exe: $(TOP)\tool\showjournal.c $(SQLITE3C) - $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ $(TOP)\tool\showjournal.c $(SQLITE3C) showwal.exe: $(TOP)\tool\showwal.c $(SQLITE3C) - $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ $(TOP)\tool\showwal.c $(SQLITE3C) fts3view.exe: $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) - $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) rollback-test.exe: $(TOP)\tool\rollback-test.c $(SQLITE3C) - $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ $(TOP)\tool\rollback-test.c $(SQLITE3C) LogEst.exe: $(TOP)\tool\logest.c sqlite3.h - $(LTLINK) -Fe$@ $(TOP)\tool\LogEst.c + $(LTLINK) $(NO_WARN) -Fe$@ $(TOP)\tool\LogEst.c wordcount.exe: $(TOP)\test\wordcount.c $(SQLITE3C) - $(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ $(TOP)\test\wordcount.c $(SQLITE3C) speedtest1.exe: $(TOP)\test\speedtest1.c $(SQLITE3C) - $(LTLINK) -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ + $(LTLINK) $(NO_WARN) -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ $(TOP)\test\speedtest1.c $(SQLITE3C) clean: - del /Q *.lo *.ilk *.lib *.obj *.pdb sqlite3.exe libsqlite3.lib - del /Q *.cod *.da *.bb *.bbg gmon.out - del /Q sqlite3.h opcodes.c opcodes.h - del /Q lemon.* lempar.c parse.* - del /Q mkkeywordhash.* keywordhash.h - del /Q notasharedlib.* - -rmdir /Q/S .deps - -rmdir /Q/S .libs - -rmdir /Q/S quota2a - -rmdir /Q/S quota2b - -rmdir /Q/S quota2c - -rmdir /Q/S tsrc - del /Q .target_source - del /Q tclsqlite3.exe tclsqlite3.exp - del /Q testloadext.dll testloadext.exp - del /Q testfixture.exe testfixture.exp test.db - del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe - del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe - del /Q wordcount.exe - del /Q sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def - del /Q sqlite3.c sqlite3-*.c - del /Q sqlite3rc.h - del /Q shell.c sqlite3ext.h - del /Q sqlite3_analyzer.exe sqlite3_analyzer.exp sqlite3_analyzer.c - del /Q sqlite-*-output.vsix - del /Q mptester.exe + del /Q *.exp *.lo *.ilk *.lib *.obj *.pdb 2>NUL + del /Q *.cod *.da *.bb *.bbg gmon.out 2>NUL + del /Q sqlite3.h opcodes.c opcodes.h 2>NUL + del /Q lemon.* lempar.c parse.* 2>NUL + del /Q mkkeywordhash.* keywordhash.h 2>NUL + del /Q notasharedlib.* 2>NUL + -rmdir /Q/S .deps 2>NUL + -rmdir /Q/S .libs 2>NUL + -rmdir /Q/S quota2a 2>NUL + -rmdir /Q/S quota2b 2>NUL + -rmdir /Q/S quota2c 2>NUL + -rmdir /Q/S tsrc 2>NUL + del /Q .target_source 2>NUL + del /Q tclsqlite3.exe 2>NUL + del /Q testloadext.dll 2>NUL + del /Q testfixture.exe test.db 2>NUL + del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe 2>NUL + del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL + del /Q mptester.exe wordcount.exe 2>NUL + del /Q sqlite3.exe sqlite3.dll sqlite3.def 2>NUL + del /Q sqlite3.c sqlite3-*.c 2>NUL + del /Q sqlite3rc.h 2>NUL + del /Q shell.c sqlite3ext.h 2>NUL + del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL + del /Q sqlite-*-output.vsix 2>NUL # Dynamic link library section. # @@ -1547,5 +1748,5 @@ sqlite3.def: libsqlite3.lib | $(NAWK) "/ 1 _?sqlite3_/ { sub(/^.* _?/,\"\");print }" \ | sort >> sqlite3.def -sqlite3.dll: $(LIBOBJ) $(LIBRESOBJS) sqlite3.def - $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /DEF:sqlite3.def /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) +sqlite3.dll: $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP) + $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) diff --git a/VERSION b/VERSION index 4982c85..ff280e4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.8.8.3 +3.8.10.2 diff --git a/autoconf/Makefile.am b/autoconf/Makefile.am index 6fc4f33..88bc23d 100644 --- a/autoconf/Makefile.am +++ b/autoconf/Makefile.am @@ -7,8 +7,7 @@ libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8 bin_PROGRAMS = sqlite3 sqlite3_SOURCES = shell.c sqlite3.h -sqlite3_LDADD = $(top_builddir)/libsqlite3.la @READLINE_LIBS@ -sqlite3_DEPENDENCIES = $(top_builddir)/libsqlite3.la +sqlite3_LDADD = sqlite3.$(OBJEXT) @READLINE_LIBS@ include_HEADERS = sqlite3.h sqlite3ext.h diff --git a/configure b/configure index 5c8a189..c73b820 100755 --- a/configure +++ b/configure @@ -1,18 +1,20 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.62 for sqlite 3.8.8.3. +# Generated by GNU Autoconf 2.69 for sqlite 3.8.10.2. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# # -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. -## --------------------- ## -## M4sh Initialization. ## -## --------------------- ## +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which @@ -20,23 +22,15 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; esac - fi - - -# PATH needs CR -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - as_nl=' ' export as_nl @@ -44,7 +38,13 @@ export as_nl as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else @@ -55,7 +55,7 @@ else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; - case $arg in + case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; @@ -78,13 +78,6 @@ if test "${PATH_SEPARATOR+set}" != set; then } fi -# Support unset when possible. -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - as_unset=unset -else - as_unset=false -fi - # IFS # We need space, tab and new line, in precisely that order. Quoting is @@ -94,15 +87,16 @@ fi IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. -case $0 in +as_myself= +case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break -done + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done IFS=$as_save_IFS ;; @@ -114,12 +108,16 @@ if test "x$as_myself" = x; then fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - { (exit 1); exit 1; } + exit 1 fi -# Work around bugs in pre-3.0 UWIN ksh. -for as_var in ENV MAIL MAILPATH -do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' @@ -131,7 +129,293 @@ export LC_ALL LANGUAGE=C export LANGUAGE -# Required to use basename. +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr @@ -145,8 +429,12 @@ else as_basename=false fi +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi -# Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ @@ -166,295 +454,19 @@ $as_echo X/"$0" | } s/.*/./; q'` -# CDPATH. -$as_unset CDPATH +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits -if test "x$CONFIG_SHELL" = x; then - if (eval ":") 2>/dev/null; then - as_have_required=yes -else - as_have_required=no -fi - - if test $as_have_required = yes && (eval ": -(as_func_return () { - (exit \$1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = \"\$1\" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test \$exitcode = 0) || { (exit 1); exit 1; } - -( - as_lineno_1=\$LINENO - as_lineno_2=\$LINENO - test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && - test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } -") 2> /dev/null; then - : -else - as_candidate_shells= - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - case $as_dir in - /*) - for as_base in sh bash ksh sh5; do - as_candidate_shells="$as_candidate_shells $as_dir/$as_base" - done;; - esac -done -IFS=$as_save_IFS - - - for as_shell in $as_candidate_shells $SHELL; do - # Try only shells that exist, to save several forks. - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { ("$as_shell") 2> /dev/null <<\_ASEOF -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; -esac - -fi - - -: -_ASEOF -}; then - CONFIG_SHELL=$as_shell - as_have_required=yes - if { "$as_shell" 2> /dev/null <<\_ASEOF -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; -esac - -fi - - -: -(as_func_return () { - (exit $1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = "$1" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test $exitcode = 0) || { (exit 1); exit 1; } - -( - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } - -_ASEOF -}; then - break -fi - -fi - - done - - if test "x$CONFIG_SHELL" != x; then - for as_var in BASH_ENV ENV - do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var - done - export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} -fi - - - if test $as_have_required = no; then - echo This script requires a shell more modern than all the - echo shells that I found on your system. Please install a - echo modern shell, or manually run the script under such a - echo shell if you do have one. - { (exit 1); exit 1; } -fi - - -fi - -fi - - - -(eval "as_func_return () { - (exit \$1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = \"\$1\" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test \$exitcode = 0") || { - echo No shell found that supports shell functions. - echo Please tell bug-autoconf@gnu.org about your system, - echo including any error possibly output before this message. - echo This can help us improve future autoconf versions. - echo Configuration will now proceed without shell functions. -} - - - - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { - - # Create $as_me.lineno as a copy of $as_myself, but with $LINENO - # uniformly replaced by the line number. The first 'sed' inserts a - # line-number line after each line using $LINENO; the second 'sed' - # does the real work. The second script uses 'N' to pair each - # line-number line with the line containing $LINENO, and appends - # trailing '-' during substitution so that $LINENO is not a special - # case at line end. - # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the - # scripts with optimization help from Paolo Bonzini. Blame Lee - # E. McMahon (1931-1989) for sed's syntax. :-) + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= @@ -471,9 +483,12 @@ test \$exitcode = 0") || { s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 - { (exit 1); exit 1; }; } + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). @@ -482,29 +497,18 @@ test \$exitcode = 0") || { exit } - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in +case `echo -n x` in #((((( -n*) - case `echo 'x\c'` in + case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. - *) ECHO_C='\c';; + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then @@ -519,49 +523,29 @@ if (echo >conf$$.file) 2>/dev/null; then # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then - as_mkdir_p=: + as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x +as_test_x='test -x' +as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -571,7 +555,6 @@ as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} @@ -720,10 +703,11 @@ fi -exec 7<&0 &1 +test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. -# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` @@ -738,14 +722,14 @@ cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= -SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.8.8.3' -PACKAGE_STRING='sqlite 3.8.8.3' +PACKAGE_VERSION='3.8.10.2' +PACKAGE_STRING='sqlite 3.8.10.2' PACKAGE_BUGREPORT='' +PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ @@ -783,118 +767,120 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL -PATH_SEPARATOR -PACKAGE_NAME -PACKAGE_TARNAME -PACKAGE_VERSION -PACKAGE_STRING -PACKAGE_BUGREPORT -exec_prefix -prefix -program_transform_name -bindir -sbindir -libexecdir -datarootdir -datadir -sysconfdir -sharedstatedir -localstatedir -includedir -oldincludedir -docdir -infodir -htmldir -dvidir -pdfdir -psdir -libdir -localedir -mandir -DEFS -ECHO_C -ECHO_N -ECHO_T -LIBS -build_alias -host_alias -target_alias -LIBTOOL -build -build_cpu -build_vendor -build_os -host -host_cpu -host_vendor -host_os -CC -CFLAGS -LDFLAGS -CPPFLAGS -ac_ct_CC -EXEEXT -OBJEXT -SED -GREP -EGREP -FGREP -LD -DUMPBIN -ac_ct_DUMPBIN -NM -LN_S -OBJDUMP -AR -STRIP -RANLIB -lt_ECHO -DSYMUTIL -NMEDIT -LIPO -OTOOL -OTOOL64 -CPP -INSTALL_PROGRAM -INSTALL_SCRIPT -INSTALL_DATA -AWK -TCLSH_CMD -TCLLIBDIR -program_prefix -VERSION -RELEASE -VERSION_NUMBER -BUILD_CC -SQLITE_THREADSAFE -ALLOWRELEASE -TEMP_STORE -BUILD_EXEEXT -SQLITE_OS_UNIX -SQLITE_OS_WIN -TARGET_EXEEXT -TCL_VERSION -TCL_BIN_DIR -TCL_SRC_DIR -TCL_INCLUDE_SPEC -TCL_LIB_FILE -TCL_LIB_FLAG -TCL_LIB_SPEC -TCL_STUB_LIB_FILE -TCL_STUB_LIB_FLAG -TCL_STUB_LIB_SPEC -HAVE_TCL -TARGET_READLINE_LIBS -TARGET_READLINE_INC -TARGET_HAVE_READLINE -TARGET_DEBUG -USE_AMALGAMATION -OPT_FEATURE_FLAGS -USE_GCOV -BUILD_CFLAGS +ac_subst_vars='LTLIBOBJS LIBOBJS -LTLIBOBJS' +BUILD_CFLAGS +USE_GCOV +OPT_FEATURE_FLAGS +USE_AMALGAMATION +TARGET_DEBUG +TARGET_HAVE_READLINE +TARGET_READLINE_INC +TARGET_READLINE_LIBS +HAVE_TCL +TCL_SHLIB_SUFFIX +TCL_STUB_LIB_SPEC +TCL_STUB_LIB_FLAG +TCL_STUB_LIB_FILE +TCL_LIB_SPEC +TCL_LIB_FLAG +TCL_LIB_FILE +TCL_INCLUDE_SPEC +TCL_SRC_DIR +TCL_BIN_DIR +TCL_VERSION +TARGET_EXEEXT +SQLITE_OS_WIN +SQLITE_OS_UNIX +BUILD_EXEEXT +TEMP_STORE +ALLOWRELEASE +SQLITE_THREADSAFE +BUILD_CC +VERSION_NUMBER +RELEASE +VERSION +program_prefix +TCLLIBDIR +TCLSH_CMD +AWK +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +CPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +lt_ECHO +RANLIB +STRIP +AR +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +LIBTOOL +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking @@ -990,8 +976,9 @@ do fi case $ac_option in - *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *) ac_optarg=yes ;; + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. @@ -1036,8 +1023,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1063,8 +1049,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1268,8 +1253,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1285,8 +1269,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1316,17 +1299,17 @@ do | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) { $as_echo "$as_me: error: unrecognized option: $ac_option -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; } + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. - expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && - { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2 - { (exit 1); exit 1; }; } + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; @@ -1335,7 +1318,7 @@ Try \`$0 --help' for more information." >&2 $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac @@ -1343,16 +1326,14 @@ done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` - { $as_echo "$as_me: error: missing argument to $ac_option" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; - fatal) { $as_echo "$as_me: error: Unrecognized options: $ac_unrecognized_opts" >&2 - { (exit 1); exit 1; }; } ;; - *) $as_echo "$as_me: WARNING: Unrecognized options: $ac_unrecognized_opts" >&2 ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1374,8 +1355,7 @@ do [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac - { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' @@ -1389,8 +1369,6 @@ target=$target_alias if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -1405,11 +1383,9 @@ test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - { $as_echo "$as_me: error: Working directory cannot be determined" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - { $as_echo "$as_me: error: pwd does not report name of working directory" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. @@ -1448,13 +1424,11 @@ else fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 - { (exit 1); exit 1; }; } + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2 - { (exit 1); exit 1; }; } + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then @@ -1480,7 +1454,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.8.8.3 to adapt to many kinds of systems. +\`configure' configures sqlite 3.8.10.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1494,7 +1468,7 @@ Configuration: --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking...' messages + -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files @@ -1545,7 +1519,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.8.8.3:";; + short | recursive ) echo "Configuration of sqlite 3.8.10.2:";; esac cat <<\_ACEOF @@ -1589,7 +1563,7 @@ Some influential environment variables: LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor TCLLIBDIR Where to install tcl plugin @@ -1597,6 +1571,7 @@ Some influential environment variables: Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. +Report bugs to the package provider. _ACEOF ac_status=$? fi @@ -1659,22 +1634,427 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.8.8.3 -generated by GNU Autoconf 2.62 +sqlite configure 3.8.10.2 +generated by GNU Autoconf 2.69 -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel 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.8.8.3, which was -generated by GNU Autoconf 2.62. Invocation command line was +It was created by sqlite $as_me 3.8.10.2, which was +generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -1710,8 +2090,8 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" -done + $as_echo "PATH: $as_dir" + done IFS=$as_save_IFS } >&5 @@ -1748,9 +2128,9 @@ do ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in - 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) - ac_configure_args1="$ac_configure_args1 '$ac_arg'" + as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else @@ -1766,13 +2146,13 @@ do -* ) ac_must_keep_next=true ;; esac fi - ac_configure_args="$ac_configure_args '$ac_arg'" + as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done -$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } -$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there @@ -1784,11 +2164,9 @@ trap 'exit_status=$? { echo - cat <<\_ASBOX -## ---------------- ## + $as_echo "## ---------------- ## ## Cache variables. ## -## ---------------- ## -_ASBOX +## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( @@ -1797,13 +2175,13 @@ _ASBOX case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 -$as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) $as_unset $ac_var ;; + *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done @@ -1822,11 +2200,9 @@ $as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; ) echo - cat <<\_ASBOX -## ----------------- ## + $as_echo "## ----------------- ## ## Output variables. ## -## ----------------- ## -_ASBOX +## ----------------- ##" echo for ac_var in $ac_subst_vars do @@ -1839,11 +2215,9 @@ _ASBOX echo if test -n "$ac_subst_files"; then - cat <<\_ASBOX -## ------------------- ## + $as_echo "## ------------------- ## ## File substitutions. ## -## ------------------- ## -_ASBOX +## ------------------- ##" echo for ac_var in $ac_subst_files do @@ -1857,11 +2231,9 @@ _ASBOX fi if test -s confdefs.h; then - cat <<\_ASBOX -## ----------- ## + $as_echo "## ----------- ## ## confdefs.h. ## -## ----------- ## -_ASBOX +## ----------- ##" echo cat confdefs.h echo @@ -1875,46 +2247,53 @@ _ASBOX exit $exit_status ' 0 for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h +$as_echo "/* confdefs.h */" > confdefs.h + # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - ac_site_file1=$CONFIG_SITE + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site @@ -1925,19 +2304,23 @@ fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue - if test -r "$ac_site_file"; then - { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special - # files actually), so we avoid doing that. - if test -f "$cache_file"; then - { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5 + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; @@ -1945,7 +2328,7 @@ $as_echo "$as_me: loading cache $cache_file" >&6;} esac fi else - { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi @@ -1960,11 +2343,11 @@ for ac_var in $ac_precious_vars; do eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) - { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; @@ -1974,17 +2357,17 @@ $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else - { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi - { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac @@ -1996,41 +2379,20 @@ $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then - { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 -$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi - - - - - - - - - - - - - - - - - - - - - - - - +## -------------------- ## +## Main body of script. ## +## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' @@ -2042,15 +2404,10 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu sqlite_version_sanity_check=`cat $srcdir/VERSION | tr -d '\n'` if test "$PACKAGE_VERSION" != "$sqlite_version_sanity_check" ; then -{ { $as_echo "$as_me:$LINENO: error: configure script is out of date: +as_fn_error $? "configure script is out of date: configure \$PACKAGE_VERSION = $PACKAGE_VERSION top level VERSION file = $sqlite_version_sanity_check -please regen with autoconf" >&5 -$as_echo "$as_me: error: configure script is out of date: - configure \$PACKAGE_VERSION = $PACKAGE_VERSION - top level VERSION file = $sqlite_version_sanity_check -please regen with autoconf" >&2;} - { (exit 1); exit 1; }; } +please regen with autoconf" "$LINENO" 5 fi ######### @@ -2058,7 +2415,7 @@ fi # case `pwd` in *\ * | *\ *) - { $as_echo "$as_me:$LINENO: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac @@ -2098,9 +2455,7 @@ for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do fi done if test -z "$ac_aux_dir"; then - { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 -$as_echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, @@ -2114,35 +2469,27 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 -$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 -{ $as_echo "$as_me:$LINENO: checking build system type" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } -if test "${ac_cv_build+set}" = set; then +if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && - { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 -$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 -$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; -*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 -$as_echo "$as_me: error: invalid value of canonical build" >&2;} - { (exit 1); exit 1; }; };; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' @@ -2158,28 +2505,24 @@ IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:$LINENO: checking host system type" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } -if test "${ac_cv_host+set}" = set; then +if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 -$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; -*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 -$as_echo "$as_me: error: invalid value of canonical host" >&2;} - { (exit 1); exit 1; }; };; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' @@ -2203,9 +2546,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -2216,24 +2559,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:$LINENO: result: $CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2243,9 +2586,9 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -2256,24 +2599,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2282,12 +2625,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2300,9 +2639,9 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -2313,24 +2652,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:$LINENO: result: $CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2340,9 +2679,9 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -2354,18 +2693,18 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then @@ -2384,10 +2723,10 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:$LINENO: result: $CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2399,9 +2738,9 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -2412,24 +2751,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:$LINENO: result: $CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2443,9 +2782,9 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -2456,24 +2795,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -2486,12 +2825,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2501,55 +2836,37 @@ fi fi -test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. -$as_echo "$as_me:$LINENO: checking for C compiler version" >&5 +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 -{ (ac_try="$ac_compiler --version >&5" +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compiler --version >&5") 2>&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -v >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compiler -v >&5") 2>&5 - ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -V >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compiler -V >&5") 2>&5 - ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2565,8 +2882,8 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: @@ -2582,17 +2899,17 @@ do done rm -f $ac_rmfiles -if { (ac_try="$ac_link_default" +if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, @@ -2609,7 +2926,7 @@ do # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -2628,80 +2945,41 @@ test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi - -{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } -if test -z "$ac_file"; then - $as_echo "$as_me: failed program was:" >&5 +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: C compiler cannot create executables -See \`config.log' for more details." >&2;} - { (exit 77); exit 77; }; } -fi - -ac_exeext=$ac_cv_exeext - -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 -# If not cross compiling, check that we can run a simple program. -if test "$cross_compiling" != yes; then - if { ac_try='./$ac_file' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } - fi - fi -fi -{ $as_echo "$as_me:$LINENO: result: yes" >&5 +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } -{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } - -{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } -if { (ac_try="$ac_link" +if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with @@ -2716,30 +2994,83 @@ for ac_file in conftest.exe conftest conftest.*; do esac done else - { { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } fi - -rm -f conftest$ac_cv_exeext -{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT -{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5 +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } -if test "${ac_cv_objext+set}" = set; then +if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2751,17 +3082,17 @@ main () } _ACEOF rm -f conftest.o conftest.obj -if { (ac_try="$ac_compile" +if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in @@ -2774,29 +3105,23 @@ else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } fi - rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then +if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2810,37 +3135,16 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_compiler_gnu=no + ac_compiler_gnu=no fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes @@ -2849,20 +3153,16 @@ else fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then +if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2873,35 +3173,11 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - CFLAGS="" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2912,36 +3188,12 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_c_try_compile "$LINENO"; then : - ac_c_werror_flag=$ac_save_c_werror_flag +else + ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2952,42 +3204,17 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS @@ -3004,23 +3231,18 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then +if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include -#include -#include +struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); @@ -3072,32 +3294,9 @@ for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then + if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done @@ -3108,17 +3307,19 @@ fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) - { $as_echo "$as_me:$LINENO: result: none needed" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) - { $as_echo "$as_me:$LINENO: result: unsupported" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac +if test "x$ac_cv_prog_cc_c89" != xno; then : +fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' @@ -3126,9 +3327,9 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } -if test "${ac_cv_path_SED+set}" = set; then +if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ @@ -3136,7 +3337,7 @@ else ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - $as_unset ac_script || ac_script= + { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST @@ -3145,10 +3346,10 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_prog in sed gsed; do + for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue + as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in @@ -3165,7 +3366,7 @@ case `"$ac_path_SED" --version 2>&1` in $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` + as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" @@ -3180,19 +3381,17 @@ esac $ac_path_SED_found && break 3 done done -done + done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then - { { $as_echo "$as_me:$LINENO: error: no acceptable sed could be found in \$PATH" >&5 -$as_echo "$as_me: error: no acceptable sed could be found in \$PATH" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_SED" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed @@ -3210,9 +3409,9 @@ Xsed="$SED -e 1s/^X//" -{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if test "${ac_cv_path_GREP+set}" = set; then +if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then @@ -3223,10 +3422,10 @@ for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do + for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in @@ -3243,7 +3442,7 @@ case `"$ac_path_GREP" --version 2>&1` in $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` + as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" @@ -3258,26 +3457,24 @@ esac $ac_path_GREP_found && break 3 done done -done + done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then - { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 -$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" -{ $as_echo "$as_me:$LINENO: checking for egrep" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then +if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 @@ -3291,10 +3488,10 @@ for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do + for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in @@ -3311,7 +3508,7 @@ case `"$ac_path_EGREP" --version 2>&1` in $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` + as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" @@ -3326,12 +3523,10 @@ esac $ac_path_EGREP_found && break 3 done done -done + done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then - { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 -$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP @@ -3339,14 +3534,14 @@ fi fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" -{ $as_echo "$as_me:$LINENO: checking for fgrep" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } -if test "${ac_cv_path_FGREP+set}" = set; then +if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 @@ -3360,10 +3555,10 @@ for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_prog in fgrep; do + for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue + as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in @@ -3380,7 +3575,7 @@ case `"$ac_path_FGREP" --version 2>&1` in $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` + as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" @@ -3395,12 +3590,10 @@ esac $ac_path_FGREP_found && break 3 done done -done + done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then - { { $as_echo "$as_me:$LINENO: error: no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 -$as_echo "$as_me: error: no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP @@ -3408,7 +3601,7 @@ fi fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_FGREP" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" @@ -3434,7 +3627,7 @@ test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then +if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no @@ -3443,7 +3636,7 @@ fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. - { $as_echo "$as_me:$LINENO: checking for ld used by $CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) @@ -3473,13 +3666,13 @@ $as_echo_n "checking for ld used by $CC... " >&6; } ;; esac elif test "$with_gnu_ld" = yes; then - { $as_echo "$as_me:$LINENO: checking for GNU ld" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else - { $as_echo "$as_me:$LINENO: checking for non-GNU ld" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi -if test "${lt_cv_path_LD+set}" = set; then +if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then @@ -3510,18 +3703,16 @@ fi LD="$lt_cv_path_LD" if test -n "$LD"; then - { $as_echo "$as_me:$LINENO: result: $LD" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 $as_echo "$LD" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi -test -z "$LD" && { { $as_echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 -$as_echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} - { (exit 1); exit 1; }; } -{ $as_echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } -if test "${lt_cv_prog_gnu_ld+set}" = set; then +if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. @@ -3534,7 +3725,7 @@ case `$LD -v 2>&1 &5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld @@ -3546,9 +3737,9 @@ with_gnu_ld=$lt_cv_prog_gnu_ld -{ $as_echo "$as_me:$LINENO: checking for BSD- or MS-compatible name lister (nm)" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } -if test "${lt_cv_path_NM+set}" = set; then +if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then @@ -3595,7 +3786,7 @@ else : ${lt_cv_path_NM=no} fi fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" @@ -3606,9 +3797,9 @@ else do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_DUMPBIN+set}" = set; then +if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then @@ -3619,24 +3810,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then - { $as_echo "$as_me:$LINENO: result: $DUMPBIN" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -3650,9 +3841,9 @@ if test -z "$DUMPBIN"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then @@ -3663,24 +3854,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_DUMPBIN" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -3693,12 +3884,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN @@ -3717,44 +3904,44 @@ test -z "$NM" && NM=nm -{ $as_echo "$as_me:$LINENO: checking the name lister ($NM) interface" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } -if test "${lt_cv_nm_interface+set}" = set; then +if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:3727: $ac_compile\"" >&5) + (eval echo "\"\$as_me:3914: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:3730: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:3917: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:3733: output\"" >&5) + (eval echo "\"\$as_me:3920: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_nm_interface" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } -{ $as_echo "$as_me:$LINENO: checking whether ln -s works" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else - { $as_echo "$as_me:$LINENO: result: no, using $LN_S" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments -{ $as_echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } -if test "${lt_cv_sys_max_cmd_len+set}" = set; then +if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 @@ -3872,10 +4059,10 @@ else fi if test -n $lt_cv_sys_max_cmd_len ; then - { $as_echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else - { $as_echo "$as_me:$LINENO: result: none" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len @@ -3889,7 +4076,7 @@ max_cmd_len=$lt_cv_sys_max_cmd_len : ${MV="mv -f"} : ${RM="rm -f"} -{ $as_echo "$as_me:$LINENO: checking whether the shell understands some XSI constructs" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no @@ -3899,17 +4086,17 @@ xsi_shell=no && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes -{ $as_echo "$as_me:$LINENO: result: $xsi_shell" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } -{ $as_echo "$as_me:$LINENO: checking whether the shell understands \"+=\"" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes -{ $as_echo "$as_me:$LINENO: result: $lt_shell_append" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } @@ -3944,14 +4131,14 @@ esac -{ $as_echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } -if test "${lt_cv_ld_reload_flag+set}" = set; then +if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in @@ -3980,9 +4167,9 @@ esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OBJDUMP+set}" = set; then +if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then @@ -3993,24 +4180,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then - { $as_echo "$as_me:$LINENO: result: $OBJDUMP" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4020,9 +4207,9 @@ if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then @@ -4033,24 +4220,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_OBJDUMP" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4059,12 +4246,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP @@ -4083,9 +4266,9 @@ test -z "$OBJDUMP" && OBJDUMP=objdump -{ $as_echo "$as_me:$LINENO: checking how to recognize dependent libraries" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } -if test "${lt_cv_deplibs_check_method+set}" = set; then +if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' @@ -4279,7 +4462,7 @@ tpf*) esac fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method @@ -4299,9 +4482,9 @@ test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AR+set}" = set; then +if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then @@ -4312,24 +4495,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then - { $as_echo "$as_me:$LINENO: result: $AR" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4339,9 +4522,9 @@ if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_AR+set}" = set; then +if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then @@ -4352,24 +4535,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4378,12 +4561,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR @@ -4408,9 +4587,9 @@ test -z "$AR_FLAGS" && AR_FLAGS=cru if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_STRIP+set}" = set; then +if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then @@ -4421,24 +4600,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then - { $as_echo "$as_me:$LINENO: result: $STRIP" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4448,9 +4627,9 @@ if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then @@ -4461,24 +4640,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4487,12 +4666,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP @@ -4511,9 +4686,9 @@ test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_RANLIB+set}" = set; then +if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then @@ -4524,24 +4699,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then - { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4551,9 +4726,9 @@ if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then @@ -4564,24 +4739,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -4590,12 +4765,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB @@ -4672,9 +4843,9 @@ compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. -{ $as_echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } -if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then +if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else @@ -4790,18 +4961,18 @@ void nm_test_func(void){} int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm - if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s "$nlist"; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" @@ -4854,11 +5025,11 @@ _LT_EOF lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" - if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s conftest${ac_exeext}; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" @@ -4892,10 +5063,10 @@ if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - { $as_echo "$as_me:$LINENO: result: failed" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else - { $as_echo "$as_me:$LINENO: result: ok" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi @@ -4922,7 +5093,7 @@ fi # Check whether --enable-libtool-lock was given. -if test "${enable_libtool_lock+set}" = set; then +if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi @@ -4934,11 +5105,11 @@ case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" @@ -4952,12 +5123,12 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 4955 "configure"' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + echo '#line 5126 "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) @@ -4991,11 +5162,11 @@ x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in @@ -5044,9 +5215,9 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" - { $as_echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } -if test "${lt_cv_cc_needs_belf+set}" = set; then +if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c @@ -5055,11 +5226,7 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -5070,38 +5237,13 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - lt_cv_cc_needs_belf=no + lt_cv_cc_needs_belf=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -5109,7 +5251,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf @@ -5119,11 +5261,11 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; } sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in @@ -5149,9 +5291,9 @@ need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_DSYMUTIL+set}" = set; then +if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then @@ -5162,24 +5304,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then - { $as_echo "$as_me:$LINENO: result: $DSYMUTIL" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5189,9 +5331,9 @@ if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then @@ -5202,24 +5344,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_DSYMUTIL" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5228,12 +5370,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL @@ -5245,9 +5383,9 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_NMEDIT+set}" = set; then +if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then @@ -5258,24 +5396,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then - { $as_echo "$as_me:$LINENO: result: $NMEDIT" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5285,9 +5423,9 @@ if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then @@ -5298,24 +5436,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_NMEDIT" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5324,12 +5462,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT @@ -5341,9 +5475,9 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_LIPO+set}" = set; then +if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then @@ -5354,24 +5488,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then - { $as_echo "$as_me:$LINENO: result: $LIPO" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5381,9 +5515,9 @@ if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then @@ -5394,24 +5528,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_LIPO" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5420,12 +5554,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO @@ -5437,9 +5567,9 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OTOOL+set}" = set; then +if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then @@ -5450,24 +5580,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then - { $as_echo "$as_me:$LINENO: result: $OTOOL" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5477,9 +5607,9 @@ if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then @@ -5490,24 +5620,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_OTOOL" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5516,12 +5646,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL @@ -5533,9 +5659,9 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OTOOL64+set}" = set; then +if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then @@ -5546,24 +5672,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then - { $as_echo "$as_me:$LINENO: result: $OTOOL64" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5573,9 +5699,9 @@ if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then @@ -5586,24 +5712,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_OTOOL64" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -5612,12 +5738,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 @@ -5652,9 +5774,9 @@ fi - { $as_echo "$as_me:$LINENO: checking for -single_module linker flag" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } -if test "${lt_cv_apple_cc_single_mod+set}" = set; then +if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no @@ -5679,22 +5801,18 @@ else rm -f conftest.* fi fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_apple_cc_single_mod" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } - { $as_echo "$as_me:$LINENO: checking for -exported_symbols_list linker flag" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } -if test "${lt_cv_ld_exported_symbols_list+set}" = set; then +if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -5705,42 +5823,17 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - lt_cv_ld_exported_symbols_list=no + lt_cv_ld_exported_symbols_list=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_ld_exported_symbols_list" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } case $host_os in rhapsody* | darwin1.[012]) @@ -5782,14 +5875,14 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then - if test "${ac_cv_prog_CPP+set}" = set; then + if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded @@ -5804,11 +5897,7 @@ do # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include @@ -5817,78 +5906,34 @@ cat >>conftest.$ac_ext <<_ACEOF #endif Syntax error _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_c_try_cpp "$LINENO"; then : +else # Broken: fails on valid input. continue fi - -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then +if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - # Passes both tests. ac_preproc_ok=: break fi - -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : break fi @@ -5900,7 +5945,7 @@ fi else ac_cv_prog_CPP=$CPP fi -{ $as_echo "$as_me:$LINENO: result: $CPP" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes @@ -5911,11 +5956,7 @@ do # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include @@ -5924,85 +5965,40 @@ cat >>conftest.$ac_ext <<_ACEOF #endif Syntax error _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_c_try_cpp "$LINENO"; then : +else # Broken: fails on valid input. continue fi - -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then +if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - # Passes both tests. ac_preproc_ok=: break fi - -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then - : +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + else - { { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." >&5 -$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c @@ -6012,16 +6008,12 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -6036,48 +6028,23 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_header_stdc=no + ac_cv_header_stdc=no fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then - : + $EGREP "memchr" >/dev/null 2>&1; then : + else ac_cv_header_stdc=no fi @@ -6087,18 +6054,14 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then - : + $EGREP "free" >/dev/null 2>&1; then : + else ac_cv_header_stdc=no fi @@ -6108,14 +6071,10 @@ fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then + if test "$cross_compiling" = yes; then : : else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -6142,117 +6101,33 @@ main () return 0; } _ACEOF -rm -f conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : +if ac_fn_c_try_run "$LINENO"; then : + else - $as_echo "$as_me: program exited with status $ac_status" >&5 -$as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -ac_cv_header_stdc=no + ac_cv_header_stdc=no fi -rm -rf conftest.dSYM -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext fi - fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then -cat >>confdefs.h <<\_ACEOF -#define STDC_HEADERS 1 -_ACEOF +$as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. - - - - - - - - - for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h -do -as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 -$as_echo_n "checking for $ac_header... " >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - $as_echo_n "(cached) " >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default - -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - eval "$as_ac_Header=yes" -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_Header=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -ac_res=`eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if test `eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` = yes; then +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -6262,61 +6137,13 @@ fi done - for ac_header in dlfcn.h -do -as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 -$as_echo_n "checking for $ac_header... " >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - $as_echo_n "(cached) " >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default - -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - eval "$as_ac_Header=yes" -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_Header=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -ac_res=`eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if test `eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` = yes; then +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define HAVE_DLFCN_H 1 _ACEOF fi @@ -6336,7 +6163,7 @@ done # Check whether --enable-shared was given. -if test "${enable_shared+set}" = set; then +if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; @@ -6367,7 +6194,7 @@ fi # Check whether --enable-static was given. -if test "${enable_static+set}" = set; then +if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; @@ -6399,7 +6226,7 @@ fi # Check whether --with-pic was given. -if test "${with_pic+set}" = set; then +if test "${with_pic+set}" = set; then : withval=$with_pic; pic_mode="$withval" else pic_mode=default @@ -6415,7 +6242,7 @@ test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. -if test "${enable_fast_install+set}" = set; then +if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; @@ -6496,9 +6323,9 @@ if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi -{ $as_echo "$as_me:$LINENO: checking for objdir" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } -if test "${lt_cv_objdir+set}" = set; then +if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null @@ -6511,7 +6338,7 @@ else fi rmdir .libs 2>/dev/null fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir @@ -6604,9 +6431,9 @@ test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then - { $as_echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } -if test "${lt_cv_path_MAGIC_CMD+set}" = set; then +if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in @@ -6657,10 +6484,10 @@ fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then - { $as_echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -6670,9 +6497,9 @@ fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then - { $as_echo "$as_me:$LINENO: checking for file" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } -if test "${lt_cv_path_MAGIC_CMD+set}" = set; then +if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in @@ -6723,10 +6550,10 @@ fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then - { $as_echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -6803,9 +6630,9 @@ lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then lt_prog_compiler_no_builtin_flag=' -fno-builtin' - { $as_echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } -if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no @@ -6821,11 +6648,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6824: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6651: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6828: \$? = $ac_status" >&5 + echo "$as_me:6655: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -6838,7 +6665,7 @@ else $RM conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then @@ -6858,7 +6685,7 @@ fi lt_prog_compiler_pic= lt_prog_compiler_static= -{ $as_echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if test "$GCC" = yes; then @@ -7130,7 +6957,7 @@ case $host_os in lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac -{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 $as_echo "$lt_prog_compiler_pic" >&6; } @@ -7142,9 +6969,9 @@ $as_echo "$lt_prog_compiler_pic" >&6; } # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then - { $as_echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test "${lt_cv_prog_compiler_pic_works+set}" = set; then +if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no @@ -7160,11 +6987,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7163: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6990: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7167: \$? = $ac_status" >&5 + echo "$as_me:6994: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7177,7 +7004,7 @@ else $RM conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_pic_works" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then @@ -7201,9 +7028,9 @@ fi # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ $as_echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test "${lt_cv_prog_compiler_static_works+set}" = set; then +if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no @@ -7229,7 +7056,7 @@ else LDFLAGS="$save_LDFLAGS" fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_static_works" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then @@ -7244,9 +7071,9 @@ fi - { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test "${lt_cv_prog_compiler_c_o+set}" = set; then +if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no @@ -7265,11 +7092,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7268: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7095: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7272: \$? = $ac_status" >&5 + echo "$as_me:7099: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -7291,7 +7118,7 @@ else $RM conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } @@ -7299,9 +7126,9 @@ $as_echo "$lt_cv_prog_compiler_c_o" >&6; } - { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test "${lt_cv_prog_compiler_c_o+set}" = set; then +if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no @@ -7320,11 +7147,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7323: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7150: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7327: \$? = $ac_status" >&5 + echo "$as_me:7154: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -7346,7 +7173,7 @@ else $RM conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } @@ -7355,7 +7182,7 @@ $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user - { $as_echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* @@ -7363,10 +7190,10 @@ $as_echo_n "checking if we can lock with hard links... " >&6; } touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no - { $as_echo "$as_me:$LINENO: result: $hard_links" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then - { $as_echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi @@ -7379,7 +7206,7 @@ fi - { $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= @@ -7821,11 +7648,7 @@ _LT_EOF allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -7836,27 +7659,7 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { @@ -7870,16 +7673,9 @@ aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpat if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" @@ -7892,11 +7688,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi else # Determine the default libpath from the value encoded in an # empty executable. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -7907,27 +7699,7 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { @@ -7941,16 +7713,9 @@ aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpat if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" @@ -8162,42 +7927,16 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi # implicitly export all symbols. save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" - cat >conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ int foo(void) {} _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' @@ -8453,7 +8192,7 @@ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ fi fi -{ $as_echo "$as_me:$LINENO: result: $ld_shlibs" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no @@ -8490,16 +8229,16 @@ x|xyes) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. - { $as_echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } 2>conftest.err; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext @@ -8513,11 +8252,11 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= - if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } then archive_cmds_need_lc=no else @@ -8528,7 +8267,7 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } cat conftest.err 1>&5 fi $RM conftest* - { $as_echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 $as_echo "$archive_cmds_need_lc" >&6; } ;; esac @@ -8692,7 +8431,7 @@ esac - { $as_echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then @@ -9127,11 +8866,7 @@ linux* | k*bsd*-gnu) save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -9142,41 +8877,13 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : shlibpath_overrides_runpath=yes fi - -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir @@ -9388,7 +9095,7 @@ uts4*) dynamic_linker=no ;; esac -{ $as_echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no @@ -9490,7 +9197,7 @@ fi - { $as_echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || @@ -9515,7 +9222,7 @@ else # directories. hardcode_action=unsupported fi -{ $as_echo "$as_me:$LINENO: result: $hardcode_action" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || @@ -9560,18 +9267,14 @@ else darwin*) # if libdl is installed we need to link against it - { $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then +if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -9589,43 +9292,18 @@ return dlopen (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dl_dlopen=no + ac_cv_lib_dl_dlopen=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test $ac_cv_lib_dl_dlopen = yes; then +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else @@ -9638,106 +9316,18 @@ fi ;; *) - { $as_echo "$as_me:$LINENO: checking for shl_load" >&5 -$as_echo_n "checking for shl_load... " >&6; } -if test "${ac_cv_func_shl_load+set}" = set; then - $as_echo_n "(cached) " >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define shl_load to an innocuous variant, in case declares shl_load. - For example, HP-UX 11i declares gettimeofday. */ -#define shl_load innocuous_shl_load - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char shl_load (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef shl_load - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_shl_load || defined __stub___shl_load -choke me -#endif - -int -main () -{ -return shl_load (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then - ac_cv_func_shl_load=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_func_shl_load=no -fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 -$as_echo "$ac_cv_func_shl_load" >&6; } -if test $ac_cv_func_shl_load = yes; then + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else - { $as_echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } -if test "${ac_cv_lib_dld_shl_load+set}" = set; then +if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -9755,145 +9345,32 @@ return shl_load (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dld_shl_load=no + ac_cv_lib_dld_shl_load=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test $ac_cv_lib_dld_shl_load = yes; then +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else - { $as_echo "$as_me:$LINENO: checking for dlopen" >&5 -$as_echo_n "checking for dlopen... " >&6; } -if test "${ac_cv_func_dlopen+set}" = set; then - $as_echo_n "(cached) " >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define dlopen to an innocuous variant, in case declares dlopen. - For example, HP-UX 11i declares gettimeofday. */ -#define dlopen innocuous_dlopen - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char dlopen (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef dlopen - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_dlopen || defined __stub___dlopen -choke me -#endif - -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then - ac_cv_func_dlopen=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_func_dlopen=no -fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 -$as_echo "$ac_cv_func_dlopen" >&6; } -if test $ac_cv_func_dlopen = yes; then + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else - { $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then +if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -9911,57 +9388,28 @@ return dlopen (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dl_dlopen=no + ac_cv_lib_dl_dlopen=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test $ac_cv_lib_dl_dlopen = yes; then +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else - { $as_echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } -if test "${ac_cv_lib_svld_dlopen+set}" = set; then +if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -9979,57 +9427,28 @@ return dlopen (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_svld_dlopen=no + ac_cv_lib_svld_dlopen=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } -if test $ac_cv_lib_svld_dlopen = yes; then +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else - { $as_echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } -if test "${ac_cv_lib_dld_dld_link+set}" = set; then +if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -10047,43 +9466,18 @@ return dld_link (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dld_dld_link=no + ac_cv_lib_dld_dld_link=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } -if test $ac_cv_lib_dld_dld_link = yes; then +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi @@ -10122,9 +9516,9 @@ fi save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" - { $as_echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } -if test "${lt_cv_dlopen_self+set}" = set; then +if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10133,7 +9527,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10136 "configure" +#line 9530 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10192,11 +9586,11 @@ int main () return status; } _LT_EOF - if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in @@ -10213,14 +9607,14 @@ rm -fr conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - { $as_echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } -if test "${lt_cv_dlopen_self_static+set}" = set; then +if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10229,7 +9623,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10232 "configure" +#line 9626 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10288,11 +9682,11 @@ int main () return status; } _LT_EOF - if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in @@ -10309,7 +9703,7 @@ rm -fr conftest* fi -{ $as_echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi @@ -10348,12 +9742,12 @@ fi striplib= old_striplib= -{ $as_echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough @@ -10362,15 +9756,15 @@ else if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac @@ -10388,12 +9782,12 @@ fi # Report which library types will actually be built - { $as_echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } - { $as_echo "$as_me:$LINENO: result: $can_build_shared" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } - { $as_echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no @@ -10414,14 +9808,14 @@ $as_echo_n "checking whether to build shared libraries... " >&6; } fi ;; esac - { $as_echo "$as_me:$LINENO: result: $enable_shared" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } - { $as_echo "$as_me:$LINENO: checking whether to build static libraries" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes - { $as_echo "$as_me:$LINENO: result: $enable_static" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } @@ -10470,10 +9864,10 @@ CC="$lt_save_CC" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if test "${ac_cv_path_install+set}" = set; then +if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10481,11 +9875,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in - ./ | .// | /cC/* | \ + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. @@ -10493,7 +9887,7 @@ case $as_dir/ in # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. @@ -10522,7 +9916,7 @@ case $as_dir/ in ;; esac -done + done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir @@ -10538,7 +9932,7 @@ fi INSTALL=$ac_install_sh fi fi -{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. @@ -10553,9 +9947,9 @@ for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AWK+set}" = set; then +if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then @@ -10566,24 +9960,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then - { $as_echo "$as_me:$LINENO: result: $AWK" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -10596,15 +9990,15 @@ done # Enable large file support (if special flags are necessary) # # Check whether --enable-largefile was given. -if test "${enable_largefile+set}" = set; then +if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then - { $as_echo "$as_me:$LINENO: checking for special C compiler options needed for large files" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } -if test "${ac_cv_sys_largefile_CC+set}" = set; then +if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no @@ -10613,11 +10007,7 @@ else while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. @@ -10636,60 +10026,14 @@ main () return 0; } _ACEOF - rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then + if ac_fn_c_try_compile "$LINENO"; then : break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" - rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then + if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext break done @@ -10697,23 +10041,19 @@ rm -f core conftest.err conftest.$ac_objext rm -f conftest.$ac_ext fi fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_CC" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi - { $as_echo "$as_me:$LINENO: checking for _FILE_OFFSET_BITS value needed for large files" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } -if test "${ac_cv_sys_file_offset_bits+set}" = set; then +if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. @@ -10732,38 +10072,11 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include @@ -10783,38 +10096,15 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_sys_file_offset_bits" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; @@ -10826,17 +10116,13 @@ _ACEOF esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then - { $as_echo "$as_me:$LINENO: checking for _LARGE_FILES value needed for large files" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } -if test "${ac_cv_sys_large_files+set}" = set; then +if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. @@ -10855,38 +10141,11 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include @@ -10906,38 +10165,15 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_sys_large_files" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; @@ -10949,106 +10185,15 @@ _ACEOF esac rm -rf conftest* fi + + fi ######### # Check for needed/wanted data types -{ $as_echo "$as_me:$LINENO: checking for int8_t" >&5 -$as_echo_n "checking for int8_t... " >&6; } -if test "${ac_cv_type_int8_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_int8_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (int8_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((int8_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_int8_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_int8_t" >&5 -$as_echo "$ac_cv_type_int8_t" >&6; } -if test $ac_cv_type_int8_t = yes; then +ac_fn_c_check_type "$LINENO" "int8_t" "ac_cv_type_int8_t" "$ac_includes_default" +if test "x$ac_cv_type_int8_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT8_T 1 @@ -11056,101 +10201,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for int16_t" >&5 -$as_echo_n "checking for int16_t... " >&6; } -if test "${ac_cv_type_int16_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_int16_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (int16_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((int16_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_int16_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_int16_t" >&5 -$as_echo "$ac_cv_type_int16_t" >&6; } -if test $ac_cv_type_int16_t = yes; then +ac_fn_c_check_type "$LINENO" "int16_t" "ac_cv_type_int16_t" "$ac_includes_default" +if test "x$ac_cv_type_int16_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT16_T 1 @@ -11158,101 +10210,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for int32_t" >&5 -$as_echo_n "checking for int32_t... " >&6; } -if test "${ac_cv_type_int32_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_int32_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (int32_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((int32_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_int32_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5 -$as_echo "$ac_cv_type_int32_t" >&6; } -if test $ac_cv_type_int32_t = yes; then +ac_fn_c_check_type "$LINENO" "int32_t" "ac_cv_type_int32_t" "$ac_includes_default" +if test "x$ac_cv_type_int32_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT32_T 1 @@ -11260,101 +10219,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for int64_t" >&5 -$as_echo_n "checking for int64_t... " >&6; } -if test "${ac_cv_type_int64_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_int64_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (int64_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((int64_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_int64_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5 -$as_echo "$ac_cv_type_int64_t" >&6; } -if test $ac_cv_type_int64_t = yes; then +ac_fn_c_check_type "$LINENO" "int64_t" "ac_cv_type_int64_t" "$ac_includes_default" +if test "x$ac_cv_type_int64_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INT64_T 1 @@ -11362,101 +10228,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for intptr_t" >&5 -$as_echo_n "checking for intptr_t... " >&6; } -if test "${ac_cv_type_intptr_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_intptr_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (intptr_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((intptr_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_intptr_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_intptr_t" >&5 -$as_echo "$ac_cv_type_intptr_t" >&6; } -if test $ac_cv_type_intptr_t = yes; then +ac_fn_c_check_type "$LINENO" "intptr_t" "ac_cv_type_intptr_t" "$ac_includes_default" +if test "x$ac_cv_type_intptr_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INTPTR_T 1 @@ -11464,101 +10237,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for uint8_t" >&5 -$as_echo_n "checking for uint8_t... " >&6; } -if test "${ac_cv_type_uint8_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_uint8_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (uint8_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((uint8_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_uint8_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uint8_t" >&5 -$as_echo "$ac_cv_type_uint8_t" >&6; } -if test $ac_cv_type_uint8_t = yes; then +ac_fn_c_check_type "$LINENO" "uint8_t" "ac_cv_type_uint8_t" "$ac_includes_default" +if test "x$ac_cv_type_uint8_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT8_T 1 @@ -11566,101 +10246,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for uint16_t" >&5 -$as_echo_n "checking for uint16_t... " >&6; } -if test "${ac_cv_type_uint16_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_uint16_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (uint16_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((uint16_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_uint16_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uint16_t" >&5 -$as_echo "$ac_cv_type_uint16_t" >&6; } -if test $ac_cv_type_uint16_t = yes; then +ac_fn_c_check_type "$LINENO" "uint16_t" "ac_cv_type_uint16_t" "$ac_includes_default" +if test "x$ac_cv_type_uint16_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT16_T 1 @@ -11668,101 +10255,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for uint32_t" >&5 -$as_echo_n "checking for uint32_t... " >&6; } -if test "${ac_cv_type_uint32_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_uint32_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (uint32_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((uint32_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_uint32_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5 -$as_echo "$ac_cv_type_uint32_t" >&6; } -if test $ac_cv_type_uint32_t = yes; then +ac_fn_c_check_type "$LINENO" "uint32_t" "ac_cv_type_uint32_t" "$ac_includes_default" +if test "x$ac_cv_type_uint32_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT32_T 1 @@ -11770,101 +10264,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for uint64_t" >&5 -$as_echo_n "checking for uint64_t... " >&6; } -if test "${ac_cv_type_uint64_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_uint64_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (uint64_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((uint64_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_uint64_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uint64_t" >&5 -$as_echo "$ac_cv_type_uint64_t" >&6; } -if test $ac_cv_type_uint64_t = yes; then +ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "$ac_includes_default" +if test "x$ac_cv_type_uint64_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT64_T 1 @@ -11872,101 +10273,8 @@ _ACEOF fi -{ $as_echo "$as_me:$LINENO: checking for uintptr_t" >&5 -$as_echo_n "checking for uintptr_t... " >&6; } -if test "${ac_cv_type_uintptr_t+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_type_uintptr_t=no -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof (uintptr_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if (sizeof ((uintptr_t))) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_uintptr_t=yes -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uintptr_t" >&5 -$as_echo "$ac_cv_type_uintptr_t" >&6; } -if test $ac_cv_type_uintptr_t = yes; then +ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "$ac_includes_default" +if test "x$ac_cv_type_uintptr_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINTPTR_T 1 @@ -11978,147 +10286,11 @@ fi ######### # Check for needed/wanted headers - - - - - for ac_header in sys/types.h stdlib.h stdint.h inttypes.h malloc.h -do -as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 -$as_echo_n "checking for $ac_header... " >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - $as_echo_n "(cached) " >&6 -fi -ac_res=`eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 -$as_echo_n "checking $ac_header usability... " >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 -$as_echo_n "checking $ac_header presence... " >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - - ;; -esac -{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 -$as_echo_n "checking for $ac_header... " >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - $as_echo_n "(cached) " >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - -fi -if test `eval 'as_val=${'$as_ac_Header'} - $as_echo "$as_val"'` = yes; then +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -12131,107 +10303,11 @@ done ######### # Figure out whether or not we have these functions # - - - - - - - - - for ac_func in fdatasync gmtime_r isnan localtime_r localtime_s malloc_usable_size strchrnul usleep utime -do -as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 -$as_echo_n "checking for $ac_func... " >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then - $as_echo_n "(cached) " >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - -int -main () -{ -return $ac_func (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then - eval "$as_ac_var=yes" -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_var=no" -fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -ac_res=`eval 'as_val=${'$as_ac_var'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if test `eval 'as_val=${'$as_ac_var'} - $as_echo "$as_val"'` = yes; then +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -12254,9 +10330,9 @@ for ac_prog in tclsh8.6 tclsh8.5 tclsh do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_TCLSH_CMD+set}" = set; then +if ${ac_cv_prog_TCLSH_CMD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$TCLSH_CMD"; then @@ -12267,24 +10343,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_TCLSH_CMD="$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi TCLSH_CMD=$ac_cv_prog_TCLSH_CMD if test -n "$TCLSH_CMD"; then - { $as_echo "$as_me:$LINENO: result: $TCLSH_CMD" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TCLSH_CMD" >&5 $as_echo "$TCLSH_CMD" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -12322,17 +10398,17 @@ fi VERSION=`cat $srcdir/VERSION | sed 's/^\([0-9]*\.*[0-9]*\).*/\1/'` -{ $as_echo "$as_me:$LINENO: Version set to $VERSION" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: Version set to $VERSION" >&5 $as_echo "$as_me: Version set to $VERSION" >&6;} RELEASE=`cat $srcdir/VERSION` -{ $as_echo "$as_me:$LINENO: Release set to $RELEASE" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: Release set to $RELEASE" >&5 $as_echo "$as_me: Release set to $RELEASE" >&6;} VERSION_NUMBER=`cat $srcdir/VERSION \ | sed 's/[^0-9]/ /g' \ | awk '{printf "%d%03d%03d",$1,$2,$3}'` -{ $as_echo "$as_me:$LINENO: Version number set to $VERSION_NUMBER" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: Version number set to $VERSION_NUMBER" >&5 $as_echo "$as_me: Version number set to $VERSION_NUMBER" >&6;} @@ -12349,9 +10425,9 @@ else do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_BUILD_CC+set}" = set; then +if ${ac_cv_prog_BUILD_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$BUILD_CC"; then @@ -12362,24 +10438,24 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_BUILD_CC="$ac_prog" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi BUILD_CC=$ac_cv_prog_BUILD_CC if test -n "$BUILD_CC"; then - { $as_echo "$as_me:$LINENO: result: $BUILD_CC" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_CC" >&5 $as_echo "$BUILD_CC" >&6; } else - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -12398,37 +10474,33 @@ fi # Do we want to support multithreaded use of sqlite # # Check whether --enable-threadsafe was given. -if test "${enable_threadsafe+set}" = set; then +if test "${enable_threadsafe+set}" = set; then : enableval=$enable_threadsafe; else enable_threadsafe=yes fi -{ $as_echo "$as_me:$LINENO: checking whether to support threadsafe operation" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support threadsafe operation" >&5 $as_echo_n "checking whether to support threadsafe operation... " >&6; } if test "$enable_threadsafe" = "no"; then SQLITE_THREADSAFE=0 - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else SQLITE_THREADSAFE=1 - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi if test "$SQLITE_THREADSAFE" = "1"; then - { $as_echo "$as_me:$LINENO: checking for library containing pthread_create" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5 $as_echo_n "checking for library containing pthread_create... " >&6; } -if test "${ac_cv_search_pthread_create+set}" = set; then +if ${ac_cv_search_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -12453,54 +10525,27 @@ for ac_lib in '' pthread; do ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then + if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_pthread_create=$ac_res -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext - if test "${ac_cv_search_pthread_create+set}" = set; then +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_pthread_create+:} false; then : break fi done -if test "${ac_cv_search_pthread_create+set}" = set; then - : +if ${ac_cv_search_pthread_create+:} false; then : + else ac_cv_search_pthread_create=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_pthread_create" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5 $as_echo "$ac_cv_search_pthread_create" >&6; } ac_res=$ac_cv_search_pthread_create -if test "$ac_res" != no; then +if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi @@ -12511,21 +10556,21 @@ fi # Do we want to support release # # Check whether --enable-releasemode was given. -if test "${enable_releasemode+set}" = set; then +if test "${enable_releasemode+set}" = set; then : enableval=$enable_releasemode; else enable_releasemode=no fi -{ $as_echo "$as_me:$LINENO: checking whether to support shared library linked as release mode or not" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support shared library linked as release mode or not" >&5 $as_echo_n "checking whether to support shared library linked as release mode or not... " >&6; } if test "$enable_releasemode" = "no"; then ALLOWRELEASE="" - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else ALLOWRELEASE="-release `cat $srcdir/VERSION`" - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi @@ -12534,38 +10579,38 @@ fi # Do we want temporary databases in memory # # Check whether --enable-tempstore was given. -if test "${enable_tempstore+set}" = set; then +if test "${enable_tempstore+set}" = set; then : enableval=$enable_tempstore; else enable_tempstore=no fi -{ $as_echo "$as_me:$LINENO: checking whether to use an in-ram database for temporary tables" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use an in-ram database for temporary tables" >&5 $as_echo_n "checking whether to use an in-ram database for temporary tables... " >&6; } case "$enable_tempstore" in never ) TEMP_STORE=0 - { $as_echo "$as_me:$LINENO: result: never" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: never" >&5 $as_echo "never" >&6; } ;; no ) TEMP_STORE=1 - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; yes ) TEMP_STORE=2 - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } ;; always ) TEMP_STORE=3 - { $as_echo "$as_me:$LINENO: result: always" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: always" >&5 $as_echo "always" >&6; } ;; * ) TEMP_STORE=1 - { $as_echo "$as_me:$LINENO: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac @@ -12577,53 +10622,17 @@ esac # the CYGWIN environment. So check for that special case and handle # things accordingly. # -{ $as_echo "$as_me:$LINENO: checking if executables have the .exe suffix" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if executables have the .exe suffix" >&5 $as_echo_n "checking if executables have the .exe suffix... " >&6; } if test "$config_BUILD_EXEEXT" = ".exe"; then CYGWIN=yes - { $as_echo "$as_me:$LINENO: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else - { $as_echo "$as_me:$LINENO: result: unknown" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unknown" >&5 $as_echo "unknown" >&6; } fi if test "$CYGWIN" != "yes"; then - { $as_echo "$as_me:$LINENO: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if test "${ac_cv_host+set}" = set; then - $as_echo_n "(cached) " >&6 -else - if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 -$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} - { (exit 1); exit 1; }; } -fi - -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 -$as_echo "$as_me: error: invalid value of canonical host" >&2;} - { (exit 1); exit 1; }; };; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac - case $host_os in *cygwin* ) CYGWIN=yes;; @@ -12665,7 +10674,7 @@ fi # minor changes to accomodate systems that do not have TCL installed. # # Check whether --enable-tcl was given. -if test "${enable_tcl+set}" = set; then +if test "${enable_tcl+set}" = set; then : enableval=$enable_tcl; use_tcl=$enableval else use_tcl=yes @@ -12674,13 +10683,13 @@ fi if test "${use_tcl}" = "yes" ; then # Check whether --with-tcl was given. -if test "${with_tcl+set}" = set; then +if test "${with_tcl+set}" = set; then : withval=$with_tcl; with_tclconfig=${withval} fi - { $as_echo "$as_me:$LINENO: checking for Tcl configuration" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5 $as_echo_n "checking for Tcl configuration... " >&6; } - if test "${ac_cv_c_tclconfig+set}" = set; then + if ${ac_cv_c_tclconfig+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12689,9 +10698,7 @@ else if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` else - { { $as_echo "$as_me:$LINENO: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&5 -$as_echo "$as_me: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5 fi fi @@ -12766,25 +10773,25 @@ fi if test x"${ac_cv_c_tclconfig}" = x ; then use_tcl=no - { $as_echo "$as_me:$LINENO: WARNING: Can't find Tcl configuration definitions" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can't find Tcl configuration definitions" >&5 $as_echo "$as_me: WARNING: Can't find Tcl configuration definitions" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&5 $as_echo "$as_me: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&5 $as_echo "$as_me: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&2;} else TCL_BIN_DIR=${ac_cv_c_tclconfig} - { $as_echo "$as_me:$LINENO: result: found $TCL_BIN_DIR/tclConfig.sh" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found $TCL_BIN_DIR/tclConfig.sh" >&5 $as_echo "found $TCL_BIN_DIR/tclConfig.sh" >&6; } - { $as_echo "$as_me:$LINENO: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5 $as_echo_n "checking for existence of $TCL_BIN_DIR/tclConfig.sh... " >&6; } if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then - { $as_echo "$as_me:$LINENO: result: loading" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5 $as_echo "loading" >&6; } . $TCL_BIN_DIR/tclConfig.sh else - { $as_echo "$as_me:$LINENO: result: file not found" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: file not found" >&5 $as_echo "file not found" >&6; } fi @@ -12827,6 +10834,7 @@ $as_echo "file not found" >&6; } + fi fi if test "${use_tcl}" = "no" ; then @@ -12844,7 +10852,7 @@ TARGET_READLINE_LIBS="" TARGET_READLINE_INC="" TARGET_HAVE_READLINE=0 # Check whether --enable-readline was given. -if test "${enable_readline+set}" = set; then +if test "${enable_readline+set}" = set; then : enableval=$enable_readline; with_readline=$enableval else with_readline=auto @@ -12856,7 +10864,7 @@ if test x"$with_readline" != xno; then # Check whether --with-readline-lib was given. -if test "${with_readline_lib+set}" = set; then +if test "${with_readline_lib+set}" = set; then : withval=$with_readline_lib; with_readline_lib=$withval else with_readline_lib="auto" @@ -12865,17 +10873,13 @@ fi if test "x$with_readline_lib" = xauto; then save_LIBS="$LIBS" LIBS="" - { $as_echo "$as_me:$LINENO: checking for library containing tgetent" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5 $as_echo_n "checking for library containing tgetent... " >&6; } -if test "${ac_cv_search_tgetent+set}" = set; then +if ${ac_cv_search_tgetent+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -12900,72 +10904,41 @@ for ac_lib in '' readline ncurses curses termcap; do ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then + if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_tgetent=$ac_res -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext - if test "${ac_cv_search_tgetent+set}" = set; then +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_tgetent+:} false; then : break fi done -if test "${ac_cv_search_tgetent+set}" = set; then - : +if ${ac_cv_search_tgetent+:} false; then : + else ac_cv_search_tgetent=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_tgetent" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetent" >&5 $as_echo "$ac_cv_search_tgetent" >&6; } ac_res=$ac_cv_search_tgetent -if test "$ac_res" != no; then +if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" term_LIBS="$LIBS" else term_LIBS="" fi - { $as_echo "$as_me:$LINENO: checking for readline in -lreadline" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5 $as_echo_n "checking for readline in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_readline+set}" = set; then +if ${ac_cv_lib_readline_readline+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -12983,43 +10956,18 @@ return readline (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_readline_readline=yes else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_readline_readline=no + ac_cv_lib_readline_readline=no fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_readline_readline" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5 $as_echo "$ac_cv_lib_readline_readline" >&6; } -if test $ac_cv_lib_readline_readline = yes; then +if test "x$ac_cv_lib_readline_readline" = xyes; then : TARGET_READLINE_LIBS="-lreadline" else found="no" @@ -13033,141 +10981,15 @@ fi # Check whether --with-readline-inc was given. -if test "${with_readline_inc+set}" = set; then +if test "${with_readline_inc+set}" = set; then : withval=$with_readline_inc; with_readline_inc=$withval else with_readline_inc="auto" fi if test "x$with_readline_inc" = xauto; then - if test "${ac_cv_header_readline_h+set}" = set; then - { $as_echo "$as_me:$LINENO: checking for readline.h" >&5 -$as_echo_n "checking for readline.h... " >&6; } -if test "${ac_cv_header_readline_h+set}" = set; then - $as_echo_n "(cached) " >&6 -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_readline_h" >&5 -$as_echo "$ac_cv_header_readline_h" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:$LINENO: checking readline.h usability" >&5 -$as_echo_n "checking readline.h usability... " >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:$LINENO: checking readline.h presence" >&5 -$as_echo_n "checking readline.h presence... " >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { $as_echo "$as_me:$LINENO: WARNING: readline.h: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: readline.h: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: readline.h: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { $as_echo "$as_me:$LINENO: WARNING: readline.h: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: readline.h: present but cannot be compiled" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: readline.h: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: readline.h: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: readline.h: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: proceeding with the preprocessor's result" >&5 -$as_echo "$as_me: WARNING: readline.h: proceeding with the preprocessor's result" >&2;} - { $as_echo "$as_me:$LINENO: WARNING: readline.h: in the future, the compiler will take precedence" >&5 -$as_echo "$as_me: WARNING: readline.h: in the future, the compiler will take precedence" >&2;} - - ;; -esac -{ $as_echo "$as_me:$LINENO: checking for readline.h" >&5 -$as_echo_n "checking for readline.h... " >&6; } -if test "${ac_cv_header_readline_h+set}" = set; then - $as_echo_n "(cached) " >&6 -else - ac_cv_header_readline_h=$ac_header_preproc -fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_readline_h" >&5 -$as_echo "$ac_cv_header_readline_h" >&6; } - -fi -if test $ac_cv_header_readline_h = yes; then + ac_fn_c_check_header_mongrel "$LINENO" "readline.h" "ac_cv_header_readline_h" "$ac_includes_default" +if test "x$ac_cv_header_readline_h" = xyes; then : found="yes" else @@ -13176,27 +10998,23 @@ else for dir in /usr /usr/local /usr/local/readline /usr/contrib /mingw; do for subdir in include include/readline; do as_ac_File=`$as_echo "ac_cv_file_$dir/$subdir/readline.h" | $as_tr_sh` -{ $as_echo "$as_me:$LINENO: checking for $dir/$subdir/readline.h" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $dir/$subdir/readline.h" >&5 $as_echo_n "checking for $dir/$subdir/readline.h... " >&6; } -if { as_var=$as_ac_File; eval "test \"\${$as_var+set}\" = set"; }; then +if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && - { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 -$as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "$dir/$subdir/readline.h"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi -ac_res=`eval 'as_val=${'$as_ac_File'} - $as_echo "$as_val"'` - { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +eval ac_res=\$$as_ac_File + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } -if test `eval 'as_val=${'$as_ac_File'} - $as_echo "$as_val"'` = yes; then +if eval test \"x\$"$as_ac_File"\" = x"yes"; then : found=yes fi @@ -13233,17 +11051,13 @@ fi # Figure out what C libraries are required to compile programs # that use "fdatasync()" function. # -{ $as_echo "$as_me:$LINENO: checking for library containing fdatasync" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fdatasync" >&5 $as_echo_n "checking for library containing fdatasync... " >&6; } -if test "${ac_cv_search_fdatasync+set}" = set; then +if ${ac_cv_search_fdatasync+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -13268,54 +11082,27 @@ for ac_lib in '' rt; do ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then + if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_fdatasync=$ac_res -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext - if test "${ac_cv_search_fdatasync+set}" = set; then +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_fdatasync+:} false; then : break fi done -if test "${ac_cv_search_fdatasync+set}" = set; then - : +if ${ac_cv_search_fdatasync+:} false; then : + else ac_cv_search_fdatasync=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_fdatasync" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fdatasync" >&5 $as_echo "$ac_cv_search_fdatasync" >&6; } ac_res=$ac_cv_search_fdatasync -if test "$ac_res" != no; then +if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi @@ -13324,7 +11111,7 @@ fi ######### # check for debug enabled # Check whether --enable-debug was given. -if test "${enable_debug+set}" = set; then +if test "${enable_debug+set}" = set; then : enableval=$enable_debug; use_debug=$enableval else use_debug=no @@ -13340,7 +11127,7 @@ fi ######### # See whether we should use the amalgamation to build # Check whether --enable-amalgamation was given. -if test "${enable_amalgamation+set}" = set; then +if test "${enable_amalgamation+set}" = set; then : enableval=$enable_amalgamation; use_amalgamation=$enableval else use_amalgamation=yes @@ -13354,7 +11141,7 @@ fi ######### # See whether we should allow loadable extensions # Check whether --enable-load-extension was given. -if test "${enable_load_extension+set}" = set; then +if test "${enable_load_extension+set}" = set; then : enableval=$enable_load_extension; use_loadextension=$enableval else use_loadextension=yes @@ -13362,17 +11149,13 @@ fi if test "${use_loadextension}" = "yes" ; then OPT_FEATURE_FLAGS="" - { $as_echo "$as_me:$LINENO: checking for library containing dlopen" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 $as_echo_n "checking for library containing dlopen... " >&6; } -if test "${ac_cv_search_dlopen+set}" = set; then +if ${ac_cv_search_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -13397,54 +11180,27 @@ for ac_lib in '' dl; do ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" -$as_echo "$ac_try_echo") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then + if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_dlopen=$ac_res -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - -rm -rf conftest.dSYM -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext - if test "${ac_cv_search_dlopen+set}" = set; then +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_dlopen+:} false; then : break fi done -if test "${ac_cv_search_dlopen+set}" = set; then - : +if ${ac_cv_search_dlopen+:} false; then : + else ac_cv_search_dlopen=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_dlopen" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 $as_echo "$ac_cv_search_dlopen" >&6; } ac_res=$ac_cv_search_dlopen -if test "$ac_res" != no; then +if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi @@ -13507,7 +11263,7 @@ BUILD_CFLAGS=$ac_temp_BUILD_CFLAGS ######### # See whether we should use GCOV # Check whether --enable-gcov was given. -if test "${enable_gcov+set}" = set; then +if test "${enable_gcov+set}" = set; then : enableval=$enable_gcov; use_gcov=$enableval else use_gcov=no @@ -13559,13 +11315,13 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 -$as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) $as_unset $ac_var ;; + *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done @@ -13573,8 +11329,8 @@ $as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes (double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \). + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" @@ -13596,12 +11352,23 @@ $as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then - test "x$cache_file" != "x/dev/null" && - { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5 + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} - cat confcache >$cache_file + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi else - { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi @@ -13615,14 +11382,15 @@ DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= +U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. - ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" - ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs @@ -13630,13 +11398,14 @@ LTLIBOBJS=$ac_ltlibobjs -: ${CONFIG_STATUS=./config.status} +: "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. @@ -13646,17 +11415,18 @@ cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 debug=false ac_cs_recheck=false ac_cs_silent=false -SHELL=\${CONFIG_SHELL-$SHELL} -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -## --------------------- ## -## M4sh Initialization. ## -## --------------------- ## +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which @@ -13664,23 +11434,15 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; esac - fi - - -# PATH needs CR -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - as_nl=' ' export as_nl @@ -13688,7 +11450,13 @@ export as_nl as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else @@ -13699,7 +11467,7 @@ else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; - case $arg in + case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; @@ -13722,13 +11490,6 @@ if test "${PATH_SEPARATOR+set}" != set; then } fi -# Support unset when possible. -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - as_unset=unset -else - as_unset=false -fi - # IFS # We need space, tab and new line, in precisely that order. Quoting is @@ -13738,15 +11499,16 @@ fi IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. -case $0 in +as_myself= +case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break -done + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done IFS=$as_save_IFS ;; @@ -13758,12 +11520,16 @@ if test "x$as_myself" = x; then fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - { (exit 1); exit 1; } + exit 1 fi -# Work around bugs in pre-3.0 UWIN ksh. -for as_var in ENV MAIL MAILPATH -do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' @@ -13775,7 +11541,89 @@ export LC_ALL LANGUAGE=C export LANGUAGE -# Required to use basename. +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr @@ -13789,8 +11637,12 @@ else as_basename=false fi +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi -# Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ @@ -13810,76 +11662,25 @@ $as_echo X/"$0" | } s/.*/./; q'` -# CDPATH. -$as_unset CDPATH - - - - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { - - # Create $as_me.lineno as a copy of $as_myself, but with $LINENO - # uniformly replaced by the line number. The first 'sed' inserts a - # line-number line after each line using $LINENO; the second 'sed' - # does the real work. The second script uses 'N' to pair each - # line-number line with the line containing $LINENO, and appends - # trailing '-' during substitution so that $LINENO is not a special - # case at line end. - # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the - # scripts with optimization help from Paolo Bonzini. Blame Lee - # E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 - { (exit 1); exit 1; }; } - - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in +case `echo -n x` in #((((( -n*) - case `echo 'x\c'` in + case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. - *) ECHO_C='\c';; + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then @@ -13894,49 +11695,85 @@ if (echo >conf$$.file) 2>/dev/null; then # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then - as_mkdir_p=: + as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -13946,13 +11783,19 @@ as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 -# Save the log message, to keep $[0] and so on meaningful, and to +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to # 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.8.8.3, which was -generated by GNU Autoconf 2.62. Invocation command line was +This file was extended by sqlite $as_me 3.8.10.2, which was +generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -13965,6 +11808,15 @@ on `(hostname || uname -n) 2>/dev/null | sed 1q` _ACEOF +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" @@ -13975,19 +11827,22 @@ _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ -\`$as_me' instantiates files from templates according to the -current configuration. +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. -Usage: $0 [OPTIONS] [FILE]... +Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit - -q, --quiet do not print progress messages + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] + --file=FILE[:TEMPLATE] instantiate the configuration file FILE - --header=FILE[:TEMPLATE] + --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: @@ -13999,16 +11854,17 @@ $config_headers Configuration commands: $config_commands -Report bugs to ." +Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -sqlite config.status 3.8.8.3 -configured by $0, generated by GNU Autoconf 2.62, - with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" +sqlite config.status 3.8.10.2 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" -Copyright (C) 2008 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -14025,11 +11881,16 @@ ac_need_defaults=: while test $# != 0 do case $1 in - --*=*) + --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; *) ac_option=$1 ac_optarg=$2 @@ -14043,27 +11904,29 @@ do ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; esac - CONFIG_FILES="$CONFIG_FILES '$ac_optarg'" + as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac - CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'" + as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header - { $as_echo "$as_me: error: ambiguous option: $1 -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; };; + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ @@ -14071,11 +11934,10 @@ Try \`$0 --help' for more information." >&2 ac_cs_silent=: ;; # This is an error. - -*) { $as_echo "$as_me: error: unrecognized option: $1 -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; } ;; + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; - *) ac_config_targets="$ac_config_targets $1" + *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac @@ -14092,7 +11954,7 @@ fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then - set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' @@ -14385,9 +12247,7 @@ do "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "sqlite3.pc") CONFIG_FILES="$CONFIG_FILES sqlite3.pc" ;; - *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 -$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;} - { (exit 1); exit 1; }; };; + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done @@ -14410,26 +12270,24 @@ fi # after its creation but before its name has been assigned to `$tmp'. $debug || { - tmp= + tmp= ac_tmp= trap 'exit_status=$? - { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 - trap '{ (exit 1); exit 1; }' 1 2 13 15 + trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -n "$tmp" && test -d "$tmp" + test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") -} || -{ - $as_echo "$as_me: cannot create a temporary directory in ." >&2 - { (exit 1); exit 1; } -} +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. @@ -14437,7 +12295,13 @@ $debug || if test -n "$CONFIG_FILES"; then -ac_cr=' ' +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' @@ -14445,7 +12309,7 @@ else ac_cs_awk_cr=$ac_cr fi -echo 'BEGIN {' >"$tmp/subs1.awk" && +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF @@ -14454,23 +12318,18 @@ _ACEOF echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || - { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} - { (exit 1); exit 1; }; } -ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || - { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` = $ac_delim_num; then + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then - { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi @@ -14478,7 +12337,7 @@ done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h @@ -14492,7 +12351,7 @@ s/'"$ac_delim"'$// t delim :nl h -s/\(.\{148\}\).*/\1/ +s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p @@ -14506,7 +12365,7 @@ s/.\{148\}// t nl :delim h -s/\(.\{148\}\).*/\1/ +s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p @@ -14526,7 +12385,7 @@ t delim rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK -cat >>"\$tmp/subs1.awk" <<_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" @@ -14558,23 +12417,29 @@ if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat -fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ - || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5 -$as_echo "$as_me: error: could not setup config files machinery" >&2;} - { (exit 1); exit 1; }; } +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF -# VPATH may cause trouble with some makes, so we remove $(srcdir), -# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=/{ -s/:*\$(srcdir):*/:/ -s/:*\${srcdir}:*/:/ -s/:*@srcdir@:*/:/ -s/^\([^=]*=[ ]*\):*/\1/ + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// s/^[^=]*=[ ]*$// }' fi @@ -14586,7 +12451,7 @@ fi # test -n "$CONFIG_FILES" # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then -cat >"$tmp/defines.awk" <<\_ACAWK || +cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF @@ -14598,13 +12463,11 @@ _ACEOF # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do - ac_t=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_t"; then + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then break elif $ac_last_try; then - { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5 -$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi @@ -14670,9 +12533,9 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 } split(mac1, mac2, "(") #) macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". - prefix = substr(line, 1, index(line, defundef) - 1) print prefix "define", macro P[macro] D[macro] next } else { @@ -14680,7 +12543,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { - print "/*", line, "*/" + print "/*", prefix defundef, macro, "*/" next } } @@ -14689,9 +12552,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5 -$as_echo "$as_me: error: could not setup config headers machinery" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" @@ -14704,9 +12565,7 @@ do esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 -$as_echo "$as_me: error: Invalid tag $ac_tag." >&2;} - { (exit 1); exit 1; }; };; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -14725,7 +12584,7 @@ $as_echo "$as_me: error: Invalid tag $ac_tag." >&2;} for ac_f do case $ac_f in - -) ac_f="$tmp/stdin";; + -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. @@ -14734,12 +12593,10 @@ $as_echo "$as_me: error: Invalid tag $ac_tag." >&2;} [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 -$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} - { (exit 1); exit 1; }; };; + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - ac_file_inputs="$ac_file_inputs '$ac_f'" + as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't @@ -14750,7 +12607,7 @@ $as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:$LINENO: creating $ac_file" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. @@ -14762,10 +12619,8 @@ $as_echo "$as_me: creating $ac_file" >&6;} esac case $ac_tag in - *:-:* | *:-) cat >"$tmp/stdin" \ - || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 -$as_echo "$as_me: error: could not create $ac_file" >&2;} - { (exit 1); exit 1; }; } ;; + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -14793,47 +12648,7 @@ $as_echo X"$ac_file" | q } s/.*/./; q'` - { as_dir="$ac_dir" - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 -$as_echo "$as_me: error: cannot create directory $as_dir" >&2;} - { (exit 1); exit 1; }; }; } + as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in @@ -14885,7 +12700,6 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= - ac_sed_dataroot=' /datarootdir/ { p @@ -14895,12 +12709,11 @@ ac_sed_dataroot=' /@docdir@/p /@infodir@/p /@localedir@/p -/@mandir@/p -' +/@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 @@ -14910,7 +12723,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; + s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF @@ -14937,27 +12750,24 @@ s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ - || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 -$as_echo "$as_me: error: could not create $ac_file" >&2;} - { (exit 1); exit 1; }; } +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&5 + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&2;} +which seems to be undefined. Please make sure it is defined" >&2;} - rm -f "$tmp/stdin" + rm -f "$ac_tmp/stdin" case $ac_file in - -) cat "$tmp/out" && rm -f "$tmp/out";; - *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ - || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 -$as_echo "$as_me: error: could not create $ac_file" >&2;} - { (exit 1); exit 1; }; } + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # @@ -14966,31 +12776,25 @@ $as_echo "$as_me: error: could not create $ac_file" >&2;} if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" - } >"$tmp/config.h" \ - || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 -$as_echo "$as_me: error: could not create $ac_file" >&2;} - { (exit 1); exit 1; }; } - if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5 + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" - mv "$tmp/config.h" "$ac_file" \ - || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 -$as_echo "$as_me: error: could not create $ac_file" >&2;} - { (exit 1); exit 1; }; } + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ - || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5 -$as_echo "$as_me: error: could not create -" >&2;} - { (exit 1); exit 1; }; } + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; - :C) { $as_echo "$as_me:$LINENO: executing $ac_file commands" >&5 + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac @@ -15637,15 +13441,12 @@ _LT_EOF done # for ac_tag -{ (exit 0); exit 0; } +as_fn_exit 0 _ACEOF -chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || - { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;} - { (exit 1); exit 1; }; } + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. @@ -15666,10 +13467,10 @@ if test "$no_create" != yes; then exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. - $ac_cs_success || { (exit 1); exit 1; } + $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:$LINENO: WARNING: Unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: Unrecognized options: $ac_unrecognized_opts" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi diff --git a/configure.ac b/configure.ac index 00ecf45..6a11888 100644 --- a/configure.ac +++ b/configure.ac @@ -430,6 +430,7 @@ if test "${use_tcl}" = "yes" ; then AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) + AC_SUBST(TCL_SHLIB_SUFFIX) fi fi if test "${use_tcl}" = "no" ; then diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index ec9f0d3..e7958d9 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -313,6 +313,13 @@ static int fts3EvalStart(Fts3Cursor *pCsr); static int fts3TermSegReaderCursor( Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **); +#ifndef SQLITE_AMALGAMATION +# if defined(SQLITE_DEBUG) +int sqlite3Fts3Always(int b) { assert( b ); return b; } +int sqlite3Fts3Never(int b) { assert( !b ); return b; } +# endif +#endif + /* ** Write a 64-bit variable-length integer to memory starting at p[0]. ** The length of data written will be between 1 and FTS3_VARINT_MAX bytes. @@ -422,7 +429,7 @@ void sqlite3Fts3Dequote(char *z){ /* If the first byte was a '[', then the close-quote character is a ']' */ if( quote=='[' ) quote = ']'; - while( ALWAYS(z[iIn]) ){ + while( z[iIn] ){ if( z[iIn]==quote ){ if( z[iIn+1]!=quote ) break; z[iOut++] = quote; @@ -501,6 +508,17 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){ return SQLITE_OK; } +/* +** Write an error message into *pzErr +*/ +void sqlite3Fts3ErrMsg(char **pzErr, const char *zFormat, ...){ + va_list ap; + sqlite3_free(*pzErr); + va_start(ap, zFormat); + *pzErr = sqlite3_vmprintf(zFormat, ap); + va_end(ap); +} + /* ** Construct one or more SQL statements from the format string given ** and then evaluate those statements. The success code is written @@ -910,11 +928,16 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){ ** This function is used when parsing the "prefix=" FTS4 parameter. */ static int fts3GobbleInt(const char **pp, int *pnOut){ + const int MAX_NPREFIX = 10000000; const char *p; /* Iterator pointer */ int nInt = 0; /* Output value */ for(p=*pp; p[0]>='0' && p[0]<='9'; p++){ nInt = nInt * 10 + (p[0] - '0'); + if( nInt>MAX_NPREFIX ){ + nInt = 0; + break; + } } if( p==*pp ) return SQLITE_ERROR; *pnOut = nInt; @@ -957,7 +980,6 @@ static int fts3PrefixParameter( aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex); *apIndex = aIndex; - *pnIndex = nIndex; if( !aIndex ){ return SQLITE_NOMEM; } @@ -967,13 +989,20 @@ static int fts3PrefixParameter( const char *p = zParam; int i; for(i=1; i=0 ); + if( nPrefix==0 ){ + nIndex--; + i--; + }else{ + aIndex[i].nPrefix = nPrefix; + } p++; } } + *pnIndex = nIndex; return SQLITE_OK; } @@ -1008,7 +1037,8 @@ static int fts3ContentColumns( const char *zTbl, /* Name of content table */ const char ***pazCol, /* OUT: Malloc'd array of column names */ int *pnCol, /* OUT: Size of array *pazCol */ - int *pnStr /* OUT: Bytes of string content */ + int *pnStr, /* OUT: Bytes of string content */ + char **pzErr /* OUT: error message */ ){ int rc = SQLITE_OK; /* Return code */ char *zSql; /* "SELECT *" statement on zTbl */ @@ -1019,6 +1049,9 @@ static int fts3ContentColumns( rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ){ + sqlite3Fts3ErrMsg(pzErr, "%s", sqlite3_errmsg(db)); + } } sqlite3_free(zSql); @@ -1097,7 +1130,7 @@ static int fts3InitVtab( const char **aCol; /* Array of column names */ sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */ - int nIndex; /* Size of aIndex[] array */ + int nIndex = 0; /* Size of aIndex[] array */ struct Fts3Index *aIndex = 0; /* Array of indexes for this table */ /* The results of parsing supported FTS4 key=value options: */ @@ -1185,13 +1218,13 @@ static int fts3InitVtab( } } if( iOpt==SizeofArray(aFts4Opt) ){ - *pzErr = sqlite3_mprintf("unrecognized parameter: %s", z); + sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z); rc = SQLITE_ERROR; }else{ switch( iOpt ){ case 0: /* MATCHINFO */ if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){ - *pzErr = sqlite3_mprintf("unrecognized matchinfo: %s", zVal); + sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal); rc = SQLITE_ERROR; } bNoDocsize = 1; @@ -1219,7 +1252,7 @@ static int fts3InitVtab( if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) ){ - *pzErr = sqlite3_mprintf("unrecognized order: %s", zVal); + sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal); rc = SQLITE_ERROR; } bDescIdx = (zVal[0]=='d' || zVal[0]=='D'); @@ -1270,7 +1303,7 @@ static int fts3InitVtab( if( nCol==0 ){ sqlite3_free((void*)aCol); aCol = 0; - rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString); + rc = fts3ContentColumns(db, argv[1], zContent,&aCol,&nCol,&nString,pzErr); /* If a languageid= option was specified, remove the language id ** column from the aCol[] array. */ @@ -1305,7 +1338,7 @@ static int fts3InitVtab( rc = fts3PrefixParameter(zPrefix, &nIndex, &aIndex); if( rc==SQLITE_ERROR ){ assert( zPrefix ); - *pzErr = sqlite3_mprintf("error parsing prefix parameter: %s", zPrefix); + sqlite3Fts3ErrMsg(pzErr, "error parsing prefix parameter: %s", zPrefix); } if( rc!=SQLITE_OK ) goto fts3_init_out; @@ -1387,7 +1420,7 @@ static int fts3InitVtab( } for(i=0; izReadExprlist = fts3ReadExprList(p, zUncompress, &rc); p->zWriteExprlist = fts3WriteExprList(p, zCompress, &rc); @@ -2491,26 +2524,33 @@ static int fts3DoclistOrMerge( ** ** The right-hand input doclist is overwritten by this function. */ -static void fts3DoclistPhraseMerge( +static int fts3DoclistPhraseMerge( int bDescDoclist, /* True if arguments are desc */ int nDist, /* Distance from left to right (1=adjacent) */ char *aLeft, int nLeft, /* Left doclist */ - char *aRight, int *pnRight /* IN/OUT: Right/output doclist */ + char **paRight, int *pnRight /* IN/OUT: Right/output doclist */ ){ sqlite3_int64 i1 = 0; sqlite3_int64 i2 = 0; sqlite3_int64 iPrev = 0; + char *aRight = *paRight; char *pEnd1 = &aLeft[nLeft]; char *pEnd2 = &aRight[*pnRight]; char *p1 = aLeft; char *p2 = aRight; char *p; int bFirstOut = 0; - char *aOut = aRight; + char *aOut; assert( nDist>0 ); - + if( bDescDoclist ){ + aOut = sqlite3_malloc(*pnRight + FTS3_VARINT_MAX); + if( aOut==0 ) return SQLITE_NOMEM; + }else{ + aOut = aRight; + } p = aOut; + fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); @@ -2539,6 +2579,12 @@ static void fts3DoclistPhraseMerge( } *pnRight = (int)(p - aOut); + if( bDescDoclist ){ + sqlite3_free(aRight); + *paRight = aOut; + } + + return SQLITE_OK; } /* @@ -2663,8 +2709,22 @@ static int fts3TermSelectMerge( ){ if( pTS->aaOutput[0]==0 ){ /* If this is the first term selected, copy the doclist to the output - ** buffer using memcpy(). */ - pTS->aaOutput[0] = sqlite3_malloc(nDoclist); + ** buffer using memcpy(). + ** + ** Add FTS3_VARINT_MAX bytes of unused space to the end of the + ** allocation. This is so as to ensure that the buffer is big enough + ** to hold the current doclist AND'd with any other doclist. If the + ** doclists are stored in order=ASC order, this padding would not be + ** required (since the size of [doclistA AND doclistB] is always less + ** than or equal to the size of [doclistA] in that case). But this is + ** not true for order=DESC. For example, a doclist containing (1, -1) + ** may be smaller than (-1), as in the first example the -1 may be stored + ** as a single-byte delta, whereas in the second it must be stored as a + ** FTS3_VARINT_MAX byte varint. + ** + ** Similar padding is added in the fts3DoclistOrMerge() function. + */ + pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1); pTS->anOutput[0] = nDoclist; if( pTS->aaOutput[0] ){ memcpy(pTS->aaOutput[0], aDoclist, nDoclist); @@ -2761,7 +2821,7 @@ static int fts3SegReaderCursor( ** calls out here. */ if( iLevel<0 && p->aIndex ){ Fts3SegReader *pSeg = 0; - rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix, &pSeg); + rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg); if( rc==SQLITE_OK && pSeg ){ rc = fts3SegReaderCursorAppend(pCsr, pSeg); } @@ -3164,10 +3224,17 @@ static int fts3FilterMethod( ** row by docid. */ if( eSearch==FTS3_FULLSCAN_SEARCH ){ - zSql = sqlite3_mprintf( - "SELECT %s ORDER BY rowid %s", - p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") - ); + if( pDocidGe || pDocidLe ){ + zSql = sqlite3_mprintf( + "SELECT %s WHERE rowid BETWEEN %lld AND %lld ORDER BY rowid %s", + p->zReadExprlist, pCsr->iMinDocid, pCsr->iMaxDocid, + (pCsr->bDesc ? "DESC" : "ASC") + ); + }else{ + zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s", + p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") + ); + } if( zSql ){ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); sqlite3_free(zSql); @@ -3403,11 +3470,31 @@ static void fts3ReversePoslist(char *pStart, char **ppPoslist){ char *p = &(*ppPoslist)[-2]; char c = 0; + /* Skip backwards passed any trailing 0x00 bytes added by NearTrim() */ while( p>pStart && (c=*p--)==0 ); + + /* Search backwards for a varint with value zero (the end of the previous + ** poslist). This is an 0x00 byte preceded by some byte that does not + ** have the 0x80 bit set. */ while( p>pStart && (*p & 0x80) | c ){ c = *p--; } - if( p>pStart ){ p = &p[2]; } + assert( p==pStart || c==0 ); + + /* At this point p points to that preceding byte without the 0x80 bit + ** set. So to find the start of the poslist, skip forward 2 bytes then + ** over a varint. + ** + ** Normally. The other case is that p==pStart and the poslist to return + ** is the first in the doclist. In this case do not skip forward 2 bytes. + ** The second part of the if condition (c==0 && *ppPoslist>&p[2]) + ** is required for cases where the first byte of a doclist and the + ** doclist is empty. For example, if the first docid is 10, a doclist + ** that begins with: + ** + ** 0x0A 0x00 + */ + if( p>pStart || (c==0 && *ppPoslist>&p[2]) ){ p = &p[2]; } while( *p++&0x80 ); *ppPoslist = p; } @@ -3478,6 +3565,8 @@ static void fts3SnippetFunc( } if( !zEllipsis || !zEnd || !zStart ){ sqlite3_result_error_nomem(pContext); + }else if( nToken==0 ){ + sqlite3_result_text(pContext, "", -1, SQLITE_STATIC); }else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis, iCol, nToken); } @@ -3913,14 +4002,17 @@ static void fts3EvalAllocateReaders( ** This function assumes that pList points to a buffer allocated using ** sqlite3_malloc(). This function takes responsibility for eventually ** freeing the buffer. +** +** SQLITE_OK is returned if successful, or SQLITE_NOMEM if an error occurs. */ -static void fts3EvalPhraseMergeToken( +static int fts3EvalPhraseMergeToken( Fts3Table *pTab, /* FTS Table pointer */ Fts3Phrase *p, /* Phrase to merge pList/nList into */ int iToken, /* Token pList/nList corresponds to */ char *pList, /* Pointer to doclist */ int nList /* Number of bytes in pList */ ){ + int rc = SQLITE_OK; assert( iToken!=p->iDoclistToken ); if( pList==0 ){ @@ -3959,13 +4051,16 @@ static void fts3EvalPhraseMergeToken( nDiff = p->iDoclistToken - iToken; } - fts3DoclistPhraseMerge(pTab->bDescIdx, nDiff, pLeft, nLeft, pRight,&nRight); + rc = fts3DoclistPhraseMerge( + pTab->bDescIdx, nDiff, pLeft, nLeft, &pRight, &nRight + ); sqlite3_free(pLeft); p->doclist.aAll = pRight; p->doclist.nAll = nRight; } if( iToken>p->iDoclistToken ) p->iDoclistToken = iToken; + return rc; } /* @@ -3991,7 +4086,7 @@ static int fts3EvalPhraseLoad( char *pThis = 0; rc = fts3TermSelect(pTab, pToken, p->iColumn, &nThis, &pThis); if( rc==SQLITE_OK ){ - fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis); + rc = fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis); } } assert( pToken->pSegcsr==0 ); @@ -4533,12 +4628,14 @@ static void fts3EvalStartReaders( ){ if( pExpr && SQLITE_OK==*pRc ){ if( pExpr->eType==FTSQUERY_PHRASE ){ - int i; int nToken = pExpr->pPhrase->nToken; - for(i=0; ipPhrase->aToken[i].pDeferred==0 ) break; + if( nToken ){ + int i; + for(i=0; ipPhrase->aToken[i].pDeferred==0 ) break; + } + pExpr->bDeferred = (i==nToken); } - pExpr->bDeferred = (i==nToken); *pRc = fts3EvalPhraseStart(pCsr, 1, pExpr->pPhrase); }else{ fts3EvalStartReaders(pCsr, pExpr->pLeft, pRc); @@ -4793,9 +4890,13 @@ static int fts3EvalSelectDeferred( char *pList = 0; rc = fts3TermSelect(pTab, pToken, pTC->iCol, &nList, &pList); assert( rc==SQLITE_OK || pList==0 ); + if( rc==SQLITE_OK ){ + rc = fts3EvalPhraseMergeToken( + pTab, pTC->pPhrase, pTC->iToken,pList,nList + ); + } if( rc==SQLITE_OK ){ int nCount; - fts3EvalPhraseMergeToken(pTab, pTC->pPhrase, pTC->iToken,pList,nList); nCount = fts3DoclistCountDocids( pTC->pPhrase->doclist.aAll, pTC->pPhrase->doclist.nAll ); @@ -5656,7 +5757,6 @@ int sqlite3Fts3EvalPhrasePoslist( if( iDocid!=pCsr->iPrevId || pExpr->bEof ){ int rc = SQLITE_OK; int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */ - int iMul; /* +1 if csr dir matches index dir, else -1 */ int bOr = 0; u8 bEof = 0; u8 bTreeEof = 0; @@ -5698,7 +5798,8 @@ int sqlite3Fts3EvalPhrasePoslist( pIter = pPhrase->pOrPoslist; iDocid = pPhrase->iOrDocid; if( pCsr->bDesc==bDescDoclist ){ - bEof = (pIter >= (pPhrase->doclist.aAll + pPhrase->doclist.nAll)); + bEof = !pPhrase->doclist.nAll || + (pIter >= (pPhrase->doclist.aAll + pPhrase->doclist.nAll)); while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){ sqlite3Fts3DoclistNext( bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll, diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index 1b8b7bd..0748d91 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -134,6 +134,11 @@ SQLITE_EXTENSION_INIT3 #ifdef SQLITE_COVERAGE_TEST # define ALWAYS(x) (1) # define NEVER(X) (0) +#elif defined(SQLITE_DEBUG) +# define ALWAYS(x) sqlite3Fts3Always((x)!=0) +# define NEVER(x) sqlite3Fts3Never((x)!=0) +int sqlite3Fts3Always(int b); +int sqlite3Fts3Never(int b); #else # define ALWAYS(x) (x) # define NEVER(x) (x) @@ -534,6 +539,7 @@ int sqlite3Fts3Incrmerge(Fts3Table*,int,int); ) /* fts3.c */ +void sqlite3Fts3ErrMsg(char**,const char*,...); int sqlite3Fts3PutVarint(char *, sqlite3_int64); int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); int sqlite3Fts3GetVarint32(const char *, int *); diff --git a/ext/fts3/fts3_aux.c b/ext/fts3/fts3_aux.c index c68b1a9..f85a48a 100644 --- a/ext/fts3/fts3_aux.c +++ b/ext/fts3/fts3_aux.c @@ -116,7 +116,7 @@ static int fts3auxConnectMethod( return SQLITE_OK; bad_args: - *pzErr = sqlite3_mprintf("invalid arguments to fts4aux constructor"); + sqlite3Fts3ErrMsg(pzErr, "invalid arguments to fts4aux constructor"); return SQLITE_ERROR; } diff --git a/ext/fts3/fts3_expr.c b/ext/fts3/fts3_expr.c index 2ba786c..d7cabd9 100644 --- a/ext/fts3/fts3_expr.c +++ b/ext/fts3/fts3_expr.c @@ -1022,13 +1022,13 @@ int sqlite3Fts3ExprParse( sqlite3Fts3ExprFree(*ppExpr); *ppExpr = 0; if( rc==SQLITE_TOOBIG ){ - *pzErr = sqlite3_mprintf( + sqlite3Fts3ErrMsg(pzErr, "FTS expression tree is too large (maximum depth %d)", SQLITE_FTS3_MAX_EXPR_DEPTH ); rc = SQLITE_ERROR; }else if( rc==SQLITE_ERROR ){ - *pzErr = sqlite3_mprintf("malformed MATCH expression: [%s]", z); + sqlite3Fts3ErrMsg(pzErr, "malformed MATCH expression: [%s]", z); } } diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c index 93ee86f..6abb169 100644 --- a/ext/fts3/fts3_snippet.c +++ b/ext/fts3/fts3_snippet.c @@ -27,6 +27,7 @@ #define FTS3_MATCHINFO_LENGTH 'l' /* nCol values */ #define FTS3_MATCHINFO_LCS 's' /* nCol values */ #define FTS3_MATCHINFO_HITS 'x' /* 3*nCol*nPhrase values */ +#define FTS3_MATCHINFO_LHITS 'y' /* nCol*nPhrase values */ /* ** The default value for the second argument to matchinfo(). @@ -682,8 +683,12 @@ static int fts3SnippetText( ** required. They are required if (a) this is not the first fragment, ** or (b) this fragment does not begin at position 0 of its column. */ - if( rc==SQLITE_OK && (iPos>0 || iFragment>0) ){ - rc = fts3StringAppend(pOut, zEllipsis, -1); + if( rc==SQLITE_OK ){ + if( iPos>0 || iFragment>0 ){ + rc = fts3StringAppend(pOut, zEllipsis, -1); + }else if( iBegin ){ + rc = fts3StringAppend(pOut, zDoc, iBegin); + } } if( rc!=SQLITE_OK || iCurrentpCursor->base.pVtab; + int rc = SQLITE_OK; + int iStart = iPhrase * p->nCol; + Fts3Expr *pEof; /* Ancestor node already at EOF */ + + /* This must be a phrase */ + assert( pExpr->pPhrase ); + + /* Initialize all output integers to zero. */ + memset(&p->aMatchinfo[iStart], 0, sizeof(u32) * p->nCol); + + /* Check if this or any parent node is at EOF. If so, then all output + ** values are zero. */ + for(pEof=pExpr; pEof && pEof->bEof==0; pEof=pEof->pParent); + + if( pEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){ + Fts3Phrase *pPhrase = pExpr->pPhrase; + char *pIter = pPhrase->doclist.pList; + int iCol = 0; + + while( 1 ){ + int nHit = fts3ColumnlistCount(&pIter); + if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){ + p->aMatchinfo[iStart + iCol] = (u32)nHit; + } + assert( *pIter==0x00 || *pIter==0x01 ); + if( *pIter!=0x01 ) break; + pIter++; + pIter += fts3GetVarint32(pIter, &iCol); + } + } + + return rc; +} + static int fts3MatchinfoCheck( Fts3Table *pTab, char cArg, @@ -817,10 +867,11 @@ static int fts3MatchinfoCheck( || (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize) || (cArg==FTS3_MATCHINFO_LCS) || (cArg==FTS3_MATCHINFO_HITS) + || (cArg==FTS3_MATCHINFO_LHITS) ){ return SQLITE_OK; } - *pzErr = sqlite3_mprintf("unrecognized matchinfo request: %c", cArg); + sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo request: %c", cArg); return SQLITE_ERROR; } @@ -840,6 +891,10 @@ static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ nVal = pInfo->nCol; break; + case FTS3_MATCHINFO_LHITS: + nVal = pInfo->nCol * pInfo->nPhrase; + break; + default: assert( cArg==FTS3_MATCHINFO_HITS ); nVal = pInfo->nCol * pInfo->nPhrase * 3; @@ -1094,6 +1149,10 @@ static int fts3MatchinfoValues( } break; + case FTS3_MATCHINFO_LHITS: + (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLHitsCb, (void*)pInfo); + break; + default: { Fts3Expr *pExpr; assert( zArg[i]==FTS3_MATCHINFO_HITS ); @@ -1249,7 +1308,7 @@ void sqlite3Fts3Snippet( */ for(iRead=0; iReadnColumn; iRead++){ SnippetFragment sF = {0, 0, 0, 0}; - int iS; + int iS = 0; if( iCol>=0 && iRead!=iCol ) continue; /* Find the best snippet of nFToken tokens in column iRead. */ diff --git a/ext/fts3/fts3_term.c b/ext/fts3/fts3_term.c index c49d5cb..7edd072 100644 --- a/ext/fts3/fts3_term.c +++ b/ext/fts3/fts3_term.c @@ -81,7 +81,7 @@ static int fts3termConnectMethod( /* The user should specify a single argument - the name of an fts3 table. */ if( argc!=4 ){ - *pzErr = sqlite3_mprintf( + sqlite3Fts3ErrMsg(pzErr, "wrong number of arguments to fts4term constructor" ); return SQLITE_ERROR; diff --git a/ext/fts3/fts3_tokenize_vtab.c b/ext/fts3/fts3_tokenize_vtab.c index fb99f8b..dfeddfe 100644 --- a/ext/fts3/fts3_tokenize_vtab.c +++ b/ext/fts3/fts3_tokenize_vtab.c @@ -85,7 +85,7 @@ static int fts3tokQueryTokenizer( p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); if( !p ){ - *pzErr = sqlite3_mprintf("unknown tokenizer: %s", zName); + sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", zName); return SQLITE_ERROR; } diff --git a/ext/fts3/fts3_tokenizer.c b/ext/fts3/fts3_tokenizer.c index 04f8446..64cfe07 100644 --- a/ext/fts3/fts3_tokenizer.c +++ b/ext/fts3/fts3_tokenizer.c @@ -69,7 +69,7 @@ static void scalarFunc( if( argc==2 ){ void *pOld; int n = sqlite3_value_bytes(argv[1]); - if( n!=sizeof(pPtr) ){ + if( zName==0 || n!=sizeof(pPtr) ){ sqlite3_result_error(context, "argument type mismatch", -1); return; } @@ -80,7 +80,9 @@ static void scalarFunc( return; } }else{ - pPtr = sqlite3Fts3HashFind(pHash, zName, nName); + if( zName ){ + pPtr = sqlite3Fts3HashFind(pHash, zName, nName); + } if( !pPtr ){ char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); sqlite3_result_error(context, zErr, -1); @@ -161,12 +163,16 @@ int sqlite3Fts3InitTokenizer( zEnd = &zCopy[strlen(zCopy)]; z = (char *)sqlite3Fts3NextToken(zCopy, &n); + if( z==0 ){ + assert( n==0 ); + z = zCopy; + } z[n] = '\0'; sqlite3Fts3Dequote(z); m = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash,z,(int)strlen(z)+1); if( !m ){ - *pzErr = sqlite3_mprintf("unknown tokenizer: %s", z); + sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", z); rc = SQLITE_ERROR; }else{ char const **aArg = 0; @@ -189,7 +195,7 @@ int sqlite3Fts3InitTokenizer( rc = m->xCreate(iArg, aArg, ppTok); assert( rc!=SQLITE_OK || *ppTok ); if( rc!=SQLITE_OK ){ - *pzErr = sqlite3_mprintf("unknown tokenizer"); + sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer"); }else{ (*ppTok)->pModule = m; } @@ -273,9 +279,9 @@ static void testFunc( p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); if( !p ){ - char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); - sqlite3_result_error(context, zErr, -1); - sqlite3_free(zErr); + char *zErr2 = sqlite3_mprintf("unknown tokenizer: %s", zName); + sqlite3_result_error(context, zErr2, -1); + sqlite3_free(zErr2); return; } diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 09294bc..4cd2aeb 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -326,7 +326,7 @@ static int fts3SqlStmt( /* 25 */ "", /* 26 */ "DELETE FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?", -/* 27 */ "SELECT DISTINCT level / (1024 * ?) FROM %Q.'%q_segdir'", +/* 27 */ "SELECT ? UNION SELECT level / (1024 * ?) FROM %Q.'%q_segdir'", /* This statement is used to determine which level to read the input from ** when performing an incremental merge. It returns the absolute level number @@ -1625,7 +1625,10 @@ int sqlite3Fts3SegReaderNew( ** an array of pending terms by term. This occurs as part of flushing ** the contents of the pending-terms hash table to the database. */ -static int fts3CompareElemByTerm(const void *lhs, const void *rhs){ +static int SQLITE_CDECL fts3CompareElemByTerm( + const void *lhs, + const void *rhs +){ char *z1 = fts3HashKey(*(Fts3HashElem **)lhs); char *z2 = fts3HashKey(*(Fts3HashElem **)rhs); int n1 = fts3HashKeysize(*(Fts3HashElem **)lhs); @@ -3441,7 +3444,8 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){ rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); if( rc==SQLITE_OK ){ int rc2; - sqlite3_bind_int(pAllLangid, 1, p->nIndex); + sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid); + sqlite3_bind_int(pAllLangid, 2, p->nIndex); while( sqlite3_step(pAllLangid)==SQLITE_ROW ){ int i; int iLangid = sqlite3_column_int(pAllLangid, 0); @@ -4773,7 +4777,7 @@ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){ pHint->n = i; i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel); i += fts3GetVarint32(&pHint->a[i], pnInput); - if( i!=nHint ) return SQLITE_CORRUPT_VTAB; + if( i!=nHint ) return FTS_CORRUPT_VTAB; return SQLITE_OK; } @@ -5141,7 +5145,8 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){ rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); if( rc==SQLITE_OK ){ int rc2; - sqlite3_bind_int(pAllLangid, 1, p->nIndex); + sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid); + sqlite3_bind_int(pAllLangid, 2, p->nIndex); while( rc==SQLITE_OK && sqlite3_step(pAllLangid)==SQLITE_ROW ){ int iLangid = sqlite3_column_int(pAllLangid, 0); int i; @@ -5154,7 +5159,6 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){ } /* This block calculates the checksum according to the %_content table */ - rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); if( rc==SQLITE_OK ){ sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule; sqlite3_stmt *pStmt = 0; @@ -5251,7 +5255,7 @@ static int fts3DoIntegrityCheck( int rc; int bOk = 0; rc = fts3IntegrityCheck(p, &bOk); - if( rc==SQLITE_OK && bOk==0 ) rc = SQLITE_CORRUPT_VTAB; + if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB; return rc; } diff --git a/ext/fts3/tool/fts3view.c b/ext/fts3/tool/fts3view.c index 3dc1ba8..6dada35 100644 --- a/ext/fts3/tool/fts3view.c +++ b/ext/fts3/tool/fts3view.c @@ -504,7 +504,7 @@ static void showSegdirMap(sqlite3 *db, const char *zTab){ sqlite3_column_int64(pStmt,5)); printf(" root %9s\n", rtag); if( iLEnd>iStart ){ - sqlite3_int64 iLower, iPrev, iX; + sqlite3_int64 iLower, iPrev = 0, iX; if( iLEnd+1<=iEnd ){ sqlite3_bind_int64(pStmt2, 1, iLEnd+1); sqlite3_bind_int64(pStmt2, 2, iEnd); @@ -548,7 +548,7 @@ static void decodeSegment( const unsigned char *aData, /* Content to print */ int nData /* Number of bytes of content */ ){ - sqlite3_int64 iChild; + sqlite3_int64 iChild = 0; sqlite3_int64 iPrefix; sqlite3_int64 nTerm; sqlite3_int64 n; diff --git a/ext/misc/amatch.c b/ext/misc/amatch.c index 98c0143..d08ef57 100644 --- a/ext/misc/amatch.c +++ b/ext/misc/amatch.c @@ -998,6 +998,23 @@ static void amatchWriteCost(amatch_word *pWord){ pWord->zCost[8] = 0; } +/* Circumvent compiler warnings about the use of strcpy() by supplying +** our own implementation. +*/ +#if defined(__OpenBSD__) +static void amatchStrcpy(char *dest, const char *src){ + while( (*(dest++) = *(src++))!=0 ){} +} +static void amatchStrcat(char *dest, const char *src){ + while( *dest ) dest++; + amatchStrcpy(dest, src); +} +#else +# define amatchStrcpy strcpy +# define amatchStrcat strcat +#endif + + /* ** Add a new amatch_word object to the queue. ** @@ -1073,7 +1090,7 @@ static void amatchAddWord( assert( pOther==0 ); (void)pOther; pWord->sWord.zKey = pWord->zWord; pWord->sWord.pWord = pWord; - strcpy(pWord->zWord, pCur->zBuf); + amatchStrcpy(pWord->zWord, pCur->zBuf); pOther = amatchAvlInsert(&pCur->pWord, &pWord->sWord); assert( pOther==0 ); (void)pOther; #ifdef AMATCH_TRACE_1 @@ -1083,6 +1100,7 @@ static void amatchAddWord( #endif } + /* ** Advance a cursor to its next row of output */ @@ -1148,7 +1166,7 @@ static int amatchNext(sqlite3_vtab_cursor *cur){ zBuf = sqlite3_realloc(zBuf, nBuf); if( zBuf==0 ) return SQLITE_NOMEM; } - strcpy(zBuf, pWord->zWord+2); + amatchStrcpy(zBuf, pWord->zWord+2); zNext[0] = 0; zNextIn[0] = pCur->zInput[pWord->nMatch]; if( zNextIn[0] ){ @@ -1163,7 +1181,7 @@ static int amatchNext(sqlite3_vtab_cursor *cur){ if( zNextIn[0] && zNextIn[0]!='*' ){ sqlite3_reset(p->pVCheck); - strcat(zBuf, zNextIn); + amatchStrcat(zBuf, zNextIn); sqlite3_bind_text(p->pVCheck, 1, zBuf, nWord+nNextIn, SQLITE_STATIC); rc = sqlite3_step(p->pVCheck); if( rc==SQLITE_ROW ){ @@ -1176,13 +1194,13 @@ static int amatchNext(sqlite3_vtab_cursor *cur){ } while( 1 ){ - strcpy(zBuf+nWord, zNext); + amatchStrcpy(zBuf+nWord, zNext); sqlite3_reset(p->pVCheck); sqlite3_bind_text(p->pVCheck, 1, zBuf, -1, SQLITE_TRANSIENT); rc = sqlite3_step(p->pVCheck); if( rc!=SQLITE_ROW ) break; zW = (const char*)sqlite3_column_text(p->pVCheck, 0); - strcpy(zBuf+nWord, zNext); + amatchStrcpy(zBuf+nWord, zNext); if( strncmp(zW, zBuf, nWord)!=0 ) break; if( (zNextIn[0]=='*' && zNextIn[1]==0) || (zNextIn[0]==0 && zW[nWord]==0) diff --git a/ext/misc/compress.c b/ext/misc/compress.c index a405911..bf38d4c 100644 --- a/ext/misc/compress.c +++ b/ext/misc/compress.c @@ -38,6 +38,7 @@ static void compressFunc( unsigned int nIn; unsigned long int nOut; unsigned char x[8]; + int rc; int i, j; pIn = sqlite3_value_blob(argv[0]); @@ -50,8 +51,12 @@ static void compressFunc( for(i=0; i<4 && x[i]==0; i++){} for(j=0; i<=4; i++, j++) pOut[j] = x[i]; pOut[j-1] |= 0x80; - compress(&pOut[j], &nOut, pIn, nIn); - sqlite3_result_blob(context, pOut, nOut+j, sqlite3_free); + rc = compress(&pOut[j], &nOut, pIn, nIn); + if( rc==Z_OK ){ + sqlite3_result_blob(context, pOut, nOut+j, sqlite3_free); + }else{ + sqlite3_free(pOut); + } } /* @@ -82,6 +87,8 @@ static void uncompressFunc( rc = uncompress(pOut, &nOut, &pIn[i], nIn-i); if( rc==Z_OK ){ sqlite3_result_blob(context, pOut, nOut, sqlite3_free); + }else{ + sqlite3_free(pOut); } } diff --git a/ext/misc/fuzzer.c b/ext/misc/fuzzer.c index dc03161..3ed4b0a 100644 --- a/ext/misc/fuzzer.c +++ b/ext/misc/fuzzer.c @@ -876,7 +876,7 @@ static fuzzer_stem *fuzzerNewStem( if( pNew==0 ) return 0; memset(pNew, 0, sizeof(*pNew)); pNew->zBasis = (char*)&pNew[1]; - pNew->nBasis = (int)strlen(zWord); + pNew->nBasis = (fuzzer_len)strlen(zWord); memcpy(pNew->zBasis, zWord, pNew->nBasis+1); pRule = pCur->pVtab->pRule; while( fuzzerSkipRule(pRule, pNew, pCur->iRuleset) ){ diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index 201d3cf..5e63c18 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -2820,11 +2820,19 @@ static int rtreeUpdate( if( nData>1 ){ int ii; - /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */ - assert( nData==(pRtree->nDim*2 + 3) ); + /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. + ** + ** NB: nData can only be less than nDim*2+3 if the rtree is mis-declared + ** with "column" that are interpreted as table constraints. + ** Example: CREATE VIRTUAL TABLE bad USING rtree(x,y,CHECK(y>5)); + ** This problem was discovered after years of use, so we silently ignore + ** these kinds of misdeclared tables to avoid breaking any legacy. + */ + assert( nData<=(pRtree->nDim*2 + 3) ); + #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ - for(ii=0; ii<(pRtree->nDim*2); ii+=2){ + for(ii=0; iicell.aCoord[ii+1].f ){ @@ -2835,7 +2843,7 @@ static int rtreeUpdate( }else #endif { - for(ii=0; ii<(pRtree->nDim*2); ii+=2){ + for(ii=0; iicell.aCoord[ii+1].i ){ diff --git a/ext/rtree/rtree9.test b/ext/rtree/rtree9.test index 6479516..571341b 100644 --- a/ext/rtree/rtree9.test +++ b/ext/rtree/rtree9.test @@ -87,7 +87,6 @@ do_catchsql_test rtree9-4.3 { # register_circle_geom db -breakpoint do_execsql_test rtree9-5.1 { CREATE VIRTUAL TABLE rt2 USING rtree(id, xmin, xmax, ymin, ymax); diff --git a/main.mk b/main.mk index 429945b..7ac6868 100644 --- a/main.mk +++ b/main.mk @@ -53,7 +53,7 @@ TCCX += -I$(TOP)/ext/async -I$(TOP)/ext/userauth LIBOBJ+= vdbe.o parse.o \ alter.o analyze.o attach.o auth.o \ backup.o bitvec.o btmutex.o btree.o build.o \ - callback.o complete.o ctime.o date.o delete.o expr.o fault.o fkey.o \ + callback.o complete.o ctime.o date.o dbstat.o delete.o expr.o fault.o fkey.o \ fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \ fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \ fts3_tokenize_vtab.o \ @@ -91,6 +91,7 @@ SRC = \ $(TOP)/src/complete.c \ $(TOP)/src/ctime.c \ $(TOP)/src/date.c \ + $(TOP)/src/dbstat.c \ $(TOP)/src/delete.c \ $(TOP)/src/expr.c \ $(TOP)/src/fault.c \ @@ -133,6 +134,7 @@ SRC = \ $(TOP)/src/pcache.h \ $(TOP)/src/pcache1.c \ $(TOP)/src/pragma.c \ + $(TOP)/src/pragma.h \ $(TOP)/src/prepare.c \ $(TOP)/src/printf.c \ $(TOP)/src/random.c \ @@ -164,6 +166,7 @@ SRC = \ $(TOP)/src/vdbetrace.c \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/vtab.c \ + $(TOP)/src/vxworks.h \ $(TOP)/src/wal.c \ $(TOP)/src/wal.h \ $(TOP)/src/walker.c \ @@ -268,7 +271,6 @@ TESTSRC = \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ - $(TOP)/src/test_stat.c \ $(TOP)/src/test_sqllog.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ @@ -304,6 +306,7 @@ TESTSRC2 = \ $(TOP)/src/btree.c \ $(TOP)/src/build.c \ $(TOP)/src/date.c \ + $(TOP)/src/dbstat.c \ $(TOP)/src/expr.c \ $(TOP)/src/func.c \ $(TOP)/src/insert.c \ @@ -356,12 +359,14 @@ HDR = \ $(TOP)/src/pager.h \ $(TOP)/src/pcache.h \ parse.h \ + $(TOP)/src/pragma.h \ sqlite3.h \ $(TOP)/src/sqlite3ext.h \ $(TOP)/src/sqliteInt.h \ $(TOP)/src/sqliteLimit.h \ $(TOP)/src/vdbe.h \ $(TOP)/src/vdbeInt.h \ + $(TOP)/src/vxworks.h \ $(TOP)/src/whereInt.h # Header files used by extensions @@ -400,10 +405,31 @@ sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h $(TOP)/src/shell.c \ libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB) +sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h + $(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \ + $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) $(THREADLIB) + +fuzzershell$(EXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h + $(TCCX) -o fuzzershell$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION\ + $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS) $(THREADLIB) + mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c $(TCCX) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \ $(TLIBS) $(THREADLIB) +MPTEST1=./mptester$(EXE) mptest.db $(TOP)/mptest/crash01.test --repeat 20 +MPTEST2=./mptester$(EXE) mptest.db $(TOP)/mptest/multiwrite01.test --repeat 20 +mptest: mptester$(EXE) + rm -f mptest.db + $(MPTEST1) --journalmode DELETE + $(MPTEST2) --journalmode WAL + $(MPTEST1) --journalmode WAL + $(MPTEST2) --journalmode PERSIST + $(MPTEST1) --journalmode PERSIST + $(MPTEST2) --journalmode TRUNCATE + $(MPTEST1) --journalmode TRUNCATE + $(MPTEST2) --journalmode DELETE + sqlite3.o: sqlite3.c $(TCCX) -I. -c sqlite3.c @@ -576,9 +602,10 @@ tclsqlite3: $(TOP)/src/tclsqlite.c libsqlite3.a $(TCCX) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite3 \ $(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) $(THREADLIB) -sqlite3_analyzer.c: sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl +sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl echo "#define TCLSH 2" > $@ - cat sqlite3.c $(TOP)/src/test_stat.c $(TOP)/src/tclsqlite.c >> $@ + echo "#define SQLITE_ENABLE_DBSTAT_VTAB 1" >> $@ + cat sqlite3.c $(TOP)/src/tclsqlite.c >> $@ echo "static const char *tclsh_main_loop(void){" >> $@ echo "static const char *zMainloop = " >> $@ $(NAWK) -f $(TOP)/tool/tostr.awk $(TOP)/tool/spaceanal.tcl >> $@ @@ -608,21 +635,34 @@ fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts3amal.c \ -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) -fulltest: testfixture$(EXE) sqlite3$(EXE) +fulltest: testfixture$(EXE) sqlite3$(EXE) fuzztest ./testfixture$(EXE) $(TOP)/test/all.test -soaktest: testfixture$(EXE) sqlite3$(EXE) +soaktest: testfixture$(EXE) sqlite3$(EXE) fuzzoomtest ./testfixture$(EXE) $(TOP)/test/all.test -soak=1 -fulltestonly: testfixture$(EXE) sqlite3$(EXE) +fulltestonly: testfixture$(EXE) sqlite3$(EXE) fuzztest ./testfixture$(EXE) $(TOP)/test/full.test queryplantest: testfixture$(EXE) sqlite3$(EXE) ./testfixture$(EXE) $(TOP)/test/permutations.test queryplanner -test: testfixture$(EXE) sqlite3$(EXE) +fuzztest: fuzzershell$(EXE) + ./fuzzershell$(EXE) $(TOP)/test/fuzzdata1.txt $(TOP)/test/fuzzdata2.txt + +fuzzoomtest: fuzzershell$(EXE) + ./fuzzershell$(EXE) -f $(TOP)/test/fuzzdata1.txt --oom + +test: testfixture$(EXE) sqlite3$(EXE) fuzztest ./testfixture$(EXE) $(TOP)/test/veryquick.test +# Run a test using valgrind. This can take a really long time +# because valgrind is so much slower than a native machine. +# +valgrindtest: testfixture$(EXE) sqlite3$(EXE) fuzzershell$(EXE) + valgrind -v ./fuzzershell$(EXE) -f $(TOP)/test/fuzzdata1.txt + OMIT_MISUSE=1 valgrind -v ./testfixture$(EXE) $(TOP)/test/permutations.test valgrind + # The next two rules are used to support the "threadtest" target. Building # threadtest runs a few thread-safety tests that are implemented in C. This # target is invoked by the releasetest.tcl script. diff --git a/manifest b/manifest index 828d587..ec3af6b 100644 --- a/manifest +++ b/manifest @@ -1,19 +1,19 @@ -C Version\s3.8.8.3 -D 2015-02-25T13:29:11.692 +C Version\s3.8.10.2 +D 2015-05-20T18:17:19.154 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in 5407a688f4d77a05c18a8142be8ae5a2829dd610 +F Makefile.in 08728ecbeddca339c77bfd564d3484b523dffdb1 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc 4c057774e6138b9023fc16ec05639ddd3329b152 +F Makefile.msc c6241f7fa2912427410ef15429c8ab5601e19a71 F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858 F README.md d58e3bebc0a4145e0f2a87994015fdb575a8e866 -F VERSION 0de46a30a2d0a7a6a686fd35186fbad0ac06ff71 +F VERSION 527b4c5a3d1a29e3b16162473d0903b569c6d7cb F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90 F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2 F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903 -F autoconf/Makefile.am 8fc2972d92769cf20ab8e4a73ea901b84d69bf44 +F autoconf/Makefile.am 4012e106208c7b86ba54d06e9ed400b59a4dee6b F autoconf/README 14458f1046c118efa721aadec5f227e876d3cd38 F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7 F autoconf/config.guess 94cc57e2a3fdb9c235b362ace86d77e89d188cad x @@ -38,8 +38,8 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.h.in 42b71ad3fe21c9e88fa59e8458ca1a6bc72eb0c0 F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 -F configure 444b4cd66ec94631b2b624cf24d01142c9aac0ae x -F configure.ac 6a8d145aea6d81f0b90013340780e43ed74fd5f4 +F configure 17b518102f77344a1709422da84afebb57f0fcfe x +F configure.ac 0b775d383c536bbaafc1e46dd3cbb81a7ea11aeb F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1 F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710 @@ -78,40 +78,40 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 845f20440dacac6e09f5c7735205609b9a86536b +F ext/fts3/fts3.c 2fb98467f4b670c8934cdd97d1ba3ffa7382764c F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h 394858c12a17740f7a1f6bd372c4606d4425a8d1 -F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365 -F ext/fts3/fts3_expr.c 40123785eaa3ebd4c45c9b23407cc44ac0c49905 +F ext/fts3/fts3Int.h 59ecaa2d7af0da44c70b6aeaebdcfc070d14abab +F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1 +F ext/fts3/fts3_expr.c 71c063da9c2a4167fb54aec089dd5ef33a58c9cb F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60 F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5 F ext/fts3/fts3_porter.c 3565faf04b626cddf85f03825e86056a4562c009 -F ext/fts3/fts3_snippet.c 55c126e07158b2a705f52dee2cdc57208d3e999a -F ext/fts3/fts3_term.c a521f75132f9a495bdca1bdd45949b3191c52763 +F ext/fts3/fts3_snippet.c 40a96ba78e90aba7d7d6d014a18049bb218060fd +F ext/fts3/fts3_term.c 88c55a6fa1a51ab494e33dced0401a6c28791fd7 F ext/fts3/fts3_test.c 8a3a78c4458b2d7c631fcf4b152a5cd656fa7038 -F ext/fts3/fts3_tokenize_vtab.c becc661223db7898b213f9e8a23d75bac02408c9 -F ext/fts3/fts3_tokenizer.c bbdc731bc91338050675c6d1da9ab82147391e16 +F ext/fts3/fts3_tokenize_vtab.c a27593ab19657166f6fa5ec073b678cc29a75860 +F ext/fts3/fts3_tokenizer.c 50e7a69a549ac5882cc1971ee43f66aaabc11395 F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3 F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004 F ext/fts3/fts3_unicode.c a93f5edc0aff44ef8b06d7cb55b52026541ca145 F ext/fts3/fts3_unicode2.c c3d01968d497bd7001e7dc774ba75b372738c057 -F ext/fts3/fts3_write.c 9b3a32cbecf40a1f41cb08c00df8c066c23c7a25 +F ext/fts3/fts3_write.c 4f005f78592a1447ca96c8475ef5342ab7dbe02a F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 -F ext/fts3/tool/fts3view.c 3986531f2fc0ceca0c89c31ec7d0589b6adb19d6 +F ext/fts3/tool/fts3view.c 8e53d0190a7b3443764bbd32ad47be2bd852026d F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7 F ext/fts3/unicode/mkunicode.tcl a2567f9d6ad6779879a2e394c120ad8718557e65 F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 F ext/icu/icu.c d415ccf984defeb9df2c0e1afcfaa2f6dc05eacb F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 -F ext/misc/amatch.c 17ba78dc9b33601a40d2a7bc54c748b6f3eb7176 +F ext/misc/amatch.c 27b9b601fb1453084e18a3432ea0240d7af8decb F ext/misc/closure.c 636024302cde41b2bf0c542f81c40c624cfb7012 -F ext/misc/compress.c 76e45655f4046e756064ab10c62e18f2eb846b9f +F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83 F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2 F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f -F ext/misc/fuzzer.c e3e18f47252c151b5553d7e806f38e757d37c4cc +F ext/misc/fuzzer.c 4c84635c71c26cfa7c2e5848cf49fe2d2cfcd767 F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342 F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63 @@ -124,7 +124,7 @@ F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95 F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/rtree.c 14e6239434d4e3f65d3e90320713f26aa24e167f +F ext/rtree/rtree.c 0c207fd8b814a35537d96681cbf57436e200b75e F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e F ext/rtree/rtree1.test 541bbcab74613907fea08b2ecdcdd5b7aa724cc9 F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba @@ -134,7 +134,7 @@ F ext/rtree/rtree5.test 6a510494f12454bf57ef28f45bc7764ea279431e F ext/rtree/rtree6.test 773a90db2dce6a8353dd0d5b64bca69b29761196 F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971 F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a -F ext/rtree/rtree9.test d86ebf08ff6328895613ed577dd8a2a37c472c34 +F ext/rtree/rtree9.test b5eb13849545dfd271a54ff16784cb00d8792aea F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e F ext/rtree/rtreeC.test df158dcc81f1a43ce7eef361af03c48ec91f1e06 @@ -152,192 +152,195 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk e392561ffe17fc4dad945eef852400d5bf2911a0 +F main.mk f012feb95fc4acfb583f89b6f9d1dc6253a8f08d F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea -F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5 +F mkopcodeh.awk d5e22023b5238985bb54a72d33e0ac71fe4f8a32 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 -F mptest/crash01.test cce8e306d8596d5a2e497e27112dae1f6e5e3538 +F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421 F mptest/crash02.subtest f4ef05adcd15d60e5d2bd654204f2c008b519df8 -F mptest/mptest.c 24c5f72415df2eab7088ef8c9f99f163aed590c8 -F mptest/multiwrite01.test 499ad0310da8dff8e8f98d2e272fc2a8aa741b2e +F mptest/mptest.c fca59f0a922e03f95ed17c44b1515ed37a841c81 +F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c ba266a779bc7ce10e52e59e7d3dc79fa342e8fdb -F src/analyze.c 91540f835163d5369ccbae78e2e6c74d0dd53c1d -F src/attach.c 7f6b3fafa2290b407e4a94dcf1afda7ec0fe394b +F src/alter.c 8f6dc4a6ddc1ebc0ed5cc470c4e57ff0d1605e90 +F src/analyze.c d23790787f80ebed58df7774744b4cf96401498b +F src/attach.c c38ac5a520a231d5d0308fd7f2ad95191c867bae F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 -F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea -F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb -F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 4c098bb6e8678e4596983862abf78f7a0fcb807e -F src/btree.h 94277c1d30c0b75705974bcc8b0c05e79c03d474 -F src/btreeInt.h a3d0ae1d511365e1a2b76ad10960dbe55c286f34 -F src/build.c f5cfd7b32216f695b995bbc7c1a395f6d451d11f +F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3 +F src/bitvec.c 5eb7958c3bf65210211cbcfc44eff86d0ded7c9d +F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 +F src/btree.c 30a80340481098d699398cba3536c895373b2e2c +F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 +F src/btreeInt.h 973a22a6fd61350b454ad614832b1f0a5e25a1e4 +F src/build.c 61b47073f79f31e80a05db9ce13c5ca81bf8f74e F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 -F src/complete.c 198a0066ba60ab06fc00fba1998d870a4d575463 -F src/ctime.c 98f89724adc891a1a4c655bee04e33e716e05887 +F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575 +F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac -F src/delete.c bd1a91ddd247ce13004075251e0b7fe2bf9925ef -F src/expr.c 7be80f7dc337329a24df45c2f3bdb2ea3b64c90e +F src/dbstat.c db36fbd268f778ea1cdb8b0c1eb9828c1f10bf70 +F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e +F src/expr.c 3fb2ab3ab69d15b4b75ae53fceb4e317f64cb306 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb -F src/fkey.c e0444b61bed271a76840cbe6182df93a9baa3f12 -F src/func.c 6d3c4ebd72aa7923ce9b110a7dc15f9b8c548430 -F src/global.c 12561d70a1b25f67b21154622bb1723426724f75 +F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 +F src/func.c 5b8b8e77a0fb644eaf8947d413804622e32692b6 +F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c 5b9243a33726008cc4132897d2be371db12a13be +F src/insert.c 8176ba5bad8fcef643558ca5708f33ed05a4035a F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 -F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660 -F src/main.c 341fcc5601a8ca84389fa32bcf5a857f65af8dd0 -F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab +F src/loadext.c 29255bbe1cfb2ce9bbff2526a5ecfddcb49b9271 +F src/main.c 331fda6b255ae6a08e6ade89f0ac1d158691f3c6 +F src/malloc.c 6a370b83d54e4bbf6f94021221c2a311cff26a18 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987 F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3 F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534 F src/mem5.c 61eeb90134f9a5be6c2e68d8daae7628b25953fb F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85 -F src/msvc.h e78002098966e39b2fd9915bd70b7bc3ec8398b7 +F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495 F src/mutex.c 19bf9acba69ca2f367c3761080f8a9f0cf4670a8 F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85 -F src/mutex_noop.c f3f09fd7a2eb4287cfc799753ffc30380e7b71a1 -F src/mutex_unix.c 551e2f25f0fa0ee8fd7a43f50fc3d8be00e95dde -F src/mutex_w32.c df48fe07562a45c5c927c45b8d5873a27f98bbb0 +F src/mutex_noop.c 529bab0743c3321c940f32c3464de494fd38cfa9 +F src/mutex_unix.c 5cf676464bd19e0a866297515d146e8bf1669dfb +F src/mutex_w32.c 61660ada28d8308ad190f444c2170c4f2a590c2f F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7 F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8 F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf -F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 +F src/os_common.h abdb9a191a367793268fe553d25bab894e986a0e F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa -F src/os_unix.c aefeaf915aaef9f81aa2645e0d5d06fa1bd83beb -F src/os_win.c 91d3d08e33ec0258d180d4c8255492f47d15e007 -F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 -F src/pager.c 4120a49ecd37697e28f5ed807f470b9c0b88410c +F src/os_unix.c 23eb5f56fac54d8fe0cb204291f3b3b2d94f23fc +F src/os_win.c 2da99cf07da7db6bcb1974013abfd89ec74749b3 +F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca +F src/pager.c 97110085b1321298412f1e5c37bddb95b36d9208 F src/pager.h c3476e7c89cdf1c6914e50a11f3714e30b4e0a77 -F src/parse.y c5d0d964f9ac023e8154cad512e54b0b6058e086 -F src/pcache.c d210cf90d04365a74f85d21374dded65af67b0cb +F src/parse.y c4e0387bc88c8e21e5ba653e2578959a1f3cdbc7 +F src/pcache.c 10539fb959849ad6efff80050541cab3d25089d4 F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 -F src/pcache1.c 1e77432b40b7d3288327d9cdf399dcdfd2b6d3bf -F src/pragma.c ba149bbbc90783f84815636c509ced8eac11bbcf -F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9 -F src/printf.c ea82bcb1b83273b4c67177c233c1f78c81fc42f9 +F src/pcache1.c 69d137620a305f814398bd29a0c998038c0695e9 +F src/pragma.c c1f4d012ea9f6b1ce52d341b2cd0ad72d560afd7 +F src/pragma.h 09c89bca58e9a44de2116cc8272b8d454657129f +F src/prepare.c 1fffbdcd6f8a0173a8f70d71f22528f4c0e1e3d3 +F src/printf.c 54dd6dce95454fadffa3ebf7717c5f6c06250d1d F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 -F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada +F src/resolve.c 99eabf7eff0bfa65b75939b46caa82e2b2133f28 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c a4e8fda24c8eab2682a058bdda0d5d68cfe3919c -F src/shell.c ee1a80bf2b0e9e0c2b93db8f0f82b841289b2641 -F src/sqlite.h.in 9dfc99d6533d36d6a549c4f3f01cacc8be956ada +F src/select.c 1b0bfc7d59e48c26b895a6b719157111a617d9e3 +F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee +F src/sqlite.h.in ca27603a36fcacdaac5a19d8ee35aaff8ce8516f F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h eaf210295b551d4e40e622aec1b2261c0b28f844 -F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d -F src/status.c 81712116e826b0089bb221b018929536b2b5406f -F src/table.c e7a09215315a978057fb42c640f890160dbcc45e -F src/tclsqlite.c 0bbb44543175ef2033d39780a233f98bf354eff9 -F src/test1.c 093d8b5b54b829dcfebae3181d4406edcc935d90 +F src/sqliteInt.h 20d9c59fd82774503b8953acfbcc6ecbdd9ee6aa +F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 +F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 +F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e +F src/tclsqlite.c d4fa052d3fbb655150d4ca8eedc70384b98bfef3 +F src/test1.c 90fbedce75330d48d99eadb7d5f4223e86969585 F src/test2.c 577961fe48961b2f2e5c8b56ee50c3f459d3359d -F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c -F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df +F src/test3.c 64d2afdd68feac1bb5e2ffb8226c8c639f798622 +F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e F src/test5.c 5a34feec76d9b3a86aab30fd4f6cc9c48cbab4c1 F src/test6.c 41cacf3b0dd180823919bf9e1fbab287c9266723 -F src/test7.c 72b732baa5642f795655ba1126ea032af46ecfd2 -F src/test8.c df8dd4c99c1dd2225cb2a6f334299cddc5dcf1f1 +F src/test7.c 9c89a4f1ed6bb13af0ed805b8d782bd83fcd57e3 +F src/test8.c 610e3d523018ca63b08081795e76794a2121ec38 F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60 F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8 F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12 -F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e -F src/test_blob.c 1f2e3e25255b731c4fcf15ee7990d06347cb6c09 +F src/test_backup.c 2e6e6a081870150f20c526a2e9d0d29cda47d803 +F src/test_blob.c e5a7a81d61a780da79101aeb1e60d300af169e07 F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f -F src/test_config.c e7b2e1634324d746aa5e1c7e0929470e8be27953 -F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9 +F src/test_config.c c2d3ff6c129d50183900c7eff14158ff7e9b3f03 +F src/test_demovfs.c 0de72c2c89551629f58486fde5734b7d90758852 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f -F src/test_func.c 14e543ae4d905ee31dc322b2f8d31bfac1769d45 +F src/test_func.c f1ac201465472e76a73e2f3695c3553c63e7322a F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd F src/test_init.c 66b33120ffe9cd853b5a905ec850d51151337b32 -F src/test_intarray.c 6c610a21ab8edde85a3a2c7f2b069244ecf4d834 +F src/test_intarray.c 870124b95ec4c645d4eb84f15efb7133528fb1a5 F src/test_intarray.h 9dc57417fb65bc7835cc18548852cc08cc062202 F src/test_journal.c 5360fbe1d1e4416ca36290562fd5a2e3f70f32aa F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4 -F src/test_malloc.c b9495384e74923aefde8311de974bf9b0f5ba570 -F src/test_multiplex.c 72c0ad1e97af3d6d19975bbd81813072b40c7290 +F src/test_malloc.c 208f09a4e21defa496bc1094fcfadea19385a112 +F src/test_multiplex.c 9fefd23f6cc3fa9bf0748a5e453167e7b9f193ce F src/test_multiplex.h c08e4e8f8651f0c5e0509b138ff4d5b43ed1f5d3 F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f -F src/test_onefile.c 0396f220561f3b4eedc450cef26d40c593c69a25 -F src/test_osinst.c 3d0340bc31a9f3d8a3547e0272373e80f78dde25 +F src/test_onefile.c 38f7cbe79d5bafe95bde683cc3a53b8ca16daf10 +F src/test_osinst.c 5423dc1d355f594371f27dd292ca54bd320b8196 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 F src/test_quota.c 180813f43683be5725458fc1ff13ac455d8e722d F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d -F src/test_rtree.c fdd8d29ca5165c7857987a2ba263fac5c69e231f +F src/test_rtree.c bfe6f4386517f70054311109f3528adffec34485 F src/test_schema.c 2bdba21b82f601da69793e1f1d11bf481a79b091 F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe -F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e -F src/test_stat.c 9898687a6c2beca733b0dd6fe19163d987826d31 -F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd +F src/test_sqllog.c b690c12933f50ff46491e0d56a251f84ae16e914 +F src/test_superlock.c 06797157176eb7085027d9dd278c0d7a105e3ec9 F src/test_syscall.c 2e21ca7f7dc54a028f1967b63f1e76155c356f9b F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa -F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb -F src/test_vfs.c 8ee7be45fe773a150b4015ef957da960179ee43a +F src/test_thread.c af391ec03d23486dffbcc250b7e58e073f172af9 +F src/test_vfs.c 3b65d42e18b262805716bd96178c81da8f2d9283 F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 -F src/threads.c 2fb3ea4d70d5acf68b539c2489b4adace61cc01b -F src/tokenize.c e00458c9938072b0ea711c850b8dcf4ddcb5fe18 -F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f +F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 +F src/tokenize.c b15511a2396641792f386ceb440d1d922972a78e +F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c -F src/util.c 98a7627ca48ad3265b6940915a1d08355eb3fc7e -F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c -F src/vdbe.c ddfc977981cd6324668aa6b114045eb1c677421a -F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 -F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 -F src/vdbeapi.c 4bc511a46b9839392ae0e90844a71dc96d9dbd71 -F src/vdbeaux.c f06d38c71d7f533348c09869d69fd1b647042a5b -F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778 -F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f -F src/vdbesort.c 6d64c5448b64851b99931ede980addc3af70d5e2 -F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 -F src/vtab.c c08ec66f45919eaa726bf88aa53eb08379d607f9 -F src/wal.c 39303f2c9db02a4e422cd8eb2c8760420c6a51fe +F src/util.c a6431c92803b975b7322724a7b433e538d243539 +F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 +F src/vdbe.c 163e045d58ec5ff5384020e48b12ea49950c2922 +F src/vdbe.h 7e538ecf47dccb307ea2d087c3ddc2dd8d70e79d +F src/vdbeInt.h 9cbaa84f53ddd2d09a0cf61a94337a3a035d08a0 +F src/vdbeapi.c 583d56b129dd27f12bed518270de9ebe521e6a75 +F src/vdbeaux.c 03591cca98ec50e1493043f0ff7abbece0b9c83d +F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90 +F src/vdbemem.c 7bfbeef0978a2e1a05d979641fdbf7c189b7ddf4 +F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b +F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0 +F src/vtab.c c535e80259ebe616467181a83a4263555b97c694 +F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb +F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 88509f19a64a36e1c22a1dbdac74ee1a62d99dc3 -F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0 +F src/where.c 85fff9c40569ccb79c3177419b339e7d7df566cb +F src/whereInt.h cbe4aa57326998d89e7698ca65bb7c28541d483c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783 -F test/alter.test 547dc2d292644301ac9a7dda22b319b74f9c08d2 +F test/alter.test 2facdddf08d0d48e75dc6cc312cd2b030f4835dd F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060 F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d F test/alter4.test c461150723ac957f3b2214aa0b11552cd72023ec F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f -F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4 -F test/analyze3.test bf41f0f680dd1e0d44eed5e769531e93a5320275 +F test/analyze.test 3eb35a4af972f98422e5dc0586501b17d103d321 +F test/analyze3.test 0f0ee6135b293a0e5af471a8423b80b688469d71 F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213 F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4 F test/analyze6.test f1c552ce39cca4ec922a7e4e0e5d0203d6b3281f F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f F test/analyze8.test c05a461d0a6b05991106467d0c47480f2e709c82 -F test/analyze9.test 72795c8113604b5dcd47a1498a61d6d7fb5d041a +F test/analyze9.test 3dd9e203fad353ec8027b18a6d9a92af59f4e727 F test/analyzeA.test 3335697f6700c7052295cfd0067fc5b2aacddf9a F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93 F test/analyzeD.test 08f9d0bee4e118a66fff3a32d02dbe0ee0a2b594 F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d +F test/analyzeF.test 7ccd7a04f7d3061bde1a8a4dacc4792edccf6bf2 F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7 F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0 F test/atof1.test 08a61df9365c341f334a65f4348897312d8f3db7 -F test/attach.test 0d112b7713611fdf0340260192749737135fda5f +F test/attach.test 437107943f14d131cf5efc2ae5305a94d7cb1d58 F test/attach2.test 0ec5defa340363de6cd50fd595046465e9aaba2d F test/attach3.test 359eb65d00102cdfcef6fa4e81dc1648f8f80b27 F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c @@ -346,7 +349,7 @@ F test/auth.test 855233ef26eb3601b6886567ea4e326c72959360 F test/auth2.test 264c6af53cad9aba5218c68bbe18036e39007bfa F test/auth3.test 5cfa94ed90c6617c42b7ba4b133fd79678b251c7 F test/autoinc.test c58912526998a39e11f66b533e23cfabea7f25b7 -F test/autoindex1.test 6ff78b94f43a59616c06c11c55b12935173506d7 +F test/autoindex1.test 14b63a9f1e405fe6d5bfc8c8d00249c2ebaf13ea F test/autoindex2.test af7e595c6864cc6ef5fc38d5db579a3e34940cb8 F test/autoindex3.test a3be0d1a53a7d2edff208a5e442312957047e972 F test/autoindex4.test 49d3cd791a9baa16fb461d7ea3de80d019a819cf @@ -381,11 +384,12 @@ F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45 F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983 F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b F test/btree01.test e08b3613540145b353f20c81cb18ead54ff12e0f +F test/btree02.test fe69453d474d8154d19b904157ff1db4812fed99 F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3 F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0 F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738 -F test/capi3.test f0718f4f90d0efdc980119bfbdf1d7f1541ee5ef +F test/capi3.test bf6f0308bbbba1e770dac13aa08e5c2ac61c7324 F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 F test/capi3c.test fdc0d67a2cb8e8fc400d5b7735e330161ea057a2 F test/capi3d.test a82b6321c50a1cfc848e386fa2c851893606f68c @@ -395,14 +399,14 @@ F test/check.test 5831ddb6f2c687782eaf2e1a07b6e17f24c4f763 F test/close.test 340bd24cc58b16c6bc01967402755027c37eb815 F test/closure01.test b1703ba40639cfc9b295cf478d70739415eec6a4 F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91 -F test/collate1.test 73b91005f264b7c403e2d63a6708d150679ac99a +F test/collate1.test 08c18e7512a5a32c97938854263fa15362eeb846 F test/collate2.test 9aaa410a00734e48bcb27f3872617d6f69b2a621 -F test/collate3.test 79558a286362cb9ed603c6fa543f1cda7f563f0f +F test/collate3.test 89defc49983ddfbf0a0555aca8c0521a676f56a5 F test/collate4.test f04d5168685f2eef637ecfa2d4ddf8ec0d600177 F test/collate5.test 65d928034d30d2d263a80f6359f7549ee1598ec6 F test/collate6.test 8be65a182abaac8011a622131486dafb8076e907 F test/collate7.test 8ec29d98f3ee4ccebce6e16ce3863fb6b8c7b868 -F test/collate8.test df26649cfcbddf109c04122b340301616d3a88f6 +F test/collate8.test cd9b3d3f999b8520ffaa7cc1647061fc5bab1334 F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6 F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1 @@ -422,15 +426,16 @@ F test/corrupt8.test 2399dfe40d2c0c63af86706e30f3e6302a8d0516 F test/corrupt9.test 730a3db08d4ab9aa43392ea30d9c2b4879cbff85 F test/corruptA.test 53e56dafd180addcdadb402244b8cb9771d2ba26 F test/corruptB.test 73a8d6c0b9833697ecf16b63e3c5c05c945b5dec -F test/corruptC.test 02405cf7ed0c1e989060e1aab6d02ffbc3906fbb +F test/corruptC.test 3fcc0f73d2cf2d69befe2d96332b942426a6aae2 F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040 F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4 F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804 F test/corruptH.test 5dd4fa98c6c1ed33b178f9e8a48c4fdd3cfc9067 F test/corruptI.test 221ad8b7f0a9ac6b80fc577e73b5ad8cdea31243 +F test/corruptJ.test 9e29e7a81ee3b6ac50f77ea7a9e2f3fa03f32d91 F test/cost.test 19d314526616ce4473eb4e4e450fcb94499ce318 -F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5 +F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62 F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651 @@ -440,6 +445,7 @@ F test/crash5.test 05dd3aa9dbb751a22d5cdaf22a9c49b6667aa219 F test/crash6.test 4c56f1e40d0291e1110790a99807aa875b1647ba F test/crash7.test 1a194c4900a255258cf94b7fcbfd29536db572df F test/crash8.test 61442a9964ab6b124fc5254e4258b45747842e6f +F test/crashM.test d95f59046fa749b0d0822edf18a717788c8f318d F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8 F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c @@ -469,8 +475,8 @@ F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306 F test/e_expr.test 8f5fdd7261e2d746813b0c6a1c0e34824ad3c5ad F test/e_fkey.test a1783fe1f759e1990e6a11adfcf0702dac4d0707 F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459 -F test/e_insert.test 7b2fa9cd1456f83474d6c5d27db3abaeb8be2023 -F test/e_reindex.test 396b7b4f0a66863b4e95116a67d93b227193e589 +F test/e_insert.test 0e63edc037afe738bb81a626a676811ed7862c90 +F test/e_reindex.test 57d439f6c644befc8274ac93cf2f5449cf2736c1 F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6 F test/e_select.test 52692ff3849541e828ad4661fe3773a9b8711763 F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f @@ -478,8 +484,8 @@ F test/e_totalchanges.test b12ee5809d3e63aeb83238dd501a7bca7fd72c10 F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52 F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585 F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9 -F test/e_wal.test 0967f0b8f1dfda871dc7b9b5574198f1f4f7d69a -F test/e_walauto.test ca70cf75c07a6cb1874ced101dd426da76625649 +F test/e_wal.test ae9a593207a77d711443ee69ffe081fda9243625 +F test/e_walauto.test 6544af03423abc61b53cfb976839385ddc2a0a70 F test/e_walckpt.test 65e29b6631e51f210f83e4ff11571e647ba93608 F test/e_walhook.test da3ea8b3483d1af72190337bda50155a91a4b664 F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea @@ -493,16 +499,16 @@ F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75 F test/exclusive2.test 32798111aae78a5deec980eee383213f189df308 F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30 -F test/expr.test c4b9bf0cc60b26862475e19999fbd2609ca8259c +F test/expr.test 79c3e7502d9e571553b85f0ecc8ff2ac7d0e4931 F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9 F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7 F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146 -F test/fkey1.test e1d1fa84cde579185ea01358436839703e415a5b -F test/fkey2.test 1db212cda86b0d3ce72714001f7b6381c321341c +F test/fkey1.test de5b287f6a480b36bd51e8debcf48168e26e4ed2 +F test/fkey2.test f3d27ecba480a348c328965d154214719bb158a9 F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49 F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d -F test/fkey5.test 488601fbda8350619b3029487e56830447056fd2 +F test/fkey5.test 56bcb5a6e8b725b17febc267fb041a6695e86853 F test/fkey6.test abb59f866c1b44926fd02d1fdd217d831fe04f48 F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13 F test/fkey8.test 8f08203458321e6c19a263829de4cfc936274ab0 @@ -545,7 +551,7 @@ F test/fts2r.test b154c30b63061d8725e320fba1a39e2201cadd5e F test/fts2token.test d8070b241a15ff13592a9ae4a8b7c171af6f445a F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654 F test/fts3_common.tcl 99cf6659b87c0f74f55963c2aea03b3a7d66ceb0 -F test/fts3aa.test edd20ddbbc5b6015ab340abf2ca278ae11ec387d +F test/fts3aa.test 6c263a6f8845205ee02550981a94c2e8dc1e7058 F test/fts3ab.test 7f6cf260ae80dda064023df8e8e503e9a412b91f F test/fts3ac.test 636ed7486043055d4f126a0e385f2d5a82ebbf63 F test/fts3ad.test e40570cb6f74f059129ad48bcef3d7cbc20dda49 @@ -560,7 +566,7 @@ F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8 F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18 F test/fts3ao.test 3e4e3d5e75c076520341d0bdf4eb17c00e8cbde2 -F test/fts3atoken.test fca30fd86db9241d571c637751e9a8a2f50f1451 +F test/fts3atoken.test e3a126365131a6db52efc20a9a6053cd44e5f289 F test/fts3auto.test b981fea19b132b4e6878f50d7c1f369b28f68eb9 F test/fts3aux1.test f8f287a4a73f381f8fa15b6a70f36245f903d221 F test/fts3aux2.test 7ae2b2c13aefdf4169279a27a5f51780ce57f6ba @@ -581,26 +587,27 @@ F test/fts3expr.test 3401d47b229c4504424caf362cc4ff704cad4162 F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a F test/fts3expr3.test 9e91b8edbcb197bf2e92161aa7696446d96dce5f F test/fts3expr4.test e1be1248566f43c252d4404d52914f1fc4bfa065 +F test/fts3expr5.test f9abfffbf5e53d48a33e12a1e8f8ba2c551c9b49 F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660 -F test/fts3fault2.test 3198eef2804deea7cac8403e771d9cbcb752d887 +F test/fts3fault2.test f953bb3cf903988172270a9a0aafd5a890b0f98f F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641 F test/fts3join.test 53e66a0c21eb568580674a43b21c059acb26f499 F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6 -F test/fts3matchinfo.test 58544fa4d254000fa4e7f494b0a832f7ba61d45e +F test/fts3matchinfo.test 3e5f5ac2e0a8ba42eafd4c685f803ca48b4c3a83 F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905 -F test/fts3prefix.test b36d4f00b128a51e7b386cc013a874246d9d7dc1 +F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2 F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce -F test/fts3query.test 4fefd43ff24993bc2c9b2778f2bec0cc7629e7ed +F test/fts3query.test c838b18f2b859e15fd31c64be3d79ef1556803ca F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0 F test/fts3shared.test 57e26a801f21027b7530da77db54286a6fe4997e -F test/fts3snippet.test d524af6bcef4714e059ef559113dbdc924cd33d1 +F test/fts3snippet.test 63dbd687d5bf5191f1b8e6a0977aa9c1e28a7004 F test/fts3sort.test ed34c716a11cc2009a35210e84ad5f9c102362ca -F test/fts3tok1.test c551043de056b0b1582a54e878991f57bad074bc +F test/fts3tok1.test 178c050199af8c05299b1ad572514ce1c54b7827 F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d F test/fts3varint.test 752c08ed5d32c5d7dc211b056f4ed68a76b7e36e F test/fts4aa.test 10aac8e9d62c7357590acfabe3fad01e9a9ce1cb -F test/fts4check.test 74d77f6cdb768ac49df5afda575cef14ae3d239a -F test/fts4content.test 2e7252557d6d24afa101d9ba1de710d6140e6d06 +F test/fts4check.test 9d9e818fd6cb29c0e007cd6d00447739d4fde430 +F test/fts4content.test abb0c77bc3da3df64fec72e00844d2257a90025d F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01 F test/fts4growth.test df10fde9f47cf5c71861e63fd8efcd573c4f7e53 F test/fts4growth2.test 2f063be1902a73cd087355837c52fed42ac11a5d @@ -620,45 +627,49 @@ F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f F test/func5.test cdd224400bc3e48d891827cc913a57051a426fa4 F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74 F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1 -F test/fuzz2.test b34fe575aa10292135421ff4bf315de4cde7824a +F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1 F test/fuzz3.test efd384b896c647b61a2c1848ba70d42aad60a7b3 F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26 +F test/fuzzdata1.txt 9fceb50868e0b798160e83742bd7e44e457176a0 +F test/fuzzdata2.txt ba9b4467d7ec46cc85d32c0d031540cd727ae6ad F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36 F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536 F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98 -F test/hexlit.test f9ecde8145bfc2341573473256c74ae37a200497 +F test/hexlit.test 1d312fa816dfd3650a3bb488093bc09a0c927f67 F test/hook.test 162d7cef7a2d2b04839fe14402934e6a1b79442f F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 -F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e +F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8 +F test/in.test b52fa96bcf6cebc5c8829c822315d0f87af9c6c2 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068 F test/in5.test 1de657472fa9ac2924be25c2c959ac5ca1aae554 F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328 -F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600 +F test/incrblob2.test a5ce5ed1d0b01e2ed347245a21170372528af0a5 F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4 F test/incrblob4.test f26502a5697893e5acea268c910f16478c2f0fab F test/incrblob_err.test af1f12ba60d220c9752073ff2bda2ad59e88960d F test/incrblobfault.test 280474078f6da9e732cd2a215d3d854969014b6e +F test/incrcorrupt.test 9786cba68c5832f01887fde1c06b43c3904d86f6 F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32 -F test/incrvacuum2.test 379eeb8740b0ef60c372c439ad4cbea20b34bb9b +F test/incrvacuum2.test 676c41428765d58f1da7dbe659ef27726d3d30ac F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635 F test/index.test 4d990005a67a36984e4f1a5f1bdccea8d08da4ee F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 -F test/index3.test 55a90cff99834305e8141df7afaef39674b57062 +F test/index3.test b6ec456cf3b81d9a32123fe7e449bde434db338b F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 F test/index5.test 25b0b451aceed4ac5f7d49f856f6de7257470b3e -F test/index6.test c56852451b574ad5b2a1789e566e62e6ab244f42 -F test/index7.test 917cf1e1c7439bb155abbeabec511b28945e157b -F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec +F test/index6.test 3ae54e53c53f2adcacda269237d8e52bdb05a481 +F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c +F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353 F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371 -F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435 +F test/insert2.test 4d14b8f1b810a41995f6286b64a6943215d52208 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30 -F test/insert4.test 4791662c50518bdd37d394cae9a7a8014e845bb3 +F test/insert4.test a20432f1c0fbbcff8f11d0e6ab4acb8c9db58023 F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6 F test/instr.test 737bbf80685232033f3abedc6ae92f75860b5dd2 F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4 @@ -680,32 +691,33 @@ F test/join6.test cfe6503791ceb0cbb509966740286ec423cbf10b F test/journal1.test 69abc726c51b4a0409189f9a85191205297c0577 F test/journal2.test ae06f566c28552c313ded3fee79a6c69e6d049b1 F test/journal3.test ff8af941f9e06161d3db1b46bb9f965ff0e7f307 -F test/jrnlmode.test 9ee3a78f53d52cca737db69293d15dc41c0cbd36 +F test/jrnlmode.test 7864d59cf7f6e552b9b99ba0f38acd167edc10fa F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 -F test/like.test e191e536d0fcd722a6b965e7cd1ee0bfd12a5991 +F test/like.test 4f2a71d36a536233727f71995fef900756705e56 F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da -F test/limit.test 3d7df19c35ac672a11f7de406cd3205d592babbb +F test/like3.test 7b0525a39e4f25c4fd113de7e2e28eb712dcdedf +F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e F test/loadext.test 648cb95f324d1775c54a55c12271b2d1156b633b F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7 -F test/lock.test 87af515b0c4cf928576d0f89946d67d7c265dfb4 +F test/lock.test b984ab9034e7389be0d863fe4e64cbbc4d2028f5 F test/lock2.test 5242d8ac4e2d59c403aebff606af449b455aceff F test/lock3.test f271375930711ae044080f4fe6d6eda930870d00 F test/lock4.test e175ae13865bc87680607563bafba21f31a26f12 F test/lock5.test c6c5e0ebcb21c61a572870cc86c0cb9f14cede38 F test/lock6.test ad5b387a3a8096afd3c68a55b9535056431b0cf5 F test/lock7.test 49f1eaff1cdc491cc5dee3669f3c671d9f172431 -F test/lock_common.tcl 0c270b121d40959fa2f3add382200c27045b3d95 +F test/lock_common.tcl 7ffb45accf6ee91c736df9bafe0806a44358f035 F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2 F test/main.test 16131264ea0c2b93b95201f0c92958e85f2ba11a F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9 -F test/malloc.test 96939d2d1a6f39667bbebe5bc27c6525f2ab614e +F test/malloc.test 21c213365f2cca95ab2d7dc078dc8525f96065f8 F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a F test/malloc4.test 957337613002b7058a85116493a262f679f3a261 -F test/malloc5.test fafce0aa9157060445cd1a56ad50fc79d82f28c3 +F test/malloc5.test 79182b8bffd6d62f77b1a5a8ba8e6bf0e5053b8e F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151 F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d @@ -721,7 +733,7 @@ F test/mallocG.test 0ff91b65c50bdaba680fb75d87fe4ad35bb7934f F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6 F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e -F test/mallocK.test 3cff7c0f64735f6883bacdd294e45a6ed5714817 +F test/mallocK.test da01dcdd316767b8356741f8d33a23a06a23def5 F test/mallocL.test 252ddc7eb4fbf75364eab17b938816085ff1fc17 F test/malloc_common.tcl 3663f9001ce3e29bbaa9677ffe15cd468e3ec7e3 F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e @@ -734,15 +746,16 @@ F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f -F test/misc1.test 1201a037c24f982cc0e956cdaa34fcaf6439c417 +F test/misc1.test 783ba75743b2cf71e0f646bf540a6cef57264811 F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 -F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5 +F test/misc5.test f96428ea95b3820aafc6f1c50cf48a09e4597ee1 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2 F test/misc8.test fc2754d38892f7dac30c22db3616c2764f117d66 F test/misuse.test 3c34719944ba045cc6c188a4852ba04680728912 +F test/mkfuzzdata1.tcl 5f9c33fadc64b078bb4a2c04c18b6dd3da075bec F test/mmap1.test 1bfd611b9841eafb44f7d83c0788e146d84a33c9 F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e @@ -750,7 +763,7 @@ F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3 F test/multiplex.test efd015ca0b5b4a57dc9535b8feb1273eebeadb60 F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101 -F test/multiplex4.test d3e8a5a522c51cbf3ed1c5b0bd496be02c29d7b1 +F test/multiplex4.test e8ae4c4bd70606a5727743241f13b5701990abe4 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41 F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660 F test/nan.test e9648b9d007c7045242af35e11a984d4b169443a @@ -759,10 +772,10 @@ F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161 F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934 F test/notnull.test f8fcf58669ddba79274daa2770d61dfad8274f62 -F test/null.test a8b09b8ed87852742343b33441a9240022108993 +F test/null.test 0dcce4f04284ec66108c503327ad6d224c0752b3 F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 -F test/orderby1.test eb246e377612b21a418fbea57047ba8ea88aaa6b +F test/orderby1.test 870e150450437d3980badbde3d0166b81d9e33f6 F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04 F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99 F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4 @@ -780,16 +793,16 @@ F test/pagerfault.test ae9ee0db5a30aecda9db8290ce3dd12e5f7bbaa1 F test/pagerfault2.test caf4c7facb914fd3b03a17b31ae2b180c8d6ca1f F test/pagerfault3.test 1003fcda009bf48a8e22a516e193b6ef0dd1bbd8 F test/pageropt.test 6b8f6a123a5572c195ad4ae40f2987007923bbd6 -F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 +F test/pagesize.test 5769fc62d8c890a83a503f67d47508dfdc543305 F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff F test/permutations.test f9cc1dd987986c9d4949211c7a4ed55ec9aecba1 -F test/pragma.test aa16dedfe01c02c8895169012f7dfde9c163f0d5 -F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 +F test/pragma.test be7195f0aa72bdb8a512133e9640ac40f15b57a2 +F test/pragma2.test f624a496a95ee878e81e59961eade66d5c00c028 F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c -F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 -F test/printf2.test b4acd4bf8734243257f01ddefa17c4fb090acc8a +F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc +F test/printf2.test 0b61566dd1c0f0b802f59dffa228c5dc5aa6b054 F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca @@ -800,11 +813,11 @@ F test/quota2.test 7dc12e08b11cbc4c16c9ba2aa2e040ea8d8ab4b8 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df -F test/rdonly.test dd30a4858d8e0fbad2304c2bd74a33d4df36412a +F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8 F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 -F test/releasetest.tcl 13f401c10dd4fe1a2fb811ae6ed27fd7d1300d3c -F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a +F test/releasetest.tcl 7ad4fd49ae50c41ec7781815bdda8a8b278781d4 +F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14 F test/rollbackfault.test 6a004f71087cc399296cffbb5429ea6da655ae65 @@ -827,20 +840,20 @@ F test/schema4.test e6a66e20cc69f0e306667c08be7fda3d11707dc5 F test/schema5.test 29699b4421f183c8f0e88bd28ce7d75d13ea653e F test/securedel.test 21749c32ccc30f1ea9e4b9f33295a6521ec20fa0 F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5 -F test/select1.test fc2a61f226a649393664ad54bc5376631801517c +F test/select1.test be62204d2bd9a5a8a149e9974cfddce893d8f686 F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56 F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054 -F test/select4.test 8c5a60d439e2df824aed56223566877a883c5c84 +F test/select4.test 824342f382f16b4afe42d0887ef82b3d6abb6075 F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535 -F test/select6.test e76bd10a56988f15726c097a5d5a7966fe82d3b2 +F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0 F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95 -F test/selectA.test 64b88a80271c1710966e50e633380696b60a12a4 +F test/selectA.test e452bdb975f488ea46d091382a9185b5853ed2c7 F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25 F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977 F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394 -F test/selectE.test fc02a1eb04c8eb537091482644b7d778ae8759b7 +F test/selectE.test a8730ca330fcf40ace158f134f4fe0eb00c7edbf F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3 F test/selectG.test e8600e379589e85e9fefd2fe4d44a4cdd63f6982 F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118 @@ -856,14 +869,14 @@ F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5 F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e F test/shared_err.test 2f2aee20db294b9924e81f6ccbe60f19e21e8506 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 -F test/shell1.test cdeb849acc2c37aada70d084564b0cc0a2c7df08 +F test/shell1.test ce5e744870387164703bf2dee2cc9753e4a71513 F test/shell2.test 12b8bf901b0e3a8ac58cf5c0c63a0a388d4d1862 F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29 -F test/shell4.test 8a9c08976291e6c6c808b4d718f4a8b299f339f5 -F test/shell5.test 81aba4793fa7441b1300daae1aec4f7e4b5741c1 +F test/shell4.test ddf0a99044e2245a87fc17423e3aaa1445b3243b +F test/shell5.test c04e9f9f948305706b88377c464c7f08ce7479f9 F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5 -F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868 +F test/shrink.test 06deac10d591186017466ce67d10645150bfdeec F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 F test/skipscan1.test 2ddfe5d168462170c4487f534e2a99fb006b2076 F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a @@ -871,11 +884,11 @@ F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5 F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2 F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f -F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24 +F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087 F test/sort.test 3f492e5b7be1d3f756728d2ff6edf4f6091e84cb F test/sort2.test 37afbc03f5559f2eb0f18940b55d38dfbb5172ac F test/sort3.test 6178ade30810ac9166fcdf14b7065e49c0f534e2 -F test/sort4.test d5e8903194ae551551349ce25dc8d0b40ca2b9c3 +F test/sort4.test 5c34d9623a4ae5921d956dfa2b70e77ed0fc6e5c F test/sort5.test a448240a42b49239edc00f85d6d7ac7a1b261e1f F test/sortfault.test d4ccf606a0c77498e2beb542764fd9394acb4d66 F test/speed1.test f2974a91d79f58507ada01864c0e323093065452 @@ -886,12 +899,13 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523 F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715 F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b -F test/speedtest1.c e4e2aa37ff66bad9f414a50a8cb9edfaac65c9e5 +F test/speedtest1.c 2b416dca3a155fcaa849540b2e7fc1df12896c23 F test/spellfix.test 24f676831acddd2f4056a598fd731a72c6311f49 -F test/sqllimits1.test 9014524e7ab16e2a4976b13397db4c29cc29c6d9 -F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de +F test/sqllimits1.test e05786eaed7950ff6a2d00031d001d8a26131e68 +F test/stat.test 8de91498c99f5298b303f70f1d1f3b9557af91bf +F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1 F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9 -F test/subquery.test 666fdecceac258f5fd84bed09a64e49d9f37edd9 +F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f F test/subquery2.test 438f8a7da1457277b22e4176510f7659b286995f F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4 F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a @@ -899,14 +913,14 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85 F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6 -F test/table.test 06271d61eb13871490d38168433c1ef3dd82bb2a +F test/table.test bd841e8df69b99172ce9c7d53587463913d711ca F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 -F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43 +F test/tclsqlite.test 7fb866443c7deceed22b63948ccd6f76b52ad054 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 -F test/tester.tcl ed77454e6c7b40eb501db7e79d1c6fbfd3eebbff +F test/tester.tcl 51211254f2ee2340d3e4fa0a83bd5381b9e1a227 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1062,23 +1076,23 @@ F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1 F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7 F test/tpch01.test 04adbf8d8300fa60a222f28d901abd76e7be6dd4 F test/trace.test 73a5508100f7fccfbc3f8018d5f6963ed478eea0 -F test/trace2.test 93b47ca6996c66b47f57224cfb146f34e07df382 +F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983 F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6 F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76 F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94 F test/transitive1.test 03f532954f46cdf5608f7766bff0b0c52bf2a7cd -F test/trigger1.test dc47573ac79ffe0ee3eecaa517d70d8dacbccd03 +F test/trigger1.test ea9624cc1dae05645469df6119fa815f9e6f1e8c F test/trigger2.test 5cd7d69a7ba1143ee045e4ae2963ff32ae4c87a6 F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945 F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359 F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83 F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9 -F test/trigger7.test b39e6dee1debe0ff9c2ef66326668f149f07c9c4 +F test/trigger7.test 200dd51e728c9cdc20c72d99d9e9d45c667248f8 F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4 F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41 F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332 F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe -F test/triggerC.test a68980c5955d62ee24be6f97129d824f199f9a4c +F test/triggerC.test 302d8995f5ffe63bbc15053abb3ef7a39cf5a092 F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650 F test/triggerE.test 355e9c5cbaed5cd039a60baad1fb2197caeb8e52 F test/tt3_checkpoint.c 9e75cf7c1c364f52e1c47fd0f14c4340a9db0fe1 @@ -1098,14 +1112,14 @@ F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9 F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d -F test/vacuum2.test af432e6e3bfc0ea20a80cb86a03c7d9876d38324 +F test/vacuum2.test aa048abee196c16c9ba308465494009057b79f9b F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 F test/view.test f311691d696a5cc27e3c1b875cec1b0866b4ccd9 -F test/vtab1.test 1cef14310144718812351a61c5cfb4ba8494a171 -F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d +F test/vtab1.test d1e5ec7a818f1d3f0402382b6a1d0c06071b770f +F test/vtab2.test 3644649aa8d1daac57fd541f6a5f914cac59203e F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275 F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391 @@ -1113,7 +1127,7 @@ F test/vtab6.test 5f5380c425e52993560ab4763db4f826d2ba7b09 F test/vtab7.test ae560ebea870ed04e9aa4177cc302f910faaabb5 F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583 F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b -F test/vtabA.test c86e1990b7e1e2bb34602a06fffa4c69f2b516dc +F test/vtabA.test 1317f06a03597eee29f40a49b6c21e1aaba4285f F test/vtabB.test 04df5dc531b9f44d9ca65b9c1b79f12b5922a796 F test/vtabC.test 4528f459a13136f982e75614d120aef165f17292 F test/vtabD.test 05b3f1d77117271671089e48719524b676842e96 @@ -1126,7 +1140,7 @@ F test/wal.test 885f32b2b390b30b4aa3dbb0e568f8f78d40f5cc F test/wal2.test 1f841d2048080d32f552942e333fd99ce541dada F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0 F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c -F test/wal5.test dba8f5f5de95178bc40521d6edf153b2e2829917 +F test/wal5.test 88b5d9a6a3d1532497ee9f4296f010d66f07e33c F test/wal6.test 527581f5527bf9c24394991e2be83000aace5f9e F test/wal64k.test 163655ecd2cb8afef4737cac2a40fdd2eeaf20b8 F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd @@ -1135,6 +1149,7 @@ F test/wal9.test 378e76a9ad09cd9bee06c172ad3547b0129a6750 F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe F test/walbak.test b9f68e39646375c2b877be906babcc15d38b4877 F test/walbig.test f437473a16cfb314867c6b5d1dbcd519e73e3434 +F test/walblock.test be48f3a75eff0b4456209f26b3ce186c2015497d F test/walcksum.test 9afeb96240296c08c72fc524d199c912cfe34daa F test/walcrash.test 451d79e528add5c42764cea74aa2750754171b25 F test/walcrash2.test a0edab4e5390f03b99a790de89aad15d6ec70b36 @@ -1155,25 +1170,26 @@ F test/where4.test d8420ceeb8323a41ceff1f1841fc528e824e1ecf F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8 -F test/where8.test 806f1dcec4088be2b826b33f757fe6e17c3236a1 +F test/where8.test 2eafe74e01cc10355985874e1ff868ac03dbae5e F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739 F test/where9.test 729c3ba9b47e8f9f1aab96bae7dad2a524f1d1a2 F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a -F test/whereD.test fd9120e262f9da3c45940f52aefeef4d15b904e5 +F test/whereD.test 9eba1f9b18e5b19a0b0bcaae5e8c037260195f2b F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7 F test/whereG.test 69f5ec4b15760a8c860f80e2d55525669390aab3 F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2 F test/whereI.test 1d89199697919d4930be05a71e7fe620f114e622 F test/whereJ.test 55a3221706a7ab706293f17cc8f96da563bf0767 +F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c -F test/win32lock.test 71642fa56e9b06e5cfffe6bad67cb8c1eb2c555a +F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972 F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d -F test/with1.test 268081a6b14817a262ced4d0ee34d4d2a1dd2068 +F test/with1.test a86bf7f9288ba759a25ee57221d3bffaca36032a F test/with2.test ee227a663586aa09771cafd4fa269c5217eaf775 F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991 F test/without_rowid1.test 7862e605753c8d25329f665fa09072e842183151 @@ -1181,52 +1197,55 @@ F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99 F test/without_rowid3.test 1081aabf60a1e1123b7f9a8f6ae19954351843b0 F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a F test/without_rowid5.test 61256715b686359df48ca1742db50cc7e3e7b862 -F test/without_rowid6.test deddb78ef539c355bddec00cdfaea6c56efd8b3f +F test/without_rowid6.test db0dbf03c49030aa3c1ba5f618620334bd2baf5f F test/wordcount.c 9915e06cb33d8ca8109b8700791afe80d305afda -F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 +F test/zeroblob.test fb3c0e4ab172d386954deda24c03f500e121d80d F test/zerodamage.test cf6748bad89553cc1632be51a6f54e487e4039ac -F tool/build-all-msvc.bat a0534c971b86fe95f1983f445db5b896d3394818 x +F tool/build-all-msvc.bat 9058bd90a3c078a3d8c17d40e853aaa0f47885f4 x F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367 F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2 F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2 F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1 F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439 +F tool/fuzzershell.c e8be9a8bd8e0e7814592c5e3e38de99ad7beee83 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce -F tool/lemon.c 1864c4fe4a72b1bb28f1792b60504804fe82c5d2 +F tool/lemon.c b9109f59b57e7b6f101c4fe644c8361ba6dee969 F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e -F tool/mkpragmatab.tcl 07a5124cf2dbafa1b375eefcf8ac4227028b0f8b +F tool/mkpragmatab.tcl 94f196c9961e0ca3513e29f57125a3197808be2d F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 -F tool/mksqlite3c-noext.tcl 9ef48e1748dce7b844f67e2450ff9dfeb0fb4ab5 -F tool/mksqlite3c.tcl cfde806851c413db7689b9cb74a4eeb92539c601 -F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12 +F tool/mksqlite3c-noext.tcl 69bae8ce4aa52d2ff82d4a8a856bf283ec035b2e +F tool/mksqlite3c.tcl 10c06c9c616415c0269c13a33304a75e3c319c3f +F tool/mksqlite3h.tcl 44730d586c9031638cdd2eb443b801c0d2dbd9f8 F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b -F tool/mkvsix.tcl 52a4c613707ac34ae9c226e5ccc69cb948556105 +F tool/mkvsix.tcl 3b58b9398f91c7dbf18d49eb87cefeee9efdbce1 F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091 F tool/omittest.tcl 34d7ac01fe4fd18e3637f64abe12c40eca0f6b97 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/showdb.c bd073a78bce714a0e42d92ea474b3eb8cb53be5d +F tool/showdb.c 3b5d335d537e4dc44d0c86967023819453c87dc6 F tool/showjournal.c 053eb1cc774710c6890b7dd6293300cc297b16a5 +F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68 F tool/showstat4.c 9515faa8ec176599d4a8288293ba8ec61f7b728a F tool/showwal.c 85cb36d4fe3e93e2fbd63e786e0d1ce42d0c4fad F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b -F tool/spaceanal.tcl 8e50b217c56a6a086a1b47eac9d09c5cd65b996f +F tool/spaceanal.tcl d5a09620c66a6c144576cb9d2bdfa9a6fbe362a5 F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355 F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c +F tool/sqldiff.c 10e3c01111f97b99627adf0954cf5ffbfba0723c F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43 F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d F tool/symbols.sh fec58532668296d7c7dc48be9c87f75ccdb5814f @@ -1237,11 +1256,11 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P ec27ab0eb3a1ee08a73dda23d2a0f9fb70962745 -R 7a9d6545656b7d4fe08d198e32a78d62 +P 40f67265c46572cdcfb802a2464d315a821f9be1 +R cbe65e60b1898893979d31fa14de6276 T +bgcolor * #d0c0ff T +sym-release * -T +sym-version-3.8.8.3 * +T +sym-version-3.8.10.2 * U drh -Z 9dbdbd01efd2c5089344e2a1709c163b +Z 9be1f4bd2e2a43cd85454d49558db35f # Remove this line to create a well-formed manifest. diff --git a/manifest.uuid b/manifest.uuid index 007138a..66cf9f1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9d6c1880fb75660bbabd693175579529785f8a6b +2ef4f3a5b1d1d0c4338f8243d40a2452cc1f7fe4 diff --git a/mkopcodeh.awk b/mkopcodeh.awk index babfdc6..94db75e 100644 --- a/mkopcodeh.awk +++ b/mkopcodeh.awk @@ -72,7 +72,6 @@ sub("\r","",name) op[name] = -1 # op[x] holds the numeric value for OP symbol x jump[name] = 0 - out2_prerelease[name] = 0 in1[name] = 0 in2[name] = 0 in3[name] = 0 @@ -92,8 +91,6 @@ sub(",","",x) if(x=="jump"){ jump[name] = 1 - }else if(x=="out2-prerelease"){ - out2_prerelease[name] = 1 }else if(x=="in1"){ in1[name] = 1 }else if(x=="in2"){ @@ -194,13 +191,12 @@ END { name = def[i] a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = 0 if( jump[name] ) a0 = 1; - if( out2_prerelease[name] ) a1 = 2; - if( in1[name] ) a2 = 4; - if( in2[name] ) a3 = 8; - if( in3[name] ) a4 = 16; - if( out2[name] ) a5 = 32; - if( out3[name] ) a6 = 64; - bv[i] = a0+a1+a2+a3+a4+a5+a6+a7; + if( in1[name] ) a2 = 2; + if( in2[name] ) a3 = 4; + if( in3[name] ) a4 = 8; + if( out2[name] ) a5 = 16; + if( out3[name] ) a6 = 32; + bv[i] = a0+a1+a2+a3+a4+a5+a6; } print "\n" print "/* Properties such as \"out2\" or \"jump\" that are specified in" @@ -208,12 +204,11 @@ END { print "** are encoded into bitvectors as follows:" print "*/" print "#define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */" - print "#define OPFLG_OUT2_PRERELEASE 0x0002 /* out2-prerelease: */" - print "#define OPFLG_IN1 0x0004 /* in1: P1 is an input */" - print "#define OPFLG_IN2 0x0008 /* in2: P2 is an input */" - print "#define OPFLG_IN3 0x0010 /* in3: P3 is an input */" - print "#define OPFLG_OUT2 0x0020 /* out2: P2 is an output */" - print "#define OPFLG_OUT3 0x0040 /* out3: P3 is an output */" + print "#define OPFLG_IN1 0x0002 /* in1: P1 is an input */" + print "#define OPFLG_IN2 0x0004 /* in2: P2 is an input */" + print "#define OPFLG_IN3 0x0008 /* in3: P3 is an input */" + print "#define OPFLG_OUT2 0x0010 /* out2: P2 is an output */" + print "#define OPFLG_OUT3 0x0020 /* out3: P3 is an output */" print "#define OPFLG_INITIALIZER {\\" for(i=0; i<=max; i++){ if( i%8==0 ) printf("/* %3d */",i) diff --git a/mptest/crash01.test b/mptest/crash01.test index 46f170c..f1483df 100644 --- a/mptest/crash01.test +++ b/mptest/crash01.test @@ -32,6 +32,7 @@ --end --wait 1 --task 2 + DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER PRIMARY KEY, b); INSERT INTO t2 SELECT a, b FROM t1; UPDATE t1 SET b='x'||a||'y'; @@ -46,6 +47,7 @@ --match 29 28 27 26 25 --end --task 3 + DROP TABLE IF EXISTS t3; CREATE TABLE t3(a INTEGER PRIMARY KEY, b); INSERT INTO t3 SELECT a, b FROM t1; UPDATE t1 SET b='x'||a||'y'; @@ -60,6 +62,7 @@ --match 29 28 27 26 25 --end --task 4 + DROP TABLE IF EXISTS t4; CREATE TABLE t4(a INTEGER PRIMARY KEY, b); INSERT INTO t4 SELECT a, b FROM t1; UPDATE t1 SET b='x'||a||'y'; @@ -74,6 +77,7 @@ --match 29 28 27 26 25 --end --task 5 + DROP TABLE IF EXISTS t5; CREATE TABLE t5(a INTEGER PRIMARY KEY, b); INSERT INTO t5 SELECT a, b FROM t1; UPDATE t1 SET b='x'||a||'y'; diff --git a/mptest/mptest.c b/mptest/mptest.c index 7b56b61..f81ffb5 100644 --- a/mptest/mptest.c +++ b/mptest/mptest.c @@ -53,6 +53,13 @@ # define GETPID getpid #endif +/* The directory separator character(s) */ +#if defined(_WIN32) +# define isDirSep(c) (((c) == '/') || ((c) == '\\')) +#else +# define isDirSep(c) ((c) == '/') +#endif + /* Mark a parameter as unused to suppress compiler warnings */ #define UNUSED_PARAMETER(x) (void)x @@ -824,7 +831,7 @@ static void waitForClient(int iClient, int iTimeout, char *zErrPrefix){ */ static char *filenameTail(char *z){ int i, j; - for(i=j=0; z[i]; i++) if( z[i]=='/' ) j = i+1; + for(i=j=0; z[i]; i++) if( isDirSep(z[i]) ) j = i+1; return z+j; } @@ -1021,9 +1028,9 @@ static void runScript( char *zNewFile, *zNewScript; char *zToDel = 0; zNewFile = azArg[0]; - if( zNewFile[0]!='/' ){ + if( !isDirSep(zNewFile[0]) ){ int k; - for(k=(int)strlen(zFilename)-1; k>=0 && zFilename[k]!='/'; k--){} + for(k=(int)strlen(zFilename)-1; k>=0 && !isDirSep(zFilename[k]); k--){} if( k>0 ){ zNewFile = zToDel = sqlite3_mprintf("%.*s/%s", k,zFilename,zNewFile); } @@ -1231,7 +1238,7 @@ static void usage(const char *argv0){ int i; const char *zTail = argv0; for(i=0; argv0[i]; i++){ - if( argv0[i]=='/' ) zTail = argv0+i+1; + if( isDirSep(argv0[i]) ) zTail = argv0+i+1; } fprintf(stderr,"Usage: %s DATABASE ?OPTIONS? ?SCRIPT?\n", zTail); exit(1); @@ -1252,7 +1259,7 @@ static void unrecognizedArguments( exit(1); } -int main(int argc, char **argv){ +int SQLITE_CDECL main(int argc, char **argv){ const char *zClient; int iClient; int n, i; @@ -1262,6 +1269,9 @@ int main(int argc, char **argv){ int taskId; const char *zTrace; const char *zCOption; + const char *zJMode; + const char *zNRep; + int nRep = 1, iRep; g.argv0 = argv[0]; g.iTrace = 1; @@ -1277,6 +1287,10 @@ int main(int argc, char **argv){ } n = argc-2; sqlite3_snprintf(sizeof(g.zName), g.zName, "%05d.mptest", GETPID()); + zJMode = findOption(argv+2, &n, "journalmode", 1); + zNRep = findOption(argv+2, &n, "repeat", 1); + if( zNRep ) nRep = atoi(zNRep); + if( nRep<1 ) nRep = 1; g.zVfs = findOption(argv+2, &n, "vfs", 1); zClient = findOption(argv+2, &n, "client", 1); g.zErrLog = findOption(argv+2, &n, "errlog", 1); @@ -1305,6 +1319,9 @@ int main(int argc, char **argv){ GETPID(), iClient); }else{ if( g.iTrace>0 ){ + printf("BEGIN: %s", argv[0]); + for(i=1; i0 ){ if( n>0 ) unrecognizedArguments(argv[0], n, argv+2); if( g.iTrace ) logMessage("start-client"); @@ -1349,6 +1377,9 @@ int main(int argc, char **argv){ } if( n>1 ) unrecognizedArguments(argv[0], n, argv+2); runSql( + "DROP TABLE IF EXISTS task;\n" + "DROP TABLE IF EXISTS counters;\n" + "DROP TABLE IF EXISTS client;\n" "CREATE TABLE task(\n" " id INTEGER PRIMARY KEY,\n" " name TEXT,\n" @@ -1364,10 +1395,12 @@ int main(int argc, char **argv){ "CREATE TABLE client(id INTEGER PRIMARY KEY, wantHalt);\n" ); zScript = readFile(argv[2]); - if( g.iTrace ) logMessage("begin script [%s]\n", argv[2]); - runScript(0, 0, zScript, argv[2]); + for(iRep=1; iRep<=nRep; iRep++){ + if( g.iTrace ) logMessage("begin script [%s] cycle %d\n", argv[2], iRep); + runScript(0, 0, zScript, argv[2]); + if( g.iTrace ) logMessage("end script [%s] cycle %d\n", argv[2], iRep); + } sqlite3_free(zScript); - if( g.iTrace ) logMessage("end script [%s]\n", argv[2]); waitForClient(0, 2000, "during shutdown...\n"); trySql("UPDATE client SET wantHalt=1"); sqlite3_sleep(10); @@ -1391,11 +1424,14 @@ int main(int argc, char **argv){ } sqlite3_finalize(pStmt); } - sqlite3_close(g.db); + sqlite3_close(g.db); maybeClose(g.pLog); maybeClose(g.pErrLog); if( iClient==0 ){ printf("Summary: %d errors out of %d tests\n", g.nError, g.nTest); + printf("END: %s", argv[0]); + for(i=1; i0; } diff --git a/mptest/multiwrite01.test b/mptest/multiwrite01.test index 4f88a68..7062ae0 100644 --- a/mptest/multiwrite01.test +++ b/mptest/multiwrite01.test @@ -361,6 +361,8 @@ PRAGMA integrity_check(10); WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 + PRAGMA integrity_check; + --match ok --end --task 5 SELECT t1.a FROM t1, t2 @@ -371,6 +373,8 @@ PRAGMA integrity_check(10); WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 + PRAGMA integrity_check; + --match ok --end --task 3 SELECT t1.a FROM t1, t2 @@ -381,6 +385,8 @@ PRAGMA integrity_check(10); WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 + PRAGMA integrity_check; + --match ok --end --task 2 SELECT t1.a FROM t1, t2 @@ -391,6 +397,8 @@ PRAGMA integrity_check(10); WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 + PRAGMA integrity_check; + --match ok --end --task 4 SELECT t1.a FROM t1, t2 @@ -401,5 +409,7 @@ PRAGMA integrity_check(10); WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 + PRAGMA integrity_check; + --match ok --end --wait all diff --git a/src/alter.c b/src/alter.c index dd06024..44422ca 100644 --- a/src/alter.c +++ b/src/alter.c @@ -126,6 +126,7 @@ static void renameParentFunc( n = sqlite3GetToken(z, &token); }while( token==TK_SPACE ); + if( token==TK_ILLEGAL ) break; zParent = sqlite3DbStrNDup(db, (const char *)z, n); if( zParent==0 ) break; sqlite3Dequote(zParent); @@ -690,7 +691,10 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ */ if( pDflt ){ sqlite3_value *pVal = 0; - if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){ + int rc; + rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal); + assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); + if( rc!=SQLITE_OK ){ db->mallocFailed = 1; return; } diff --git a/src/analyze.c b/src/analyze.c index fec2bdb..2a0d6d2 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -1519,14 +1519,17 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ z = argv[2]; if( pIndex ){ + tRowcnt *aiRowEst = 0; int nCol = pIndex->nKeyCol+1; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - tRowcnt * const aiRowEst = pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero( - sizeof(tRowcnt) * nCol - ); - if( aiRowEst==0 ) pInfo->db->mallocFailed = 1; -#else - tRowcnt * const aiRowEst = 0; + /* Index.aiRowEst may already be set here if there are duplicate + ** sqlite_stat1 entries for this index. In that case just clobber + ** the old data with the new instead of allocating a new array. */ + if( pIndex->aiRowEst==0 ){ + pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol); + if( pIndex->aiRowEst==0 ) pInfo->db->mallocFailed = 1; + } + aiRowEst = pIndex->aiRowEst; #endif pIndex->bUnordered = 0; decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex); diff --git a/src/attach.c b/src/attach.c index de87429..efc9eb9 100644 --- a/src/attach.c +++ b/src/attach.c @@ -191,7 +191,7 @@ static void attachFunc( case SQLITE_NULL: /* No key specified. Use the key from the main database */ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); - if( nKey>0 || sqlite3BtreeGetReserve(db->aDb[0].pBt)>0 ){ + if( nKey>0 || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){ rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); } break; @@ -298,7 +298,7 @@ static void detachFunc( sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; - sqlite3ResetAllSchemasOfConnection(db); + sqlite3CollapseDatabaseArray(db); return; detach_error: @@ -332,7 +332,6 @@ static void codeAttach( SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) ){ - pParse->nErr++; goto attach_end; } diff --git a/src/backup.c b/src/backup.c index e3f8690..81c8b5c 100644 --- a/src/backup.c +++ b/src/backup.c @@ -247,7 +247,7 @@ static int backupOnePage( ** guaranteed that the shared-mutex is held by this thread, handle ** p->pSrc may not actually be the owner. */ int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc); - int nDestReserve = sqlite3BtreeGetReserve(p->pDest); + int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest); #endif int rc = SQLITE_OK; i64 iOff; diff --git a/src/bitvec.c b/src/bitvec.c index 52184aa..c348974 100644 --- a/src/bitvec.c +++ b/src/bitvec.c @@ -341,7 +341,7 @@ int sqlite3BitvecBuiltinTest(int sz, int *aOp){ ** bits to act as the reference */ pBitvec = sqlite3BitvecCreate( sz ); pV = sqlite3MallocZero( (sz+7)/8 + 1 ); - pTmpSpace = sqlite3_malloc(BITVEC_SZ); + pTmpSpace = sqlite3_malloc64(BITVEC_SZ); if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; /* NULL pBitvec tests */ diff --git a/src/btmutex.c b/src/btmutex.c index f9fe5b3..c9c8572 100644 --- a/src/btmutex.c +++ b/src/btmutex.c @@ -141,6 +141,7 @@ static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){ ** Exit the recursive mutex on a Btree. */ void sqlite3BtreeLeave(Btree *p){ + assert( sqlite3_mutex_held(p->db->mutex) ); if( p->sharable ){ assert( p->wantToLock>0 ); p->wantToLock--; diff --git a/src/btree.c b/src/btree.c index f9f76c2..4831657 100644 --- a/src/btree.c +++ b/src/btree.c @@ -175,6 +175,12 @@ static int hasSharedCacheTableLock( for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){ Index *pIdx = (Index *)sqliteHashData(p); if( pIdx->tnum==(int)iRoot ){ + if( iTab ){ + /* Two or more indexes share the same root page. There must + ** be imposter tables. So just return true. The assert is not + ** useful in that case. */ + return 1; + } iTab = pIdx->pTable->tnum; } } @@ -594,10 +600,15 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){ static int saveCursorPosition(BtCursor *pCur){ int rc; - assert( CURSOR_VALID==pCur->eState ); + assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); + if( pCur->eState==CURSOR_SKIPNEXT ){ + pCur->eState = CURSOR_VALID; + }else{ + pCur->skipNext = 0; + } rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); assert( rc==SQLITE_OK ); /* KeySize() cannot fail */ @@ -668,7 +679,7 @@ static int SQLITE_NOINLINE saveCursorsOnList( ){ do{ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){ - if( p->eState==CURSOR_VALID ){ + if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){ int rc = saveCursorPosition(p); if( SQLITE_OK!=rc ){ return rc; @@ -740,17 +751,19 @@ static int btreeMoveto( */ static int btreeRestoreCursorPosition(BtCursor *pCur){ int rc; + int skipNext; assert( cursorHoldsMutex(pCur) ); assert( pCur->eState>=CURSOR_REQUIRESEEK ); if( pCur->eState==CURSOR_FAULT ){ return pCur->skipNext; } pCur->eState = CURSOR_INVALID; - rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skipNext); + rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); if( rc==SQLITE_OK ){ sqlite3_free(pCur->pKey); pCur->pKey = 0; assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID ); + pCur->skipNext |= skipNext; if( pCur->skipNext && pCur->eState==CURSOR_VALID ){ pCur->eState = CURSOR_SKIPNEXT; } @@ -802,9 +815,10 @@ int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){ *pDifferentRow = 1; return rc; } - if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){ + if( pCur->eState!=CURSOR_VALID ){ *pDifferentRow = 1; }else{ + assert( pCur->skipNext==0 ); *pDifferentRow = 0; } return SQLITE_OK; @@ -1945,16 +1959,18 @@ int sqlite3BtreeOpen( */ if( isTempDb==0 && (isMemdb==0 || (vfsFlags&SQLITE_OPEN_URI)!=0) ){ if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){ + int nFilename = sqlite3Strlen30(zFilename)+1; int nFullPathname = pVfs->mxPathname+1; - char *zFullPathname = sqlite3Malloc(nFullPathname); + char *zFullPathname = sqlite3Malloc(MAX(nFullPathname,nFilename)); MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) + p->sharable = 1; if( !zFullPathname ){ sqlite3_free(p); return SQLITE_NOMEM; } if( isMemdb ){ - memcpy(zFullPathname, zFilename, sqlite3Strlen30(zFilename)+1); + memcpy(zFullPathname, zFilename, nFilename); }else{ rc = sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); @@ -2011,8 +2027,8 @@ int sqlite3BtreeOpen( ** the right size. This is to guard against size changes that result ** when compiling on a different architecture. */ - assert( sizeof(i64)==8 || sizeof(i64)==4 ); - assert( sizeof(u64)==8 || sizeof(u64)==4 ); + assert( sizeof(i64)==8 ); + assert( sizeof(u64)==8 ); assert( sizeof(u32)==4 ); assert( sizeof(u16)==2 ); assert( sizeof(Pgno)==4 ); @@ -2399,6 +2415,9 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){ BtShared *pBt = p->pBt; assert( nReserve>=-1 && nReserve<=255 ); sqlite3BtreeEnter(p); +#if SQLITE_HAS_CODEC + if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve; +#endif if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){ sqlite3BtreeLeave(p); return SQLITE_READONLY; @@ -2410,7 +2429,7 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){ if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE && ((pageSize-1)&pageSize)==0 ){ assert( (pageSize & 7)==0 ); - assert( !pBt->pPage1 && !pBt->pCursor ); + assert( !pBt->pCursor ); pBt->pageSize = (u32)pageSize; freeTempSpace(pBt); } @@ -2428,7 +2447,6 @@ int sqlite3BtreeGetPageSize(Btree *p){ return p->pBt->pageSize; } -#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_DEBUG) /* ** This function is similar to sqlite3BtreeGetReserve(), except that it ** may only be called if it is guaranteed that the b-tree mutex is already @@ -2441,25 +2459,33 @@ int sqlite3BtreeGetPageSize(Btree *p){ ** database handle that owns *p, causing undefined behavior. */ int sqlite3BtreeGetReserveNoMutex(Btree *p){ + int n; assert( sqlite3_mutex_held(p->pBt->mutex) ); - return p->pBt->pageSize - p->pBt->usableSize; + n = p->pBt->pageSize - p->pBt->usableSize; + return n; } -#endif /* SQLITE_HAS_CODEC || SQLITE_DEBUG */ -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) /* ** Return the number of bytes of space at the end of every page that ** are intentually left unused. This is the "reserved" space that is ** sometimes used by extensions. +** +** If SQLITE_HAS_MUTEX is defined then the number returned is the +** greater of the current reserved space and the maximum requested +** reserve space. */ -int sqlite3BtreeGetReserve(Btree *p){ +int sqlite3BtreeGetOptimalReserve(Btree *p){ int n; sqlite3BtreeEnter(p); - n = p->pBt->pageSize - p->pBt->usableSize; + n = sqlite3BtreeGetReserveNoMutex(p); +#ifdef SQLITE_HAS_CODEC + if( npBt->optimalReserve ) n = p->pBt->optimalReserve; +#endif sqlite3BtreeLeave(p); return n; } + /* ** Set the maximum page count for a database if mxPage is positive. ** No changes are made if mxPage is 0 or negative. @@ -2490,7 +2516,6 @@ int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ sqlite3BtreeLeave(p); return b; } -#endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */ /* ** Change the 'auto-vacuum' property of the database. If the 'autoVacuum' @@ -3610,7 +3635,7 @@ int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ for(p=pBtree->pBt->pCursor; p; p=p->pNext){ int i; if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ - if( p->eState==CURSOR_VALID ){ + if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){ rc = saveCursorPosition(p); if( rc!=SQLITE_OK ){ (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0); @@ -4016,6 +4041,8 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); + assert( pCur->iPage>=0 ); + assert( pCur->iPageapPage[pCur->iPage]->intKeyLeaf==1 ); getCellInfo(pCur); *pSize = pCur->info.nPayload; @@ -4424,13 +4451,18 @@ static const void *fetchPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ u32 *pAmt /* Write the number of available bytes here */ ){ + u32 amt; assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]); assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorHoldsMutex(pCur) ); assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); assert( pCur->info.nSize>0 ); - *pAmt = pCur->info.nLocal; + assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB ); + assert( pCur->info.pPayloadapPage[pCur->iPage]->aDataEnd ||CORRUPT_DB); + amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload); + if( pCur->info.nLocalinfo.nLocal; + *pAmt = amt; return (void*)pCur->info.pPayload; } @@ -4494,7 +4526,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ return SQLITE_OK; } -#if 0 +#if SQLITE_DEBUG /* ** Page pParent is an internal (non-leaf) tree page. This function ** asserts that page number iChild is the left-child if the iIdx'th @@ -4503,6 +4535,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ ** the page. */ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){ + if( CORRUPT_DB ) return; /* The conditions tested below might not be true + ** in a corrupt database */ assert( iIdx<=pParent->nCell ); if( iIdx==pParent->nCell ){ assert( get4byte(&pParent->aData[pParent->hdrOffset+8])==iChild ); @@ -4527,19 +4561,11 @@ static void moveToParent(BtCursor *pCur){ assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>0 ); assert( pCur->apPage[pCur->iPage] ); - - /* UPDATE: It is actually possible for the condition tested by the assert - ** below to be untrue if the database file is corrupt. This can occur if - ** one cursor has modified page pParent while a reference to it is held - ** by a second cursor. Which can only happen if a single page is linked - ** into more than one b-tree structure in a corrupt database. */ -#if 0 assertParentIndex( pCur->apPage[pCur->iPage-1], pCur->aiIdx[pCur->iPage-1], pCur->apPage[pCur->iPage]->pgno ); -#endif testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell ); releasePage(pCur->apPage[pCur->iPage]); @@ -6714,7 +6740,6 @@ static int balance_nonroot( }else if( iParentIdx==i ){ nxDiv = i-2+bBulk; }else{ - assert( bBulk==0 ); nxDiv = iParentIdx-1; } i = 2-bBulk; @@ -7465,7 +7490,8 @@ static int balance(BtCursor *pCur){ ** pSpace buffer passed to the latter call to balance_nonroot(). */ u8 *pSpace = sqlite3PageMalloc(pCur->pBt->pageSize); - rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1, pCur->hints); + rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1, + pCur->hints&BTREE_BULKLOAD); if( pFree ){ /* If pFree is not NULL, it points to the pSpace buffer used ** by a previous call to balance_nonroot(). Its contents are @@ -7486,6 +7512,7 @@ static int balance(BtCursor *pCur){ /* The next iteration of the do-loop balances the parent page. */ releasePage(pPage); pCur->iPage--; + assert( pCur->iPage>=0 ); } }while( rc==SQLITE_OK ); @@ -7962,9 +7989,13 @@ static int clearDatabasePage( if( pgno>btreePagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } - rc = getAndInitPage(pBt, pgno, &pPage, 0); if( rc ) return rc; + if( pPage->bBusy ){ + rc = SQLITE_CORRUPT_BKPT; + goto cleardatabasepage_out; + } + pPage->bBusy = 1; hdr = pPage->hdrOffset; for(i=0; inCell; i++){ pCell = findCell(pPage, i); @@ -7989,6 +8020,7 @@ static int clearDatabasePage( } cleardatabasepage_out: + pPage->bBusy = 0; releasePage(pPage); return rc; } @@ -8496,6 +8528,57 @@ static void checkList( } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ +/* +** An implementation of a min-heap. +** +** aHeap[0] is the number of elements on the heap. aHeap[1] is the +** root element. The daughter nodes of aHeap[N] are aHeap[N*2] +** and aHeap[N*2+1]. +** +** The heap property is this: Every node is less than or equal to both +** of its daughter nodes. A consequence of the heap property is that the +** root node aHeap[1] is always the minimum value currently in the heap. +** +** The btreeHeapInsert() routine inserts an unsigned 32-bit number onto +** the heap, preserving the heap property. The btreeHeapPull() routine +** removes the root element from the heap (the minimum value in the heap) +** and then moves other nodes around as necessary to preserve the heap +** property. +** +** This heap is used for cell overlap and coverage testing. Each u32 +** entry represents the span of a cell or freeblock on a btree page. +** The upper 16 bits are the index of the first byte of a range and the +** lower 16 bits are the index of the last byte of that range. +*/ +static void btreeHeapInsert(u32 *aHeap, u32 x){ + u32 j, i = ++aHeap[0]; + aHeap[i] = x; + while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){ + x = aHeap[j]; + aHeap[j] = aHeap[i]; + aHeap[i] = x; + i = j; + } +} +static int btreeHeapPull(u32 *aHeap, u32 *pOut){ + u32 j, i, x; + if( (x = aHeap[0])==0 ) return 0; + *pOut = aHeap[1]; + aHeap[1] = aHeap[x]; + aHeap[x] = 0xffffffff; + aHeap[0]--; + i = 1; + while( (j = i*2)<=aHeap[0] ){ + if( aHeap[j]>aHeap[j+1] ) j++; + if( aHeap[i]zPfx; @@ -8673,15 +8757,15 @@ static int checkTreePage( */ data = pPage->aData; hdr = pPage->hdrOffset; - hit = sqlite3PageMalloc( pBt->pageSize ); + heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); pCheck->zPfx = 0; - if( hit==0 ){ + if( heap==0 ){ pCheck->mallocFailed = 1; }else{ int contentOffset = get2byteNotZero(&data[hdr+5]); assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */ - memset(hit+contentOffset, 0, usableSize-contentOffset); - memset(hit, 1, contentOffset); + heap[0] = 0; + btreeHeapInsert(heap, contentOffset-1); /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the ** number of cells on the page. */ nCell = get2byte(&data[hdr+3]); @@ -8693,7 +8777,6 @@ static int checkTreePage( for(i=0; i=pc; j--) hit[j]++; + btreeHeapInsert(heap, (pc<<16)|(pc+size-1)); } } /* EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header @@ -8714,7 +8797,7 @@ static int checkTreePage( assert( i<=usableSize-4 ); /* Enforced by btreeInitPage() */ size = get2byte(&data[i+2]); assert( i+size<=usableSize ); /* Enforced by btreeInitPage() */ - for(j=i+size-1; j>=i; j--) hit[j]++; + btreeHeapInsert(heap, (i<<16)|(i+size-1)); /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a ** big-endian integer which is the offset in the b-tree page of the next ** freeblock in the chain, or zero if the freeblock is the last on the @@ -8726,27 +8809,33 @@ static int checkTreePage( assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */ i = j; } - for(i=cnt=0; i1 ){ + cnt = 0; + assert( heap[0]>0 ); + assert( (heap[1]>>16)==0 ); + btreeHeapPull(heap,&prev); + while( btreeHeapPull(heap,&x) ){ + if( (prev&0xffff)+1>(x>>16) ){ checkAppendMsg(pCheck, - "Multiple uses for byte %d of page %d", i, iPage); + "Multiple uses for byte %u of page %d", x>>16, iPage); break; + }else{ + cnt += (x>>16) - (prev&0xffff) - 1; + prev = x; } } + cnt += usableSize - (prev&0xffff) - 1; /* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments ** is stored in the fifth field of the b-tree page header. ** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the ** number of fragmented free bytes within the cell content area. */ - if( cnt!=data[hdr+7] ){ + if( heap[0]==0 && cnt!=data[hdr+7] ){ checkAppendMsg(pCheck, "Fragmentation of %d bytes reported as %d on page %d", cnt, data[hdr+7], iPage); } } - sqlite3PageFree(hit); + sqlite3PageFree(heap); releasePage(pPage); end_of_check: @@ -8810,8 +8899,7 @@ char *sqlite3BtreeIntegrityCheck( } i = PENDING_BYTE_PAGE(pBt); if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i); - sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), SQLITE_MAX_LENGTH); - sCheck.errMsg.useMalloc = 2; + sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH); /* Check the integrity of the freelist */ @@ -9128,14 +9216,23 @@ int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ } /* -** set the mask of hint flags for cursor pCsr. Currently the only valid -** values are 0 and BTREE_BULKLOAD. +** set the mask of hint flags for cursor pCsr. */ void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){ - assert( mask==BTREE_BULKLOAD || mask==0 ); + assert( mask==BTREE_BULKLOAD || mask==BTREE_SEEK_EQ || mask==0 ); pCsr->hints = mask; } +#ifdef SQLITE_DEBUG +/* +** Return true if the cursor has a hint specified. This routine is +** only used from within assert() statements +*/ +int sqlite3BtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){ + return (pCsr->hints & mask)!=0; +} +#endif + /* ** Return true if the given Btree is read-only. */ diff --git a/src/btree.h b/src/btree.h index b57d500..3edc2b3 100644 --- a/src/btree.h +++ b/src/btree.h @@ -73,10 +73,8 @@ int sqlite3BtreeGetPageSize(Btree*); int sqlite3BtreeMaxPageCount(Btree*,int); u32 sqlite3BtreeLastPage(Btree*); int sqlite3BtreeSecureDelete(Btree*,int); -int sqlite3BtreeGetReserve(Btree*); -#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_DEBUG) +int sqlite3BtreeGetOptimalReserve(Btree*); int sqlite3BtreeGetReserveNoMutex(Btree *p); -#endif int sqlite3BtreeSetAutoVacuum(Btree *, int); int sqlite3BtreeGetAutoVacuum(Btree *); int sqlite3BtreeBeginTrans(Btree*,int); @@ -154,8 +152,18 @@ int sqlite3BtreeNewDb(Btree *p); /* ** Values that may be OR'd together to form the second argument of an ** sqlite3BtreeCursorHints() call. +** +** The BTREE_BULKLOAD flag is set on index cursors when the index is going +** to be filled with content that is already in sorted order. +** +** The BTREE_SEEK_EQ flag is set on cursors that will get OP_SeekGE or +** OP_SeekLE opcodes for a range search, but where the range of entries +** selected will all have the same key. In other words, the cursor will +** be used only for equality key searches. +** */ -#define BTREE_BULKLOAD 0x00000001 +#define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */ +#define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */ int sqlite3BtreeCursor( Btree*, /* BTree containing table to open */ @@ -201,6 +209,9 @@ void sqlite3BtreeIncrblobCursor(BtCursor *); void sqlite3BtreeClearCursor(BtCursor *); int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask); +#ifdef SQLITE_DEBUG +int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask); +#endif int sqlite3BtreeIsReadonly(Btree *pBt); int sqlite3HeaderSizeBtree(void); diff --git a/src/btreeInt.h b/src/btreeInt.h index ed4d75e..33ef641 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -280,6 +280,7 @@ struct MemPage { u8 hdrOffset; /* 100 for page 1. 0 otherwise */ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ u8 max1bytePayload; /* min(maxLocal,127) */ + u8 bBusy; /* Prevent endless loops on corrupt database files */ u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ @@ -418,6 +419,9 @@ struct BtShared { #endif u8 inTransaction; /* Transaction state */ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */ +#ifdef SQLITE_HAS_CODEC + u8 optimalReserve; /* Desired amount of reserved space per page */ +#endif u16 btsFlags; /* Boolean parameters. See BTS_* macros below */ u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */ u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */ diff --git a/src/build.c b/src/build.c index f02989b..7990561 100644 --- a/src/build.c +++ b/src/build.c @@ -142,9 +142,11 @@ void sqlite3FinishCoding(Parse *pParse){ assert( pParse->pToplevel==0 ); db = pParse->db; - if( db->mallocFailed ) return; if( pParse->nested ) return; - if( pParse->nErr ) return; + if( db->mallocFailed || pParse->nErr ){ + if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR; + return; + } /* Begin by generating some termination code at the end of the ** vdbe program @@ -226,7 +228,7 @@ void sqlite3FinishCoding(Parse *pParse){ /* Get the VDBE program ready for execution */ - if( v && ALWAYS(pParse->nErr==0) && !db->mallocFailed ){ + if( v && pParse->nErr==0 && !db->mallocFailed ){ assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */ /* A minimum of one cursor is required if autoincrement is used * See ticket [a696379c1f08866] */ @@ -308,10 +310,6 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ Table *p = 0; int i; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zName==0 ) return 0; -#endif - /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); #if SQLITE_USER_AUTHENTICATION @@ -765,14 +763,12 @@ int sqlite3TwoPartName( if( ALWAYS(pName2!=0) && pName2->n>0 ){ if( db->init.busy ) { sqlite3ErrorMsg(pParse, "corrupt database"); - pParse->nErr++; return -1; } *pUnqual = pName2; iDb = sqlite3FindDb(db, pName1); if( iDb<0 ){ sqlite3ErrorMsg(pParse, "unknown database %T", pName1); - pParse->nErr++; return -1; } }else{ @@ -931,7 +927,7 @@ void sqlite3StartTable( if( !noErr ){ sqlite3ErrorMsg(pParse, "table %T already exists", pName); }else{ - assert( !db->init.busy ); + assert( !db->init.busy || CORRUPT_DB ); sqlite3CodeVerifySchema(pParse, iDb); } goto begin_table_error; @@ -1220,7 +1216,8 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){ p = pParse->pNewTable; if( p==0 || NEVER(p->nCol<1) ) return; pCol = &p->aCol[p->nCol-1]; - assert( pCol->zType==0 ); + assert( pCol->zType==0 || CORRUPT_DB ); + sqlite3DbFree(pParse->db, pCol->zType); pCol->zType = sqlite3NameFromToken(pParse->db, pType); pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst); } @@ -1731,11 +1728,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ assert( pPk!=0 ); nPk = pPk->nKeyCol; - /* Make sure every column of the PRIMARY KEY is NOT NULL */ - for(i=0; iaCol[pPk->aiColumn[i]].notNull = 1; + /* Make sure every column of the PRIMARY KEY is NOT NULL. (Except, + ** do not enforce this for imposter tables.) */ + if( !db->init.imposterTable ){ + for(i=0; iaCol[pPk->aiColumn[i]].notNull = 1; + } + pPk->uniqNotNull = 1; } - pPk->uniqNotNull = 1; /* The root page of the PRIMARY KEY is the table root page */ pPk->tnum = pTab->tnum; @@ -2451,6 +2451,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); + if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; @@ -2764,7 +2765,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); - sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1); + sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1); + sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v); @@ -2857,8 +2859,7 @@ Index *sqlite3CreateIndex( char *zExtra = 0; /* Extra space after the Index object */ Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ - assert( pParse->nErr==0 ); /* Never called with prior errors */ - if( db->mallocFailed || IN_DECLARE_VTAB ){ + if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){ goto exit_create_index; } if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ @@ -3184,6 +3185,7 @@ Index *sqlite3CreateIndex( pIdx->onError = pIndex->onError; } } + pRet = pIdx; goto exit_create_index; } } @@ -3776,7 +3778,6 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ void sqlite3SrcListShiftJoinType(SrcList *p){ if( p ){ int i; - assert( p->a || p->nSrc==0 ); for(i=p->nSrc-1; i>0; i--){ p->a[i].jointype = p->a[i-1].jointype; } @@ -4023,8 +4024,7 @@ void sqlite3UniqueConstraint( StrAccum errMsg; Table *pTab = pIdx->pTable; - sqlite3StrAccumInit(&errMsg, 0, 0, 200); - errMsg.db = pParse->db; + sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); for(j=0; jnKeyCol; j++){ char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName; if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); diff --git a/src/complete.c b/src/complete.c index f7a35cc..a12184e 100644 --- a/src/complete.c +++ b/src/complete.c @@ -269,7 +269,7 @@ int sqlite3_complete(const char *zSql){ int sqlite3_complete16(const void *zSql){ sqlite3_value *pVal; char const *zSql8; - int rc = SQLITE_NOMEM; + int rc; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); diff --git a/src/ctime.c b/src/ctime.c index 4f98ffe..9503214 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -75,6 +75,9 @@ static const char * const azCompileOpt[] = { #if SQLITE_ENABLE_COLUMN_METADATA "ENABLE_COLUMN_METADATA", #endif +#if SQLITE_ENABLE_DBSTAT_VTAB + "ENABLE_DBSTAT_VTAB", +#endif #if SQLITE_ENABLE_EXPENSIVE_ASSERT "ENABLE_EXPENSIVE_ASSERT", #endif diff --git a/src/test_stat.c b/src/dbstat.c similarity index 81% rename from src/test_stat.c rename to src/dbstat.c index 615df3d..64cd5d8 100644 --- a/src/test_stat.c +++ b/src/dbstat.c @@ -18,11 +18,9 @@ ** for an example implementation. */ -#ifndef SQLITE_AMALGAMATION -# include "sqliteInt.h" -#endif - -#ifndef SQLITE_OMIT_VIRTUALTABLE +#if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \ + && !defined(SQLITE_OMIT_VIRTUALTABLE) +#include "sqliteInt.h" /* Requires access to internal data structures */ /* ** Page paths: @@ -124,6 +122,7 @@ struct StatCursor { struct StatTable { sqlite3_vtab base; sqlite3 *db; + int iDb; /* Index of database to analyze */ }; #ifndef get2byte @@ -140,15 +139,34 @@ static int statConnect( sqlite3_vtab **ppVtab, char **pzErr ){ - StatTable *pTab; + StatTable *pTab = 0; + int rc = SQLITE_OK; + int iDb; - pTab = (StatTable *)sqlite3_malloc(sizeof(StatTable)); - memset(pTab, 0, sizeof(StatTable)); - pTab->db = db; + if( argc>=4 ){ + iDb = sqlite3FindDbName(db, argv[3]); + if( iDb<0 ){ + *pzErr = sqlite3_mprintf("no such database: %s", argv[3]); + return SQLITE_ERROR; + } + }else{ + iDb = 0; + } + rc = sqlite3_declare_vtab(db, VTAB_SCHEMA); + if( rc==SQLITE_OK ){ + pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable)); + if( pTab==0 ) rc = SQLITE_NOMEM; + } - sqlite3_declare_vtab(db, VTAB_SCHEMA); - *ppVtab = &pTab->base; - return SQLITE_OK; + assert( rc==SQLITE_OK || pTab==0 ); + if( rc==SQLITE_OK ){ + memset(pTab, 0, sizeof(StatTable)); + pTab->db = db; + pTab->iDb = iDb; + } + + *ppVtab = (sqlite3_vtab*)pTab; + return rc; } /* @@ -195,33 +213,45 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ StatCursor *pCsr; int rc; - pCsr = (StatCursor *)sqlite3_malloc(sizeof(StatCursor)); - memset(pCsr, 0, sizeof(StatCursor)); - pCsr->base.pVtab = pVTab; + pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor)); + if( pCsr==0 ){ + rc = SQLITE_NOMEM; + }else{ + char *zSql; + memset(pCsr, 0, sizeof(StatCursor)); + pCsr->base.pVtab = pVTab; - rc = sqlite3_prepare_v2(pTab->db, - "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type" - " UNION ALL " - "SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0" - " ORDER BY name", -1, - &pCsr->pStmt, 0 - ); - if( rc!=SQLITE_OK ){ - sqlite3_free(pCsr); - return rc; + zSql = sqlite3_mprintf( + "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type" + " UNION ALL " + "SELECT name, rootpage, type" + " FROM \"%w\".sqlite_master WHERE rootpage!=0" + " ORDER BY name", pTab->db->aDb[pTab->iDb].zName); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0); + sqlite3_free(zSql); + } + if( rc!=SQLITE_OK ){ + sqlite3_free(pCsr); + pCsr = 0; + } } *ppCursor = (sqlite3_vtab_cursor *)pCsr; - return SQLITE_OK; + return rc; } static void statClearPage(StatPage *p){ int i; - for(i=0; inCell; i++){ - sqlite3_free(p->aCell[i].aOvfl); + if( p->aCell ){ + for(i=0; inCell; i++){ + sqlite3_free(p->aCell[i].aOvfl); + } + sqlite3_free(p->aCell); } sqlite3PagerUnref(p->pPg); - sqlite3_free(p->aCell); sqlite3_free(p->zPath); memset(p, 0, sizeof(StatPage)); } @@ -301,9 +331,13 @@ static int statDecodePage(Btree *pBt, StatPage *p){ if( p->nCell ){ int i; /* Used to iterate through cells */ - int nUsable = szPage - sqlite3BtreeGetReserve(pBt); + int nUsable; /* Usable bytes per page */ - p->aCell = sqlite3_malloc((p->nCell+1) * sizeof(StatCell)); + sqlite3BtreeEnter(pBt); + nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt); + sqlite3BtreeLeave(pBt); + p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell)); + if( p->aCell==0 ) return SQLITE_NOMEM; memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell)); for(i=0; inCell; i++){ @@ -335,7 +369,8 @@ static int statDecodePage(Btree *pBt, StatPage *p){ int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); pCell->nOvfl = nOvfl; - pCell->aOvfl = sqlite3_malloc(sizeof(u32)*nOvfl); + pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl); + if( pCell->aOvfl==0 ) return SQLITE_NOMEM; pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]); for(j=1; jpVtab; - Btree *pBt = pTab->db->aDb[0].pBt; + Btree *pBt = pTab->db->aDb[pTab->iDb].pBt; Pager *pPager = sqlite3BtreePager(pBt); sqlite3_file *fd; sqlite3_int64 x[2]; @@ -377,7 +412,7 @@ static void statSizeAndOffset(StatCursor *pCsr){ */ fd = sqlite3PagerFile(pPager); x[0] = pCsr->iPageno; - if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){ + if( fd->pMethods!=0 && sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){ pCsr->iOffset = x[0]; pCsr->szPage = (int)x[1]; } @@ -389,9 +424,10 @@ static void statSizeAndOffset(StatCursor *pCsr){ static int statNext(sqlite3_vtab_cursor *pCursor){ int rc; int nPayload; + char *z; StatCursor *pCsr = (StatCursor *)pCursor; StatTable *pTab = (StatTable *)pCursor->pVtab; - Btree *pBt = pTab->db->aDb[0].pBt; + Btree *pBt = pTab->db->aDb[pTab->iDb].pBt; Pager *pPager = sqlite3BtreePager(pBt); sqlite3_free(pCsr->zPath); @@ -411,8 +447,9 @@ statNextRestart: rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg); pCsr->aPage[0].iPgno = iRoot; pCsr->aPage[0].iCell = 0; - pCsr->aPage[0].zPath = sqlite3_mprintf("/"); + pCsr->aPage[0].zPath = z = sqlite3_mprintf("/"); pCsr->iPage = 0; + if( z==0 ) rc = SQLITE_NOMEM; }else{ pCsr->isEof = 1; return sqlite3_reset(pCsr->pStmt); @@ -425,13 +462,17 @@ statNextRestart: while( p->iCellnCell ){ StatCell *pCell = &p->aCell[p->iCell]; if( pCell->iOvflnOvfl ){ - int nUsable = sqlite3BtreeGetPageSize(pBt)-sqlite3BtreeGetReserve(pBt); + int nUsable; + sqlite3BtreeEnter(pBt); + nUsable = sqlite3BtreeGetPageSize(pBt) - + sqlite3BtreeGetReserveNoMutex(pBt); + sqlite3BtreeLeave(pBt); pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); pCsr->iPageno = pCell->aOvfl[pCell->iOvfl]; pCsr->zPagetype = "overflow"; pCsr->nCell = 0; pCsr->nMxPayload = 0; - pCsr->zPath = sqlite3_mprintf( + pCsr->zPath = z = sqlite3_mprintf( "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl ); if( pCell->iOvflnOvfl-1 ){ @@ -443,7 +484,7 @@ statNextRestart: } pCell->iOvfl++; statSizeAndOffset(pCsr); - return SQLITE_OK; + return z==0 ? SQLITE_NOMEM : SQLITE_OK; } if( p->iRightChildPg ) break; p->iCell++; @@ -465,8 +506,9 @@ statNextRestart: } rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg); p[1].iCell = 0; - p[1].zPath = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell); + p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell); p->iCell++; + if( z==0 ) rc = SQLITE_NOMEM; } @@ -479,31 +521,34 @@ statNextRestart: pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); pCsr->iPageno = p->iPgno; - statDecodePage(pBt, p); - statSizeAndOffset(pCsr); + rc = statDecodePage(pBt, p); + if( rc==SQLITE_OK ){ + statSizeAndOffset(pCsr); - switch( p->flags ){ - case 0x05: /* table internal */ - case 0x02: /* index internal */ - pCsr->zPagetype = "internal"; - break; - case 0x0D: /* table leaf */ - case 0x0A: /* index leaf */ - pCsr->zPagetype = "leaf"; - break; - default: - pCsr->zPagetype = "corrupted"; - break; + switch( p->flags ){ + case 0x05: /* table internal */ + case 0x02: /* index internal */ + pCsr->zPagetype = "internal"; + break; + case 0x0D: /* table leaf */ + case 0x0A: /* index leaf */ + pCsr->zPagetype = "leaf"; + break; + default: + pCsr->zPagetype = "corrupted"; + break; + } + pCsr->nCell = p->nCell; + pCsr->nUnused = p->nUnused; + pCsr->nMxPayload = p->nMxPayload; + pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath); + if( z==0 ) rc = SQLITE_NOMEM; + nPayload = 0; + for(i=0; inCell; i++){ + nPayload += p->aCell[i].nLocal; + } + pCsr->nPayload = nPayload; } - pCsr->nCell = p->nCell; - pCsr->nUnused = p->nUnused; - pCsr->nMxPayload = p->nMxPayload; - pCsr->zPath = sqlite3_mprintf("%s", p->zPath); - nPayload = 0; - for(i=0; inCell; i++){ - nPayload += p->aCell[i].nLocal; - } - pCsr->nPayload = nPayload; } return rc; @@ -533,7 +578,7 @@ static int statColumn( StatCursor *pCsr = (StatCursor *)pCursor; switch( i ){ case 0: /* name */ - sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_STATIC); + sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT); break; case 1: /* path */ sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT); @@ -559,7 +604,8 @@ static int statColumn( case 8: /* pgoffset */ sqlite3_result_int64(ctx, pCsr->iOffset); break; - case 9: /* pgsize */ + default: /* pgsize */ + assert( i==9 ); sqlite3_result_int(ctx, pCsr->szPage); break; } @@ -572,6 +618,9 @@ static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ return SQLITE_OK; } +/* +** Invoke this routine to register the "dbstat" virtual table module +*/ int sqlite3_dbstat_register(sqlite3 *db){ static sqlite3_module dbstat_module = { 0, /* iVersion */ @@ -595,46 +644,6 @@ int sqlite3_dbstat_register(sqlite3 *db){ 0, /* xFindMethod */ 0, /* xRename */ }; - sqlite3_create_module(db, "dbstat", &dbstat_module, 0); - return SQLITE_OK; + return sqlite3_create_module(db, "dbstat", &dbstat_module, 0); } - -#endif - -#if defined(SQLITE_TEST) || TCLSH==2 -#include - -static int test_dbstat( - void *clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ -#ifdef SQLITE_OMIT_VIRTUALTABLE - Tcl_AppendResult(interp, "dbstat not available because of " - "SQLITE_OMIT_VIRTUALTABLE", (void*)0); - return TCL_ERROR; -#else - struct SqliteDb { sqlite3 *db; }; - char *zDb; - Tcl_CmdInfo cmdInfo; - - if( objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "DB"); - return TCL_ERROR; - } - - zDb = Tcl_GetString(objv[1]); - if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){ - sqlite3* db = ((struct SqliteDb*)cmdInfo.objClientData)->db; - sqlite3_dbstat_register(db); - } - return TCL_OK; -#endif -} - -int SqlitetestStat_Init(Tcl_Interp *interp){ - Tcl_CreateObjCommand(interp, "register_dbstat_vtab", test_dbstat, 0, 0); - return TCL_OK; -} -#endif /* if defined(SQLITE_TEST) || TCLSH==2 */ +#endif /* SQLITE_ENABLE_DBSTAT_VTAB */ diff --git a/src/delete.c b/src/delete.c index 011fb80..ef6aace 100644 --- a/src/delete.c +++ b/src/delete.c @@ -189,7 +189,7 @@ Expr *sqlite3LimitWhere( pInClause->x.pSelect = pSelect; pInClause->flags |= EP_xIsSelect; - sqlite3ExprSetHeight(pParse, pInClause); + sqlite3ExprSetHeightAndFlags(pParse, pInClause); return pInClause; /* something went wrong. clean up anything allocated. */ diff --git a/src/expr.c b/src/expr.c index 32adedf..7e27ba9 100644 --- a/src/expr.c +++ b/src/expr.c @@ -69,10 +69,11 @@ char sqlite3ExprAffinity(Expr *pExpr){ Expr *sqlite3ExprAddCollateToken( Parse *pParse, /* Parsing context */ Expr *pExpr, /* Add the "COLLATE" clause to this expression */ - const Token *pCollName /* Name of collating sequence */ + const Token *pCollName, /* Name of collating sequence */ + int dequote /* True to dequote pCollName */ ){ if( pCollName->n>0 ){ - Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1); + Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote); if( pNew ){ pNew->pLeft = pExpr; pNew->flags |= EP_Collate|EP_Skip; @@ -86,7 +87,7 @@ Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){ assert( zC!=0 ); s.z = zC; s.n = sqlite3Strlen30(s.z); - return sqlite3ExprAddCollateToken(pParse, pExpr, &s); + return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0); } /* @@ -132,9 +133,9 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken); break; } - if( p->pTab!=0 - && (op==TK_AGG_COLUMN || op==TK_COLUMN + if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER || op==TK_TRIGGER) + && p->pTab!=0 ){ /* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally ** a TK_COLUMN but was previously evaluated and cached in a register */ @@ -146,10 +147,25 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ break; } if( p->flags & EP_Collate ){ - if( ALWAYS(p->pLeft) && (p->pLeft->flags & EP_Collate)!=0 ){ + if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){ p = p->pLeft; }else{ - p = p->pRight; + Expr *pNext = p->pRight; + /* The Expr.x union is never used at the same time as Expr.pRight */ + assert( p->x.pList==0 || p->pRight==0 ); + /* p->flags holds EP_Collate and p->pLeft->flags does not. And + ** p->x.pSelect cannot. So if p->x.pLeft exists, it must hold at + ** least one EP_Collate. Thus the following two ALWAYS. */ + if( p->x.pList!=0 && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) ){ + int i; + for(i=0; ALWAYS(ix.pList->nExpr); i++){ + if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){ + pNext = p->x.pList->a[i].pExpr; + break; + } + } + } + p = pNext; } }else{ break; @@ -355,6 +371,9 @@ static void heightOfSelect(Select *p, int *pnHeight){ ** Expr.pSelect member has a height of 1. Any other expression ** has a height equal to the maximum height of any other ** referenced Expr plus one. +** +** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags, +** if appropriate. */ static void exprSetHeight(Expr *p){ int nHeight = 0; @@ -362,8 +381,9 @@ static void exprSetHeight(Expr *p){ heightOfExpr(p->pRight, &nHeight); if( ExprHasProperty(p, EP_xIsSelect) ){ heightOfSelect(p->x.pSelect, &nHeight); - }else{ + }else if( p->x.pList ){ heightOfExprList(p->x.pList, &nHeight); + p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); } p->nHeight = nHeight + 1; } @@ -372,8 +392,12 @@ static void exprSetHeight(Expr *p){ ** Set the Expr.nHeight variable using the exprSetHeight() function. If ** the height is greater than the maximum allowed expression depth, ** leave an error in pParse. +** +** Also propagate all EP_Propagate flags from the Expr.x.pList into +** Expr.flags. */ -void sqlite3ExprSetHeight(Parse *pParse, Expr *p){ +void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ + if( pParse->nErr ) return; exprSetHeight(p); sqlite3ExprCheckHeight(pParse, p->nHeight); } @@ -387,8 +411,17 @@ int sqlite3SelectExprHeight(Select *p){ heightOfSelect(p, &nHeight); return nHeight; } -#else - #define exprSetHeight(y) +#else /* ABOVE: Height enforcement enabled. BELOW: Height enforcement off */ +/* +** Propagate all EP_Propagate flags from the Expr.x.pList into +** Expr.flags. +*/ +void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ + if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){ + p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); + } +} +#define exprSetHeight(y) #endif /* SQLITE_MAX_EXPR_DEPTH>0 */ /* @@ -490,11 +523,11 @@ void sqlite3ExprAttachSubtrees( }else{ if( pRight ){ pRoot->pRight = pRight; - pRoot->flags |= EP_Collate & pRight->flags; + pRoot->flags |= EP_Propagate & pRight->flags; } if( pLeft ){ pRoot->pLeft = pLeft; - pRoot->flags |= EP_Collate & pLeft->flags; + pRoot->flags |= EP_Propagate & pLeft->flags; } exprSetHeight(pRoot); } @@ -594,7 +627,7 @@ Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){ } pNew->x.pList = pList; assert( !ExprHasProperty(pNew, EP_xIsSelect) ); - sqlite3ExprSetHeight(pParse, pNew); + sqlite3ExprSetHeightAndFlags(pParse, pNew); return pNew; } @@ -1209,6 +1242,22 @@ void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ sqlite3DbFree(db, pList); } +/* +** Return the bitwise-OR of all Expr.flags fields in the given +** ExprList. +*/ +u32 sqlite3ExprListFlags(const ExprList *pList){ + int i; + u32 m = 0; + if( pList ){ + for(i=0; inExpr; i++){ + Expr *pExpr = pList->a[i].pExpr; + if( ALWAYS(pExpr) ) m |= pExpr->flags; + } + } + return m; +} + /* ** These routines are Walker callbacks used to check expressions to ** see if they are "constant" for some definition of constant. The @@ -1249,7 +1298,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ ** and either pWalker->eCode==4 or 5 or the function has the ** SQLITE_FUNC_CONST flag. */ case TK_FUNCTION: - if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_Constant) ){ + if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc) ){ return WRC_Continue; }else{ pWalker->eCode = 0; @@ -1643,7 +1692,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){ ** ephemeral table. */ p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0); - if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){ + if( pParse->nErr==0 && isCandidateForInOpt(p) ){ sqlite3 *db = pParse->db; /* Database connection */ Table *pTab; /* Table
    . */ Expr *pExpr; /* Expression */ @@ -1968,6 +2017,7 @@ int sqlite3CodeSubselect( pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[1]); pSel->iLimit = 0; + pSel->selFlags &= ~SF_MultiValue; if( sqlite3Select(pParse, pSel, &dest) ){ return 0; } @@ -2256,7 +2306,8 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){ int idxLru; struct yColCache *p; - assert( iReg>0 ); /* Register numbers are always positive */ + /* Unless an error has occurred, register numbers are always positive. */ + assert( iReg>0 || pParse->nErr || pParse->db->mallocFailed ); assert( iCol>=-1 && iCol<32768 ); /* Finite column numbers */ /* The SQLITE_ColumnCache flag disables the column cache. This is used @@ -3332,7 +3383,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ break; } case TK_ID: { - sqlite3TreeViewLine(pView,"ID %Q", pExpr->u.zToken); + sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); break; } #ifndef SQLITE_OMIT_CAST @@ -3967,7 +4018,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2; if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; - if( ALWAYS((combinedFlags & EP_Reduced)==0) ){ + if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){ if( pA->iColumn!=pB->iColumn ) return 2; if( pA->iTable!=pB->iTable && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2; diff --git a/src/fkey.c b/src/fkey.c index fa148ba..09513e4 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -1184,7 +1184,8 @@ static Trigger *fkActionTrigger( iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iFromCol>=0 ); - tToCol.z = pIdx ? pTab->aCol[pIdx->aiColumn[i]].zName : "oid"; + assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKeynCol) ); + tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName; tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName; tToCol.n = sqlite3Strlen30(tToCol.z); @@ -1196,10 +1197,10 @@ static Trigger *fkActionTrigger( ** parent table are used for the comparison. */ pEq = sqlite3PExpr(pParse, TK_EQ, sqlite3PExpr(pParse, TK_DOT, - sqlite3PExpr(pParse, TK_ID, 0, 0, &tOld), - sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol) + sqlite3ExprAlloc(db, TK_ID, &tOld, 0), + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0) , 0), - sqlite3PExpr(pParse, TK_ID, 0, 0, &tFromCol) + sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0) , 0); pWhere = sqlite3ExprAnd(db, pWhere, pEq); @@ -1211,12 +1212,12 @@ static Trigger *fkActionTrigger( if( pChanges ){ pEq = sqlite3PExpr(pParse, TK_IS, sqlite3PExpr(pParse, TK_DOT, - sqlite3PExpr(pParse, TK_ID, 0, 0, &tOld), - sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol), + sqlite3ExprAlloc(db, TK_ID, &tOld, 0), + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0), 0), sqlite3PExpr(pParse, TK_DOT, - sqlite3PExpr(pParse, TK_ID, 0, 0, &tNew), - sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol), + sqlite3ExprAlloc(db, TK_ID, &tNew, 0), + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0), 0), 0); pWhen = sqlite3ExprAnd(db, pWhen, pEq); @@ -1226,8 +1227,8 @@ static Trigger *fkActionTrigger( Expr *pNew; if( action==OE_Cascade ){ pNew = sqlite3PExpr(pParse, TK_DOT, - sqlite3PExpr(pParse, TK_ID, 0, 0, &tNew), - sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol) + sqlite3ExprAlloc(db, TK_ID, &tNew, 0), + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0) , 0); }else if( action==OE_SetDflt ){ Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt; @@ -1274,13 +1275,12 @@ static Trigger *fkActionTrigger( pTrigger = (Trigger *)sqlite3DbMallocZero(db, sizeof(Trigger) + /* struct Trigger */ sizeof(TriggerStep) + /* Single step in trigger program */ - nFrom + 1 /* Space for pStep->target.z */ + nFrom + 1 /* Space for pStep->zTarget */ ); if( pTrigger ){ pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1]; - pStep->target.z = (char *)&pStep[1]; - pStep->target.n = nFrom; - memcpy((char *)pStep->target.z, zFrom, nFrom); + pStep->zTarget = (char *)&pStep[1]; + memcpy((char *)pStep->zTarget, zFrom, nFrom); pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE); diff --git a/src/func.c b/src/func.c index a057993..62abf13 100644 --- a/src/func.c +++ b/src/func.c @@ -22,7 +22,9 @@ ** Return the collating function associated with a function. */ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ - VdbeOp *pOp = &context->pVdbe->aOp[context->iOp-1]; + VdbeOp *pOp; + assert( context->pVdbe!=0 ); + pOp = &context->pVdbe->aOp[context->iOp-1]; assert( pOp->opcode==OP_CollSeq ); assert( pOp->p4type==P4_COLLSEQ ); return pOp->p4.pColl; @@ -230,13 +232,13 @@ static void printfFunc( StrAccum str; const char *zFormat; int n; + sqlite3 *db = sqlite3_context_db_handle(context); if( argc>=1 && (zFormat = (const char*)sqlite3_value_text(argv[0]))!=0 ){ x.nArg = argc-1; x.nUsed = 0; x.apArg = argv+1; - sqlite3StrAccumInit(&str, 0, 0, SQLITE_MAX_LENGTH); - str.db = sqlite3_context_db_handle(context); + sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); sqlite3XPrintf(&str, SQLITE_PRINTF_SQLFUNC, zFormat, &x); n = str.nChar; sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, @@ -291,6 +293,14 @@ static void substrFunc( } } } +#ifdef SQLITE_SUBSTR_COMPATIBILITY + /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as + ** as substr(X,1,N) - it returns the first N characters of X. This + ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8] + ** from 2009-02-02 for compatibility of applications that exploited the + ** old buggy behavior. */ + if( p1==0 ) p1 = 1; /* */ +#endif if( argc==3 ){ p2 = sqlite3_value_int(argv[2]); if( p2<0 ){ @@ -378,7 +388,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ #endif /* -** Allocate nByte bytes of space using sqlite3_malloc(). If the +** Allocate nByte bytes of space using sqlite3Malloc(). If the ** allocation fails, call sqlite3_result_error_nomem() to notify ** the database handle that malloc() has failed and return NULL. ** If nByte is larger than the maximum string or blob length, then @@ -1047,7 +1057,7 @@ static void charFunc( ){ unsigned char *z, *zOut; int i; - zOut = z = sqlite3_malloc( argc*4+1 ); + zOut = z = sqlite3_malloc64( argc*4+1 ); if( z==0 ){ sqlite3_result_error_nomem(context); return; @@ -1195,7 +1205,7 @@ static void replaceFunc( return; } zOld = zOut; - zOut = sqlite3_realloc(zOut, (int)nOut); + zOut = sqlite3_realloc64(zOut, (int)nOut); if( zOut==0 ){ sqlite3_result_error_nomem(context); sqlite3_free(zOld); @@ -1557,8 +1567,7 @@ static void groupConcatStep( if( pAccum ){ sqlite3 *db = sqlite3_context_db_handle(context); - int firstTerm = pAccum->useMalloc==0; - pAccum->useMalloc = 2; + int firstTerm = pAccum->mxAlloc==0; pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; if( !firstTerm ){ if( argc==2 ){ @@ -1642,6 +1651,11 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ ** then set aWc[0] through aWc[2] to the wildcard characters and ** return TRUE. If the function is not a LIKE-style function then ** return FALSE. +** +** *pIsNocase is set to true if uppercase and lowercase are equivalent for +** the function (default for LIKE). If the function makes the distinction +** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to +** false. */ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ FuncDef *pDef; diff --git a/src/global.c b/src/global.c index c7043bb..61450b3 100644 --- a/src/global.c +++ b/src/global.c @@ -46,16 +46,16 @@ const unsigned char sqlite3UpperToLower[] = { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */ - 96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */ - 112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */ + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 6x */ + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 7x */ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */ - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */ + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, /* 9x */ 160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */ 192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */ 208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */ - 224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */ - 239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */ + 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */ + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */ #endif }; diff --git a/src/insert.c b/src/insert.c index a5c3f3e..c794ae4 100644 --- a/src/insert.c +++ b/src/insert.c @@ -342,20 +342,23 @@ static int xferOptimization( /* ** This routine is called to handle SQL of the following forms: ** -** insert into TABLE (IDLIST) values(EXPRLIST) +** insert into TABLE (IDLIST) values(EXPRLIST),(EXPRLIST),... ** insert into TABLE (IDLIST) select +** insert into TABLE (IDLIST) default values ** ** The IDLIST following the table name is always optional. If omitted, -** then a list of all columns for the table is substituted. The IDLIST -** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted. +** then a list of all (non-hidden) columns for the table is substituted. +** The IDLIST appears in the pColumn parameter. pColumn is NULL if IDLIST +** is omitted. ** -** The pList parameter holds EXPRLIST in the first form of the INSERT -** statement above, and pSelect is NULL. For the second form, pList is -** NULL and pSelect is a pointer to the select statement used to generate -** data for the insert. +** For the pSelect parameter holds the values to be inserted for the +** first two forms shown above. A VALUES clause is really just short-hand +** for a SELECT statement that omits the FROM clause and everything else +** that follows. If the pSelect parameter is NULL, that means that the +** DEFAULT VALUES form of the INSERT statement is intended. ** ** The code generated follows one of four templates. For a simple -** insert with data coming from a VALUES clause, the code executes +** insert with data coming from a single-row VALUES clause, the code executes ** once straight down through. Pseudo-code follows (we call this ** the "1st template"): ** @@ -462,7 +465,7 @@ void sqlite3Insert( u8 useTempTable = 0; /* Store SELECT results in intermediate table */ u8 appendFlag = 0; /* True if the insert is likely to be an append */ u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ - u8 bIdListInOrder = 1; /* True if IDLIST is in table order */ + u8 bIdListInOrder; /* True if IDLIST is in table order */ ExprList *pList = 0; /* List of VALUES() to be inserted */ /* Register allocations */ @@ -487,8 +490,8 @@ void sqlite3Insert( } /* If the Select object is really just a simple VALUES() list with a - ** single row values (the common case) then keep that one row of values - ** and go ahead and discard the Select object + ** single row (the common case) then keep that one row of values + ** and discard the other (unused) parts of the pSelect object */ if( pSelect && (pSelect->selFlags & SF_Values)!=0 && pSelect->pPrior==0 ){ pList = pSelect->pEList; @@ -596,6 +599,7 @@ void sqlite3Insert( ** is appears in the original table. (The index of the INTEGER ** PRIMARY KEY in the original table is pTab->iPKey.) */ + bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==0; if( pColumn ){ for(i=0; inId; i++){ pColumn->a[i].idx = -1; @@ -631,7 +635,8 @@ void sqlite3Insert( ** co-routine is the common header to the 3rd and 4th templates. */ if( pSelect ){ - /* Data is coming from a SELECT. Generate a co-routine to run the SELECT */ + /* Data is coming from a SELECT or from a multi-row VALUES clause. + ** Generate a co-routine to run the SELECT. */ int regYield; /* Register holding co-routine entry-point */ int addrTop; /* Top of the co-routine */ int rc; /* Result code */ @@ -644,8 +649,7 @@ void sqlite3Insert( dest.nSdst = pTab->nCol; rc = sqlite3Select(pParse, pSelect, &dest); regFromSelect = dest.iSdst; - assert( pParse->nErr==0 || rc ); - if( rc || db->mallocFailed ) goto insert_cleanup; + if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup; sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ assert( pSelect->pEList ); @@ -693,8 +697,8 @@ void sqlite3Insert( sqlite3ReleaseTempReg(pParse, regTempRowid); } }else{ - /* This is the case if the data for the INSERT is coming from a VALUES - ** clause + /* This is the case if the data for the INSERT is coming from a + ** single-row VALUES clause */ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); @@ -1765,6 +1769,7 @@ static int xferOptimization( int onError, /* How to handle constraint errors */ int iDbDest /* The database of pDest */ ){ + sqlite3 *db = pParse->db; ExprList *pEList; /* The result set of the SELECT */ Table *pSrc; /* The table in the FROM clause of SELECT */ Index *pSrcIdx, *pDestIdx; /* Source and destination indices */ @@ -1912,11 +1917,11 @@ static int xferOptimization( ** 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 ){ + if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ return 0; } #endif - if( (pParse->db->flags & SQLITE_CountRows)!=0 ){ + if( (db->flags & SQLITE_CountRows)!=0 ){ return 0; /* xfer opt does not play well with PRAGMA count_changes */ } @@ -1927,7 +1932,7 @@ static int xferOptimization( #ifdef SQLITE_TEST sqlite3_xferopt_count++; #endif - iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema); + iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema); v = sqlite3GetVdbe(pParse); sqlite3CodeVerifySchema(pParse, iDbSrc); iSrc = pParse->nTab++; @@ -1937,14 +1942,18 @@ static int xferOptimization( regRowid = sqlite3GetTempReg(pParse); sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); assert( HasRowid(pDest) || destHasUniqueIdx ); - if( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ + if( (db->flags & SQLITE_Vacuum)==0 && ( + (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ || destHasUniqueIdx /* (2) */ || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */ - ){ + )){ /* In some circumstances, we are able to run the xfer optimization - ** only if the destination table is initially empty. This code makes - ** that determination. Conditions under which the destination must - ** be empty: + ** only if the destination table is initially empty. Unless the + ** SQLITE_Vacuum flag is set, this block generates code to make + ** that determination. If SQLITE_Vacuum is set, then the destination + ** table is always empty. + ** + ** Conditions under which the destination must be empty: ** ** (1) There is no INTEGER PRIMARY KEY but there are indices. ** (If the destination is not initially empty, the rowid fields @@ -1987,6 +1996,7 @@ static int xferOptimization( sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName); } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ + u8 useSeekResult = 0; for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){ if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break; } @@ -2000,7 +2010,33 @@ static int xferOptimization( VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData); + if( db->flags & SQLITE_Vacuum ){ + /* This INSERT command is part of a VACUUM operation, which guarantees + ** that the destination table is empty. If all indexed columns use + ** collation sequence BINARY, then it can also be assumed that the + ** index will be populated by inserting keys in strictly sorted + ** order. In this case, instead of seeking within the b-tree as part + ** of every OP_IdxInsert opcode, an OP_Last is added before the + ** OP_IdxInsert to seek to the point within the b-tree where each key + ** should be inserted. This is faster. + ** + ** If any of the indexed columns use a collation sequence other than + ** BINARY, this optimization is disabled. This is because the user + ** might change the definition of a collation sequence and then run + ** a VACUUM command. In that case keys may not be written in strictly + ** sorted order. */ + for(i=0; inColumn; i++){ + char *zColl = pSrcIdx->azColl[i]; + assert( zColl!=0 ); + if( sqlite3_stricmp("BINARY", zColl) ) break; + } + if( i==pSrcIdx->nColumn ){ + useSeekResult = OPFLAG_USESEEKRESULT; + sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1); + } + } sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1); + sqlite3VdbeChangeP5(v, useSeekResult); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); diff --git a/src/loadext.c b/src/loadext.c index 7b39ff1..5a2b9d2 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -430,7 +430,7 @@ static int sqlite3LoadExtension( const char *zEntry; char *zAltEntry = 0; void **aHandle; - int nMsg = 300 + sqlite3Strlen30(zFile); + u64 nMsg = 300 + sqlite3Strlen30(zFile); int ii; /* Shared library endings to try if zFile cannot be loaded as written */ @@ -473,7 +473,7 @@ static int sqlite3LoadExtension( #endif if( handle==0 ){ if( pzErrMsg ){ - *pzErrMsg = zErrmsg = sqlite3_malloc(nMsg); + *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); if( zErrmsg ){ sqlite3_snprintf(nMsg, zErrmsg, "unable to open shared library [%s]", zFile); @@ -499,7 +499,7 @@ static int sqlite3LoadExtension( if( xInit==0 && zProc==0 ){ int iFile, iEntry, c; int ncFile = sqlite3Strlen30(zFile); - zAltEntry = sqlite3_malloc(ncFile+30); + zAltEntry = sqlite3_malloc64(ncFile+30); if( zAltEntry==0 ){ sqlite3OsDlClose(pVfs, handle); return SQLITE_NOMEM; @@ -521,7 +521,7 @@ static int sqlite3LoadExtension( if( xInit==0 ){ if( pzErrMsg ){ nMsg += sqlite3Strlen30(zEntry); - *pzErrMsg = zErrmsg = sqlite3_malloc(nMsg); + *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); if( zErrmsg ){ sqlite3_snprintf(nMsg, zErrmsg, "no entry point [%s] in shared library [%s]", zEntry, zFile); @@ -620,7 +620,7 @@ static const sqlite3_api_routines sqlite3Apis = { 0 }; */ typedef struct sqlite3AutoExtList sqlite3AutoExtList; static SQLITE_WSD struct sqlite3AutoExtList { - int nExt; /* Number of entries in aExt[] */ + u32 nExt; /* Number of entries in aExt[] */ void (**aExt)(void); /* Pointers to the extension init functions */ } sqlite3Autoext = { 0, 0 }; @@ -653,7 +653,7 @@ int sqlite3_auto_extension(void (*xInit)(void)){ }else #endif { - int i; + u32 i; #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); #endif @@ -663,9 +663,9 @@ int sqlite3_auto_extension(void (*xInit)(void)){ if( wsdAutoext.aExt[i]==xInit ) break; } if( i==wsdAutoext.nExt ){ - int nByte = (wsdAutoext.nExt+1)*sizeof(wsdAutoext.aExt[0]); + u64 nByte = (wsdAutoext.nExt+1)*sizeof(wsdAutoext.aExt[0]); void (**aNew)(void); - aNew = sqlite3_realloc(wsdAutoext.aExt, nByte); + aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte); if( aNew==0 ){ rc = SQLITE_NOMEM; }else{ @@ -697,7 +697,7 @@ int sqlite3_cancel_auto_extension(void (*xInit)(void)){ int n = 0; wsdAutoextInit; sqlite3_mutex_enter(mutex); - for(i=wsdAutoext.nExt-1; i>=0; i--){ + for(i=(int)wsdAutoext.nExt-1; i>=0; i--){ if( wsdAutoext.aExt[i]==xInit ){ wsdAutoext.nExt--; wsdAutoext.aExt[i] = wsdAutoext.aExt[wsdAutoext.nExt]; @@ -735,7 +735,7 @@ void sqlite3_reset_auto_extension(void){ ** If anything goes wrong, set an error in the database connection. */ void sqlite3AutoLoadExtensions(sqlite3 *db){ - int i; + u32 i; int go = 1; int rc; int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); diff --git a/src/main.c b/src/main.c index 5aa37fa..cc819c3 100644 --- a/src/main.c +++ b/src/main.c @@ -55,6 +55,18 @@ int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; } */ int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } +/* +** When compiling the test fixture or with debugging enabled (on Win32), +** this variable being set to non-zero will cause OSTRACE macros to emit +** extra diagnostic information. +*/ +#ifdef SQLITE_HAVE_OS_TRACE +# ifndef SQLITE_DEBUG_OS_TRACE +# define SQLITE_DEBUG_OS_TRACE 0 +# endif + int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE; +#endif + #if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) /* ** If the following function pointer is not NULL and if @@ -62,7 +74,7 @@ int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } ** I/O active are written using this function. These messages ** are intended for debugging activity only. */ -/* not-private */ void (*sqlite3IoTrace)(const char*, ...) = 0; +SQLITE_API void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...) = 0; #endif /* @@ -128,6 +140,11 @@ int sqlite3_initialize(void){ } #endif + /* If the following assert() fails on some obscure processor/compiler + ** combination, the work-around is to set the correct pointer + ** size at compile-time using -DSQLITE_PTRSIZE=n compile-time option */ + assert( SQLITE_PTRSIZE==sizeof(char*) ); + /* If SQLite is already completely initialized, then this call ** to sqlite3_initialize() should be a no-op. But the initialization ** must be complete. So isInit must not be set until the very end @@ -340,26 +357,28 @@ int sqlite3_config(int op, ...){ */ #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */ case SQLITE_CONFIG_SINGLETHREAD: { - /* Disable all mutexing */ - sqlite3GlobalConfig.bCoreMutex = 0; - sqlite3GlobalConfig.bFullMutex = 0; + /* EVIDENCE-OF: R-02748-19096 This option sets the threading mode to + ** Single-thread. */ + sqlite3GlobalConfig.bCoreMutex = 0; /* Disable mutex on core */ + sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ break; } #endif #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */ case SQLITE_CONFIG_MULTITHREAD: { - /* Disable mutexing of database connections */ - /* Enable mutexing of core data structures */ - sqlite3GlobalConfig.bCoreMutex = 1; - sqlite3GlobalConfig.bFullMutex = 0; + /* EVIDENCE-OF: R-14374-42468 This option sets the threading mode to + ** Multi-thread. */ + sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ + sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ break; } #endif #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */ case SQLITE_CONFIG_SERIALIZED: { - /* Enable all mutexing */ - sqlite3GlobalConfig.bCoreMutex = 1; - sqlite3GlobalConfig.bFullMutex = 1; + /* EVIDENCE-OF: R-41220-51800 This option sets the threading mode to + ** Serialized. */ + sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ + sqlite3GlobalConfig.bFullMutex = 1; /* Enable mutex on connections */ break; } #endif @@ -471,7 +490,8 @@ int sqlite3_config(int op, ...){ case SQLITE_CONFIG_HEAP: { /* EVIDENCE-OF: R-19854-42126 There are three arguments to ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the - ** number of bytes in the memory buffer, and the minimum allocation size. */ + ** number of bytes in the memory buffer, and the minimum allocation size. + */ sqlite3GlobalConfig.pHeap = va_arg(ap, void*); sqlite3GlobalConfig.nHeap = va_arg(ap, int); sqlite3GlobalConfig.mnReq = va_arg(ap, int); @@ -576,7 +596,9 @@ int sqlite3_config(int op, ...){ ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE ** compile-time option. */ - if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ) mxMmap = SQLITE_MAX_MMAP_SIZE; + if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ + mxMmap = SQLITE_MAX_MMAP_SIZE; + } if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; if( szMmap>mxMmap) szMmap = mxMmap; sqlite3GlobalConfig.mxMmap = mxMmap; @@ -1184,7 +1206,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ ** Return a static string containing the name corresponding to the error code ** specified in the argument. */ -#if (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) || defined(SQLITE_TEST) +#if defined(SQLITE_NEED_ERR_NAME) const char *sqlite3ErrName(int rc){ const char *zName = 0; int i, origRc = rc; @@ -1414,7 +1436,7 @@ int sqlite3_busy_handler( void *pArg ){ #ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE; + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->busyHandler.xFunc = xBusy; @@ -2409,18 +2431,30 @@ int sqlite3ParseUri( int eState; /* Parser state when parsing URI */ int iIn; /* Input character index */ int iOut = 0; /* Output character index */ - int nByte = nUri+2; /* Bytes of space to allocate */ + u64 nByte = nUri+2; /* Bytes of space to allocate */ /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen ** method that there may be extra parameters following the file-name. */ flags |= SQLITE_OPEN_URI; for(iIn=0; iInmallocFailed && rc==SQLITE_OK){ + int sqlite3_dbstat_register(sqlite3*); + rc = sqlite3_dbstat_register(db); + } +#endif + /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking ** mode. Doing nothing at all also makes NORMAL the default. @@ -2860,7 +2904,8 @@ static int openDatabase( opendb_out: sqlite3_free(zOpen); if( db ){ - assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 ); + assert( db->mutex!=0 || isThreadsafe==0 + || sqlite3GlobalConfig.bFullMutex==0 ); sqlite3_mutex_leave(db->mutex); } rc = sqlite3_errcode(db); @@ -3142,13 +3187,19 @@ int sqlite3_table_column_metadata( Table *pTab = 0; Column *pCol = 0; int iCol = 0; - char const *zDataType = 0; char const *zCollSeq = 0; int notnull = 0; int primarykey = 0; int autoinc = 0; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + /* Ensure the database schema has been loaded */ sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); @@ -3295,7 +3346,7 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){ sqlite3BtreeLeave(pBtree); } sqlite3_mutex_leave(db->mutex); - return rc; + return rc; } /* @@ -3598,6 +3649,35 @@ int sqlite3_test_control(int op, ...){ if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; break; } + + /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum); + ** + ** This test control is used to create imposter tables. "db" is a pointer + ** to the database connection. dbName is the database name (ex: "main" or + ** "temp") which will receive the imposter. "onOff" turns imposter mode on + ** or off. "tnum" is the root page of the b-tree to which the imposter + ** table should connect. + ** + ** Enable imposter mode only when the schema has already been parsed. Then + ** run a single CREATE TABLE statement to construct the imposter table in + ** the parsed schema. Then turn imposter mode back off again. + ** + ** If onOff==0 and tnum>0 then reset the schema for all databases, causing + ** the schema to be reparsed the next time it is needed. This has the + ** effect of erasing all imposter tables. + */ + case SQLITE_TESTCTRL_IMPOSTER: { + sqlite3 *db = va_arg(ap, sqlite3*); + sqlite3_mutex_enter(db->mutex); + db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*)); + db->init.busy = db->init.imposterTable = va_arg(ap,int); + db->init.newTnum = va_arg(ap,int); + if( db->init.busy==0 && db->init.newTnum>0 ){ + sqlite3ResetAllSchemasOfConnection(db); + } + sqlite3_mutex_leave(db->mutex); + break; + } } va_end(ap); #endif /* SQLITE_OMIT_BUILTIN_TEST */ diff --git a/src/malloc.c b/src/malloc.c index 4960f91..f06e27d 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -75,6 +75,13 @@ static SQLITE_WSD struct Mem0Global { #define mem0 GLOBAL(struct Mem0Global, mem0) +/* +** Return the memory allocator mutex. sqlite3_status() needs it. +*/ +sqlite3_mutex *sqlite3MallocMutex(void){ + return mem0.mutex; +} + /* ** This routine runs when the memory allocator sees that the ** total memory allocation is about to exceed the soft heap @@ -97,7 +104,7 @@ static int sqlite3MemoryAlarm( void *pArg, sqlite3_int64 iThreshold ){ - int nUsed; + sqlite3_int64 nUsed; sqlite3_mutex_enter(mem0.mutex); mem0.alarmCallback = xCallback; mem0.alarmArg = pArg; @@ -155,6 +162,7 @@ void sqlite3_soft_heap_limit(int n){ ** Initialize the memory allocation subsystem. */ int sqlite3MallocInit(void){ + int rc; if( sqlite3GlobalConfig.m.xMalloc==0 ){ sqlite3MemSetDefault(); } @@ -190,7 +198,9 @@ int sqlite3MallocInit(void){ sqlite3GlobalConfig.szPage = 0; sqlite3GlobalConfig.nPage = 0; } - return sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData); + rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData); + if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0)); + return rc; } /* @@ -266,7 +276,7 @@ static int mallocWithAlarm(int n, void **pp){ nFull = sqlite3GlobalConfig.m.xRoundup(n); sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n); if( mem0.alarmCallback!=0 ){ - int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); + sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); if( nUsed >= mem0.alarmThreshold - nFull ){ mem0.nearlyFull = 1; sqlite3MallocAlarm(nFull); @@ -283,8 +293,8 @@ static int mallocWithAlarm(int n, void **pp){ #endif if( p ){ nFull = sqlite3MallocSize(p); - sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull); - sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, 1); + sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nFull); + sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1); } *pp = p; return nFull; @@ -361,14 +371,14 @@ void *sqlite3ScratchMalloc(int n){ p = mem0.pScratchFree; mem0.pScratchFree = mem0.pScratchFree->pNext; mem0.nScratchFree--; - sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1); + sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1); sqlite3_mutex_leave(mem0.mutex); }else{ sqlite3_mutex_leave(mem0.mutex); p = sqlite3Malloc(n); if( sqlite3GlobalConfig.bMemstat && p ){ sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p)); + sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p)); sqlite3_mutex_leave(mem0.mutex); } sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH); @@ -409,19 +419,19 @@ void sqlite3ScratchFree(void *p){ mem0.pScratchFree = pSlot; mem0.nScratchFree++; assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch ); - sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1); + sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1); sqlite3_mutex_leave(mem0.mutex); }else{ /* Release memory back to the heap */ assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) ); - assert( sqlite3MemdebugNoType(p, ~MEMTYPE_SCRATCH) ); + assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); if( sqlite3GlobalConfig.bMemstat ){ int iSize = sqlite3MallocSize(p); sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, -iSize); - sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -iSize); - sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1); + sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize); + sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize); + sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1); sqlite3GlobalConfig.m.xFree(p); sqlite3_mutex_leave(mem0.mutex); }else{ @@ -452,7 +462,7 @@ int sqlite3MallocSize(void *p){ } int sqlite3DbMallocSize(sqlite3 *db, void *p){ if( db==0 ){ - assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); + assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return sqlite3MallocSize(p); }else{ @@ -461,13 +471,13 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){ return db->lookaside.sz; }else{ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); - assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); return sqlite3GlobalConfig.m.xSize(p); } } } sqlite3_uint64 sqlite3_msize(void *p){ - assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); + assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p); } @@ -478,11 +488,11 @@ sqlite3_uint64 sqlite3_msize(void *p){ void sqlite3_free(void *p){ if( p==0 ) return; /* IMP: R-49053-54554 */ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); - assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) ); + assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p)); - sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1); + sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, sqlite3MallocSize(p)); + sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1); sqlite3GlobalConfig.m.xFree(p); sqlite3_mutex_leave(mem0.mutex); }else{ @@ -523,7 +533,7 @@ void sqlite3DbFree(sqlite3 *db, void *p){ } } assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); - assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); @@ -536,7 +546,7 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){ int nOld, nNew, nDiff; void *pNew; assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); - assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) ); + assert( sqlite3MemdebugNoType(pOld, (u8)~MEMTYPE_HEAP) ); if( pOld==0 ){ return sqlite3Malloc(nBytes); /* IMP: R-04300-56712 */ } @@ -570,7 +580,7 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){ } if( pNew ){ nNew = sqlite3MallocSize(pNew); - sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld); + sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld); } sqlite3_mutex_leave(mem0.mutex); }else{ @@ -703,7 +713,7 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){ } }else{ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); - assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); pNew = sqlite3_realloc64(p, n); if( !pNew ){ diff --git a/src/msvc.h b/src/msvc.h index 4508e69..01ebf2b 100644 --- a/src/msvc.h +++ b/src/msvc.h @@ -20,6 +20,7 @@ #pragma warning(disable : 4055) #pragma warning(disable : 4100) #pragma warning(disable : 4127) +#pragma warning(disable : 4130) #pragma warning(disable : 4152) #pragma warning(disable : 4189) #pragma warning(disable : 4206) diff --git a/src/mutex_noop.c b/src/mutex_noop.c index 1a900c2..7f68aea 100644 --- a/src/mutex_noop.c +++ b/src/mutex_noop.c @@ -120,8 +120,12 @@ static sqlite3_mutex *debugMutexAlloc(int id){ break; } default: { - assert( id-2 >= 0 ); - assert( id-2 < (int)(sizeof(aStatic)/sizeof(aStatic[0])) ); +#ifdef SQLITE_ENABLE_API_ARMOR + if( id-2<0 || id-2>=ArraySize(aStatic) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif pNew = &aStatic[id-2]; pNew->id = id; break; @@ -136,8 +140,13 @@ static sqlite3_mutex *debugMutexAlloc(int id){ static void debugMutexFree(sqlite3_mutex *pX){ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; assert( p->cnt==0 ); - assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); - sqlite3_free(p); + if( p->id==SQLITE_MUTEX_RECURSIVE || p->id==SQLITE_MUTEX_FAST ){ + sqlite3_free(p); + }else{ +#ifdef SQLITE_ENABLE_API_ARMOR + (void)SQLITE_MISUSE_BKPT; +#endif + } } /* diff --git a/src/mutex_unix.c b/src/mutex_unix.c index c936914..e08448e 100644 --- a/src/mutex_unix.c +++ b/src/mutex_unix.c @@ -40,8 +40,10 @@ */ struct sqlite3_mutex { pthread_mutex_t mutex; /* Mutex controlling the lock */ -#if SQLITE_MUTEX_NREF +#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) int id; /* Mutex type */ +#endif +#if SQLITE_MUTEX_NREF volatile int nRef; /* Number of entrances */ volatile pthread_t owner; /* Thread that is within this mutex */ int trace; /* True to trace changes */ @@ -157,9 +159,6 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&p->mutex, &recursiveAttr); pthread_mutexattr_destroy(&recursiveAttr); -#endif -#if SQLITE_MUTEX_NREF - p->id = iType; #endif } break; @@ -167,9 +166,6 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ case SQLITE_MUTEX_FAST: { p = sqlite3MallocZero( sizeof(*p) ); if( p ){ -#if SQLITE_MUTEX_NREF - p->id = iType; -#endif pthread_mutex_init(&p->mutex, 0); } break; @@ -182,12 +178,12 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ } #endif p = &staticMutexes[iType-2]; -#if SQLITE_MUTEX_NREF - p->id = iType; -#endif break; } } +#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) + if( p ) p->id = iType; +#endif return p; } @@ -199,9 +195,18 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ */ static void pthreadMutexFree(sqlite3_mutex *p){ assert( p->nRef==0 ); - assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); - pthread_mutex_destroy(&p->mutex); - sqlite3_free(p); +#if SQLITE_ENABLE_API_ARMOR + if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ) +#endif + { + pthread_mutex_destroy(&p->mutex); + sqlite3_free(p); + } +#ifdef SQLITE_ENABLE_API_ARMOR + else{ + (void)SQLITE_MISUSE_BKPT; + } +#endif } /* diff --git a/src/mutex_w32.c b/src/mutex_w32.c index a799c86..6786614 100644 --- a/src/mutex_w32.c +++ b/src/mutex_w32.c @@ -194,8 +194,8 @@ static sqlite3_mutex *winMutexAlloc(int iType){ case SQLITE_MUTEX_RECURSIVE: { p = sqlite3MallocZero( sizeof(*p) ); if( p ){ -#ifdef SQLITE_DEBUG p->id = iType; +#ifdef SQLITE_DEBUG #ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC p->trace = 1; #endif @@ -215,12 +215,9 @@ static sqlite3_mutex *winMutexAlloc(int iType){ return 0; } #endif - assert( iType-2 >= 0 ); - assert( iType-2 < ArraySize(winMutex_staticMutexes) ); - assert( winMutex_isInit==1 ); p = &winMutex_staticMutexes[iType-2]; -#ifdef SQLITE_DEBUG p->id = iType; +#ifdef SQLITE_DEBUG #ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC p->trace = 1; #endif @@ -239,13 +236,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){ */ static void winMutexFree(sqlite3_mutex *p){ assert( p ); -#ifdef SQLITE_DEBUG assert( p->nRef==0 && p->owner==0 ); - assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); + if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){ + DeleteCriticalSection(&p->mutex); + sqlite3_free(p); + }else{ +#ifdef SQLITE_ENABLE_API_ARMOR + (void)SQLITE_MISUSE_BKPT; #endif - assert( winMutex_isInit==1 ); - DeleteCriticalSection(&p->mutex); - sqlite3_free(p); + } } /* diff --git a/src/os_common.h b/src/os_common.h index f6c3e7f..d18b95a 100644 --- a/src/os_common.h +++ b/src/os_common.h @@ -29,16 +29,6 @@ # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." #endif -#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) -# ifndef SQLITE_DEBUG_OS_TRACE -# define SQLITE_DEBUG_OS_TRACE 0 -# endif - int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE; -# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X -#else -# define OSTRACE(X) -#endif - /* ** Macros for performance tracing. Normally turned off. Only works ** on i486 hardware. diff --git a/src/os_unix.c b/src/os_unix.c index ddd6a80..9ec1003 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -71,18 +71,6 @@ # endif #endif -/* -** Define the OS_VXWORKS pre-processor macro to 1 if building on -** vxworks, or 0 otherwise. -*/ -#ifndef OS_VXWORKS -# if defined(__RTP__) || defined(_WRS_KERNEL) -# define OS_VXWORKS 1 -# else -# define OS_VXWORKS 0 -# endif -#endif - /* ** standard include files. */ @@ -97,18 +85,30 @@ # include #endif -#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS +#if SQLITE_ENABLE_LOCKING_STYLE # include -# if OS_VXWORKS -# include -# include -# else -# include -# include -# endif +# include +# include #endif /* SQLITE_ENABLE_LOCKING_STYLE */ -#if defined(__APPLE__) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) +#if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \ + (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000)) +# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \ + && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0)) +# define HAVE_GETHOSTUUID 1 +# else +# warning "gethostuuid() is disabled." +# endif +#endif + + +#if OS_VXWORKS +# include +# include +# include +#endif /* OS_VXWORKS */ + +#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE # include #endif @@ -149,6 +149,10 @@ */ #define MAX_PATHNAME 512 +/* Always cast the getpid() return type for compatibility with +** kernel modules in VxWorks. */ +#define osGetpid(X) (pid_t)getpid() + /* ** Only set the lastErrno if the error code is a real error and not ** a normal expected return code of SQLITE_BUSY or SQLITE_OK @@ -237,7 +241,7 @@ struct unixFile { ** method was called. If xOpen() is called from a different process id, ** indicating that a fork() has occurred, the PRNG will be reset. */ -static int randomnessPid = 0; +static pid_t randomnessPid = 0; /* ** Allowed values for the unixFile.ctrlFlags bitmask: @@ -254,7 +258,8 @@ static int randomnessPid = 0; #define UNIXFILE_DELETE 0x20 /* Delete on close */ #define UNIXFILE_URI 0x40 /* Filename might have query parameters */ #define UNIXFILE_NOLOCK 0x80 /* Do no file locking */ -#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings have been issued */ +#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings issued */ +#define UNIXFILE_BLOCK 0x0200 /* Next SHM lock might block */ /* ** Include code that is common to all os_*.c files @@ -385,7 +390,7 @@ static struct unix_syscall { { "read", (sqlite3_syscall_ptr)read, 0 }, #define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) -#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) +#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE { "pread", (sqlite3_syscall_ptr)pread, 0 }, #else { "pread", (sqlite3_syscall_ptr)0, 0 }, @@ -402,7 +407,7 @@ static struct unix_syscall { { "write", (sqlite3_syscall_ptr)write, 0 }, #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) -#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) +#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, #else { "pwrite", (sqlite3_syscall_ptr)0, 0 }, @@ -636,7 +641,7 @@ static int unixMutexHeld(void) { #endif -#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) +#ifdef SQLITE_HAVE_OS_TRACE /* ** Helper function for printing out trace information from debugging ** binaries. This returns the string representation of the supplied @@ -717,9 +722,9 @@ static int lockTrace(int fd, int op, struct flock *p){ /* ** Retry ftruncate() calls that fail due to EINTR ** -** All calls to ftruncate() within this file should be made through this wrapper. -** On the Android platform, bypassing the logic below could lead to a corrupt -** database. +** All calls to ftruncate() within this file should be made through +** this wrapper. On the Android platform, bypassing the logic below +** could lead to a corrupt database. */ static int robust_ftruncate(int h, sqlite3_int64 sz){ int rc; @@ -899,7 +904,7 @@ static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){ assert( zAbsoluteName[0]=='/' ); n = (int)strlen(zAbsoluteName); - pNew = sqlite3_malloc( sizeof(*pNew) + (n+1) ); + pNew = sqlite3_malloc64( sizeof(*pNew) + (n+1) ); if( pNew==0 ) return 0; pNew->zCanonicalName = (char*)&pNew[1]; memcpy(pNew->zCanonicalName, zAbsoluteName, n+1); @@ -1178,6 +1183,14 @@ static void robust_close(unixFile *pFile, int h, int lineno){ } } +/* +** Set the pFile->lastErrno. Do this in a subroutine as that provides +** a convenient place to set a breakpoint. +*/ +static void storeLastErrno(unixFile *pFile, int error){ + pFile->lastErrno = error; +} + /* ** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. */ @@ -1251,7 +1264,7 @@ static int findInodeInfo( fd = pFile->h; rc = osFstat(fd, &statbuf); if( rc!=0 ){ - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); #ifdef EOVERFLOW if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS; #endif @@ -1272,12 +1285,12 @@ static int findInodeInfo( if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){ do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR ); if( rc!=1 ){ - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); return SQLITE_IOERR; } rc = osFstat(fd, &statbuf); if( rc!=0 ){ - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); return SQLITE_IOERR; } } @@ -1295,7 +1308,7 @@ static int findInodeInfo( pInode = pInode->pNext; } if( pInode==0 ){ - pInode = sqlite3_malloc( sizeof(*pInode) ); + pInode = sqlite3_malloc64( sizeof(*pInode) ); if( pInode==0 ){ return SQLITE_NOMEM; } @@ -1400,7 +1413,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ lock.l_type = F_WRLCK; if( osFcntl(pFile->h, F_GETLK, &lock) ){ rc = SQLITE_IOERR_CHECKRESERVEDLOCK; - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); } else if( lock.l_type!=F_UNLCK ){ reserved = 1; } @@ -1533,7 +1546,8 @@ static int unixLock(sqlite3_file *id, int eFileLock){ assert( pFile ); OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h, azFileLock(eFileLock), azFileLock(pFile->eFileLock), - azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared , getpid())); + azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared, + osGetpid(0))); /* If there is already a lock of this type or more restrictive on the ** unixFile, do nothing. Don't use the end_lock: exit path, as @@ -1600,7 +1614,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( rc!=SQLITE_BUSY ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } goto end_lock; } @@ -1635,7 +1649,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ if( rc ){ if( rc!=SQLITE_BUSY ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } goto end_lock; }else{ @@ -1668,7 +1682,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( rc!=SQLITE_BUSY ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } } } @@ -1741,7 +1755,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ assert( pFile ); OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock, pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, - getpid())); + osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); if( pFile->eFileLock<=eFileLock ){ @@ -1775,7 +1789,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ ** 4: [RRRR.] */ if( eFileLock==SHARED_LOCK ){ - #if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE (void)handleNFSUnlock; assert( handleNFSUnlock==0 ); @@ -1793,7 +1806,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ tErrno = errno; rc = SQLITE_IOERR_UNLOCK; if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } goto end_unlock; } @@ -1805,7 +1818,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } goto end_unlock; } @@ -1817,7 +1830,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ tErrno = errno; rc = SQLITE_IOERR_UNLOCK; if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } goto end_unlock; } @@ -1836,7 +1849,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ ** SQLITE_BUSY would confuse the upper layer (in practice it causes ** an assert to fail). */ rc = SQLITE_IOERR_RDLOCK; - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); goto end_unlock; } } @@ -1849,7 +1862,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ pInode->eFileLock = SHARED_LOCK; }else{ rc = SQLITE_IOERR_UNLOCK; - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); goto end_unlock; } } @@ -1867,7 +1880,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ pInode->eFileLock = NO_LOCK; }else{ rc = SQLITE_IOERR_UNLOCK; - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); pInode->eFileLock = NO_LOCK; pFile->eFileLock = NO_LOCK; } @@ -2142,7 +2155,7 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) { } else { rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } } return rc; @@ -2169,7 +2182,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { assert( pFile ); OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock, - pFile->eFileLock, getpid())); + pFile->eFileLock, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); /* no-op if possible */ @@ -2196,7 +2209,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { rc = SQLITE_IOERR_UNLOCK; } if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } return rc; } @@ -2232,10 +2245,9 @@ static int dotlockClose(sqlite3_file *id) { ** still works when you do this, but concurrency is reduced since ** only a single process can be reading the database at a time. ** -** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if -** compiling for VXWORKS. +** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off */ -#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS +#if SQLITE_ENABLE_LOCKING_STYLE /* ** Retry flock() calls that fail with EINTR @@ -2283,7 +2295,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ /* unlock failed with an error */ lrc = SQLITE_IOERR_UNLOCK; if( IS_LOCK_ERROR(lrc) ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); rc = lrc; } } @@ -2293,7 +2305,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ /* someone else might have it reserved */ lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(lrc) ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); rc = lrc; } } @@ -2359,7 +2371,7 @@ static int flockLock(sqlite3_file *id, int eFileLock) { /* didn't get, must be busy */ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } } else { /* got it, set the type and return ok */ @@ -2388,7 +2400,7 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) { assert( pFile ); OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock, - pFile->eFileLock, getpid())); + pFile->eFileLock, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); /* no-op if possible */ @@ -2449,7 +2461,7 @@ static int flockClose(sqlite3_file *id) { ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ -static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { +static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) { int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; @@ -2471,7 +2483,7 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { int tErrno = errno; if( EAGAIN != tErrno ){ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK); - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } else { /* someone else has the lock when we are in NO_LOCK */ reserved = (pFile->eFileLock < SHARED_LOCK); @@ -2516,7 +2528,7 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ -static int semLock(sqlite3_file *id, int eFileLock) { +static int semXLock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; sem_t *pSem = pFile->pInode->pSem; int rc = SQLITE_OK; @@ -2549,14 +2561,14 @@ static int semLock(sqlite3_file *id, int eFileLock) { ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ -static int semUnlock(sqlite3_file *id, int eFileLock) { +static int semXUnlock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; sem_t *pSem = pFile->pInode->pSem; assert( pFile ); assert( pSem ); OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock, - pFile->eFileLock, getpid())); + pFile->eFileLock, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); /* no-op if possible */ @@ -2575,7 +2587,7 @@ static int semUnlock(sqlite3_file *id, int eFileLock) { int rc, tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } return rc; } @@ -2586,10 +2598,10 @@ static int semUnlock(sqlite3_file *id, int eFileLock) { /* ** Close a file. */ -static int semClose(sqlite3_file *id) { +static int semXClose(sqlite3_file *id) { if( id ){ unixFile *pFile = (unixFile*)id; - semUnlock(id, NO_LOCK); + semXUnlock(id, NO_LOCK); assert( pFile ); unixEnterMutex(); releaseInodeInfo(pFile); @@ -2677,7 +2689,7 @@ static int afpSetLock( setLockFlag ? SQLITE_IOERR_LOCK : SQLITE_IOERR_UNLOCK); #endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */ if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; + storeLastErrno(pFile, tErrno); } return rc; } else { @@ -2770,7 +2782,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){ assert( pFile ); OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h, azFileLock(eFileLock), azFileLock(pFile->eFileLock), - azFileLock(pInode->eFileLock), pInode->nShared , getpid())); + azFileLock(pInode->eFileLock), pInode->nShared , osGetpid(0))); /* If there is already a lock of this type or more restrictive on the ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as @@ -2860,7 +2872,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){ lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0); if( IS_LOCK_ERROR(lrc1) ) { - pFile->lastErrno = lrc1Errno; + storeLastErrno(pFile, lrc1Errno); rc = lrc1; goto afp_end_lock; } else if( IS_LOCK_ERROR(lrc2) ){ @@ -2956,7 +2968,7 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) { assert( pFile ); OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock, pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, - getpid())); + osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); if( pFile->eFileLock<=eFileLock ){ @@ -3147,9 +3159,9 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ SimulateIOError( newOffset-- ); if( newOffset!=offset ){ if( newOffset == -1 ){ - ((unixFile*)id)->lastErrno = errno; + storeLastErrno((unixFile*)id, errno); }else{ - ((unixFile*)id)->lastErrno = 0; + storeLastErrno((unixFile*)id, 0); } return -1; } @@ -3159,7 +3171,7 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ if( got<0 ){ if( errno==EINTR ){ got = 1; continue; } prior = 0; - ((unixFile*)id)->lastErrno = errno; + storeLastErrno((unixFile*)id, errno); break; }else if( got>0 ){ cnt -= got; @@ -3224,7 +3236,7 @@ static int unixRead( /* lastErrno set by seekAndRead */ return SQLITE_IOERR_READ; }else{ - pFile->lastErrno = 0; /* not a system error */ + storeLastErrno(pFile, 0); /* not a system error */ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[got], 0, amt-got); return SQLITE_IOERR_SHORT_READ; @@ -3253,9 +3265,9 @@ static int seekAndWriteFd( TIMER_START; #if defined(USE_PREAD) - do{ rc = osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR ); + do{ rc = (int)osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR ); #elif defined(USE_PREAD64) - do{ rc = osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR); + do{ rc = (int)osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR); #else do{ i64 iSeek = lseek(fd, iOff, SEEK_SET); @@ -3365,7 +3377,7 @@ static int unixWrite( /* lastErrno set by seekAndWrite */ return SQLITE_IOERR_WRITE; }else{ - pFile->lastErrno = 0; /* not a system error */ + storeLastErrno(pFile, 0); /* not a system error */ return SQLITE_FULL; } } @@ -3574,7 +3586,7 @@ static int unixSync(sqlite3_file *id, int flags){ rc = full_fsync(pFile->h, isFullsync, isDataOnly); SimulateIOError( rc=1 ); if( rc ){ - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath); } @@ -3618,7 +3630,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){ rc = robust_ftruncate(pFile->h, nByte); if( rc ){ - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); }else{ #ifdef SQLITE_DEBUG @@ -3658,7 +3670,7 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){ rc = osFstat(((unixFile*)id)->h, &buf); SimulateIOError( rc=1 ); if( rc!=0 ){ - ((unixFile*)id)->lastErrno = errno; + storeLastErrno((unixFile*)id, errno); return SQLITE_IOERR_FSTAT; } *pSize = buf.st_size; @@ -3694,7 +3706,9 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ i64 nSize; /* Required file size */ struct stat buf; /* Used to hold return values of fstat() */ - if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT; + if( osFstat(pFile->h, &buf) ){ + return SQLITE_IOERR_FSTAT; + } nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk; if( nSize>(i64)buf.st_size ){ @@ -3741,7 +3755,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ int rc; if( pFile->szChunk<=0 ){ if( robust_ftruncate(pFile->h, nByte) ){ - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); } } @@ -3779,11 +3793,15 @@ static int unixGetTempname(int nBuf, char *zBuf); static int unixFileControl(sqlite3_file *id, int op, void *pArg){ unixFile *pFile = (unixFile*)id; switch( op ){ + case SQLITE_FCNTL_WAL_BLOCK: { + /* pFile->ctrlFlags |= UNIXFILE_BLOCK; // Deferred feature */ + return SQLITE_OK; + } case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->eFileLock; return SQLITE_OK; } - case SQLITE_LAST_ERRNO: { + case SQLITE_FCNTL_LAST_ERRNO: { *(int*)pArg = pFile->lastErrno; return SQLITE_OK; } @@ -3811,7 +3829,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ return SQLITE_OK; } case SQLITE_FCNTL_TEMPFILENAME: { - char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname ); + char *zTFile = sqlite3_malloc64( pFile->pVfs->mxPathname ); if( zTFile ){ unixGetTempname(pFile->pVfs->mxPathname, zTFile); *(char**)pArg = zTFile; @@ -3852,8 +3870,8 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ } #endif #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) - case SQLITE_SET_LOCKPROXYFILE: - case SQLITE_GET_LOCKPROXYFILE: { + case SQLITE_FCNTL_SET_LOCKPROXYFILE: + case SQLITE_FCNTL_GET_LOCKPROXYFILE: { return proxyFileControl(id,op,pArg); } #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ @@ -3993,7 +4011,9 @@ static int unixDeviceCharacteristics(sqlite3_file *id){ ** Instead, it should be called via macro osGetpagesize(). */ static int unixGetpagesize(void){ -#if defined(_BSD_SOURCE) +#if OS_VXWORKS + return 1024; +#elif defined(_BSD_SOURCE) return getpagesize(); #else return (int)sysconf(_SC_PAGESIZE); @@ -4086,15 +4106,17 @@ struct unixShm { ** otherwise. */ static int unixShmSystemLock( - unixShmNode *pShmNode, /* Apply locks to this open shared-memory segment */ + unixFile *pFile, /* Open connection to the WAL file */ int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */ int ofst, /* First byte of the locking range */ int n /* Number of bytes to lock */ ){ - struct flock f; /* The posix advisory locking structure */ - int rc = SQLITE_OK; /* Result code form fcntl() */ + unixShmNode *pShmNode; /* Apply locks to this open shared-memory segment */ + struct flock f; /* The posix advisory locking structure */ + int rc = SQLITE_OK; /* Result code form fcntl() */ /* Access to the unixShmNode object is serialized by the caller */ + pShmNode = pFile->pInode->pShmNode; assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 ); /* Shared locks never span more than one byte */ @@ -4104,6 +4126,7 @@ static int unixShmSystemLock( assert( n>=1 && nh>=0 ){ + int lkType; /* Initialize the locking parameters */ memset(&f, 0, sizeof(f)); f.l_type = lockType; @@ -4111,8 +4134,10 @@ static int unixShmSystemLock( f.l_start = ofst; f.l_len = n; - rc = osFcntl(pShmNode->h, F_SETLK, &f); + lkType = (pFile->ctrlFlags & UNIXFILE_BLOCK)!=0 ? F_SETLKW : F_SETLK; + rc = osFcntl(pShmNode->h, lkType, &f); rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY; + pFile->ctrlFlags &= ~UNIXFILE_BLOCK; } /* Update the global lock state and do debug tracing */ @@ -4245,7 +4270,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ int nShmFilename; /* Size of the SHM filename in bytes */ /* Allocate space for the new unixShm object. */ - p = sqlite3_malloc( sizeof(*p) ); + p = sqlite3_malloc64( sizeof(*p) ); if( p==0 ) return SQLITE_NOMEM; memset(p, 0, sizeof(*p)); assert( pDbFd->pShm==0 ); @@ -4258,6 +4283,9 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ pShmNode = pInode->pShmNode; if( pShmNode==0 ){ struct stat sStat; /* fstat() info for database file */ +#ifndef SQLITE_SHM_DIRECTORY + const char *zBasePath = pDbFd->zPath; +#endif /* Call fstat() to figure out the permissions on the database file. If ** a new *-shm file is created, an attempt will be made to create it @@ -4271,9 +4299,9 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ #ifdef SQLITE_SHM_DIRECTORY nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31; #else - nShmFilename = 6 + (int)strlen(pDbFd->zPath); + nShmFilename = 6 + (int)strlen(zBasePath); #endif - pShmNode = sqlite3_malloc( sizeof(*pShmNode) + nShmFilename ); + pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename ); if( pShmNode==0 ){ rc = SQLITE_NOMEM; goto shm_open_err; @@ -4285,7 +4313,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x", (u32)sStat.st_ino, (u32)sStat.st_dev); #else - sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath); + sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", zBasePath); sqlite3FileSuffix3(pDbFd->zPath, zShmFilename); #endif pShmNode->h = -1; @@ -4319,13 +4347,13 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ ** If not, truncate the file to zero length. */ rc = SQLITE_OK; - if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){ + if( unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){ if( robust_ftruncate(pShmNode->h, 0) ){ rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename); } } if( rc==SQLITE_OK ){ - rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1); + rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1); } if( rc ) goto shm_open_err; } @@ -4483,7 +4511,7 @@ static int unixShmMap( goto shmpage_out; } }else{ - pMem = sqlite3_malloc(szRegion); + pMem = sqlite3_malloc64(szRegion); if( pMem==0 ){ rc = SQLITE_NOMEM; goto shmpage_out; @@ -4557,7 +4585,7 @@ static int unixShmLock( /* Unlock the system-level locks */ if( (mask & allMask)==0 ){ - rc = unixShmSystemLock(pShmNode, F_UNLCK, ofst+UNIX_SHM_BASE, n); + rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); }else{ rc = SQLITE_OK; } @@ -4585,7 +4613,7 @@ static int unixShmLock( /* Get shared locks at the system level, if necessary */ if( rc==SQLITE_OK ){ if( (allShared & mask)==0 ){ - rc = unixShmSystemLock(pShmNode, F_RDLCK, ofst+UNIX_SHM_BASE, n); + rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); }else{ rc = SQLITE_OK; } @@ -4610,7 +4638,7 @@ static int unixShmLock( ** also mark the local connection as being locked. */ if( rc==SQLITE_OK ){ - rc = unixShmSystemLock(pShmNode, F_WRLCK, ofst+UNIX_SHM_BASE, n); + rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n); if( rc==SQLITE_OK ){ assert( (p->sharedMask & mask)==0 ); p->exclMask |= mask; @@ -4619,7 +4647,7 @@ static int unixShmLock( } sqlite3_mutex_leave(pShmNode->mutex); OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", - p->id, getpid(), p->sharedMask, p->exclMask)); + p->id, osGetpid(0), p->sharedMask, p->exclMask)); return rc; } @@ -4678,7 +4706,9 @@ static int unixShmUnmap( assert( pShmNode->nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ - if( deleteFlag && pShmNode->h>=0 ) osUnlink(pShmNode->zFilename); + if( deleteFlag && pShmNode->h>=0 ){ + osUnlink(pShmNode->zFilename); + } unixShmPurge(pDbFd); } unixLeaveMutex(); @@ -4955,7 +4985,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){ ** * An I/O method finder function called FINDER that returns a pointer ** to the METHOD object in the previous bullet. */ -#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK, SHMMAP) \ +#define IOMETHODS(FINDER,METHOD,VERSION,CLOSE,LOCK,UNLOCK,CKLOCK,SHMMAP) \ static const sqlite3_io_methods METHOD = { \ VERSION, /* iVersion */ \ CLOSE, /* xClose */ \ @@ -5020,7 +5050,7 @@ IOMETHODS( 0 /* xShmMap method */ ) -#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS +#if SQLITE_ENABLE_LOCKING_STYLE IOMETHODS( flockIoFinder, /* Finder function name */ flockIoMethods, /* sqlite3_io_methods object name */ @@ -5038,10 +5068,10 @@ IOMETHODS( semIoFinder, /* Finder function name */ semIoMethods, /* sqlite3_io_methods object name */ 1, /* shared memory is disabled */ - semClose, /* xClose method */ - semLock, /* xLock method */ - semUnlock, /* xUnlock method */ - semCheckReservedLock, /* xCheckReservedLock method */ + semXClose, /* xClose method */ + semXLock, /* xLock method */ + semXUnlock, /* xUnlock method */ + semXCheckReservedLock, /* xCheckReservedLock method */ 0 /* xShmMap method */ ) #endif @@ -5165,15 +5195,13 @@ static const sqlite3_io_methods #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ -#if OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE -/* -** This "finder" function attempts to determine the best locking strategy -** for the database file "filePath". It then returns the sqlite3_io_methods -** object that implements that strategy. -** -** This is for VXWorks only. +#if OS_VXWORKS +/* +** This "finder" function for VxWorks checks to see if posix advisory +** locking works. If it does, then that is what is used. If it does not +** work, then fallback to named semaphore locking. */ -static const sqlite3_io_methods *autolockIoFinderImpl( +static const sqlite3_io_methods *vxworksIoFinderImpl( const char *filePath, /* name of the database file */ unixFile *pNew /* the open file object */ ){ @@ -5199,9 +5227,9 @@ static const sqlite3_io_methods *autolockIoFinderImpl( } } static const sqlite3_io_methods - *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; + *(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl; -#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */ +#endif /* OS_VXWORKS */ /* ** An abstract type for a pointer to an IO method finder function: @@ -5320,7 +5348,7 @@ static int fillInUnixFile( ** the afpLockingContext. */ afpLockingContext *pCtx; - pNew->lockingContext = pCtx = sqlite3_malloc( sizeof(*pCtx) ); + pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) ); if( pCtx==0 ){ rc = SQLITE_NOMEM; }else{ @@ -5350,7 +5378,7 @@ static int fillInUnixFile( int nFilename; assert( zFilename!=0 ); nFilename = (int)strlen(zFilename) + 6; - zLockFile = (char *)sqlite3_malloc(nFilename); + zLockFile = (char *)sqlite3_malloc64(nFilename); if( zLockFile==0 ){ rc = SQLITE_NOMEM; }else{ @@ -5383,7 +5411,7 @@ static int fillInUnixFile( } #endif - pNew->lastErrno = 0; + storeLastErrno(pNew, 0); #if OS_VXWORKS if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); @@ -5714,8 +5742,8 @@ static int unixOpen( ** the same instant might all reset the PRNG. But multiple resets ** are harmless. */ - if( randomnessPid!=getpid() ){ - randomnessPid = getpid(); + if( randomnessPid!=osGetpid(0) ){ + randomnessPid = osGetpid(0); sqlite3_randomness(0,0); } @@ -5727,7 +5755,7 @@ static int unixOpen( if( pUnused ){ fd = pUnused->fd; }else{ - pUnused = sqlite3_malloc(sizeof(*pUnused)); + pUnused = sqlite3_malloc64(sizeof(*pUnused)); if( !pUnused ){ return SQLITE_NOMEM; } @@ -5831,13 +5859,16 @@ static int unixOpen( #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE if( fstatfs(fd, &fsInfo) == -1 ){ - ((unixFile*)pFile)->lastErrno = errno; + storeLastErrno(p, errno); robust_close(p, fd, __LINE__); return SQLITE_IOERR_ACCESS; } if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) { ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS; } + if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) { + ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS; + } #endif /* Set up appropriate ctrlFlags */ @@ -5860,19 +5891,6 @@ static int unixOpen( if( envforce!=NULL ){ useProxy = atoi(envforce)>0; }else{ - if( statfs(zPath, &fsInfo) == -1 ){ - /* In theory, the close(fd) call is sub-optimal. If the file opened - ** with fd is a database file, and there are other connections open - ** on that file that are currently holding advisory locks on it, - ** then the call to close() will cancel those locks. In practice, - ** we're assuming that statfs() doesn't fail very often. At least - ** not while other file descriptors opened by the same process on - ** the same file are working. */ - p->lastErrno = errno; - robust_close(p, fd, __LINE__); - rc = SQLITE_IOERR_ACCESS; - goto open_finished; - } useProxy = !(fsInfo.f_flags&MNT_LOCAL); } if( useProxy ){ @@ -6116,8 +6134,8 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){ ** tests repeatable. */ memset(zBuf, 0, nBuf); - randomnessPid = getpid(); -#if !defined(SQLITE_TEST) + randomnessPid = osGetpid(0); +#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) { int fd, got; fd = robust_open("/dev/urandom", O_RDONLY, 0); @@ -6298,9 +6316,10 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** ** C APIs ** -** sqlite3_file_control(db, dbname, SQLITE_SET_LOCKPROXYFILE, +** sqlite3_file_control(db, dbname, SQLITE_FCNTL_SET_LOCKPROXYFILE, ** | ":auto:"); -** sqlite3_file_control(db, dbname, SQLITE_GET_LOCKPROXYFILE, &); +** sqlite3_file_control(db, dbname, SQLITE_FCNTL_GET_LOCKPROXYFILE, +** &); ** ** ** SQL pragmas @@ -6393,7 +6412,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will ** force proxy locking to be used for every database file opened, and 0 ** will force automatic proxy locking to be disabled for all database -** files (explicitly calling the SQLITE_SET_LOCKPROXYFILE pragma or +** files (explicitly calling the SQLITE_FCNTL_SET_LOCKPROXYFILE pragma or ** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING). */ @@ -6414,6 +6433,7 @@ struct proxyLockingContext { char *lockProxyPath; /* Name of the proxy lock file */ char *dbPath; /* Name of the open file */ int conchHeld; /* 1 if the conch is held, -1 if lockless */ + int nFails; /* Number of conch taking failures */ void *oldLockingContext; /* Original lockingcontext to restore on close */ sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */ }; @@ -6435,7 +6455,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ { if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", - lPath, errno, getpid())); + lPath, errno, osGetpid(0))); return SQLITE_IOERR_LOCK; } len = strlcat(lPath, "sqliteplocks", maxLen); @@ -6457,7 +6477,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ } lPath[i+len]='\0'; strlcat(lPath, ":auto:", maxLen); - OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, getpid())); + OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, osGetpid(0))); return SQLITE_OK; } @@ -6484,7 +6504,7 @@ static int proxyCreateLockPath(const char *lockPath){ if( err!=EEXIST ) { OSTRACE(("CREATELOCKPATH FAILED creating %s, " "'%s' proxy lock path=%s pid=%d\n", - buf, strerror(err), lockPath, getpid())); + buf, strerror(err), lockPath, osGetpid(0))); return err; } } @@ -6493,7 +6513,7 @@ static int proxyCreateLockPath(const char *lockPath){ } buf[i] = lockPath[i]; } - OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, getpid())); + OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, osGetpid(0))); return 0; } @@ -6527,7 +6547,7 @@ static int proxyCreateUnixFile( if( pUnused ){ fd = pUnused->fd; }else{ - pUnused = sqlite3_malloc(sizeof(*pUnused)); + pUnused = sqlite3_malloc64(sizeof(*pUnused)); if( !pUnused ){ return SQLITE_NOMEM; } @@ -6560,7 +6580,7 @@ static int proxyCreateUnixFile( } } - pNew = (unixFile *)sqlite3_malloc(sizeof(*pNew)); + pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew)); if( pNew==NULL ){ rc = SQLITE_NOMEM; goto end_create_proxy; @@ -6593,8 +6613,10 @@ int sqlite3_hostid_num = 0; #define PROXY_HOSTIDLEN 16 /* conch file host id length */ +#ifdef HAVE_GETHOSTUUID /* Not always defined in the headers as it ought to be */ extern int gethostuuid(uuid_t id, const struct timespec *wait); +#endif /* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN ** bytes of writable memory. @@ -6602,10 +6624,9 @@ extern int gethostuuid(uuid_t id, const struct timespec *wait); static int proxyGetHostID(unsigned char *pHostID, int *pError){ assert(PROXY_HOSTIDLEN == sizeof(uuid_t)); memset(pHostID, 0, PROXY_HOSTIDLEN); -#if defined(__MAX_OS_X_VERSION_MIN_REQUIRED)\ - && __MAC_OS_X_VERSION_MIN_REQUIRED<1050 +#ifdef HAVE_GETHOSTUUID { - static const struct timespec timeout = {1, 0}; /* 1 sec timeout */ + struct timespec timeout = {1, 0}; /* 1 sec timeout */ if( gethostuuid(pHostID, &timeout) ){ int err = errno; if( pError ){ @@ -6720,7 +6741,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ */ struct stat buf; if( osFstat(conchFile->h, &buf) ){ - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); return SQLITE_IOERR_LOCK; } @@ -6740,7 +6761,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ char tBuf[PROXY_MAXCONCHLEN]; int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0); if( len<0 ){ - pFile->lastErrno = errno; + storeLastErrno(pFile, errno); return SQLITE_IOERR_LOCK; } if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){ @@ -6760,7 +6781,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ if( 0==proxyBreakConchLock(pFile, myHostID) ){ rc = SQLITE_OK; if( lockType==EXCLUSIVE_LOCK ){ - rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK); + rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK); } if( !rc ){ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); @@ -6798,11 +6819,12 @@ static int proxyTakeConch(unixFile *pFile){ int forceNewLockPath = 0; OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h, - (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid())); + (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), + osGetpid(0))); rc = proxyGetHostID(myHostID, &pError); if( (rc&0xff)==SQLITE_IOERR ){ - pFile->lastErrno = pError; + storeLastErrno(pFile, pError); goto end_takeconch; } rc = proxyConchLock(pFile, myHostID, SHARED_LOCK); @@ -6813,7 +6835,7 @@ static int proxyTakeConch(unixFile *pFile){ readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN); if( readLen<0 ){ /* I/O error: lastErrno set by seekAndRead */ - pFile->lastErrno = conchFile->lastErrno; + storeLastErrno(pFile, conchFile->lastErrno); rc = SQLITE_IOERR_READ; goto end_takeconch; }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || @@ -6886,7 +6908,7 @@ static int proxyTakeConch(unixFile *pFile){ rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK); } }else{ - rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, EXCLUSIVE_LOCK); + rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK); } if( rc==SQLITE_OK ){ char writeBuffer[PROXY_MAXCONCHLEN]; @@ -6895,7 +6917,8 @@ static int proxyTakeConch(unixFile *pFile){ writeBuffer[0] = (char)PROXY_CONCHVERSION; memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN); if( pCtx->lockProxyPath!=NULL ){ - strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, MAXPATHLEN); + strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, + MAXPATHLEN); }else{ strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN); } @@ -7007,7 +7030,7 @@ static int proxyReleaseConch(unixFile *pFile){ conchFile = pCtx->conchFile; OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h, (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), - getpid())); + osGetpid(0))); if( pCtx->conchHeld>0 ){ rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); } @@ -7019,7 +7042,7 @@ static int proxyReleaseConch(unixFile *pFile){ /* ** Given the name of a database file, compute the name of its conch file. -** Store the conch filename in memory obtained from sqlite3_malloc(). +** Store the conch filename in memory obtained from sqlite3_malloc64(). ** Make *pConchPath point to the new name. Return SQLITE_OK on success ** or SQLITE_NOMEM if unable to obtain memory. ** @@ -7035,7 +7058,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){ /* Allocate space for the conch filename and initialize the name to ** the name of the original database file. */ - *pConchPath = conchPath = (char *)sqlite3_malloc(len + 8); + *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8); if( conchPath==0 ){ return SQLITE_NOMEM; } @@ -7107,7 +7130,8 @@ static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){ /* afp style keeps a reference to the db path in the filePath field ** of the struct */ assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); - strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath, MAXPATHLEN); + strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath, + MAXPATHLEN); } else #endif if( pFile->pMethod == &dotlockIoMethods ){ @@ -7148,9 +7172,9 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) { } OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h, - (lockPath ? lockPath : ":auto:"), getpid())); + (lockPath ? lockPath : ":auto:"), osGetpid(0))); - pCtx = sqlite3_malloc( sizeof(*pCtx) ); + pCtx = sqlite3_malloc64( sizeof(*pCtx) ); if( pCtx==0 ){ return SQLITE_NOMEM; } @@ -7220,7 +7244,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) { */ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){ switch( op ){ - case SQLITE_GET_LOCKPROXYFILE: { + case SQLITE_FCNTL_GET_LOCKPROXYFILE: { unixFile *pFile = (unixFile*)id; if( pFile->pMethod == &proxyIoMethods ){ proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; @@ -7235,13 +7259,16 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){ } return SQLITE_OK; } - case SQLITE_SET_LOCKPROXYFILE: { + case SQLITE_FCNTL_SET_LOCKPROXYFILE: { unixFile *pFile = (unixFile*)id; int rc = SQLITE_OK; int isProxyStyle = (pFile->pMethod == &proxyIoMethods); if( pArg==NULL || (const char *)pArg==0 ){ if( isProxyStyle ){ - /* turn off proxy locking - not supported */ + /* turn off proxy locking - not supported. If support is added for + ** switching proxy locking mode off then it will need to fail if + ** the journal mode is WAL mode. + */ rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/; }else{ /* turn off proxy locking - already off - NOOP */ @@ -7486,8 +7513,10 @@ int sqlite3_os_init(void){ ** array cannot be const. */ static sqlite3_vfs aVfs[] = { -#if SQLITE_ENABLE_LOCKING_STYLE && (OS_VXWORKS || defined(__APPLE__)) +#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) UNIXVFS("unix", autolockIoFinder ), +#elif OS_VXWORKS + UNIXVFS("unix", vxworksIoFinder ), #else UNIXVFS("unix", posixIoFinder ), #endif @@ -7497,11 +7526,11 @@ int sqlite3_os_init(void){ #if OS_VXWORKS UNIXVFS("unix-namedsem", semIoFinder ), #endif -#if SQLITE_ENABLE_LOCKING_STYLE +#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS UNIXVFS("unix-posix", posixIoFinder ), -#if !OS_VXWORKS - UNIXVFS("unix-flock", flockIoFinder ), #endif +#if SQLITE_ENABLE_LOCKING_STYLE + UNIXVFS("unix-flock", flockIoFinder ), #endif #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) UNIXVFS("unix-afp", afpIoFinder ), diff --git a/src/os_win.c b/src/os_win.c index e2f9aec..0ebea5a 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -197,8 +197,10 @@ WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T); #endif /* SQLITE_OS_WINRT */ /* -** This file mapping API is common to both Win32 and WinRT. +** These file mapping APIs are common to both Win32 and WinRT. */ + +WINBASEAPI BOOL WINAPI FlushViewOfFile(LPCVOID, SIZE_T); WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); #endif /* SQLITE_WIN32_FILEMAPPING_API */ @@ -1066,6 +1068,32 @@ static struct win_syscall { SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent) #endif /* defined(InterlockedCompareExchange) */ +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID + { "UuidCreate", (SYSCALL)UuidCreate, 0 }, +#else + { "UuidCreate", (SYSCALL)0, 0 }, +#endif + +#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent) + +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID + { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 }, +#else + { "UuidCreateSequential", (SYSCALL)0, 0 }, +#endif + +#define osUuidCreateSequential \ + ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent) + +#if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0 + { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 }, +#else + { "FlushViewOfFile", (SYSCALL)0, 0 }, +#endif + +#define osFlushViewOfFile \ + ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent) + }; /* End of the overrideable system calls */ /* @@ -1949,11 +1977,11 @@ static int winRetryIoerr(int *pnRetry, DWORD *pError){ /* ** Log a I/O error retry episode. */ -static void winLogIoerr(int nRetry){ +static void winLogIoerr(int nRetry, int lineno){ if( nRetry ){ - sqlite3_log(SQLITE_IOERR, - "delayed %dms for lock/sharing conflict", - winIoerrRetryDelay*nRetry*(nRetry+1)/2 + sqlite3_log(SQLITE_NOTICE, + "delayed %dms for lock/sharing conflict at line %d", + winIoerrRetryDelay*nRetry*(nRetry+1)/2, lineno ); } } @@ -2433,7 +2461,8 @@ static int winClose(sqlite3_file *id){ assert( pFile->pShm==0 ); #endif assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE ); - OSTRACE(("CLOSE file=%p\n", pFile->h)); + OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p\n", + osGetCurrentProcessId(), pFile, pFile->h)); #if SQLITE_MAX_MMAP_SIZE>0 winUnmapfile(pFile); @@ -2462,7 +2491,8 @@ static int winClose(sqlite3_file *id){ pFile->h = NULL; } OpenCounter(-1); - OSTRACE(("CLOSE file=%p, rc=%s\n", pFile->h, rc ? "ok" : "failed")); + OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p, rc=%s\n", + osGetCurrentProcessId(), pFile, pFile->h, rc ? "ok" : "failed")); return rc ? SQLITE_OK : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(), "winClose", pFile->zPath); @@ -2490,7 +2520,8 @@ static int winRead( assert( amt>0 ); assert( offset>=0 ); SimulateIOError(return SQLITE_IOERR_READ); - OSTRACE(("READ file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n", + OSTRACE(("READ pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, " + "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, pFile->h, pBuf, amt, offset, pFile->locktype)); #if SQLITE_MAX_MMAP_SIZE>0 @@ -2499,7 +2530,8 @@ static int winRead( if( offsetmmapSize ){ if( offset+amt <= pFile->mmapSize ){ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt); - OSTRACE(("READ-MMAP file=%p, rc=SQLITE_OK\n", pFile->h)); + OSTRACE(("READ-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; }else{ int nCopy = (int)(pFile->mmapSize - offset); @@ -2513,7 +2545,8 @@ static int winRead( #if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) if( winSeekFile(pFile, offset) ){ - OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h)); + OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n", + osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_FULL; } while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ @@ -2527,19 +2560,22 @@ static int winRead( DWORD lastErrno; if( winRetryIoerr(&nRetry, &lastErrno) ) continue; pFile->lastErrno = lastErrno; - OSTRACE(("READ file=%p, rc=SQLITE_IOERR_READ\n", pFile->h)); + OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n", + osGetCurrentProcessId(), pFile, pFile->h)); return winLogError(SQLITE_IOERR_READ, pFile->lastErrno, "winRead", pFile->zPath); } - winLogIoerr(nRetry); + winLogIoerr(nRetry, __LINE__); if( nRead<(DWORD)amt ){ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[nRead], 0, amt-nRead); - OSTRACE(("READ file=%p, rc=SQLITE_IOERR_SHORT_READ\n", pFile->h)); + OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n", + osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_IOERR_SHORT_READ; } - OSTRACE(("READ file=%p, rc=SQLITE_OK\n", pFile->h)); + OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; } @@ -2562,7 +2598,8 @@ static int winWrite( SimulateIOError(return SQLITE_IOERR_WRITE); SimulateDiskfullError(return SQLITE_FULL); - OSTRACE(("WRITE file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n", + OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, " + "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, pFile->h, pBuf, amt, offset, pFile->locktype)); #if SQLITE_MAX_MMAP_SIZE>0 @@ -2571,7 +2608,8 @@ static int winWrite( if( offsetmmapSize ){ if( offset+amt <= pFile->mmapSize ){ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt); - OSTRACE(("WRITE-MMAP file=%p, rc=SQLITE_OK\n", pFile->h)); + OSTRACE(("WRITE-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; }else{ int nCopy = (int)(pFile->mmapSize - offset); @@ -2634,17 +2672,20 @@ static int winWrite( if( rc ){ if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ) || ( pFile->lastErrno==ERROR_DISK_FULL )){ - OSTRACE(("WRITE file=%p, rc=SQLITE_FULL\n", pFile->h)); + OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n", + osGetCurrentProcessId(), pFile, pFile->h)); return winLogError(SQLITE_FULL, pFile->lastErrno, "winWrite1", pFile->zPath); } - OSTRACE(("WRITE file=%p, rc=SQLITE_IOERR_WRITE\n", pFile->h)); + OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n", + osGetCurrentProcessId(), pFile, pFile->h)); return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno, "winWrite2", pFile->zPath); }else{ - winLogIoerr(nRetry); + winLogIoerr(nRetry, __LINE__); } - OSTRACE(("WRITE file=%p, rc=SQLITE_OK\n", pFile->h)); + OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; } @@ -2658,8 +2699,8 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ assert( pFile ); SimulateIOError(return SQLITE_IOERR_TRUNCATE); - OSTRACE(("TRUNCATE file=%p, size=%lld, lock=%d\n", - pFile->h, nByte, pFile->locktype)); + OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n", + osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype)); /* If the user has configured a chunk-size for this file, truncate the ** file so that it consists of an integer number of chunks (i.e. the @@ -2691,7 +2732,8 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ } #endif - OSTRACE(("TRUNCATE file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); + OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n", + osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc))); return rc; } @@ -2715,7 +2757,7 @@ static int winSync(sqlite3_file *id, int flags){ BOOL rc; #endif #if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \ - (defined(SQLITE_TEST) && defined(SQLITE_DEBUG)) + defined(SQLITE_HAVE_OS_TRACE) /* ** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or ** OSTRACE() macros. @@ -2736,8 +2778,9 @@ static int winSync(sqlite3_file *id, int flags){ */ SimulateDiskfullError( return SQLITE_FULL ); - OSTRACE(("SYNC file=%p, flags=%x, lock=%d\n", - pFile->h, flags, pFile->locktype)); + OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, flags=%x, lock=%d\n", + osGetCurrentProcessId(), pFile, pFile->h, flags, + pFile->locktype)); #ifndef SQLITE_TEST UNUSED_PARAMETER(flags); @@ -2752,19 +2795,38 @@ static int winSync(sqlite3_file *id, int flags){ ** no-op */ #ifdef SQLITE_NO_SYNC - OSTRACE(("SYNC-NOP file=%p, rc=SQLITE_OK\n", pFile->h)); + OSTRACE(("SYNC-NOP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; #else +#if SQLITE_MAX_MMAP_SIZE>0 + if( pFile->pMapRegion ){ + if( osFlushViewOfFile(pFile->pMapRegion, 0) ){ + OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, " + "rc=SQLITE_OK\n", osGetCurrentProcessId(), + pFile, pFile->pMapRegion)); + }else{ + pFile->lastErrno = osGetLastError(); + OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, " + "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), + pFile, pFile->pMapRegion)); + return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, + "winSync1", pFile->zPath); + } + } +#endif rc = osFlushFileBuffers(pFile->h); SimulateIOError( rc=FALSE ); if( rc ){ - OSTRACE(("SYNC file=%p, rc=SQLITE_OK\n", pFile->h)); + OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; }else{ pFile->lastErrno = osGetLastError(); - OSTRACE(("SYNC file=%p, rc=SQLITE_IOERR_FSYNC\n", pFile->h)); + OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n", + osGetCurrentProcessId(), pFile, pFile->h)); return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno, - "winSync", pFile->zPath); + "winSync2", pFile->zPath); } #endif } @@ -3372,7 +3434,7 @@ struct winShmNode { int nRef; /* Number of winShm objects pointing to this */ winShm *pFirst; /* All winShm objects pointing to this */ winShmNode *pNext; /* Next in list of all winShmNode objects */ -#ifdef SQLITE_DEBUG +#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) u8 nextShmId; /* Next available winShm.id value */ #endif }; @@ -3403,7 +3465,7 @@ struct winShm { u8 hasMutex; /* True if holding the winShmNode mutex */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ -#ifdef SQLITE_DEBUG +#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) u8 id; /* Id of this connection with its winShmNode */ #endif }; @@ -3594,7 +3656,7 @@ static int winOpenSharedMemory(winFile *pDbFd){ /* Make the new connection a child of the winShmNode */ p->pShmNode = pShmNode; -#ifdef SQLITE_DEBUG +#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) p->id = pShmNode->nextShmId++; #endif pShmNode->nRef++; @@ -3814,16 +3876,16 @@ static int winShmMap( void volatile **pp /* OUT: Mapped memory */ ){ winFile *pDbFd = (winFile*)fd; - winShm *p = pDbFd->pShm; + winShm *pShm = pDbFd->pShm; winShmNode *pShmNode; int rc = SQLITE_OK; - if( !p ){ + if( !pShm ){ rc = winOpenSharedMemory(pDbFd); if( rc!=SQLITE_OK ) return rc; - p = pDbFd->pShm; + pShm = pDbFd->pShm; } - pShmNode = p->pShmNode; + pShmNode = pShm->pShmNode; sqlite3_mutex_enter(pShmNode->mutex); assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); @@ -3863,7 +3925,7 @@ static int winShmMap( } /* Map the requested memory region into this processes address space. */ - apNew = (struct ShmRegion *)sqlite3_realloc( + apNew = (struct ShmRegion *)sqlite3_realloc64( pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0]) ); if( !apNew ){ @@ -4735,7 +4797,7 @@ static int winOpen( } } #endif - winLogIoerr(cnt); + winLogIoerr(cnt, __LINE__); OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name, dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); @@ -4919,7 +4981,7 @@ static int winDelete( if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){ rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename); }else{ - winLogIoerr(cnt); + winLogIoerr(cnt, __LINE__); } sqlite3_free(zConverted); OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc))); @@ -4969,7 +5031,7 @@ static int winAccess( attr = sAttrData.dwFileAttributes; } }else{ - winLogIoerr(cnt); + winLogIoerr(cnt, __LINE__); if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){ sqlite3_free(zConverted); return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", @@ -5310,7 +5372,7 @@ static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ int n = 0; UNUSED_PARAMETER(pVfs); -#if defined(SQLITE_TEST) +#if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) n = nBuf; memset(zBuf, 0, nBuf); #else @@ -5344,7 +5406,23 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ memcpy(&zBuf[n], &i, sizeof(i)); n += sizeof(i); } +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID + if( sizeof(UUID)<=nBuf-n ){ + UUID id; + memset(&id, 0, sizeof(UUID)); + osUuidCreate(&id); + memcpy(zBuf, &id, sizeof(UUID)); + n += sizeof(UUID); + } + if( sizeof(UUID)<=nBuf-n ){ + UUID id; + memset(&id, 0, sizeof(UUID)); + osUuidCreateSequential(&id); + memcpy(zBuf, &id, sizeof(UUID)); + n += sizeof(UUID); + } #endif +#endif /* defined(SQLITE_TEST) || defined(SQLITE_ZERO_PRNG_SEED) */ return n; } @@ -5522,7 +5600,7 @@ int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==77 ); + assert( ArraySize(aSyscall)==80 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); diff --git a/src/os_win.h b/src/os_win.h index 5174ac7..17d6a2b 100644 --- a/src/os_win.h +++ b/src/os_win.h @@ -74,4 +74,15 @@ # define SQLITE_WIN32_VOLATILE volatile #endif +/* +** For some Windows sub-platforms, the _beginthreadex() / _endthreadex() +** functions are not available (e.g. those not using MSVC, Cygwin, etc). +*/ +#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ + SQLITE_THREADSAFE>0 && !defined(__CYGWIN__) +# define SQLITE_OS_WIN_THREADS 1 +#else +# define SQLITE_OS_WIN_THREADS 0 +#endif + #endif /* _OS_WIN_H_ */ diff --git a/src/pager.c b/src/pager.c index 2230174..91378f0 100644 --- a/src/pager.c +++ b/src/pager.c @@ -3044,9 +3044,7 @@ static int pagerWalFrames( ){ int rc; /* Return code */ int nList; /* Number of pages in pList */ -#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES) PgHdr *p; /* For looping over pages */ -#endif assert( pPager->pWal ); assert( pList ); @@ -3063,7 +3061,6 @@ static int pagerWalFrames( ** any pages with page numbers greater than nTruncate into the WAL file. ** They will never be read by any client. So remove them from the pDirty ** list here. */ - PgHdr *p; PgHdr **ppNext = &pList; nList = 0; for(p=pList; (*ppNext = p)!=0; p=p->pDirty){ @@ -3083,7 +3080,6 @@ static int pagerWalFrames( pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags ); if( rc==SQLITE_OK && pPager->pBackup ){ - PgHdr *p; for(p=pList; p; p=p->pDirty){ sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData); } @@ -7014,6 +7010,8 @@ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ } assert( state==pPager->eState ); } + }else if( eMode==PAGER_JOURNALMODE_OFF ){ + sqlite3OsClose(pPager->jfd); } } diff --git a/src/parse.y b/src/parse.y index 544888a..6a64206 100644 --- a/src/parse.y +++ b/src/parse.y @@ -409,28 +409,35 @@ cmd ::= select(X). { %type oneselect {Select*} %destructor oneselect {sqlite3SelectDelete(pParse->db, $$);} -select(A) ::= with(W) selectnowith(X). { - Select *p = X, *pNext, *pLoop; - if( p ){ - int cnt = 0, mxSelect; - p->pWith = W; +%include { + /* + ** For a compound SELECT statement, make sure p->pPrior->pNext==p for + ** all elements in the list. And make sure list length does not exceed + ** SQLITE_LIMIT_COMPOUND_SELECT. + */ + static void parserDoubleLinkSelect(Parse *pParse, Select *p){ if( p->pPrior ){ - u16 allValues = SF_Values; - pNext = 0; + Select *pNext = 0, *pLoop; + int mxSelect, cnt = 0; for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){ pLoop->pNext = pNext; pLoop->selFlags |= SF_Compound; - allValues &= pLoop->selFlags; } - if( allValues ){ - p->selFlags |= SF_AllValues; - }else if( - (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 - && cnt>mxSelect + if( (p->selFlags & SF_MultiValue)==0 && + (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && + cnt>mxSelect ){ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); } } + } +} + +select(A) ::= with(W) selectnowith(X). { + Select *p = X; + if( p ){ + p->pWith = W; + parserDoubleLinkSelect(pParse, p); }else{ sqlite3WithDelete(pParse->db, W); } @@ -445,12 +452,14 @@ selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). { SrcList *pFrom; Token x; x.n = 0; + parserDoubleLinkSelect(pParse, pRhs); pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0); pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0); } if( pRhs ){ pRhs->op = (u8)Y; pRhs->pPrior = X; + pRhs->selFlags &= ~SF_MultiValue; if( Y!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, X); @@ -498,13 +507,16 @@ values(A) ::= VALUES LP nexprlist(X) RP. { A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0,0); } values(A) ::= values(X) COMMA LP exprlist(Y) RP. { - Select *pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values,0,0); + Select *pRight, *pLeft = X; + pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0,0); + if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; if( pRight ){ pRight->op = TK_ALL; - pRight->pPrior = X; + pLeft = X; + pRight->pPrior = pLeft; A = pRight; }else{ - A = X; + A = pLeft; } } @@ -860,7 +872,7 @@ expr(A) ::= VARIABLE(X). { spanSet(&A, &X, &X); } expr(A) ::= expr(E) COLLATE ids(C). { - A.pExpr = sqlite3ExprAddCollateToken(pParse, E.pExpr, &C); + A.pExpr = sqlite3ExprAddCollateToken(pParse, E.pExpr, &C, 1); A.zStart = E.zStart; A.zEnd = &C.z[C.n]; } @@ -1078,7 +1090,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0); if( A.pExpr ){ A.pExpr->x.pList = Y; - sqlite3ExprSetHeight(pParse, A.pExpr); + sqlite3ExprSetHeightAndFlags(pParse, A.pExpr); }else{ sqlite3ExprListDelete(pParse->db, Y); } @@ -1091,8 +1103,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { A.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0); if( A.pExpr ){ A.pExpr->x.pSelect = X; - ExprSetProperty(A.pExpr, EP_xIsSelect); - sqlite3ExprSetHeight(pParse, A.pExpr); + ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery); + sqlite3ExprSetHeightAndFlags(pParse, A.pExpr); }else{ sqlite3SelectDelete(pParse->db, X); } @@ -1103,8 +1115,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0); if( A.pExpr ){ A.pExpr->x.pSelect = Y; - ExprSetProperty(A.pExpr, EP_xIsSelect); - sqlite3ExprSetHeight(pParse, A.pExpr); + ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery); + sqlite3ExprSetHeightAndFlags(pParse, A.pExpr); }else{ sqlite3SelectDelete(pParse->db, Y); } @@ -1117,8 +1129,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0); if( A.pExpr ){ A.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); - ExprSetProperty(A.pExpr, EP_xIsSelect); - sqlite3ExprSetHeight(pParse, A.pExpr); + ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery); + sqlite3ExprSetHeightAndFlags(pParse, A.pExpr); }else{ sqlite3SrcListDelete(pParse->db, pSrc); } @@ -1130,8 +1142,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { Expr *p = A.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0); if( p ){ p->x.pSelect = Y; - ExprSetProperty(p, EP_xIsSelect); - sqlite3ExprSetHeight(pParse, p); + ExprSetProperty(p, EP_xIsSelect|EP_Subquery); + sqlite3ExprSetHeightAndFlags(pParse, p); }else{ sqlite3SelectDelete(pParse->db, Y); } @@ -1145,7 +1157,7 @@ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). { A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0, 0); if( A.pExpr ){ A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y; - sqlite3ExprSetHeight(pParse, A.pExpr); + sqlite3ExprSetHeightAndFlags(pParse, A.pExpr); }else{ sqlite3ExprListDelete(pParse->db, Y); sqlite3ExprDelete(pParse->db, Z); @@ -1206,14 +1218,14 @@ uniqueflag(A) ::= . {A = OE_None;} idxlist_opt(A) ::= . {A = 0;} idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;} idxlist(A) ::= idxlist(X) COMMA nm(Y) collate(C) sortorder(Z). { - Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C); + Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C, 1); A = sqlite3ExprListAppend(pParse,X, p); sqlite3ExprListSetName(pParse,A,&Y,1); sqlite3ExprListCheckLength(pParse, A, "index"); if( A ) A->a[A->nExpr-1].sortOrder = (u8)Z; } idxlist(A) ::= nm(Y) collate(C) sortorder(Z). { - Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C); + Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C, 1); A = sqlite3ExprListAppend(pParse,0, p); sqlite3ExprListSetName(pParse, A, &Y, 1); sqlite3ExprListCheckLength(pParse, A, "index"); diff --git a/src/pcache.c b/src/pcache.c index 467e2b3..d768fe0 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -114,12 +114,20 @@ static void pcacheUnpin(PgHdr *p){ } /* -** Compute the number of pages of cache requested. +** Compute the number of pages of cache requested. p->szCache is the +** cache size requested by the "PRAGMA cache_size" statement. +** +** */ static int numberOfCachePages(PCache *p){ if( p->szCache>=0 ){ + /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the + ** suggested cache size is set to N. */ return p->szCache; }else{ + /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then + ** the number of cache pages is adjusted to use approximately abs(N*1024) + ** bytes of memory. */ return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); } } diff --git a/src/pcache1.c b/src/pcache1.c index f5f7893..a8755a3 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -195,7 +195,6 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ static void *pcache1Alloc(int nByte){ void *p = 0; assert( sqlite3_mutex_notheld(pcache1.grp.mutex) ); - sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte); if( nByte<=pcache1.szSlot ){ sqlite3_mutex_enter(pcache1.mutex); p = (PgHdr1 *)pcache1.pFree; @@ -204,7 +203,8 @@ static void *pcache1Alloc(int nByte){ pcache1.nFreeSlot--; pcache1.bUnderPressure = pcache1.nFreeSlot=0 ); - sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1); + sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte); + sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1); } sqlite3_mutex_leave(pcache1.mutex); } @@ -217,7 +217,8 @@ static void *pcache1Alloc(int nByte){ if( p ){ int sz = sqlite3MallocSize(p); sqlite3_mutex_enter(pcache1.mutex); - sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz); + sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte); + sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz); sqlite3_mutex_leave(pcache1.mutex); } #endif @@ -235,7 +236,7 @@ static int pcache1Free(void *p){ if( p>=pcache1.pStart && ppNext = pcache1.pFree; pcache1.pFree = pSlot; @@ -249,7 +250,7 @@ static int pcache1Free(void *p){ nFreed = sqlite3MallocSize(p); #ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS sqlite3_mutex_enter(pcache1.mutex); - sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -nFreed); + sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed); sqlite3_mutex_leave(pcache1.mutex); #endif sqlite3_free(p); @@ -986,6 +987,14 @@ void sqlite3PCacheSetDefault(void){ */ int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); } +/* +** Return the global mutex used by this PCACHE implementation. The +** sqlite3_status() routine needs access to this mutex. +*/ +sqlite3_mutex *sqlite3Pcache1Mutex(void){ + return pcache1.mutex; +} + #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* ** This function is called to free superfluous dynamically allocated memory diff --git a/src/pragma.c b/src/pragma.c index 34830e3..1b42138 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -22,464 +22,13 @@ #endif /*************************************************************************** -** The next block of code, including the PragTyp_XXXX macro definitions and -** the aPragmaName[] object is composed of generated code. DO NOT EDIT. -** -** To add new pragmas, edit the code in ../tool/mkpragmatab.tcl and rerun -** that script. Then copy/paste the output in place of the following: -*/ -#define PragTyp_HEADER_VALUE 0 -#define PragTyp_AUTO_VACUUM 1 -#define PragTyp_FLAG 2 -#define PragTyp_BUSY_TIMEOUT 3 -#define PragTyp_CACHE_SIZE 4 -#define PragTyp_CASE_SENSITIVE_LIKE 5 -#define PragTyp_COLLATION_LIST 6 -#define PragTyp_COMPILE_OPTIONS 7 -#define PragTyp_DATA_STORE_DIRECTORY 8 -#define PragTyp_DATABASE_LIST 9 -#define PragTyp_DEFAULT_CACHE_SIZE 10 -#define PragTyp_ENCODING 11 -#define PragTyp_FOREIGN_KEY_CHECK 12 -#define PragTyp_FOREIGN_KEY_LIST 13 -#define PragTyp_INCREMENTAL_VACUUM 14 -#define PragTyp_INDEX_INFO 15 -#define PragTyp_INDEX_LIST 16 -#define PragTyp_INTEGRITY_CHECK 17 -#define PragTyp_JOURNAL_MODE 18 -#define PragTyp_JOURNAL_SIZE_LIMIT 19 -#define PragTyp_LOCK_PROXY_FILE 20 -#define PragTyp_LOCKING_MODE 21 -#define PragTyp_PAGE_COUNT 22 -#define PragTyp_MMAP_SIZE 23 -#define PragTyp_PAGE_SIZE 24 -#define PragTyp_SECURE_DELETE 25 -#define PragTyp_SHRINK_MEMORY 26 -#define PragTyp_SOFT_HEAP_LIMIT 27 -#define PragTyp_STATS 28 -#define PragTyp_SYNCHRONOUS 29 -#define PragTyp_TABLE_INFO 30 -#define PragTyp_TEMP_STORE 31 -#define PragTyp_TEMP_STORE_DIRECTORY 32 -#define PragTyp_THREADS 33 -#define PragTyp_WAL_AUTOCHECKPOINT 34 -#define PragTyp_WAL_CHECKPOINT 35 -#define PragTyp_ACTIVATE_EXTENSIONS 36 -#define PragTyp_HEXKEY 37 -#define PragTyp_KEY 38 -#define PragTyp_REKEY 39 -#define PragTyp_LOCK_STATUS 40 -#define PragTyp_PARSER_TRACE 41 -#define PragFlag_NeedSchema 0x01 -#define PragFlag_ReadOnly 0x02 -static const struct sPragmaNames { - const char *const zName; /* Name of pragma */ - u8 ePragTyp; /* PragTyp_XXX value */ - u8 mPragFlag; /* Zero or more PragFlag_XXX values */ - u32 iArg; /* Extra argument */ -} aPragmaNames[] = { -#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) - { /* zName: */ "activate_extensions", - /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - { /* zName: */ "application_id", - /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ 0, - /* iArg: */ BTREE_APPLICATION_ID }, -#endif -#if !defined(SQLITE_OMIT_AUTOVACUUM) - { /* zName: */ "auto_vacuum", - /* ePragTyp: */ PragTyp_AUTO_VACUUM, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) -#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX) - { /* zName: */ "automatic_index", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_AutoIndex }, -#endif -#endif - { /* zName: */ "busy_timeout", - /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "cache_size", - /* ePragTyp: */ PragTyp_CACHE_SIZE, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "cache_spill", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_CacheSpill }, -#endif - { /* zName: */ "case_sensitive_like", - /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "checkpoint_fullfsync", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_CkptFullFSync }, -#endif -#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - { /* zName: */ "collation_list", - /* ePragTyp: */ PragTyp_COLLATION_LIST, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) - { /* zName: */ "compile_options", - /* ePragTyp: */ PragTyp_COMPILE_OPTIONS, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "count_changes", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_CountRows }, -#endif -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN - { /* zName: */ "data_store_directory", - /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - { /* zName: */ "data_version", - /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ PragFlag_ReadOnly, - /* iArg: */ BTREE_DATA_VERSION }, -#endif -#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - { /* zName: */ "database_list", - /* ePragTyp: */ PragTyp_DATABASE_LIST, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) - { /* zName: */ "default_cache_size", - /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) -#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - { /* zName: */ "defer_foreign_keys", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_DeferFKs }, -#endif -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "empty_result_callbacks", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_NullCallback }, -#endif -#if !defined(SQLITE_OMIT_UTF16) - { /* zName: */ "encoding", - /* ePragTyp: */ PragTyp_ENCODING, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - { /* zName: */ "foreign_key_check", - /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FOREIGN_KEY) - { /* zName: */ "foreign_key_list", - /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) -#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - { /* zName: */ "foreign_keys", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_ForeignKeys }, -#endif -#endif -#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - { /* zName: */ "freelist_count", - /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ PragFlag_ReadOnly, - /* iArg: */ BTREE_FREE_PAGE_COUNT }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "full_column_names", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_FullColNames }, - { /* zName: */ "fullfsync", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_FullFSync }, -#endif -#if defined(SQLITE_HAS_CODEC) - { /* zName: */ "hexkey", - /* ePragTyp: */ PragTyp_HEXKEY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "hexrekey", - /* ePragTyp: */ PragTyp_HEXKEY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) -#if !defined(SQLITE_OMIT_CHECK) - { /* zName: */ "ignore_check_constraints", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_IgnoreChecks }, -#endif -#endif -#if !defined(SQLITE_OMIT_AUTOVACUUM) - { /* zName: */ "incremental_vacuum", - /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - { /* zName: */ "index_info", - /* ePragTyp: */ PragTyp_INDEX_INFO, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, - { /* zName: */ "index_list", - /* ePragTyp: */ PragTyp_INDEX_LIST, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_INTEGRITY_CHECK) - { /* zName: */ "integrity_check", - /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "journal_mode", - /* ePragTyp: */ PragTyp_JOURNAL_MODE, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, - { /* zName: */ "journal_size_limit", - /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if defined(SQLITE_HAS_CODEC) - { /* zName: */ "key", - /* ePragTyp: */ PragTyp_KEY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "legacy_file_format", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_LegacyFileFmt }, -#endif -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE - { /* zName: */ "lock_proxy_file", - /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - { /* zName: */ "lock_status", - /* ePragTyp: */ PragTyp_LOCK_STATUS, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "locking_mode", - /* ePragTyp: */ PragTyp_LOCKING_MODE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "max_page_count", - /* ePragTyp: */ PragTyp_PAGE_COUNT, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, - { /* zName: */ "mmap_size", - /* ePragTyp: */ PragTyp_MMAP_SIZE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "page_count", - /* ePragTyp: */ PragTyp_PAGE_COUNT, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, - { /* zName: */ "page_size", - /* ePragTyp: */ PragTyp_PAGE_SIZE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if defined(SQLITE_DEBUG) - { /* zName: */ "parser_trace", - /* ePragTyp: */ PragTyp_PARSER_TRACE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "query_only", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_QueryOnly }, -#endif -#if !defined(SQLITE_OMIT_INTEGRITY_CHECK) - { /* zName: */ "quick_check", - /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "read_uncommitted", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_ReadUncommitted }, - { /* zName: */ "recursive_triggers", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_RecTriggers }, -#endif -#if defined(SQLITE_HAS_CODEC) - { /* zName: */ "rekey", - /* ePragTyp: */ PragTyp_REKEY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "reverse_unordered_selects", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_ReverseOrder }, -#endif -#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - { /* zName: */ "schema_version", - /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ 0, - /* iArg: */ BTREE_SCHEMA_VERSION }, -#endif -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "secure_delete", - /* ePragTyp: */ PragTyp_SECURE_DELETE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "short_column_names", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_ShortColNames }, -#endif - { /* zName: */ "shrink_memory", - /* ePragTyp: */ PragTyp_SHRINK_MEMORY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "soft_heap_limit", - /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) -#if defined(SQLITE_DEBUG) - { /* zName: */ "sql_trace", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_SqlTrace }, -#endif -#endif -#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - { /* zName: */ "stats", - /* ePragTyp: */ PragTyp_STATS, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "synchronous", - /* ePragTyp: */ PragTyp_SYNCHRONOUS, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - { /* zName: */ "table_info", - /* ePragTyp: */ PragTyp_TABLE_INFO, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "temp_store", - /* ePragTyp: */ PragTyp_TEMP_STORE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "temp_store_directory", - /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#endif - { /* zName: */ "threads", - /* ePragTyp: */ PragTyp_THREADS, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, -#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - { /* zName: */ "user_version", - /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ 0, - /* iArg: */ BTREE_USER_VERSION }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) -#if defined(SQLITE_DEBUG) - { /* zName: */ "vdbe_addoptrace", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_VdbeAddopTrace }, - { /* zName: */ "vdbe_debug", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace }, - { /* zName: */ "vdbe_eqp", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_VdbeEQP }, - { /* zName: */ "vdbe_listing", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_VdbeListing }, - { /* zName: */ "vdbe_trace", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_VdbeTrace }, -#endif -#endif -#if !defined(SQLITE_OMIT_WAL) - { /* zName: */ "wal_autocheckpoint", - /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "wal_checkpoint", - /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "writable_schema", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, -#endif -}; -/* Number of pragmas: 58 on by default, 71 total. */ -/* End of the automatically generated pragma table. -***************************************************************************/ +** The "pragma.h" include file is an automatically generated file that +** that includes the PragType_XXXX macro definitions and the aPragmaName[] +** object. This ensures that the aPragmaName[] table is arranged in +** lexicographical order to facility a binary search of the pragma name. +** Do not edit pragma.h directly. Edit and rerun the script in at +** ../tool/mkpragmatab.tcl. */ +#include "pragma.h" /* ** Interpret the given string as a safety level. Return 0 for OFF, @@ -615,15 +164,15 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){ */ static void returnSingleInt(Parse *pParse, const char *zLabel, i64 value){ Vdbe *v = sqlite3GetVdbe(pParse); - int mem = ++pParse->nMem; + int nMem = ++pParse->nMem; i64 *pI64 = sqlite3DbMallocRaw(pParse->db, sizeof(value)); if( pI64 ){ memcpy(pI64, &value, sizeof(value)); } - sqlite3VdbeAddOp4(v, OP_Int64, 0, mem, 0, (char*)pI64, P4_INT64); + sqlite3VdbeAddOp4(v, OP_Int64, 0, nMem, 0, (char*)pI64, P4_INT64); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC); - sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1); + sqlite3VdbeAddOp2(v, OP_ResultRow, nMem, 1); } @@ -732,6 +281,7 @@ void sqlite3Pragma( sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* The specific database being pragmaed */ Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ + const struct sPragmaNames *pPragma; if( v==0 ) return; sqlite3VdbeRunOnlyOnce(v); @@ -767,6 +317,17 @@ void sqlite3Pragma( /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS ** connection. If it returns SQLITE_OK, then assume that the VFS ** handled the pragma and generate a no-op prepared statement. + ** + ** IMPLEMENTATION-OF: R-12238-55120 Whenever a PRAGMA statement is parsed, + ** an SQLITE_FCNTL_PRAGMA file control is sent to the open sqlite3_file + ** object corresponding to the database file to which the pragma + ** statement refers. + ** + ** IMPLEMENTATION-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA + ** file control is an array of pointers to strings (char**) in which the + ** second element of the array is the name of the pragma and the third + ** element is the argument to the pragma or NULL if the pragma has no + ** argument. */ aFcntl[0] = 0; aFcntl[1] = zLeft; @@ -776,11 +337,11 @@ void sqlite3Pragma( rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl); if( rc==SQLITE_OK ){ if( aFcntl[0] ){ - int mem = ++pParse->nMem; - sqlite3VdbeAddOp4(v, OP_String8, 0, mem, 0, aFcntl[0], 0); + int nMem = ++pParse->nMem; + sqlite3VdbeAddOp4(v, OP_String8, 0, nMem, 0, aFcntl[0], 0); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "result", SQLITE_STATIC); - sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1); + sqlite3VdbeAddOp2(v, OP_ResultRow, nMem, 1); sqlite3_free(aFcntl[0]); } goto pragma_out; @@ -809,14 +370,15 @@ void sqlite3Pragma( } } if( lwr>upr ) goto pragma_out; + pPragma = &aPragmaNames[mid]; /* Make sure the database schema is loaded if the pragma requires that */ - if( (aPragmaNames[mid].mPragFlag & PragFlag_NeedSchema)!=0 ){ + if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){ if( sqlite3ReadSchema(pParse) ) goto pragma_out; } /* Jump to the appropriate pragma handler */ - switch( aPragmaNames[mid].ePragTyp ){ + switch( pPragma->ePragTyp ){ #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) /* @@ -1384,7 +946,9 @@ void sqlite3Pragma( sqlite3ErrorMsg(pParse, "Safety level may not be changed inside a transaction"); }else{ - pDb->safety_level = getSafetyLevel(zRight,0,1)+1; + int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK; + if( iLevel==0 ) iLevel = 1; + pDb->safety_level = iLevel; setAllPagerFlags(db); } } @@ -1395,10 +959,9 @@ void sqlite3Pragma( #ifndef SQLITE_OMIT_FLAG_PRAGMAS case PragTyp_FLAG: { if( zRight==0 ){ - returnSingleInt(pParse, aPragmaNames[mid].zName, - (db->flags & aPragmaNames[mid].iArg)!=0 ); + returnSingleInt(pParse, pPragma->zName, (db->flags & pPragma->iArg)!=0 ); }else{ - int mask = aPragmaNames[mid].iArg; /* Mask of bits to set or clear. */ + int mask = pPragma->iArg; /* Mask of bits to set or clear. */ if( db->autoCommit==0 ){ /* Foreign key support may not be enabled or disabled while not ** in auto-commit mode. */ @@ -1480,7 +1043,7 @@ void sqlite3Pragma( }else if( pPk==0 ){ k = 1; }else{ - for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){} + for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){} } sqlite3VdbeAddOp2(v, OP_Integer, k, 6); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); @@ -1527,20 +1090,42 @@ void sqlite3Pragma( pIdx = sqlite3FindIndex(db, zRight, zDb); if( pIdx ){ int i; + int mx; + if( pPragma->iArg ){ + /* PRAGMA index_xinfo (newer version with more rows and columns) */ + mx = pIdx->nColumn; + pParse->nMem = 6; + }else{ + /* PRAGMA index_info (legacy version) */ + mx = pIdx->nKeyCol; + pParse->nMem = 3; + } pTab = pIdx->pTable; - sqlite3VdbeSetNumCols(v, 3); - pParse->nMem = 3; + sqlite3VdbeSetNumCols(v, pParse->nMem); sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC); - for(i=0; inKeyCol; i++){ + if( pPragma->iArg ){ + sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "desc", SQLITE_STATIC); + sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "coll", SQLITE_STATIC); + sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "key", SQLITE_STATIC); + } + for(i=0; iaiColumn[i]; sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2); - assert( pTab->nCol>cnum ); - sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); + if( cnum<0 ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, 3); + }else{ + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0); + } + if( pPragma->iArg ){ + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->aSortOrder[i], 4); + sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, pIdx->azColl[i], 0); + sqlite3VdbeAddOp2(v, OP_Integer, inKeyCol, 6); + } + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem); } } } @@ -1553,17 +1138,22 @@ void sqlite3Pragma( pTab = sqlite3FindTable(db, zRight, zDb); if( pTab ){ v = sqlite3GetVdbe(pParse); - sqlite3VdbeSetNumCols(v, 3); - pParse->nMem = 3; + sqlite3VdbeSetNumCols(v, 5); + pParse->nMem = 5; sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC); + sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "origin", SQLITE_STATIC); + sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "partial", SQLITE_STATIC); for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ + const char *azOrigin[] = { "c", "u", "pk" }; sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); + sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, azOrigin[pIdx->idxType], 0); + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->pPartIdxWhere!=0, 5); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); } } } @@ -2133,9 +1723,9 @@ void sqlite3Pragma( ** applications for any purpose. */ case PragTyp_HEADER_VALUE: { - int iCookie = aPragmaNames[mid].iArg; /* Which cookie to read or write */ + int iCookie = pPragma->iArg; /* Which cookie to read or write */ sqlite3VdbeUsesBtree(v, iDb); - if( zRight && (aPragmaNames[mid].mPragFlag & PragFlag_ReadOnly)==0 ){ + if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){ /* Write the specified cookie value */ static const VdbeOpList setCookie[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ @@ -2237,8 +1827,9 @@ void sqlite3Pragma( /* ** PRAGMA shrink_memory ** - ** This pragma attempts to free as much memory as possible from the - ** current database connection. + ** IMPLEMENTATION-OF: R-23445-46109 This pragma causes the database + ** connection on which it is invoked to free up as much memory as it + ** can, by calling sqlite3_db_release_memory(). */ case PragTyp_SHRINK_MEMORY: { sqlite3_db_release_memory(db); @@ -2255,7 +1846,7 @@ void sqlite3Pragma( ** disables the timeout. */ /*case PragTyp_BUSY_TIMEOUT*/ default: { - assert( aPragmaNames[mid].ePragTyp==PragTyp_BUSY_TIMEOUT ); + assert( pPragma->ePragTyp==PragTyp_BUSY_TIMEOUT ); if( zRight ){ sqlite3_busy_timeout(db, sqlite3Atoi(zRight)); } @@ -2267,8 +1858,12 @@ void sqlite3Pragma( ** PRAGMA soft_heap_limit ** PRAGMA soft_heap_limit = N ** - ** Call sqlite3_soft_heap_limit64(N). Return the result. If N is omitted, - ** use -1. + ** IMPLEMENTATION-OF: R-26343-45930 This pragma invokes the + ** sqlite3_soft_heap_limit64() interface with the argument N, if N is + ** specified and is a non-negative integer. + ** IMPLEMENTATION-OF: R-64451-07163 The soft_heap_limit pragma always + ** returns the same integer that would be returned by the + ** sqlite3_soft_heap_limit64(-1) C-language function. */ case PragTyp_SOFT_HEAP_LIMIT: { sqlite3_int64 N; diff --git a/src/pragma.h b/src/pragma.h new file mode 100644 index 0000000..c9ae8e6 --- /dev/null +++ b/src/pragma.h @@ -0,0 +1,459 @@ +/* DO NOT EDIT! +** This file is automatically generated by the script at +** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit +** that script and rerun it. +*/ +#define PragTyp_HEADER_VALUE 0 +#define PragTyp_AUTO_VACUUM 1 +#define PragTyp_FLAG 2 +#define PragTyp_BUSY_TIMEOUT 3 +#define PragTyp_CACHE_SIZE 4 +#define PragTyp_CASE_SENSITIVE_LIKE 5 +#define PragTyp_COLLATION_LIST 6 +#define PragTyp_COMPILE_OPTIONS 7 +#define PragTyp_DATA_STORE_DIRECTORY 8 +#define PragTyp_DATABASE_LIST 9 +#define PragTyp_DEFAULT_CACHE_SIZE 10 +#define PragTyp_ENCODING 11 +#define PragTyp_FOREIGN_KEY_CHECK 12 +#define PragTyp_FOREIGN_KEY_LIST 13 +#define PragTyp_INCREMENTAL_VACUUM 14 +#define PragTyp_INDEX_INFO 15 +#define PragTyp_INDEX_LIST 16 +#define PragTyp_INTEGRITY_CHECK 17 +#define PragTyp_JOURNAL_MODE 18 +#define PragTyp_JOURNAL_SIZE_LIMIT 19 +#define PragTyp_LOCK_PROXY_FILE 20 +#define PragTyp_LOCKING_MODE 21 +#define PragTyp_PAGE_COUNT 22 +#define PragTyp_MMAP_SIZE 23 +#define PragTyp_PAGE_SIZE 24 +#define PragTyp_SECURE_DELETE 25 +#define PragTyp_SHRINK_MEMORY 26 +#define PragTyp_SOFT_HEAP_LIMIT 27 +#define PragTyp_STATS 28 +#define PragTyp_SYNCHRONOUS 29 +#define PragTyp_TABLE_INFO 30 +#define PragTyp_TEMP_STORE 31 +#define PragTyp_TEMP_STORE_DIRECTORY 32 +#define PragTyp_THREADS 33 +#define PragTyp_WAL_AUTOCHECKPOINT 34 +#define PragTyp_WAL_CHECKPOINT 35 +#define PragTyp_ACTIVATE_EXTENSIONS 36 +#define PragTyp_HEXKEY 37 +#define PragTyp_KEY 38 +#define PragTyp_REKEY 39 +#define PragTyp_LOCK_STATUS 40 +#define PragTyp_PARSER_TRACE 41 +#define PragFlag_NeedSchema 0x01 +#define PragFlag_ReadOnly 0x02 +static const struct sPragmaNames { + const char *const zName; /* Name of pragma */ + u8 ePragTyp; /* PragTyp_XXX value */ + u8 mPragFlag; /* Zero or more PragFlag_XXX values */ + u32 iArg; /* Extra argument */ +} aPragmaNames[] = { +#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) + { /* zName: */ "activate_extensions", + /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + { /* zName: */ "application_id", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlag: */ 0, + /* iArg: */ BTREE_APPLICATION_ID }, +#endif +#if !defined(SQLITE_OMIT_AUTOVACUUM) + { /* zName: */ "auto_vacuum", + /* ePragTyp: */ PragTyp_AUTO_VACUUM, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX) + { /* zName: */ "automatic_index", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_AutoIndex }, +#endif +#endif + { /* zName: */ "busy_timeout", + /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { /* zName: */ "cache_size", + /* ePragTyp: */ PragTyp_CACHE_SIZE, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + { /* zName: */ "cache_spill", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_CacheSpill }, +#endif + { /* zName: */ "case_sensitive_like", + /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + { /* zName: */ "checkpoint_fullfsync", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_CkptFullFSync }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + { /* zName: */ "collation_list", + /* ePragTyp: */ PragTyp_COLLATION_LIST, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) + { /* zName: */ "compile_options", + /* ePragTyp: */ PragTyp_COMPILE_OPTIONS, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + { /* zName: */ "count_changes", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_CountRows }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN + { /* zName: */ "data_store_directory", + /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + { /* zName: */ "data_version", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlag: */ PragFlag_ReadOnly, + /* iArg: */ BTREE_DATA_VERSION }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + { /* zName: */ "database_list", + /* ePragTyp: */ PragTyp_DATABASE_LIST, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) + { /* zName: */ "default_cache_size", + /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) + { /* zName: */ "defer_foreign_keys", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_DeferFKs }, +#endif +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + { /* zName: */ "empty_result_callbacks", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_NullCallback }, +#endif +#if !defined(SQLITE_OMIT_UTF16) + { /* zName: */ "encoding", + /* ePragTyp: */ PragTyp_ENCODING, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) + { /* zName: */ "foreign_key_check", + /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FOREIGN_KEY) + { /* zName: */ "foreign_key_list", + /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) + { /* zName: */ "foreign_keys", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_ForeignKeys }, +#endif +#endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + { /* zName: */ "freelist_count", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlag: */ PragFlag_ReadOnly, + /* iArg: */ BTREE_FREE_PAGE_COUNT }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + { /* zName: */ "full_column_names", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_FullColNames }, + { /* zName: */ "fullfsync", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_FullFSync }, +#endif +#if defined(SQLITE_HAS_CODEC) + { /* zName: */ "hexkey", + /* ePragTyp: */ PragTyp_HEXKEY, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, + { /* zName: */ "hexrekey", + /* ePragTyp: */ PragTyp_HEXKEY, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if !defined(SQLITE_OMIT_CHECK) + { /* zName: */ "ignore_check_constraints", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_IgnoreChecks }, +#endif +#endif +#if !defined(SQLITE_OMIT_AUTOVACUUM) + { /* zName: */ "incremental_vacuum", + /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + { /* zName: */ "index_info", + /* ePragTyp: */ PragTyp_INDEX_INFO, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, + { /* zName: */ "index_list", + /* ePragTyp: */ PragTyp_INDEX_LIST, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, + { /* zName: */ "index_xinfo", + /* ePragTyp: */ PragTyp_INDEX_INFO, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 1 }, +#endif +#if !defined(SQLITE_OMIT_INTEGRITY_CHECK) + { /* zName: */ "integrity_check", + /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { /* zName: */ "journal_mode", + /* ePragTyp: */ PragTyp_JOURNAL_MODE, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, + { /* zName: */ "journal_size_limit", + /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if defined(SQLITE_HAS_CODEC) + { /* zName: */ "key", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + { /* zName: */ "legacy_file_format", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_LegacyFileFmt }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE + { /* zName: */ "lock_proxy_file", + /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + { /* zName: */ "lock_status", + /* ePragTyp: */ PragTyp_LOCK_STATUS, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { /* zName: */ "locking_mode", + /* ePragTyp: */ PragTyp_LOCKING_MODE, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, + { /* zName: */ "max_page_count", + /* ePragTyp: */ PragTyp_PAGE_COUNT, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, + { /* zName: */ "mmap_size", + /* ePragTyp: */ PragTyp_MMAP_SIZE, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, + { /* zName: */ "page_count", + /* ePragTyp: */ PragTyp_PAGE_COUNT, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, + { /* zName: */ "page_size", + /* ePragTyp: */ PragTyp_PAGE_SIZE, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if defined(SQLITE_DEBUG) + { /* zName: */ "parser_trace", + /* ePragTyp: */ PragTyp_PARSER_TRACE, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + { /* zName: */ "query_only", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_QueryOnly }, +#endif +#if !defined(SQLITE_OMIT_INTEGRITY_CHECK) + { /* zName: */ "quick_check", + /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + { /* zName: */ "read_uncommitted", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_ReadUncommitted }, + { /* zName: */ "recursive_triggers", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_RecTriggers }, +#endif +#if defined(SQLITE_HAS_CODEC) + { /* zName: */ "rekey", + /* ePragTyp: */ PragTyp_REKEY, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + { /* zName: */ "reverse_unordered_selects", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_ReverseOrder }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + { /* zName: */ "schema_version", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlag: */ 0, + /* iArg: */ BTREE_SCHEMA_VERSION }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { /* zName: */ "secure_delete", + /* ePragTyp: */ PragTyp_SECURE_DELETE, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + { /* zName: */ "short_column_names", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_ShortColNames }, +#endif + { /* zName: */ "shrink_memory", + /* ePragTyp: */ PragTyp_SHRINK_MEMORY, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, + { /* zName: */ "soft_heap_limit", + /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if defined(SQLITE_DEBUG) + { /* zName: */ "sql_trace", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_SqlTrace }, +#endif +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + { /* zName: */ "stats", + /* ePragTyp: */ PragTyp_STATS, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { /* zName: */ "synchronous", + /* ePragTyp: */ PragTyp_SYNCHRONOUS, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + { /* zName: */ "table_info", + /* ePragTyp: */ PragTyp_TABLE_INFO, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + { /* zName: */ "temp_store", + /* ePragTyp: */ PragTyp_TEMP_STORE, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, + { /* zName: */ "temp_store_directory", + /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#endif + { /* zName: */ "threads", + /* ePragTyp: */ PragTyp_THREADS, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + { /* zName: */ "user_version", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlag: */ 0, + /* iArg: */ BTREE_USER_VERSION }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if defined(SQLITE_DEBUG) + { /* zName: */ "vdbe_addoptrace", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_VdbeAddopTrace }, + { /* zName: */ "vdbe_debug", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace }, + { /* zName: */ "vdbe_eqp", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_VdbeEQP }, + { /* zName: */ "vdbe_listing", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_VdbeListing }, + { /* zName: */ "vdbe_trace", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_VdbeTrace }, +#endif +#endif +#if !defined(SQLITE_OMIT_WAL) + { /* zName: */ "wal_autocheckpoint", + /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, + /* ePragFlag: */ 0, + /* iArg: */ 0 }, + { /* zName: */ "wal_checkpoint", + /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, + /* ePragFlag: */ PragFlag_NeedSchema, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + { /* zName: */ "writable_schema", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlag: */ 0, + /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, +#endif +}; +/* Number of pragmas: 59 on by default, 72 total. */ diff --git a/src/prepare.c b/src/prepare.c index 97be900..a55a0fe 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -67,7 +67,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ if( argv[1]==0 ){ corruptSchema(pData, argv[0], 0); - }else if( argv[2] && argv[2][0] ){ + }else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){ /* Call the parser to process a CREATE TABLE, INDEX or VIEW. ** But because db->init.busy is set to 1, no VDBE code is generated ** or executed. All the parser does is build the internal data @@ -98,8 +98,8 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ } } sqlite3_finalize(pStmt); - }else if( argv[0]==0 ){ - corruptSchema(pData, 0, 0); + }else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){ + corruptSchema(pData, argv[0], 0); }else{ /* If the SQL column is blank it means this is an index that ** was created to be the PRIMARY KEY or to fulfill a UNIQUE diff --git a/src/printf.c b/src/printf.c index 428c959..1d50d77 100644 --- a/src/printf.c +++ b/src/printf.c @@ -138,6 +138,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ ** Set the StrAccum object to an error mode. */ static void setStrAccumError(StrAccum *p, u8 eError){ + assert( eError==STRACCUM_NOMEM || eError==STRACCUM_TOOBIG ); p->accError = eError; p->nAlloc = 0; } @@ -212,13 +213,6 @@ void sqlite3VXPrintf( PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */ char buf[etBUFSIZE]; /* Conversion buffer */ -#ifdef SQLITE_ENABLE_API_ARMOR - if( ap==0 ){ - (void)SQLITE_MISUSE_BKPT; - sqlite3StrAccumReset(pAccum); - return; - } -#endif bufpt = 0; if( bFlags ){ if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){ @@ -259,7 +253,6 @@ void sqlite3VXPrintf( } }while( !done && (c=(*++fmt))!=0 ); /* Get the field width */ - width = 0; if( c=='*' ){ if( bArgList ){ width = (int)getIntArg(pArgList); @@ -268,18 +261,21 @@ void sqlite3VXPrintf( } if( width<0 ){ flag_leftjustify = 1; - width = -width; + width = width >= -2147483647 ? -width : 0; } c = *++fmt; }else{ + unsigned wx = 0; while( c>='0' && c<='9' ){ - width = width*10 + c - '0'; + wx = wx*10 + c - '0'; c = *++fmt; } + testcase( wx>0x7fffffff ); + width = wx & 0x7fffffff; } + /* Get the precision */ if( c=='.' ){ - precision = 0; c = *++fmt; if( c=='*' ){ if( bArgList ){ @@ -287,13 +283,18 @@ void sqlite3VXPrintf( }else{ precision = va_arg(ap,int); } - if( precision<0 ) precision = -precision; c = *++fmt; + if( precision<0 ){ + precision = precision >= -2147483647 ? -precision : -1; + } }else{ + unsigned px = 0; while( c>='0' && c<='9' ){ - precision = precision*10 + c - '0'; + px = px*10 + c - '0'; c = *++fmt; } + testcase( px>0x7fffffff ); + precision = px & 0x7fffffff; } }else{ precision = -1; @@ -457,7 +458,8 @@ void sqlite3VXPrintf( else prefix = 0; } if( xtype==etGENERIC && precision>0 ) precision--; - for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){} + testcase( precision>0xfff ); + for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){} if( xtype==etFLOAT ) realvalue += rounder; /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; @@ -512,8 +514,9 @@ void sqlite3VXPrintf( }else{ e2 = exp; } - if( MAX(e2,0)+precision+width > etBUFSIZE - 15 ){ - bufpt = zExtra = sqlite3Malloc( MAX(e2,0)+precision+width+15 ); + if( MAX(e2,0)+(i64)precision+(i64)width > etBUFSIZE - 15 ){ + bufpt = zExtra + = sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 ); if( bufpt==0 ){ setStrAccumError(pAccum, STRACCUM_NOMEM); return; @@ -745,13 +748,13 @@ void sqlite3VXPrintf( */ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ char *zNew; - assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */ + assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */ if( p->accError ){ testcase(p->accError==STRACCUM_TOOBIG); testcase(p->accError==STRACCUM_NOMEM); return 0; } - if( !p->useMalloc ){ + if( p->mxAlloc==0 ){ N = p->nAlloc - p->nChar - 1; setStrAccumError(p, STRACCUM_TOOBIG); return N; @@ -771,10 +774,10 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ }else{ p->nAlloc = (int)szNew; } - if( p->useMalloc==1 ){ + if( p->db ){ zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); }else{ - zNew = sqlite3_realloc(zOld, p->nAlloc); + zNew = sqlite3_realloc64(zOld, p->nAlloc); } if( zNew ){ assert( p->zText!=0 || p->nChar==0 ); @@ -794,7 +797,10 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ ** Append N copies of character c to the given string buffer. */ void sqlite3AppendChar(StrAccum *p, int N, char c){ - if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return; + testcase( p->nChar + (i64)N > 0x7fffffff ); + if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){ + return; + } while( (N--)>0 ) p->zText[p->nChar++] = c; } @@ -819,7 +825,7 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ ** size of the memory allocation for StrAccum if necessary. */ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ - assert( z!=0 ); + assert( z!=0 || N==0 ); assert( p->zText!=0 || p->nChar==0 || p->accError ); assert( N>=0 ); assert( p->accError==0 || p->nAlloc==0 ); @@ -848,12 +854,8 @@ void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){ char *sqlite3StrAccumFinish(StrAccum *p){ if( p->zText ){ p->zText[p->nChar] = 0; - if( p->useMalloc && p->zText==p->zBase ){ - if( p->useMalloc==1 ){ - p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); - }else{ - p->zText = sqlite3_malloc(p->nChar+1); - } + if( p->mxAlloc>0 && p->zText==p->zBase ){ + p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); if( p->zText ){ memcpy(p->zText, p->zBase, p->nChar+1); }else{ @@ -869,25 +871,31 @@ char *sqlite3StrAccumFinish(StrAccum *p){ */ void sqlite3StrAccumReset(StrAccum *p){ if( p->zText!=p->zBase ){ - if( p->useMalloc==1 ){ - sqlite3DbFree(p->db, p->zText); - }else{ - sqlite3_free(p->zText); - } + sqlite3DbFree(p->db, p->zText); } p->zText = 0; } /* -** Initialize a string accumulator +** Initialize a string accumulator. +** +** p: The accumulator to be initialized. +** db: Pointer to a database connection. May be NULL. Lookaside +** memory is used if not NULL. db->mallocFailed is set appropriately +** when not NULL. +** zBase: An initial buffer. May be NULL in which case the initial buffer +** is malloced. +** n: Size of zBase in bytes. If total space requirements never exceed +** n then no memory allocations ever occur. +** mx: Maximum number of bytes to accumulate. If mx==0 then no memory +** allocations will ever occur. */ -void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n, int mx){ +void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){ p->zText = p->zBase = zBase; - p->db = 0; + p->db = db; p->nChar = 0; p->nAlloc = n; p->mxAlloc = mx; - p->useMalloc = 1; p->accError = 0; } @@ -900,9 +908,8 @@ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){ char zBase[SQLITE_PRINT_BUF_SIZE]; StrAccum acc; assert( db!=0 ); - sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), + sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase), db->aLimit[SQLITE_LIMIT_LENGTH]); - acc.db = db; sqlite3VXPrintf(&acc, SQLITE_PRINTF_INTERNAL, zFormat, ap); z = sqlite3StrAccumFinish(&acc); if( acc.accError==STRACCUM_NOMEM ){ @@ -960,8 +967,7 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif - sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), SQLITE_MAX_LENGTH); - acc.useMalloc = 2; + sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH); sqlite3VXPrintf(&acc, 0, zFormat, ap); z = sqlite3StrAccumFinish(&acc); return z; @@ -1002,12 +1008,11 @@ char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){ #ifdef SQLITE_ENABLE_API_ARMOR if( zBuf==0 || zFormat==0 ) { (void)SQLITE_MISUSE_BKPT; - if( zBuf && n>0 ) zBuf[0] = 0; + if( zBuf ) zBuf[0] = 0; return zBuf; } #endif - sqlite3StrAccumInit(&acc, zBuf, n, 0); - acc.useMalloc = 0; + sqlite3StrAccumInit(&acc, 0, zBuf, n, 0); sqlite3VXPrintf(&acc, 0, zFormat, ap); return sqlite3StrAccumFinish(&acc); } @@ -1033,8 +1038,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ StrAccum acc; /* String accumulator */ char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ - sqlite3StrAccumInit(&acc, zMsg, sizeof(zMsg), 0); - acc.useMalloc = 0; + sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); sqlite3VXPrintf(&acc, 0, zFormat, ap); sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, sqlite3StrAccumFinish(&acc)); @@ -1052,7 +1056,7 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...){ } } -#if defined(SQLITE_DEBUG) +#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) /* ** A version of printf() that understands %lld. Used for debugging. ** The printf() built into some versions of windows does not understand %lld @@ -1062,8 +1066,7 @@ void sqlite3DebugPrintf(const char *zFormat, ...){ va_list ap; StrAccum acc; char zBuf[500]; - sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0); - acc.useMalloc = 0; + sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); va_start(ap,zFormat); sqlite3VXPrintf(&acc, 0, zFormat, ap); va_end(ap); @@ -1090,7 +1093,7 @@ void sqlite3DebugPrintf(const char *zFormat, ...){ ** is not the last item in the tree. */ TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ if( p==0 ){ - p = sqlite3_malloc( sizeof(*p) ); + p = sqlite3_malloc64( sizeof(*p) ); if( p==0 ) return 0; memset(p, 0, sizeof(*p)); }else{ @@ -1113,8 +1116,7 @@ void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ int i; StrAccum acc; char zBuf[500]; - sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0); - acc.useMalloc = 0; + sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); if( p ){ for(i=0; iiLevel && ibLine)-1; i++){ sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4); diff --git a/src/resolve.c b/src/resolve.c index d4bd548..23636ea 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -79,7 +79,7 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){ ** SELECT a+b, c+d FROM t1 ORDER BY (a+b) COLLATE nocase; ** ** The nSubquery parameter specifies how many levels of subquery the -** alias is removed from the original expression. The usually value is +** alias is removed from the original expression. The usual value is ** zero but it might be more if the alias is contained within a subquery ** of the original expression. The Expr.op2 field of TK_AGG_FUNCTION ** structures must be increased by the nSubquery amount. @@ -99,7 +99,6 @@ static void resolveAlias( assert( iCol>=0 && iColnExpr ); pOrig = pEList->a[iCol].pExpr; assert( pOrig!=0 ); - assert( pOrig->flags & EP_Resolved ); db = pParse->db; pDup = sqlite3ExprDup(db, pOrig, 0); if( pDup==0 ) return; @@ -247,9 +246,10 @@ static int lookupName( testcase( pNC->ncFlags & NC_PartIdx ); testcase( pNC->ncFlags & NC_IsCheck ); if( (pNC->ncFlags & (NC_PartIdx|NC_IsCheck))!=0 ){ - /* Silently ignore database qualifiers inside CHECK constraints and partial - ** indices. Do not raise errors because that might break legacy and - ** because it does not hurt anything to just ignore the database name. */ + /* Silently ignore database qualifiers inside CHECK constraints and + ** partial indices. Do not raise errors because that might break + ** legacy and because it does not hurt anything to just ignore the + ** database name. */ zDb = 0; }else{ for(i=0; inDb; i++){ @@ -320,7 +320,8 @@ static int lookupName( if( pMatch ){ pExpr->iTable = pMatch->iCursor; pExpr->pTab = pMatch->pTab; - assert( (pMatch->jointype & JT_RIGHT)==0 ); /* RIGHT JOIN not (yet) supported */ + /* RIGHT JOIN not (yet) supported */ + assert( (pMatch->jointype & JT_RIGHT)==0 ); if( (pMatch->jointype & JT_LEFT)!=0 ){ ExprSetProperty(pExpr, EP_CanBeNull); } @@ -641,7 +642,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pExpr->affinity = SQLITE_AFF_INTEGER; break; } -#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) */ +#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) + && !defined(SQLITE_OMIT_SUBQUERY) */ /* A lone identifier is the name of a column. */ @@ -706,19 +708,20 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ if( n==2 ){ pExpr->iTable = exprProbability(pList->a[1].pExpr); if( pExpr->iTable<0 ){ - sqlite3ErrorMsg(pParse, "second argument to likelihood() must be a " - "constant between 0.0 and 1.0"); + sqlite3ErrorMsg(pParse, + "second argument to likelihood() must be a " + "constant between 0.0 and 1.0"); pNC->nErr++; } }else{ - /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is equivalent to - ** likelihood(X, 0.0625). - ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is short-hand for - ** likelihood(X,0.0625). - ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand for - ** likelihood(X,0.9375). - ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent to - ** likelihood(X,0.9375). */ + /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is + ** equivalent to likelihood(X, 0.0625). + ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is + ** short-hand for likelihood(X,0.0625). + ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand + ** for likelihood(X,0.9375). + ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent + ** to likelihood(X,0.9375). */ /* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */ pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120; } @@ -735,7 +738,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ return WRC_Prune; } #endif - if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant); + if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ){ + ExprSetProperty(pExpr,EP_ConstFunc); + } } if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); @@ -987,9 +992,11 @@ static int resolveCompoundOrderBy( if( pItem->pExpr==pE ){ pItem->pExpr = pNew; }else{ - assert( pItem->pExpr->op==TK_COLLATE ); - assert( pItem->pExpr->pLeft==pE ); - pItem->pExpr->pLeft = pNew; + Expr *pParent = pItem->pExpr; + assert( pParent->op==TK_COLLATE ); + while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft; + assert( pParent->pLeft==pE ); + pParent->pLeft = pNew; } sqlite3ExprDelete(db, pE); pItem->u.x.iOrderByCol = (u16)iCol; @@ -1046,7 +1053,8 @@ int sqlite3ResolveOrderGroupBy( resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr); return 1; } - resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr, zType,0); + resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr, + zType,0); } } return 0; @@ -1179,6 +1187,20 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ sqlite3ResolveExprNames(&sNC, p->pOffset) ){ return WRC_Abort; } + + /* If the SF_Converted flags is set, then this Select object was + ** was created by the convertCompoundSelectToSubquery() function. + ** In this case the ORDER BY clause (p->pOrderBy) should be resolved + ** as if it were part of the sub-query, not the parent. This block + ** moves the pOrderBy down to the sub-query. It will be moved back + ** after the names have been resolved. */ + if( p->selFlags & SF_Converted ){ + Select *pSub = p->pSrc->a[0].pSelect; + assert( p->pSrc->nSrc==1 && p->pOrderBy ); + assert( pSub->pPrior && pSub->pOrderBy==0 ); + pSub->pOrderBy = p->pOrderBy; + p->pOrderBy = 0; + } /* Recursively resolve names in all subqueries */ @@ -1261,12 +1283,30 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ sNC.pNext = 0; sNC.ncFlags |= NC_AllowAgg; + /* If this is a converted compound query, move the ORDER BY clause from + ** the sub-query back to the parent query. At this point each term + ** within the ORDER BY clause has been transformed to an integer value. + ** These integers will be replaced by copies of the corresponding result + ** set expressions by the call to resolveOrderGroupBy() below. */ + if( p->selFlags & SF_Converted ){ + Select *pSub = p->pSrc->a[0].pSelect; + p->pOrderBy = pSub->pOrderBy; + pSub->pOrderBy = 0; + } + /* Process the ORDER BY clause for singleton SELECT statements. ** The ORDER BY clause for compounds SELECT statements is handled ** below, after all of the result-sets for all of the elements of ** the compound have been resolved. + ** + ** If there is an ORDER BY clause on a term of a compound-select other + ** than the right-most term, then that is a syntax error. But the error + ** is not detected until much later, and so we need to go ahead and + ** resolve those symbols on the incorrect ORDER BY for consistency. */ - if( !isCompound && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER") ){ + if( isCompound<=nCompound /* Defer right-most ORDER BY of a compound */ + && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER") + ){ return WRC_Abort; } if( db->mallocFailed ){ diff --git a/src/select.c b/src/select.c index 39a0550..beb52c7 100644 --- a/src/select.c +++ b/src/select.c @@ -111,7 +111,6 @@ Select *sqlite3SelectNew( Select standin; sqlite3 *db = pParse->db; pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); - assert( db->mallocFailed || !pOffset || pLimit ); /* OFFSET implies LIMIT */ if( pNew==0 ){ assert( db->mallocFailed ); pNew = &standin; @@ -131,7 +130,7 @@ Select *sqlite3SelectNew( pNew->op = TK_SELECT; pNew->pLimit = pLimit; pNew->pOffset = pOffset; - assert( pOffset==0 || pLimit!=0 ); + assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 ); pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; if( db->mallocFailed ) { @@ -563,20 +562,17 @@ static void pushOntoSorter( } sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); if( pSelect->iLimit ){ - int addr1, addr2; + int addr; int iLimit; if( pSelect->iOffset ){ iLimit = pSelect->iOffset+1; }else{ iLimit = pSelect->iLimit; } - addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1); - addr2 = sqlite3VdbeAddOp0(v, OP_Goto); - sqlite3VdbeJumpHere(v, addr1); + addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, -1); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); - sqlite3VdbeJumpHere(v, addr2); + sqlite3VdbeJumpHere(v, addr); } } @@ -973,7 +969,7 @@ static void selectInnerLoop( ** the output for us. */ if( pSort==0 && p->iLimit ){ - sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v); } } @@ -1384,7 +1380,7 @@ static const char *columnTypeImpl( ** of the SELECT statement. Return the declaration type and origin ** data for the result-set column of the sub-select. */ - if( iCol>=0 && ALWAYS(iColpEList->nExpr) ){ + if( iCol>=0 && iColpEList->nExpr ){ /* If iCol is less than zero, then the expression requests the ** rowid of the sub-select or view. This expression is legal (see ** test case misc2.2.2) - it always evaluates to NULL. @@ -1704,12 +1700,14 @@ static void selectAddColumnTypeAndCollation( a = pSelect->pEList->a; for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ p = a[i].pExpr; - pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst)); + if( pCol->zType==0 ){ + pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst)); + } szAll += pCol->szEst; pCol->affinity = sqlite3ExprAffinity(p); if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_NONE; pColl = sqlite3ExprCollSeq(pParse, p); - if( pColl ){ + if( pColl && pCol->zColl==0 ){ pCol->zColl = sqlite3DbStrDup(db, pColl->zName); } } @@ -1826,7 +1824,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ sqlite3ExprCode(pParse, p->pLimit, iLimit); sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v); VdbeComment((v, "LIMIT counter")); - sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v); } if( p->pOffset ){ p->iOffset = iOffset = ++pParse->nMem; @@ -2045,7 +2043,7 @@ static void generateWithRecursiveQuery( selectInnerLoop(pParse, p, p->pEList, iCurrent, 0, 0, pDest, addrCont, addrBreak); if( regLimit ){ - sqlite3VdbeAddOp3(v, OP_IfZero, regLimit, addrBreak, -1); + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak); VdbeCoverage(v); } sqlite3VdbeResolveLabel(v, addrCont); @@ -2111,8 +2109,7 @@ static int multiSelectValues( int nExpr = p->pEList->nExpr; int nRow = 1; int rc = 0; - assert( p->pNext==0 ); - assert( p->selFlags & SF_AllValues ); + assert( p->selFlags & SF_MultiValue ); do{ assert( p->selFlags & SF_Values ); assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); @@ -2221,7 +2218,7 @@ static int multiSelect( /* Special handling for a compound-select that originates as a VALUES clause. */ - if( p->selFlags & SF_AllValues ){ + if( p->selFlags & SF_MultiValue ){ rc = multiSelectValues(pParse, p, &dest); goto multi_select_end; } @@ -2270,7 +2267,7 @@ static int multiSelect( p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; if( p->iLimit ){ - addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit); VdbeCoverage(v); + addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); VdbeComment((v, "Jump ahead if LIMIT reached")); } explainSetInteger(iSub2, pParse->iNextSelectId); @@ -2606,7 +2603,7 @@ static int generateOutputSubroutine( */ case SRT_Set: { int r1; - assert( pIn->nSdst==1 ); + assert( pIn->nSdst==1 || pParse->nErr>0 ); pDest->affSdst = sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst); r1 = sqlite3GetTempReg(pParse); @@ -2632,7 +2629,7 @@ static int generateOutputSubroutine( ** of the scan loop. */ case SRT_Mem: { - assert( pIn->nSdst==1 ); + assert( pIn->nSdst==1 || pParse->nErr>0 ); testcase( pIn->nSdst!=1 ); sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, 1); /* The LIMIT clause will jump out of the loop for us */ break; @@ -2647,7 +2644,7 @@ static int generateOutputSubroutine( pDest->iSdst = sqlite3GetTempRange(pParse, pIn->nSdst); pDest->nSdst = pIn->nSdst; } - sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSdst, pDest->nSdst); + sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSdst, pIn->nSdst); sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); break; } @@ -2671,7 +2668,7 @@ static int generateOutputSubroutine( /* Jump to the end of the loop if the LIMIT is reached. */ if( p->iLimit ){ - sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v); } /* Generate the subroutine return @@ -2863,8 +2860,10 @@ static int multiSelectOrderBy( if( aPermute ){ struct ExprList_item *pItem; for(i=0, pItem=pOrderBy->a; iu.x.iOrderByCol>0 - && pItem->u.x.iOrderByCol<=p->pEList->nExpr ); + assert( pItem->u.x.iOrderByCol>0 ); + /* assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ) is also true + ** but only for well-formed SELECT statements. */ + testcase( pItem->u.x.iOrderByCol > p->pEList->nExpr ); aPermute[i] = pItem->u.x.iOrderByCol - 1; } pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1); @@ -3074,7 +3073,7 @@ static int multiSelectOrderBy( /*** TBD: Insert subroutine calls to close cursors on incomplete **** subqueries ****/ explainComposite(pParse, p->op, iSub1, iSub2, 0); - return SQLITE_OK; + return pParse->nErr!=0; } #endif @@ -3194,7 +3193,10 @@ static void substSelect( ** ** (1) The subquery and the outer query do not both use aggregates. ** -** (2) The subquery is not an aggregate or the outer query is not a join. +** (2) The subquery is not an aggregate or (2a) the outer query is not a join +** and (2b) the outer query does not use subqueries other than the one +** FROM-clause subquery that is a candidate for flattening. (2b is +** due to ticket [2f7170d73bf9abf80] from 2015-02-09.) ** ** (3) The subquery is not the right operand of a left outer join ** (Originally ticket #306. Strengthened by ticket #3300) @@ -3331,8 +3333,17 @@ static int flattenSubquery( iParent = pSubitem->iCursor; pSub = pSubitem->pSelect; assert( pSub!=0 ); - if( isAgg && subqueryIsAgg ) return 0; /* Restriction (1) */ - if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; /* Restriction (2) */ + if( subqueryIsAgg ){ + if( isAgg ) return 0; /* Restriction (1) */ + if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */ + if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery)) + || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0 + || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0 + ){ + return 0; /* Restriction (2b) */ + } + } + pSubSrc = pSub->pSrc; assert( pSubSrc ); /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, @@ -3874,7 +3885,10 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ pNew->pOrderBy = 0; p->pPrior = 0; p->pNext = 0; + p->pWith = 0; p->selFlags &= ~SF_Compound; + assert( (p->selFlags & SF_Converted)==0 ); + p->selFlags |= SF_Converted; assert( pNew->pPrior!=0 ); pNew->pPrior->pNext = pNew; pNew->pLimit = 0; @@ -4026,7 +4040,7 @@ static int withExpand( for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior); pEList = pLeft->pEList; if( pCte->pCols ){ - if( pEList->nExpr!=pCte->pCols->nExpr ){ + if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){ sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns", pCte->zName, pEList->nExpr, pCte->pCols->nExpr ); @@ -4153,7 +4167,7 @@ static int selectExpander(Walker *pWalker, Select *p){ /* A sub-query in the FROM clause of a SELECT */ assert( pSel!=0 ); assert( pFrom->pTab==0 ); - sqlite3WalkSelect(pWalker, pSel); + if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; pTab->nRef = 1; @@ -4410,7 +4424,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; - if( (pSelect->selFlags & SF_AllValues)==0 ){ + if( (pSelect->selFlags & SF_MultiValue)==0 ){ w.xSelectCallback2 = selectPopWith; } sqlite3WalkSelect(&w, pSelect); @@ -4596,7 +4610,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ } if( pF->iDistinct>=0 ){ addrNext = sqlite3VdbeMakeLabel(v); - assert( nArg==1 ); + testcase( nArg==0 ); /* Error condition */ + testcase( nArg>1 ); /* Also an error */ codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg); } if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ @@ -4752,6 +4767,13 @@ int sqlite3Select( } isAgg = (p->selFlags & SF_Aggregate)!=0; assert( pEList!=0 ); +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x100 ){ + SELECTTRACE(0x100,pParse,p, ("after name resolution:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + /* Begin generating code. */ @@ -5464,10 +5486,9 @@ int sqlite3Select( */ sqlite3VdbeResolveLabel(v, iEnd); - /* The SELECT was successfully coded. Set the return code to 0 - ** to indicate no errors. - */ - rc = 0; + /* The SELECT has been coded. If there is an error in the Parse structure, + ** set the return code to 1. Otherwise 0. */ + rc = (pParse->nErr>0); /* Control jumps to here if an error is encountered above, or upon ** successful coding of the SELECT. @@ -5497,9 +5518,9 @@ select_end: void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ int n = 0; pView = sqlite3TreeViewPush(pView, moreToFollow); - sqlite3TreeViewLine(pView, "SELECT%s%s", + sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p)", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), - ((p->selFlags & SF_Aggregate) ? " agg_flag" : "") + ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p ); if( p->pSrc && p->pSrc->nSrc ) n++; if( p->pWhere ) n++; @@ -5518,7 +5539,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ struct SrcList_item *pItem = &p->pSrc->a[i]; StrAccum x; char zLine[100]; - sqlite3StrAccumInit(&x, zLine, sizeof(zLine), 0); + sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor); if( pItem->zDatabase ){ sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName); diff --git a/src/shell.c b/src/shell.c index 02c27f4..7db8dbd 100644 --- a/src/shell.c +++ b/src/shell.c @@ -24,6 +24,13 @@ #include "msvc.h" #endif +/* +** No support for loadable extensions in VxWorks. +*/ +#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION +# define SQLITE_OMIT_LOAD_EXTENSION 1 +#endif + /* ** Enable large-file support for fopen() and friends on unix. */ @@ -107,10 +114,15 @@ */ extern int isatty(int); -/* popen and pclose are not C89 functions and so are sometimes omitted from -** the header */ -extern FILE *popen(const char*,const char*); -extern int pclose(FILE*); +#if !defined(__RTP__) && !defined(_WRS_KERNEL) + /* popen and pclose are not C89 functions and so are sometimes omitted from + ** the header */ + extern FILE *popen(const char*,const char*); + extern int pclose(FILE*); +#else +# define SQLITE_OMIT_POPEN 1 +#endif + #endif #if defined(_WIN32_WCE) @@ -126,6 +138,26 @@ extern int pclose(FILE*); #define IsDigit(X) isdigit((unsigned char)X) #define ToLower(X) (char)tolower((unsigned char)X) +/* On Windows, we normally run with output mode of TEXT so that \n characters +** are automatically translated into \r\n. However, this behavior needs +** to be disabled in some cases (ex: when generating CSV output and when +** rendering quoted strings that contain \n characters). The following +** routines take care of that. +*/ +#if defined(_WIN32) || defined(WIN32) +static void setBinaryMode(FILE *out){ + fflush(out); + _setmode(_fileno(out), _O_BINARY); +} +static void setTextMode(FILE *out){ + fflush(out); + _setmode(_fileno(out), _O_TEXT); +} +#else +# define setBinaryMode(X) +# define setTextMode(X) +#endif + /* True if the timer is enabled */ static int enableTimer = 0; @@ -145,11 +177,19 @@ static sqlite3_int64 timeOfDay(void){ return t; } -#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \ - && !defined(__minux) +#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux) #include #include +/* VxWorks does not support getrusage() as far as we can determine */ +#if defined(_WRS_KERNEL) || defined(__RTP__) +struct rusage { + struct timeval ru_utime; /* user CPU time used */ + struct timeval ru_stime; /* system CPU time used */ +}; +#define getrusage(A,B) memset(B,0,sizeof(*B)) +#endif + /* Saved resource information for the beginning of an operation */ static struct rusage sBegin; /* CPU time at start */ static sqlite3_int64 iBegin; /* Wall-clock time at start */ @@ -175,8 +215,8 @@ static double timeDiff(struct timeval *pStart, struct timeval *pEnd){ */ static void endTimer(void){ if( enableTimer ){ - struct rusage sEnd; sqlite3_int64 iEnd = timeOfDay(); + struct rusage sEnd; getrusage(RUSAGE_SELF, &sEnd); printf("Run Time: real %.3f user %f sys %f\n", (iEnd - iBegin)*0.001, @@ -296,7 +336,7 @@ static int stdin_is_interactive = 1; ** to this database a static variable so that it can be accessed ** by the SIGINT handler to interrupt database processing. */ -static sqlite3 *db = 0; +static sqlite3 *globalDb = 0; /* ** True if an interrupt (Control-C) has been received. @@ -330,7 +370,7 @@ static FILE *iotrace = 0; ** is written to iotrace. */ #ifdef SQLITE_ENABLE_IOTRACE -static void iotracePrintf(const char *zFormat, ...){ +static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ va_list ap; char *z; if( iotrace==0 ) return; @@ -487,6 +527,7 @@ struct ShellState { int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ int statsOn; /* True to display memory stats before each finalize */ int scanstatsOn; /* True to display scan stats before each finalize */ + int backslashOn; /* Resolve C-style \x escapes in SQL input text */ int outCount; /* Revert to stdout when reaching zero */ int cnt; /* Number of records displayed so far */ FILE *out; /* Write results here */ @@ -604,6 +645,7 @@ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ static void output_quoted_string(FILE *out, const char *z){ int i; int nSingle = 0; + setBinaryMode(out); for(i=0; z[i]; i++){ if( z[i]=='\'' ) nSingle++; } @@ -626,6 +668,7 @@ static void output_quoted_string(FILE *out, const char *z){ } fprintf(out,"'"); } + setTextMode(out); } /* @@ -762,7 +805,7 @@ static void interrupt_handler(int NotUsed){ UNUSED_PARAMETER(NotUsed); seenInterrupt++; if( seenInterrupt>2 ) exit(1); - if( db ) sqlite3_interrupt(db); + if( globalDb ) sqlite3_interrupt(globalDb); } #endif @@ -928,10 +971,7 @@ static int shell_callback( break; } case MODE_Csv: { -#if defined(WIN32) || defined(_WIN32) - fflush(p->out); - _setmode(_fileno(p->out), _O_BINARY); -#endif + setBinaryMode(p->out); if( p->cnt++==0 && p->showHeader ){ for(i=0; iout, "%s", p->rowSeparator); } -#if defined(WIN32) || defined(_WIN32) - fflush(p->out); - _setmode(_fileno(p->out), _O_TEXT); -#endif + setTextMode(p->out); break; } case MODE_Insert: { p->cnt++; if( azArg==0 ) break; - fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable); + fprintf(p->out,"INSERT INTO %s",p->zDestTable); + if( p->showHeader ){ + fprintf(p->out,"("); + for(i=0; i0 ? ",": ""; + fprintf(p->out, "%s%s", zSep, azCol[i]); + } + fprintf(p->out,")"); + } + fprintf(p->out," VALUES("); for(i=0; i0 ? ",": ""; if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ @@ -1154,7 +1200,7 @@ static char *save_err_msg( sqlite3 *db /* Database to query */ ){ int nErrMsg = 1+strlen30(sqlite3_errmsg(db)); - char *zErrMsg = sqlite3_malloc(nErrMsg); + char *zErrMsg = sqlite3_malloc64(nErrMsg); if( zErrMsg ){ memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg); } @@ -1391,8 +1437,8 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){ /* Grow the p->aiIndent array as required */ if( iOp>=nAlloc ){ nAlloc += 100; - p->aiIndent = (int*)sqlite3_realloc(p->aiIndent, nAlloc*sizeof(int)); - abYield = (int*)sqlite3_realloc(abYield, nAlloc*sizeof(int)); + p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int)); + abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int)); } abYield[iOp] = str_in_array(zOp, azYield); p->aiIndent[iOp] = 0; @@ -1509,7 +1555,7 @@ static int shell_exec( if( xCallback ){ /* allocate space for col name ptr, value ptr, and type */ int nCol = sqlite3_column_count(pStmt); - void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1); + void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1); if( !pData ){ rc = SQLITE_NOMEM; }else{ @@ -1735,8 +1781,10 @@ static int run_schema_dump_query( static char zHelp[] = ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" ".bail on|off Stop after hitting an error. Default OFF\n" + ".binary on|off Turn binary output on or off. Default OFF\n" ".clone NEWDB Clone data into NEWDB from the existing database\n" ".databases List names and files of attached databases\n" + ".dbinfo ?DB? Show status information about the database\n" ".dump ?TABLE? ... Dump the database in an SQL text format\n" " If TABLE specified, only dump tables matching\n" " LIKE pattern TABLE.\n" @@ -1749,12 +1797,13 @@ static char zHelp[] = ".headers on|off Turn display of headers on or off\n" ".help Show this message\n" ".import FILE TABLE Import data from FILE into TABLE\n" - ".indices ?TABLE? Show names of all indices\n" - " If TABLE specified, only show indices for tables\n" + ".indexes ?TABLE? Show names of all indexes\n" + " If TABLE specified, only show indexes for tables\n" " matching LIKE pattern TABLE.\n" #ifdef SQLITE_ENABLE_IOTRACE ".iotrace FILE Enable I/O diagnostic logging to FILE\n" #endif + ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT\n" #ifndef SQLITE_OMIT_LOAD_EXTENSION ".load FILE ?ENTRY? Load an extension library\n" #endif @@ -1824,7 +1873,7 @@ static void readfileFunc( fseek(in, 0, SEEK_END); nIn = ftell(in); rewind(in); - pBuf = sqlite3_malloc( nIn ); + pBuf = sqlite3_malloc64( nIn ); if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ sqlite3_result_blob(context, pBuf, nIn, sqlite3_free); }else{ @@ -1871,23 +1920,23 @@ static void open_db(ShellState *p, int keepAlive){ if( p->db==0 ){ sqlite3_initialize(); sqlite3_open(p->zDbFilename, &p->db); - db = p->db; - if( db && sqlite3_errcode(db)==SQLITE_OK ){ - sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0, + globalDb = p->db; + if( p->db && sqlite3_errcode(p->db)==SQLITE_OK ){ + sqlite3_create_function(p->db, "shellstatic", 0, SQLITE_UTF8, 0, shellstaticFunc, 0, 0); } - if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){ + if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ fprintf(stderr,"Error: unable to open database \"%s\": %s\n", - p->zDbFilename, sqlite3_errmsg(db)); + p->zDbFilename, sqlite3_errmsg(p->db)); if( keepAlive ) return; exit(1); } #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); #endif - sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0, + sqlite3_create_function(p->db, "readfile", 1, SQLITE_UTF8, 0, readfileFunc, 0, 0); - sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0, + sqlite3_create_function(p->db, "writefile", 2, SQLITE_UTF8, 0, writefileFunc, 0, 0); } } @@ -1895,26 +1944,44 @@ static void open_db(ShellState *p, int keepAlive){ /* ** Do C-language style dequoting. ** +** \a -> alarm +** \b -> backspace ** \t -> tab ** \n -> newline +** \v -> vertical tab +** \f -> form feed ** \r -> carriage return +** \s -> space ** \" -> " -** \NNN -> ascii character NNN in octal +** \' -> ' ** \\ -> backslash +** \NNN -> ascii character NNN in octal */ static void resolve_backslashes(char *z){ int i, j; char c; while( *z && *z!='\\' ) z++; for(i=j=0; (c = z[i])!=0; i++, j++){ - if( c=='\\' ){ + if( c=='\\' && z[i+1]!=0 ){ c = z[++i]; - if( c=='n' ){ - c = '\n'; + if( c=='a' ){ + c = '\a'; + }else if( c=='b' ){ + c = '\b'; }else if( c=='t' ){ c = '\t'; + }else if( c=='n' ){ + c = '\n'; + }else if( c=='v' ){ + c = '\v'; + }else if( c=='f' ){ + c = '\f'; }else if( c=='r' ){ c = '\r'; + }else if( c=='"' ){ + c = '"'; + }else if( c=='\'' ){ + c = '\''; }else if( c=='\\' ){ c = '\\'; }else if( c>='0' && c<='7' ){ @@ -2084,7 +2151,7 @@ struct ImportCtx { static void import_append_char(ImportCtx *p, int c){ if( p->n+1>=p->nAlloc ){ p->nAlloc += p->nAlloc + 100; - p->z = sqlite3_realloc(p->z, p->nAlloc); + p->z = sqlite3_realloc64(p->z, p->nAlloc); if( p->z==0 ){ fprintf(stderr, "out of memory\n"); exit(1); @@ -2098,7 +2165,7 @@ static void import_append_char(ImportCtx *p, int c){ ** ** + Input comes from p->in. ** + Store results in p->z of length p->n. Space to hold p->z comes -** from sqlite3_malloc(). +** from sqlite3_malloc64(). ** + Use p->cSep as the column separator. The default is ",". ** + Use p->rSep as the row separator. The default is "\n". ** + Keep track of the line number in p->nLine. @@ -2106,7 +2173,7 @@ static void import_append_char(ImportCtx *p, int c){ ** EOF on end-of-file. ** + Report syntax errors on stderr */ -static char *csv_read_one_field(ImportCtx *p){ +static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){ int c; int cSep = p->cColSep; int rSep = p->cRowSep; @@ -2172,7 +2239,7 @@ static char *csv_read_one_field(ImportCtx *p){ ** ** + Input comes from p->in. ** + Store results in p->z of length p->n. Space to hold p->z comes -** from sqlite3_malloc(). +** from sqlite3_malloc64(). ** + Use p->cSep as the column separator. The default is "\x1F". ** + Use p->rSep as the row separator. The default is "\x1E". ** + Keep track of the row number in p->nLine. @@ -2180,7 +2247,7 @@ static char *csv_read_one_field(ImportCtx *p){ ** EOF on end-of-file. ** + Report syntax errors on stderr */ -static char *ascii_read_one_field(ImportCtx *p){ +static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){ int c; int cSep = p->cColSep; int rSep = p->cRowSep; @@ -2232,7 +2299,7 @@ static void tryToCloneData( goto end_data_xfer; } n = sqlite3_column_count(pQuery); - zInsert = sqlite3_malloc(200 + nTable + n*3); + zInsert = sqlite3_malloc64(200 + nTable + n*3); if( zInsert==0 ){ fprintf(stderr, "out of memory\n"); goto end_data_xfer; @@ -2422,7 +2489,9 @@ static void tryToClone(ShellState *p, const char *zNewDb){ */ static void output_reset(ShellState *p){ if( p->outfile[0]=='|' ){ +#ifndef SQLITE_OMIT_POPEN pclose(p->out); +#endif }else{ output_file_close(p->out); } @@ -2430,6 +2499,115 @@ static void output_reset(ShellState *p){ p->out = stdout; } +/* +** Run an SQL command and return the single integer result. +*/ +static int db_int(ShellState *p, const char *zSql){ + sqlite3_stmt *pStmt; + int res = 0; + sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ + res = sqlite3_column_int(pStmt,0); + } + sqlite3_finalize(pStmt); + return res; +} + +/* +** Convert a 2-byte or 4-byte big-endian integer into a native integer +*/ +unsigned int get2byteInt(unsigned char *a){ + return (a[0]<<8) + a[1]; +} +unsigned int get4byteInt(unsigned char *a){ + return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; +} + +/* +** Implementation of the ".info" command. +** +** Return 1 on error, 2 to exit, and 0 otherwise. +*/ +static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){ + static const struct { const char *zName; int ofst; } aField[] = { + { "file change counter:", 24 }, + { "database page count:", 28 }, + { "freelist page count:", 36 }, + { "schema cookie:", 40 }, + { "schema format:", 44 }, + { "default cache size:", 48 }, + { "autovacuum top root:", 52 }, + { "incremental vacuum:", 64 }, + { "text encoding:", 56 }, + { "user version:", 60 }, + { "application id:", 68 }, + { "software version:", 96 }, + }; + static const struct { const char *zName; const char *zSql; } aQuery[] = { + { "number of tables:", + "SELECT count(*) FROM %s WHERE type='table'" }, + { "number of indexes:", + "SELECT count(*) FROM %s WHERE type='index'" }, + { "number of triggers:", + "SELECT count(*) FROM %s WHERE type='trigger'" }, + { "number of views:", + "SELECT count(*) FROM %s WHERE type='view'" }, + { "schema size:", + "SELECT total(length(sql)) FROM %s" }, + }; + sqlite3_file *pFile; + int i; + char *zSchemaTab; + char *zDb = nArg>=2 ? azArg[1] : "main"; + unsigned char aHdr[100]; + open_db(p, 0); + if( p->db==0 ) return 1; + sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile); + if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){ + return 1; + } + i = pFile->pMethods->xRead(pFile, aHdr, 100, 0); + if( i!=SQLITE_OK ){ + fprintf(stderr, "unable to read database header\n"); + return 1; + } + i = get2byteInt(aHdr+16); + if( i==1 ) i = 65536; + fprintf(p->out, "%-20s %d\n", "database page size:", i); + fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]); + fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]); + fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]); + for(i=0; iout, "%-20s %u", aField[i].zName, val); + switch( ofst ){ + case 56: { + if( val==1 ) fprintf(p->out, " (utf8)"); + if( val==2 ) fprintf(p->out, " (utf16le)"); + if( val==3 ) fprintf(p->out, " (utf16be)"); + } + } + fprintf(p->out, "\n"); + } + if( zDb==0 ){ + zSchemaTab = sqlite3_mprintf("main.sqlite_master"); + }else if( strcmp(zDb,"temp")==0 ){ + zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master"); + }else{ + zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb); + } + for(i=0; iout, "%-20s %d\n", aQuery[i].zName, val); + } + sqlite3_free(zSchemaTab); + return 0; +} + + /* ** If an input line begins with "." then invoke this routine to ** process that line. @@ -2437,7 +2615,7 @@ static void output_reset(ShellState *p){ ** Return 1 on error, 2 to exit, and 0 otherwise. */ static int do_meta_command(char *zLine, ShellState *p){ - int i = 1; + int h = 1; int nArg = 0; int n, c; int rc = 0; @@ -2445,24 +2623,24 @@ static int do_meta_command(char *zLine, ShellState *p){ /* Parse the input line into tokens. */ - while( zLine[i] && nArg=3 && strncmp(azArg[0], "binary", n)==0 ){ + if( nArg==2 ){ + if( booleanValue(azArg[1]) ){ + setBinaryMode(p->out); + }else{ + setTextMode(p->out); + } + }else{ + fprintf(stderr, "Usage: .binary on|off\n"); + rc = 1; + } + }else + /* The undocumented ".breakpoint" command causes a call to the no-op ** routine named test_breakpoint(). */ @@ -2572,6 +2763,10 @@ static int do_meta_command(char *zLine, ShellState *p){ } }else + if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){ + rc = shell_dbinfo_command(p, nArg, azArg); + }else + if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ open_db(p, 0); /* When playing back a "dump", the content might appear in an order @@ -2759,8 +2954,8 @@ static int do_meta_command(char *zLine, ShellState *p){ int nSep; /* Number of bytes in p->colSeparator[] */ char *zSql; /* An SQL statement */ ImportCtx sCtx; /* Reader context */ - char *(*xRead)(ImportCtx*); /* Procedure to read one value */ - int (*xCloser)(FILE*); /* Procedure to close th3 connection */ + char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */ + int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */ if( nArg!=3 ){ fprintf(stderr, "Usage: .import FILE TABLE\n"); @@ -2802,9 +2997,14 @@ static int do_meta_command(char *zLine, ShellState *p){ sCtx.zFile = zFile; sCtx.nLine = 1; if( sCtx.zFile[0]=='|' ){ +#ifdef SQLITE_OMIT_POPEN + fprintf(stderr, "Error: pipes are not supported in this OS\n"); + return 1; +#else sCtx.in = popen(sCtx.zFile+1, "r"); sCtx.zFile = ""; xCloser = pclose; +#endif }else{ sCtx.in = fopen(sCtx.zFile, "rb"); xCloser = fclose; @@ -2829,7 +3029,7 @@ static int do_meta_command(char *zLine, ShellState *p){ nByte = strlen30(zSql); rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */ - if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){ + if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){ char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable); char cSep = '('; while( xRead(&sCtx) ){ @@ -2849,7 +3049,7 @@ static int do_meta_command(char *zLine, ShellState *p){ sqlite3_free(zCreate); if( rc ){ fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable, - sqlite3_errmsg(db)); + sqlite3_errmsg(p->db)); sqlite3_free(sCtx.z); xCloser(sCtx.in); return 1; @@ -2859,7 +3059,7 @@ static int do_meta_command(char *zLine, ShellState *p){ sqlite3_free(zSql); if( rc ){ if (pStmt) sqlite3_finalize(pStmt); - fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); + fprintf(stderr,"Error: %s\n", sqlite3_errmsg(p->db)); xCloser(sCtx.in); return 1; } @@ -2867,7 +3067,7 @@ static int do_meta_command(char *zLine, ShellState *p){ sqlite3_finalize(pStmt); pStmt = 0; if( nCol==0 ) return 0; /* no columns, no error */ - zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 ); + zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 ); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); xCloser(sCtx.in); @@ -2884,13 +3084,13 @@ static int do_meta_command(char *zLine, ShellState *p){ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ){ - fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); + fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); if (pStmt) sqlite3_finalize(pStmt); xCloser(sCtx.in); return 1; } - needCommit = sqlite3_get_autocommit(db); - if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0); + needCommit = sqlite3_get_autocommit(p->db); + if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0); do{ int startLine = sCtx.nLine; for(i=0; idb)); } } }while( sCtx.cTerm!=EOF ); @@ -2937,10 +3137,11 @@ static int do_meta_command(char *zLine, ShellState *p){ xCloser(sCtx.in); sqlite3_free(sCtx.z); sqlite3_finalize(pStmt); - if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0); + if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0); }else - if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){ + if( c=='i' && (strncmp(azArg[0], "indices", n)==0 + || strncmp(azArg[0], "indexes", n)==0) ){ ShellState data; char *zErrMsg = 0; open_db(p, 0); @@ -2970,7 +3171,7 @@ static int do_meta_command(char *zLine, ShellState *p){ ); zShellStatic = 0; }else{ - fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n"); + fprintf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n"); rc = 1; goto meta_command_exit; } @@ -2986,7 +3187,7 @@ static int do_meta_command(char *zLine, ShellState *p){ #ifdef SQLITE_ENABLE_IOTRACE if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){ - extern void (*sqlite3IoTrace)(const char*, ...); + SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...); if( iotrace && iotrace!=stdout ) fclose(iotrace); iotrace = 0; if( nArg<2 ){ @@ -3006,6 +3207,64 @@ static int do_meta_command(char *zLine, ShellState *p){ } }else #endif + if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){ + static const struct { + const char *zLimitName; /* Name of a limit */ + int limitCode; /* Integer code for that limit */ + } aLimit[] = { + { "length", SQLITE_LIMIT_LENGTH }, + { "sql_length", SQLITE_LIMIT_SQL_LENGTH }, + { "column", SQLITE_LIMIT_COLUMN }, + { "expr_depth", SQLITE_LIMIT_EXPR_DEPTH }, + { "compound_select", SQLITE_LIMIT_COMPOUND_SELECT }, + { "vdbe_op", SQLITE_LIMIT_VDBE_OP }, + { "function_arg", SQLITE_LIMIT_FUNCTION_ARG }, + { "attached", SQLITE_LIMIT_ATTACHED }, + { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, + { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER }, + { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH }, + { "worker_threads", SQLITE_LIMIT_WORKER_THREADS }, + }; + int i, n2; + open_db(p, 0); + if( nArg==1 ){ + for(i=0; idb, aLimit[i].limitCode, -1)); + } + }else if( nArg>3 ){ + fprintf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n"); + rc = 1; + goto meta_command_exit; + }else{ + int iLimit = -1; + n2 = strlen30(azArg[1]); + for(i=0; idb, aLimit[iLimit].limitCode, + (int)integerValue(azArg[2])); + } + printf("%20s %d\n", aLimit[iLimit].zLimitName, + sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1)); + } + }else #ifndef SQLITE_OMIT_LOAD_EXTENSION if( c=='l' && strncmp(azArg[0], "load", n)==0 ){ @@ -3126,6 +3385,11 @@ static int do_meta_command(char *zLine, ShellState *p){ } output_reset(p); if( zFile[0]=='|' ){ +#ifdef SQLITE_OMIT_POPEN + fprintf(stderr,"Error: pipes are not supported in this OS\n"); + rc = 1; + p->out = stdout; +#else p->out = popen(zFile + 1, "w"); if( p->out==0 ){ fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1); @@ -3134,6 +3398,7 @@ static int do_meta_command(char *zLine, ShellState *p){ }else{ sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); } +#endif }else{ p->out = output_file_open(zFile); if( p->out==0 ){ @@ -3333,7 +3598,7 @@ static int do_meta_command(char *zLine, ShellState *p){ #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){ extern int sqlite3SelectTrace; - sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff; + sqlite3SelectTrace = integerValue(azArg[1]); }else #endif @@ -3484,13 +3749,13 @@ static int do_meta_command(char *zLine, ShellState *p){ while( sqlite3_step(pStmt)==SQLITE_ROW ){ if( nRow>=nAlloc ){ char **azNew; - int n = nAlloc*2 + 10; - azNew = sqlite3_realloc(azResult, sizeof(azResult[0])*n); + int n2 = nAlloc*2 + 10; + azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2); if( azNew==0 ){ fprintf(stderr, "Error: out of memory\n"); break; } - nAlloc = n; + nAlloc = n2; azResult = azNew; } azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0)); @@ -3539,17 +3804,19 @@ static int do_meta_command(char *zLine, ShellState *p){ { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD }, { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC }, { "byteorder", SQLITE_TESTCTRL_BYTEORDER }, + { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT }, + { "imposter", SQLITE_TESTCTRL_IMPOSTER }, }; int testctrl = -1; - int rc = 0; - int i, n; + int rc2 = 0; + int i, n2; open_db(p, 0); /* convert testctrl text option to value. allow any unique prefix ** of the option name, or a numerical value. */ - n = strlen30(azArg[1]); + n2 = strlen30(azArg[1]); for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){ - if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){ + if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){ if( testctrl<0 ){ testctrl = aCtrl[i].ctrlCode; }else{ @@ -3570,8 +3837,8 @@ static int do_meta_command(char *zLine, ShellState *p){ case SQLITE_TESTCTRL_RESERVE: if( nArg==3 ){ int opt = (int)strtol(azArg[2], 0, 0); - rc = sqlite3_test_control(testctrl, p->db, opt); - fprintf(p->out, "%d (0x%08x)\n", rc, rc); + rc2 = sqlite3_test_control(testctrl, p->db, opt); + fprintf(p->out, "%d (0x%08x)\n", rc2, rc2); } else { fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]); @@ -3584,8 +3851,8 @@ static int do_meta_command(char *zLine, ShellState *p){ case SQLITE_TESTCTRL_PRNG_RESET: case SQLITE_TESTCTRL_BYTEORDER: if( nArg==2 ){ - rc = sqlite3_test_control(testctrl); - fprintf(p->out, "%d (0x%08x)\n", rc, rc); + rc2 = sqlite3_test_control(testctrl); + fprintf(p->out, "%d (0x%08x)\n", rc2, rc2); } else { fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]); } @@ -3595,8 +3862,8 @@ static int do_meta_command(char *zLine, ShellState *p){ case SQLITE_TESTCTRL_PENDING_BYTE: if( nArg==3 ){ unsigned int opt = (unsigned int)integerValue(azArg[2]); - rc = sqlite3_test_control(testctrl, opt); - fprintf(p->out, "%d (0x%08x)\n", rc, rc); + rc2 = sqlite3_test_control(testctrl, opt); + fprintf(p->out, "%d (0x%08x)\n", rc2, rc2); } else { fprintf(stderr,"Error: testctrl %s takes a single unsigned" " int option\n", azArg[1]); @@ -3605,11 +3872,12 @@ static int do_meta_command(char *zLine, ShellState *p){ /* sqlite3_test_control(int, int) */ case SQLITE_TESTCTRL_ASSERT: - case SQLITE_TESTCTRL_ALWAYS: + case SQLITE_TESTCTRL_ALWAYS: + case SQLITE_TESTCTRL_NEVER_CORRUPT: if( nArg==3 ){ int opt = booleanValue(azArg[2]); - rc = sqlite3_test_control(testctrl, opt); - fprintf(p->out, "%d (0x%08x)\n", rc, rc); + rc2 = sqlite3_test_control(testctrl, opt); + fprintf(p->out, "%d (0x%08x)\n", rc2, rc2); } else { fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]); @@ -3621,8 +3889,8 @@ static int do_meta_command(char *zLine, ShellState *p){ case SQLITE_TESTCTRL_ISKEYWORD: if( nArg==3 ){ const char *opt = azArg[2]; - rc = sqlite3_test_control(testctrl, opt); - fprintf(p->out, "%d (0x%08x)\n", rc, rc); + rc2 = sqlite3_test_control(testctrl, opt); + fprintf(p->out, "%d (0x%08x)\n", rc2, rc2); } else { fprintf(stderr,"Error: testctrl %s takes a single char * option\n", azArg[1]); @@ -3630,6 +3898,18 @@ static int do_meta_command(char *zLine, ShellState *p){ break; #endif + case SQLITE_TESTCTRL_IMPOSTER: + if( nArg==5 ){ + rc2 = sqlite3_test_control(testctrl, p->db, + azArg[2], + integerValue(azArg[3]), + integerValue(azArg[4])); + fprintf(p->out, "%d (0x%08x)\n", rc2, rc2); + }else{ + fprintf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n"); + } + break; + case SQLITE_TESTCTRL_BITVEC_TEST: case SQLITE_TESTCTRL_FAULT_INSTALL: case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: @@ -3662,12 +3942,12 @@ static int do_meta_command(char *zLine, ShellState *p){ if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){ open_db(p, 0); - output_file_close(p->traceOut); if( nArg!=2 ){ fprintf(stderr, "Usage: .trace FILE|off\n"); rc = 1; goto meta_command_exit; } + output_file_close(p->traceOut); p->traceOut = output_file_open(azArg[1]); #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) if( p->traceOut==0 ){ @@ -3932,6 +4212,7 @@ static int process_input(ShellState *p, FILE *in){ && sqlite3_complete(zSql) ){ p->cnt = 0; open_db(p, 0); + if( p->backslashOn ) resolve_backslashes(zSql); BEGIN_TIMER; rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg); END_TIMER; @@ -4043,7 +4324,7 @@ static char *find_home_dir(void){ ** ** Returns the number of errors. */ -static int process_sqliterc( +static void process_sqliterc( ShellState *p, /* Configuration data */ const char *sqliterc_override /* Name of config file. NULL to use default */ ){ @@ -4051,15 +4332,13 @@ static int process_sqliterc( const char *sqliterc = sqliterc_override; char *zBuf = 0; FILE *in = NULL; - int rc = 0; if (sqliterc == NULL) { home_dir = find_home_dir(); if( home_dir==0 ){ -#if !defined(__RTP__) && !defined(_WRS_KERNEL) - fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0); -#endif - return 1; + fprintf(stderr, "-- warning: cannot find home directory;" + " cannot read ~/.sqliterc\n"); + return; } sqlite3_initialize(); zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir); @@ -4070,11 +4349,10 @@ static int process_sqliterc( if( stdin_is_interactive ){ fprintf(stderr,"-- Loading resources from %s\n",sqliterc); } - rc = process_input(p,in); + process_input(p,in); fclose(in); } sqlite3_free(zBuf); - return rc; } /* @@ -4178,7 +4456,7 @@ static char *cmdline_option_value(int argc, char **argv, int i){ return argv[i]; } -int main(int argc, char **argv){ +int SQLITE_CDECL main(int argc, char **argv){ char *zErrMsg = 0; ShellState data; const char *zInitFile = 0; @@ -4196,6 +4474,8 @@ int main(int argc, char **argv){ exit(1); } #endif + setBinaryMode(stdin); + setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ Argv0 = argv[0]; main_init(&data); stdin_is_interactive = isatty(0); @@ -4348,10 +4628,7 @@ int main(int argc, char **argv){ ** is given on the command line, look for a file named ~/.sqliterc and ** try to process it. */ - rc = process_sqliterc(&data,zInitFile); - if( rc>0 ){ - return rc; - } + process_sqliterc(&data,zInitFile); /* Make a second pass through the command-line argument and set ** options. This second pass is delayed until after the initialization @@ -4402,6 +4679,13 @@ int main(int argc, char **argv){ data.statsOn = 1; }else if( strcmp(z,"-scanstats")==0 ){ data.scanstatsOn = 1; + }else if( strcmp(z,"-backslash")==0 ){ + /* Undocumented command-line option: -backslash + ** Causes C-style backslash escapes to be evaluated in SQL statements + ** prior to sending the SQL into SQLite. Useful for injecting + ** crazy bytes in the middle of SQL statements for testing and debugging. + */ + data.backslashOn = 1; }else if( strcmp(z,"-bail")==0 ){ bail_on_error = 1; }else if( strcmp(z,"-version")==0 ){ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index f2e802e..163bc69 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -43,11 +43,20 @@ extern "C" { /* -** Add the ability to override 'extern' +** Provide the ability to override linkage features of the interface. */ #ifndef SQLITE_EXTERN # define SQLITE_EXTERN extern #endif +#ifndef SQLITE_API +# define SQLITE_API +#endif +#ifndef SQLITE_CDECL +# define SQLITE_CDECL +#endif +#ifndef SQLITE_STDCALL +# define SQLITE_STDCALL +#endif /* ** These no-op macros are used in front of interfaces to mark those @@ -261,6 +270,7 @@ typedef sqlite_uint64 sqlite3_uint64; /* ** CAPI3REF: Closing A Database Connection +** DESTRUCTOR: sqlite3 ** ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors ** for the [sqlite3] object. @@ -312,6 +322,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); /* ** CAPI3REF: One-Step Query Execution Interface +** METHOD: sqlite3 ** ** The sqlite3_exec() interface is a convenience wrapper around ** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], @@ -751,14 +762,16 @@ struct sqlite3_io_methods { ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] ** interface. ** +**
      +**
    • [[SQLITE_FCNTL_LOCKSTATE]] ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) ** into an integer that the pArg argument points to. This capability -** is used during testing and only needs to be supported when SQLITE_TEST -** is defined. -**
        +** is used during testing and is only available when the SQLITE_TEST +** compile-time option is used. +** **
      • [[SQLITE_FCNTL_SIZE_HINT]] ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS ** layer a hint of how large the database file will grow to be during the @@ -883,7 +896,9 @@ struct sqlite3_io_methods { ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] ** file control returns [SQLITE_OK], then the parser assumes that the ** VFS has handled the PRAGMA itself and the parser generates a no-op -** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns +** prepared statement if result string is NULL, or that returns a copy +** of the result string if the string is non-NULL. +** ^If the [SQLITE_FCNTL_PRAGMA] file control returns ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means ** that the VFS encountered an error while handling the [PRAGMA] and the ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] @@ -941,12 +956,19 @@ struct sqlite3_io_methods { ** pointed to by the pArg argument. This capability is used during testing ** and only needs to be supported when SQLITE_TEST is defined. ** +**
      • [[SQLITE_FCNTL_WAL_BLOCK]] +** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might +** be advantageous to block on the next WAL lock if the lock is not immediately +** available. The WAL subsystem issues this signal during rare +** circumstances in order to fix a problem with priority inversion. +** Applications should not use this file-control. +** **
      */ #define SQLITE_FCNTL_LOCKSTATE 1 -#define SQLITE_GET_LOCKPROXYFILE 2 -#define SQLITE_SET_LOCKPROXYFILE 3 -#define SQLITE_LAST_ERRNO 4 +#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 +#define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 +#define SQLITE_FCNTL_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 @@ -965,6 +987,13 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_SYNC 21 #define SQLITE_FCNTL_COMMIT_PHASETWO 22 #define SQLITE_FCNTL_WIN32_SET_HANDLE 23 +#define SQLITE_FCNTL_WAL_BLOCK 24 + +/* deprecated names */ +#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE +#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE +#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO + /* ** CAPI3REF: Mutex Handle @@ -1351,6 +1380,7 @@ int sqlite3_config(int, ...); /* ** CAPI3REF: Configure database connections +** METHOD: sqlite3 ** ** The sqlite3_db_config() interface is used to make configuration ** changes to a [database connection]. The interface is similar to @@ -1525,7 +1555,7 @@ struct sqlite3_mem_methods { **
    • [sqlite3_memory_used()] **
    • [sqlite3_memory_highwater()] **
    • [sqlite3_soft_heap_limit64()] -**
    • [sqlite3_status()] +**
    • [sqlite3_status64()] **
    )^ ** ^Memory allocation statistics are enabled by default unless SQLite is ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory @@ -1736,7 +1766,6 @@ struct sqlite3_mem_methods { ** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro ** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value ** that specifies the maximum size of the created heap. -** ** ** [[SQLITE_CONFIG_PCACHE_HDRSZ]] **
    SQLITE_CONFIG_PCACHE_HDRSZ @@ -1849,6 +1878,7 @@ struct sqlite3_mem_methods { /* ** CAPI3REF: Enable Or Disable Extended Result Codes +** METHOD: sqlite3 ** ** ^The sqlite3_extended_result_codes() routine enables or disables the ** [extended result codes] feature of SQLite. ^The extended result @@ -1858,6 +1888,7 @@ int sqlite3_extended_result_codes(sqlite3*, int onoff); /* ** CAPI3REF: Last Insert Rowid +** METHOD: sqlite3 ** ** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables) ** has a unique 64-bit signed @@ -1909,6 +1940,7 @@ sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); /* ** CAPI3REF: Count The Number Of Rows Modified +** METHOD: sqlite3 ** ** ^This function returns the number of rows modified, inserted or ** deleted by the most recently completed INSERT, UPDATE or DELETE @@ -1961,6 +1993,7 @@ int sqlite3_changes(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified +** METHOD: sqlite3 ** ** ^This function returns the total number of rows inserted, modified or ** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed @@ -1984,6 +2017,7 @@ int sqlite3_total_changes(sqlite3*); /* ** CAPI3REF: Interrupt A Long-Running Query +** METHOD: sqlite3 ** ** ^This function causes any pending database operation to abort and ** return at its earliest opportunity. This routine is typically @@ -2060,6 +2094,7 @@ int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors ** KEYWORDS: {busy-handler callback} {busy handler} +** METHOD: sqlite3 ** ** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X ** that might be invoked with argument P whenever @@ -2119,6 +2154,7 @@ int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); /* ** CAPI3REF: Set A Busy Timeout +** METHOD: sqlite3 ** ** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps ** for a specified amount of time when a table is locked. ^The handler @@ -2141,6 +2177,7 @@ int sqlite3_busy_timeout(sqlite3*, int ms); /* ** CAPI3REF: Convenience Routines For Running Queries +** METHOD: sqlite3 ** ** This is a legacy interface that is preserved for backwards compatibility. ** Use of this interface is not recommended. @@ -2226,6 +2263,10 @@ void sqlite3_free_table(char **result); ** ** These routines are work-alikes of the "printf()" family of functions ** from the standard C library. +** These routines understand most of the common K&R formatting options, +** plus some additional non-standard formats, detailed below. +** Note that some of the more obscure formatting options from recent +** C-library standards are omitted from this implementation. ** ** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their ** results into memory obtained from [sqlite3_malloc()]. @@ -2258,7 +2299,7 @@ void sqlite3_free_table(char **result); ** These routines all implement some additional formatting ** options that are useful for constructing SQL statements. ** All of the usual printf() formatting options apply. In addition, there -** is are "%q", "%Q", and "%z" options. +** is are "%q", "%Q", "%w" and "%z" options. ** ** ^(The %q option works like %s in that it substitutes a nul-terminated ** string from the argument list. But %q also doubles every '\'' character. @@ -2311,6 +2352,12 @@ void sqlite3_free_table(char **result); ** The code above will render a correct SQL statement in the zSQL ** variable even if the zText variable is a NULL pointer. ** +** ^(The "%w" formatting option is like "%q" except that it expects to +** be contained within double-quotes instead of single quotes, and it +** escapes the double-quote character instead of the single-quote +** character.)^ The "%w" formatting option is intended for safely inserting +** table and column names into a constructed SQL statement. +** ** ^(The "%z" formatting option works like "%s" but with the ** addition that after the string has been read and copied into ** the result, [sqlite3_free()] is called on the input string.)^ @@ -2466,6 +2513,7 @@ void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks +** METHOD: sqlite3 ** ** ^This routine registers an authorizer callback with a particular ** [database connection], supplied in the first argument. @@ -2622,6 +2670,7 @@ int sqlite3_set_authorizer( /* ** CAPI3REF: Tracing And Profiling Functions +** METHOD: sqlite3 ** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. @@ -2654,6 +2703,7 @@ SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*, /* ** CAPI3REF: Query Progress Callbacks +** METHOD: sqlite3 ** ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to @@ -2687,6 +2737,7 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); /* ** CAPI3REF: Opening A New Database Connection +** CONSTRUCTOR: sqlite3 ** ** ^These routines open an SQLite database file as specified by the ** filename argument. ^The filename argument is interpreted as UTF-8 for @@ -2972,12 +3023,15 @@ sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); /* ** CAPI3REF: Error Codes And Messages +** METHOD: sqlite3 ** -** ^The sqlite3_errcode() interface returns the numeric [result code] or -** [extended result code] for the most recent failed sqlite3_* API call -** associated with a [database connection]. If a prior API call failed -** but the most recent API call succeeded, the return value from -** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode() +** ^If the most recent sqlite3_* API call associated with +** [database connection] D failed, then the sqlite3_errcode(D) interface +** returns the numeric [result code] or [extended result code] for that +** API call. +** If the most recent API call was successful, +** then the return value from sqlite3_errcode() is undefined. +** ^The sqlite3_extended_errcode() ** interface is the same except that it always returns the ** [extended result code] even when extended result codes are ** disabled. @@ -3015,33 +3069,34 @@ const void *sqlite3_errmsg16(sqlite3*); const char *sqlite3_errstr(int); /* -** CAPI3REF: SQL Statement Object +** CAPI3REF: Prepared Statement Object ** KEYWORDS: {prepared statement} {prepared statements} ** -** An instance of this object represents a single SQL statement. -** This object is variously known as a "prepared statement" or a -** "compiled SQL statement" or simply as a "statement". +** An instance of this object represents a single SQL statement that +** has been compiled into binary form and is ready to be evaluated. ** -** The life of a statement object goes something like this: +** Think of each SQL statement as a separate computer program. The +** original SQL text is source code. A prepared statement object +** is the compiled object code. All SQL must be converted into a +** prepared statement before it can be run. +** +** The life-cycle of a prepared statement object usually goes like this: ** **
      -**
    1. Create the object using [sqlite3_prepare_v2()] or a related -** function. -**
    2. Bind values to [host parameters] using the sqlite3_bind_*() +**
    3. Create the prepared statement object using [sqlite3_prepare_v2()]. +**
    4. Bind values to [parameters] using the sqlite3_bind_*() ** interfaces. **
    5. Run the SQL by calling [sqlite3_step()] one or more times. -**
    6. Reset the statement using [sqlite3_reset()] then go back +**
    7. Reset the prepared statement using [sqlite3_reset()] then go back ** to step 2. Do this zero or more times. **
    8. Destroy the object using [sqlite3_finalize()]. **
    -** -** Refer to documentation on individual methods above for additional -** information. */ typedef struct sqlite3_stmt sqlite3_stmt; /* ** CAPI3REF: Run-time Limits +** METHOD: sqlite3 ** ** ^(This interface allows the size of various constructs to be limited ** on a connection by connection basis. The first parameter is the @@ -3153,6 +3208,8 @@ int sqlite3_limit(sqlite3*, int id, int newVal); /* ** CAPI3REF: Compiling An SQL Statement ** KEYWORDS: {SQL statement compiler} +** METHOD: sqlite3 +** CONSTRUCTOR: sqlite3_stmt ** ** To execute an SQL query, it must first be compiled into a byte-code ** program using one of these routines. @@ -3166,16 +3223,14 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() ** use UTF-16. ** -** ^If the nByte argument is less than zero, then zSql is read up to the -** first zero terminator. ^If nByte is non-negative, then it is the maximum -** number of bytes read from zSql. ^When nByte is non-negative, the -** zSql string ends at either the first '\000' or '\u0000' character or -** the nByte-th byte, whichever comes first. If the caller knows -** that the supplied string is nul-terminated, then there is a small -** performance advantage to be gained by passing an nByte parameter that -** is equal to the number of bytes in the input string including -** the nul-terminator bytes as this saves SQLite from having to -** make a copy of the input string. +** ^If the nByte argument is negative, then zSql is read up to the +** first zero terminator. ^If nByte is positive, then it is the +** number of bytes read from zSql. ^If nByte is zero, then no prepared +** statement is generated. +** If the caller knows that the supplied string is nul-terminated, then +** there is a small performance advantage to passing an nByte parameter that +** is the number of bytes in the input string including +** the nul-terminator. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** past the end of the first SQL statement in zSql. These routines only @@ -3262,6 +3317,7 @@ int sqlite3_prepare16_v2( /* ** CAPI3REF: Retrieving Statement SQL +** METHOD: sqlite3_stmt ** ** ^This interface can be used to retrieve a saved copy of the original ** SQL text used to create a [prepared statement] if that statement was @@ -3271,6 +3327,7 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database +** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if ** and only if the [prepared statement] X makes no direct changes to @@ -3302,6 +3359,7 @@ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset +** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the ** [prepared statement] S has been stepped at least once using @@ -3376,6 +3434,7 @@ typedef struct sqlite3_context sqlite3_context; ** CAPI3REF: Binding Values To Prepared Statements ** KEYWORDS: {host parameter} {host parameters} {host parameter name} ** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding} +** METHOD: sqlite3_stmt ** ** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants, ** literals may be replaced by a [parameter] that matches one of following @@ -3494,6 +3553,7 @@ int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); /* ** CAPI3REF: Number Of SQL Parameters +** METHOD: sqlite3_stmt ** ** ^This routine can be used to find the number of [SQL parameters] ** in a [prepared statement]. SQL parameters are tokens of the @@ -3514,6 +3574,7 @@ int sqlite3_bind_parameter_count(sqlite3_stmt*); /* ** CAPI3REF: Name Of A Host Parameter +** METHOD: sqlite3_stmt ** ** ^The sqlite3_bind_parameter_name(P,N) interface returns ** the name of the N-th [SQL parameter] in the [prepared statement] P. @@ -3541,6 +3602,7 @@ const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); /* ** CAPI3REF: Index Of A Parameter With A Given Name +** METHOD: sqlite3_stmt ** ** ^Return the index of an SQL parameter given its name. ^The ** index value returned is suitable for use as the second @@ -3557,6 +3619,7 @@ int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); /* ** CAPI3REF: Reset All Bindings On A Prepared Statement +** METHOD: sqlite3_stmt ** ** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset ** the [sqlite3_bind_blob | bindings] on a [prepared statement]. @@ -3566,6 +3629,7 @@ int sqlite3_clear_bindings(sqlite3_stmt*); /* ** CAPI3REF: Number Of Columns In A Result Set +** METHOD: sqlite3_stmt ** ** ^Return the number of columns in the result set returned by the ** [prepared statement]. ^This routine returns 0 if pStmt is an SQL @@ -3577,6 +3641,7 @@ int sqlite3_column_count(sqlite3_stmt *pStmt); /* ** CAPI3REF: Column Names In A Result Set +** METHOD: sqlite3_stmt ** ** ^These routines return the name assigned to a particular column ** in the result set of a [SELECT] statement. ^The sqlite3_column_name() @@ -3606,6 +3671,7 @@ const void *sqlite3_column_name16(sqlite3_stmt*, int N); /* ** CAPI3REF: Source Of Data In A Query Result +** METHOD: sqlite3_stmt ** ** ^These routines provide a means to determine the database, table, and ** table column that is the origin of a particular result column in @@ -3658,6 +3724,7 @@ const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); /* ** CAPI3REF: Declared Datatype Of A Query Result +** METHOD: sqlite3_stmt ** ** ^(The first parameter is a [prepared statement]. ** If this statement is a [SELECT] statement and the Nth column of the @@ -3690,6 +3757,7 @@ const void *sqlite3_column_decltype16(sqlite3_stmt*,int); /* ** CAPI3REF: Evaluate An SQL Statement +** METHOD: sqlite3_stmt ** ** After a [prepared statement] has been prepared using either ** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy @@ -3769,6 +3837,7 @@ int sqlite3_step(sqlite3_stmt*); /* ** CAPI3REF: Number of columns in a result set +** METHOD: sqlite3_stmt ** ** ^The sqlite3_data_count(P) interface returns the number of columns in the ** current row of the result set of [prepared statement] P. @@ -3822,6 +3891,7 @@ int sqlite3_data_count(sqlite3_stmt *pStmt); /* ** CAPI3REF: Result Values From A Query ** KEYWORDS: {column access functions} +** METHOD: sqlite3_stmt ** ** These routines form the "result set" interface. ** @@ -3994,6 +4064,7 @@ sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); /* ** CAPI3REF: Destroy A Prepared Statement Object +** DESTRUCTOR: sqlite3_stmt ** ** ^The sqlite3_finalize() function is called to delete a [prepared statement]. ** ^If the most recent evaluation of the statement encountered no errors @@ -4021,6 +4092,7 @@ int sqlite3_finalize(sqlite3_stmt *pStmt); /* ** CAPI3REF: Reset A Prepared Statement Object +** METHOD: sqlite3_stmt ** ** The sqlite3_reset() function is called to reset a [prepared statement] ** object back to its initial state, ready to be re-executed. @@ -4050,6 +4122,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt); ** KEYWORDS: {function creation routines} ** KEYWORDS: {application-defined SQL function} ** KEYWORDS: {application-defined SQL functions} +** METHOD: sqlite3 ** ** ^These functions (collectively known as "function creation routines") ** are used to add SQL functions or aggregates or to redefine the behavior @@ -4204,8 +4277,8 @@ int sqlite3_create_function_v2( ** These functions are [deprecated]. In order to maintain ** backwards compatibility with older code, these functions continue ** to be supported. However, new applications should avoid -** the use of these functions. To help encourage people to avoid -** using these functions, we are not going to tell you what they do. +** the use of these functions. To encourage programmers to avoid +** these functions, we will not explain what they do. */ #ifndef SQLITE_OMIT_DEPRECATED SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); @@ -4219,6 +4292,7 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), /* ** CAPI3REF: Obtaining SQL Function Parameter Values +** METHOD: sqlite3_value ** ** The C-language implementation of SQL functions and aggregates uses ** this set of interface routines to access the parameter values on @@ -4277,6 +4351,7 @@ int sqlite3_value_numeric_type(sqlite3_value*); /* ** CAPI3REF: Obtain Aggregate Function Context +** METHOD: sqlite3_context ** ** Implementations of aggregate SQL functions use this ** routine to allocate memory for storing their state. @@ -4321,6 +4396,7 @@ void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); /* ** CAPI3REF: User Data For Functions +** METHOD: sqlite3_context ** ** ^The sqlite3_user_data() interface returns a copy of ** the pointer that was the pUserData parameter (the 5th parameter) @@ -4335,6 +4411,7 @@ void *sqlite3_user_data(sqlite3_context*); /* ** CAPI3REF: Database Connection For Functions +** METHOD: sqlite3_context ** ** ^The sqlite3_context_db_handle() interface returns a copy of ** the pointer to the [database connection] (the 1st parameter) @@ -4346,6 +4423,7 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*); /* ** CAPI3REF: Function Auxiliary Data +** METHOD: sqlite3_context ** ** These functions may be used by (non-aggregate) SQL functions to ** associate metadata with argument values. If the same value is passed to @@ -4418,6 +4496,7 @@ typedef void (*sqlite3_destructor_type)(void*); /* ** CAPI3REF: Setting The Result Of An SQL Function +** METHOD: sqlite3_context ** ** These routines are used by the xFunc or xFinal callbacks that ** implement SQL functions and aggregates. See @@ -4553,6 +4632,7 @@ void sqlite3_result_zeroblob(sqlite3_context*, int n); /* ** CAPI3REF: Define New Collating Sequences +** METHOD: sqlite3 ** ** ^These functions add, remove, or modify a [collation] associated ** with the [database connection] specified as the first argument. @@ -4655,6 +4735,7 @@ int sqlite3_create_collation16( /* ** CAPI3REF: Collation Needed Callbacks +** METHOD: sqlite3 ** ** ^To avoid having to register all collation sequences before a database ** can be used, a single callback function may be registered with the @@ -4862,6 +4943,7 @@ SQLITE_EXTERN char *sqlite3_data_directory; /* ** CAPI3REF: Test For Auto-Commit Mode ** KEYWORDS: {autocommit mode} +** METHOD: sqlite3 ** ** ^The sqlite3_get_autocommit() interface returns non-zero or ** zero if the given database connection is or is not in autocommit mode, @@ -4884,6 +4966,7 @@ int sqlite3_get_autocommit(sqlite3*); /* ** CAPI3REF: Find The Database Handle Of A Prepared Statement +** METHOD: sqlite3_stmt ** ** ^The sqlite3_db_handle interface returns the [database connection] handle ** to which a [prepared statement] belongs. ^The [database connection] @@ -4896,6 +4979,7 @@ sqlite3 *sqlite3_db_handle(sqlite3_stmt*); /* ** CAPI3REF: Return The Filename For A Database Connection +** METHOD: sqlite3 ** ** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename ** associated with database N of connection D. ^The main database file @@ -4912,6 +4996,7 @@ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Determine if a database is read-only +** METHOD: sqlite3 ** ** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N ** of connection D is read-only, 0 if it is read/write, or -1 if N is not @@ -4921,6 +5006,7 @@ int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Find the next prepared statement +** METHOD: sqlite3 ** ** ^This interface returns a pointer to the next [prepared statement] after ** pStmt associated with the [database connection] pDb. ^If pStmt is NULL @@ -4936,6 +5022,7 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); /* ** CAPI3REF: Commit And Rollback Notification Callbacks +** METHOD: sqlite3 ** ** ^The sqlite3_commit_hook() interface registers a callback ** function to be invoked whenever a transaction is [COMMIT | committed]. @@ -4985,6 +5072,7 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** CAPI3REF: Data Change Notification Callbacks +** METHOD: sqlite3 ** ** ^The sqlite3_update_hook() interface registers a callback function ** with the [database connection] identified by the first argument @@ -5061,6 +5149,11 @@ void *sqlite3_update_hook( ** future releases of SQLite. Applications that care about shared ** cache setting should set it explicitly. ** +** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0 +** and will always return SQLITE_MISUSE. On those systems, +** shared cache mode should be enabled per-database connection via +** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE]. +** ** This interface is threadsafe on processors where writing a ** 32-bit integer is atomic. ** @@ -5086,6 +5179,7 @@ int sqlite3_release_memory(int); /* ** CAPI3REF: Free Memory Used By A Database Connection +** METHOD: sqlite3 ** ** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap ** memory as possible from database connection D. Unlike the @@ -5163,6 +5257,7 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); /* ** CAPI3REF: Extract Metadata About A Column Of A Table +** METHOD: sqlite3 ** ** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns ** information about column C of table T in database D @@ -5241,6 +5336,7 @@ int sqlite3_table_column_metadata( /* ** CAPI3REF: Load An Extension +** METHOD: sqlite3 ** ** ^This interface loads an SQLite extension library from the named file. ** @@ -5282,6 +5378,7 @@ int sqlite3_load_extension( /* ** CAPI3REF: Enable Or Disable Extension Loading +** METHOD: sqlite3 ** ** ^So as not to open security holes in older applications that are ** unprepared to deal with [extension loading], and as a means of disabling @@ -5531,6 +5628,7 @@ struct sqlite3_index_info { /* ** CAPI3REF: Register A Virtual Table Implementation +** METHOD: sqlite3 ** ** ^These routines are used to register a new [virtual table module] name. ** ^Module names must be registered before @@ -5588,7 +5686,7 @@ int sqlite3_create_module_v2( */ struct sqlite3_vtab { const sqlite3_module *pModule; /* The module for this virtual table */ - int nRef; /* NO LONGER USED */ + int nRef; /* Number of open cursors */ char *zErrMsg; /* Error message from sqlite3_mprintf() */ /* Virtual table implementations will typically add additional fields */ }; @@ -5627,6 +5725,7 @@ int sqlite3_declare_vtab(sqlite3*, const char *zSQL); /* ** CAPI3REF: Overload A Function For A Virtual Table +** METHOD: sqlite3 ** ** ^(Virtual tables can provide alternative implementations of functions ** using the [xFindFunction] method of the [virtual table module]. @@ -5669,6 +5768,8 @@ typedef struct sqlite3_blob sqlite3_blob; /* ** CAPI3REF: Open A BLOB For Incremental I/O +** METHOD: sqlite3 +** CONSTRUCTOR: sqlite3_blob ** ** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located ** in row iRow, column zColumn, table zTable in database zDb; @@ -5750,6 +5851,7 @@ int sqlite3_blob_open( /* ** CAPI3REF: Move a BLOB Handle to a New Row +** METHOD: sqlite3_blob ** ** ^This function is used to move an existing blob handle so that it points ** to a different row of the same database table. ^The new row is identified @@ -5774,6 +5876,7 @@ SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); /* ** CAPI3REF: Close A BLOB Handle +** DESTRUCTOR: sqlite3_blob ** ** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed ** unconditionally. Even if this routine returns an error code, the @@ -5796,6 +5899,7 @@ int sqlite3_blob_close(sqlite3_blob *); /* ** CAPI3REF: Return The Size Of An Open BLOB +** METHOD: sqlite3_blob ** ** ^Returns the size in bytes of the BLOB accessible via the ** successfully opened [BLOB handle] in its only argument. ^The @@ -5811,6 +5915,7 @@ int sqlite3_blob_bytes(sqlite3_blob *); /* ** CAPI3REF: Read Data From A BLOB Incrementally +** METHOD: sqlite3_blob ** ** ^(This function is used to read data from an open [BLOB handle] into a ** caller-supplied buffer. N bytes of data are copied into buffer Z @@ -5839,6 +5944,7 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); /* ** CAPI3REF: Write Data Into A BLOB Incrementally +** METHOD: sqlite3_blob ** ** ^(This function is used to write data into an open [BLOB handle] from a ** caller-supplied buffer. N bytes of data are copied from the buffer Z @@ -6166,6 +6272,7 @@ int sqlite3_mutex_notheld(sqlite3_mutex*); /* ** CAPI3REF: Retrieve the mutex for a database connection +** METHOD: sqlite3 ** ** ^This interface returns a pointer the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument @@ -6177,6 +6284,7 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*); /* ** CAPI3REF: Low-Level Control Of Database Files +** METHOD: sqlite3 ** ** ^The [sqlite3_file_control()] interface makes a direct call to the ** xFileControl method for the [sqlite3_io_methods] object associated @@ -6260,12 +6368,13 @@ int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_ISINIT 23 #define SQLITE_TESTCTRL_SORTER_MMAP 24 -#define SQLITE_TESTCTRL_LAST 24 +#define SQLITE_TESTCTRL_IMPOSTER 25 +#define SQLITE_TESTCTRL_LAST 25 /* ** CAPI3REF: SQLite Runtime Status ** -** ^This interface is used to retrieve runtime status information +** ^These interfaces are used to retrieve runtime status information ** about the performance of SQLite, and optionally to reset various ** highwater marks. ^The first argument is an integer code for ** the specific parameter to measure. ^(Recognized integer codes @@ -6279,19 +6388,22 @@ int sqlite3_test_control(int op, ...); ** ^(Other parameters record only the highwater mark and not the current ** value. For these latter parameters nothing is written into *pCurrent.)^ ** -** ^The sqlite3_status() routine returns SQLITE_OK on success and a -** non-zero [error code] on failure. +** ^The sqlite3_status() and sqlite3_status64() routines return +** SQLITE_OK on success and a non-zero [error code] on failure. ** -** This routine is threadsafe but is not atomic. This routine can be -** called while other threads are running the same or different SQLite -** interfaces. However the values returned in *pCurrent and -** *pHighwater reflect the status of SQLite at different points in time -** and it is possible that another thread might change the parameter -** in between the times when *pCurrent and *pHighwater are written. +** If either the current value or the highwater mark is too large to +** be represented by a 32-bit integer, then the values returned by +** sqlite3_status() are undefined. ** ** See also: [sqlite3_db_status()] */ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); +int sqlite3_status64( + int op, + sqlite3_int64 *pCurrent, + sqlite3_int64 *pHighwater, + int resetFlag +); /* @@ -6389,6 +6501,7 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); /* ** CAPI3REF: Database Connection Status +** METHOD: sqlite3 ** ** ^This interface is used to retrieve runtime status information ** about a single [database connection]. ^The first argument is the @@ -6517,6 +6630,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); /* ** CAPI3REF: Prepared Statement Status +** METHOD: sqlite3_stmt ** ** ^(Each prepared statement maintains various ** [SQLITE_STMTSTATUS counters] that measure the number @@ -6961,20 +7075,20 @@ typedef struct sqlite3_backup sqlite3_backup; ** is not a permanent error and does not affect the return value of ** sqlite3_backup_finish(). ** -** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] +** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]] ** sqlite3_backup_remaining() and sqlite3_backup_pagecount() ** -** ^Each call to sqlite3_backup_step() sets two values inside -** the [sqlite3_backup] object: the number of pages still to be backed -** up and the total number of pages in the source database file. -** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces -** retrieve these two values, respectively. -** -** ^The values returned by these functions are only updated by -** sqlite3_backup_step(). ^If the source database is modified during a backup -** operation, then the values are not updated to account for any extra -** pages that need to be updated or the size of the source database file -** changing. +** ^The sqlite3_backup_remaining() routine returns the number of pages still +** to be backed up at the conclusion of the most recent sqlite3_backup_step(). +** ^The sqlite3_backup_pagecount() routine returns the total number of pages +** in the source database at the conclusion of the most recent +** sqlite3_backup_step(). +** ^(The values returned by these functions are only updated by +** sqlite3_backup_step(). If the source database is modified in a way that +** changes the size of the source database or the number of pages remaining, +** those changes are not reflected in the output of sqlite3_backup_pagecount() +** and sqlite3_backup_remaining() until after the next +** sqlite3_backup_step().)^ ** ** Concurrent Usage of Database Handles ** @@ -7020,6 +7134,7 @@ int sqlite3_backup_pagecount(sqlite3_backup *p); /* ** CAPI3REF: Unlock Notification +** METHOD: sqlite3 ** ** ^When running in shared-cache mode, a database operation may fail with ** an [SQLITE_LOCKED] error if the required locks on the shared-cache or @@ -7190,6 +7305,7 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...); /* ** CAPI3REF: Write-Ahead Log Commit Hook +** METHOD: sqlite3 ** ** ^The [sqlite3_wal_hook()] function is used to register a callback that ** is invoked each time data is committed to a database in wal mode. @@ -7229,6 +7345,7 @@ void *sqlite3_wal_hook( /* ** CAPI3REF: Configure an auto-checkpoint +** METHOD: sqlite3 ** ** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around ** [sqlite3_wal_hook()] that causes any database on [database connection] D @@ -7259,6 +7376,7 @@ int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); /* ** CAPI3REF: Checkpoint a database +** METHOD: sqlite3 ** ** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to ** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^ @@ -7280,6 +7398,7 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Checkpoint a database +** METHOD: sqlite3 ** ** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint ** operation on database X of [database connection] D in mode M. Status @@ -7534,6 +7653,7 @@ int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Prepared Statement Scan Status +** METHOD: sqlite3_stmt ** ** This interface returns information about the predicted and measured ** performance for pStmt. Advanced applications can use this @@ -7571,6 +7691,7 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( /* ** CAPI3REF: Zero Scan-Status Counters +** METHOD: sqlite3_stmt ** ** ^Zero all [sqlite3_stmt_scanstatus()] related event counters. ** diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 379456d..7b9542a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -23,6 +23,11 @@ */ #include "msvc.h" +/* +** Special setup for VxWorks +*/ +#include "vxworks.h" + /* ** These #defines should enable >2GB file support on POSIX if the ** underlying operating system supports it. If the OS lacks @@ -357,6 +362,32 @@ # define NEVER(X) (X) #endif +/* +** Declarations used for tracing the operating system interfaces. +*/ +#if defined(SQLITE_FORCE_OS_TRACE) || defined(SQLITE_TEST) || \ + (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) + extern int sqlite3OSTrace; +# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X +# define SQLITE_HAVE_OS_TRACE +#else +# define OSTRACE(X) +# undef SQLITE_HAVE_OS_TRACE +#endif + +/* +** Is the sqlite3ErrName() function needed in the build? Currently, +** it is needed by "mutex_w32.c" (when debugging), "os_win.c" (when +** OSTRACE is enabled), and by several "test*.c" files (which are +** compiled using SQLITE_TEST). +*/ +#if defined(SQLITE_HAVE_OS_TRACE) || defined(SQLITE_TEST) || \ + (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) +# define SQLITE_NEED_ERR_NAME +#else +# undef SQLITE_NEED_ERR_NAME +#endif + /* ** Return true (non-zero) if the input is an integer that is too large ** to fit in 32-bits. This macro is used inside of various testcase() @@ -589,6 +620,20 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */ */ typedef INT16_TYPE LogEst; +/* +** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer +*/ +#ifndef SQLITE_PTRSIZE +# if defined(__SIZEOF_POINTER__) +# define SQLITE_PTRSIZE __SIZEOF_POINTER__ +# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(_M_ARM) || defined(__arm__) || defined(__x86) +# define SQLITE_PTRSIZE 4 +# else +# define SQLITE_PTRSIZE 8 +# endif +#endif + /* ** Macros to determine whether the machine is big or little endian, ** and whether or not that determination is run-time or compile-time. @@ -1087,11 +1132,13 @@ struct sqlite3 { u8 iDb; /* Which db file is being initialized */ u8 busy; /* TRUE if currently initializing */ u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */ + u8 imposterTable; /* Building an imposter table */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ int nVdbeWrite; /* Number of active VDBEs that read and write */ int nVdbeExec; /* Number of nested calls to VdbeExec() */ + int nVDestroy; /* Number of active OP_VDestroy operations */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ void (*xTrace)(void*,const char*); /* Trace function */ @@ -1205,6 +1252,7 @@ struct sqlite3 { #define SQLITE_DeferFKs 0x01000000 /* Defer all FK constraints */ #define SQLITE_QueryOnly 0x02000000 /* Disable database changes */ #define SQLITE_VdbeEQP 0x04000000 /* Debug EXPLAIN QUERY PLAN */ +#define SQLITE_Vacuum 0x08000000 /* Currently in a VACUUM */ /* @@ -1535,34 +1583,8 @@ struct VTable { }; /* -** Each SQL table is represented in memory by an instance of the -** following structure. -** -** Table.zName is the name of the table. The case of the original -** CREATE TABLE statement is stored, but case is not significant for -** comparisons. -** -** Table.nCol is the number of columns in this table. Table.aCol is a -** pointer to an array of Column structures, one for each column. -** -** If the table has an INTEGER PRIMARY KEY, then Table.iPKey is the index of -** the column that is that key. Otherwise Table.iPKey is negative. Note -** that the datatype of the PRIMARY KEY must be INTEGER for this field to -** be set. An INTEGER PRIMARY KEY is used as the rowid for each row of -** the table. If a table has no INTEGER PRIMARY KEY, then a random rowid -** is generated for each row of the table. TF_HasPrimaryKey is set if -** the table has any PRIMARY KEY, INTEGER or otherwise. -** -** Table.tnum is the page number for the root BTree page of the table in the -** database file. If Table.iDb is the index of the database table backend -** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that -** holds temporary tables and indices. If TF_Ephemeral is set -** then the table is stored in a file that is automatically deleted -** when the VDBE cursor to the table is closed. In this case Table.tnum -** refers VDBE cursor number that holds the table open, not to the root -** page number. Transient tables are used to hold the results of a -** sub-query that appears instead of a real table name in the FROM clause -** of a SELECT statement. +** The schema for each SQL table and view is represented in memory +** by an instance of the following structure. */ struct Table { char *zName; /* Name of the table or view */ @@ -1574,11 +1596,11 @@ struct Table { #ifndef SQLITE_OMIT_CHECK ExprList *pCheck; /* All CHECK constraints */ #endif - LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ - int tnum; /* Root BTree node for this table (see note above) */ - i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */ + int tnum; /* Root BTree page for this table */ + i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */ i16 nCol; /* Number of columns in this table */ u16 nRef; /* Number of pointers to this Table */ + LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ #ifdef SQLITE_ENABLE_COSTMULT LogEst costMult; /* Cost multiplier for using this table */ @@ -1600,6 +1622,12 @@ struct Table { /* ** Allowed values for Table.tabFlags. +** +** TF_OOOHidden applies to virtual tables that have hidden columns that are +** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING +** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden, +** the TF_OOOHidden attribute would apply in this case. Such tables require +** special handling during INSERT processing. */ #define TF_Readonly 0x01 /* Read-only system table */ #define TF_Ephemeral 0x02 /* An ephemeral table */ @@ -1607,6 +1635,7 @@ struct Table { #define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */ #define TF_Virtual 0x10 /* Is a virtual table */ #define TF_WithoutRowid 0x20 /* No rowid used. PRIMARY KEY is the key */ +#define TF_OOOHidden 0x40 /* Out-of-Order hidden columns */ /* @@ -2043,8 +2072,14 @@ struct Expr { #define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ #define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ -#define EP_Constant 0x080000 /* Node is a constant */ +#define EP_ConstFunc 0x080000 /* Node is a SQLITE_FUNC_CONSTANT function */ #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ +#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ + +/* +** Combinations of two or more EP_* flags +*/ +#define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */ /* ** These macros can be used to test, set, or clear bits in the @@ -2243,7 +2278,7 @@ struct SrcList { #define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */ #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ - /* 0x0080 // not currently used */ +#define WHERE_NO_AUTOINDEX 0x0080 /* Disallow automatic indexes */ #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ @@ -2357,11 +2392,12 @@ struct Select { #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ #define SF_Compound 0x0040 /* Part of a compound query */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */ -#define SF_AllValues 0x0100 /* All terms of compound are VALUES */ +#define SF_MultiValue 0x0100 /* Single VALUES term with multiple rows */ #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */ #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */ #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */ #define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */ +#define SF_Converted 0x2000 /* By convertCompoundSelectToSubquery() */ /* @@ -2680,7 +2716,8 @@ struct AuthContext { #define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ #define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */ #define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */ -#define OPFLAG_P2ISREG 0x02 /* P2 to OP_Open** is a register number */ +#define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */ +#define OPFLAG_P2ISREG 0x04 /* P2 to OP_Open** is a register number */ #define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ /* @@ -2739,7 +2776,7 @@ struct Trigger { * orconf -> stores the ON CONFLICT algorithm * pSelect -> If this is an INSERT INTO ... SELECT ... statement, then * this stores a pointer to the SELECT statement. Otherwise NULL. - * target -> A token holding the quoted name of the table to insert into. + * zTarget -> Dequoted name of the table to insert into. * pExprList -> If this is an INSERT INTO ... VALUES ... statement, then * this stores values to be inserted. Otherwise NULL. * pIdList -> If this is an INSERT INTO ... () VALUES ... @@ -2747,12 +2784,12 @@ struct Trigger { * inserted into. * * (op == TK_DELETE) - * target -> A token holding the quoted name of the table to delete from. + * zTarget -> Dequoted name of the table to delete from. * pWhere -> The WHERE clause of the DELETE statement if one is specified. * Otherwise NULL. * * (op == TK_UPDATE) - * target -> A token holding the quoted name of the table to update rows of. + * zTarget -> Dequoted name of the table to update. * pWhere -> The WHERE clause of the UPDATE statement if one is specified. * Otherwise NULL. * pExprList -> A list of the columns to update and the expressions to update @@ -2764,8 +2801,8 @@ struct TriggerStep { u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */ u8 orconf; /* OE_Rollback etc. */ Trigger *pTrig; /* The trigger that this step is a part of */ - Select *pSelect; /* SELECT statment or RHS of INSERT INTO .. SELECT ... */ - Token target; /* Target table for DELETE, UPDATE, INSERT */ + Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */ + char *zTarget; /* Target table for DELETE, UPDATE, INSERT */ Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ ExprList *pExprList; /* SET clause for UPDATE. */ IdList *pIdList; /* Column names for INSERT */ @@ -2798,8 +2835,7 @@ struct StrAccum { char *zText; /* The string collected so far */ int nChar; /* Length of the string so far */ int nAlloc; /* Amount of space allocated in zText */ - int mxAlloc; /* Maximum allowed string length */ - u8 useMalloc; /* 0: none, 1: sqlite3DbMalloc, 2: sqlite3_malloc */ + int mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */ u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */ }; #define STRACCUM_NOMEM 1 @@ -3084,10 +3120,15 @@ const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); int sqlite3MutexEnd(void); #endif -int sqlite3StatusValue(int); -void sqlite3StatusAdd(int, int); +sqlite3_int64 sqlite3StatusValue(int); +void sqlite3StatusUp(int, int); +void sqlite3StatusDown(int, int); void sqlite3StatusSet(int, int); +/* Access to mutexes used by sqlite3_status() */ +sqlite3_mutex *sqlite3Pcache1Mutex(void); +sqlite3_mutex *sqlite3MallocMutex(void); + #ifndef SQLITE_OMIT_FLOATING_POINT int sqlite3IsNaN(double); #else @@ -3111,7 +3152,7 @@ void sqlite3XPrintf(StrAccum*, u32, const char*, ...); char *sqlite3MPrintf(sqlite3*,const char*, ...); char *sqlite3VMPrintf(sqlite3*,const char*, va_list); char *sqlite3MAppendf(sqlite3*,char*,const char*,...); -#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) +#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) void sqlite3DebugPrintf(const char*, ...); #endif #if defined(SQLITE_TEST) @@ -3152,6 +3193,7 @@ ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*); void sqlite3ExprListDelete(sqlite3*, ExprList*); +u32 sqlite3ExprListFlags(const ExprList*); int sqlite3Init(sqlite3*, char**); int sqlite3InitCallback(void*, int, char**, char**); void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); @@ -3457,7 +3499,7 @@ void *sqlite3HexToBlob(sqlite3*, const char *z, int n); u8 sqlite3HexToInt(int h); int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); -#if defined(SQLITE_TEST) +#if defined(SQLITE_NEED_ERR_NAME) const char *sqlite3ErrName(int); #endif @@ -3466,7 +3508,7 @@ int sqlite3ReadSchema(Parse *pParse); CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); -Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*); +Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); Expr *sqlite3ExprSkipCollate(Expr*); int sqlite3CheckCollSeq(Parse *, CollSeq *); @@ -3551,7 +3593,7 @@ int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, int sqlite3ApiExit(sqlite3 *db, int); int sqlite3OpenTempDatabase(Parse *); -void sqlite3StrAccumInit(StrAccum*, char*, int, int); +void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); void sqlite3StrAccumAppend(StrAccum*,const char*,int); void sqlite3StrAccumAppendAll(StrAccum*,const char*); void sqlite3AppendChar(StrAccum*,int,char); @@ -3735,12 +3777,11 @@ void sqlite3MemJournalOpen(sqlite3_file *); int sqlite3MemJournalSize(void); int sqlite3IsMemJournal(sqlite3_file *); +void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p); #if SQLITE_MAX_EXPR_DEPTH>0 - void sqlite3ExprSetHeight(Parse *pParse, Expr *p); int sqlite3SelectExprHeight(Select *); int sqlite3ExprCheckHeight(Parse*, int); #else - #define sqlite3ExprSetHeight(x,y) #define sqlite3SelectExprHeight(x) 0 #define sqlite3ExprCheckHeight(x,y) #endif @@ -3770,7 +3811,7 @@ void sqlite3Put4byte(u8*, u32); #ifdef SQLITE_ENABLE_IOTRACE # define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; } void sqlite3VdbeIOTraceSql(Vdbe*); -SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...); +SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...); #else # define IOTRACE(A) # define sqlite3VdbeIOTraceSql(X) diff --git a/src/sqliteLimit.h b/src/sqliteLimit.h index c7aee53..75cad12 100644 --- a/src/sqliteLimit.h +++ b/src/sqliteLimit.h @@ -98,15 +98,17 @@ #endif /* -** The maximum number of in-memory pages to use for the main database -** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE +** The suggested maximum number of in-memory pages to use for +** the main database table and for temporary tables. +** +** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size +** is 2000 pages. +** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be +** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options. */ #ifndef SQLITE_DEFAULT_CACHE_SIZE # define SQLITE_DEFAULT_CACHE_SIZE 2000 #endif -#ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE -# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500 -#endif /* ** The default number of frames to accumulate in the log file before diff --git a/src/status.c b/src/status.c index 4c2eabb..ac32753 100644 --- a/src/status.c +++ b/src/status.c @@ -21,10 +21,32 @@ */ typedef struct sqlite3StatType sqlite3StatType; static SQLITE_WSD struct sqlite3StatType { - int nowValue[10]; /* Current value */ - int mxValue[10]; /* Maximum value */ +#if SQLITE_PTRSIZE>4 + sqlite3_int64 nowValue[10]; /* Current value */ + sqlite3_int64 mxValue[10]; /* Maximum value */ +#else + u32 nowValue[10]; /* Current value */ + u32 mxValue[10]; /* Maximum value */ +#endif } sqlite3Stat = { {0,}, {0,} }; +/* +** Elements of sqlite3Stat[] are protected by either the memory allocator +** mutex, or by the pcache1 mutex. The following array determines which. +*/ +static const char statMutex[] = { + 0, /* SQLITE_STATUS_MEMORY_USED */ + 1, /* SQLITE_STATUS_PAGECACHE_USED */ + 1, /* SQLITE_STATUS_PAGECACHE_OVERFLOW */ + 0, /* SQLITE_STATUS_SCRATCH_USED */ + 0, /* SQLITE_STATUS_SCRATCH_OVERFLOW */ + 0, /* SQLITE_STATUS_MALLOC_SIZE */ + 0, /* SQLITE_STATUS_PARSER_STACK */ + 1, /* SQLITE_STATUS_PAGECACHE_SIZE */ + 0, /* SQLITE_STATUS_SCRATCH_SIZE */ + 0, /* SQLITE_STATUS_MALLOC_COUNT */ +}; + /* The "wsdStat" macro will resolve to the status information ** state vector. If writable static data is unsupported on the target, @@ -41,33 +63,60 @@ static SQLITE_WSD struct sqlite3StatType { #endif /* -** Return the current value of a status parameter. +** Return the current value of a status parameter. The caller must +** be holding the appropriate mutex. */ -int sqlite3StatusValue(int op){ +sqlite3_int64 sqlite3StatusValue(int op){ wsdStatInit; assert( op>=0 && op=0 && op=0 && op=0 && opwsdStat.mxValue[op] ){ wsdStat.mxValue[op] = wsdStat.nowValue[op]; } } +void sqlite3StatusDown(int op, int N){ + wsdStatInit; + assert( N>=0 ); + assert( op>=0 && op=0 && op=0 && op=0 && opwsdStat.mxValue[op] ){ wsdStat.mxValue[op] = wsdStat.nowValue[op]; @@ -76,12 +125,14 @@ void sqlite3StatusSet(int op, int X){ /* ** Query status information. -** -** This implementation assumes that reading or writing an aligned -** 32-bit integer is an atomic operation. If that assumption is not true, -** then this routine is not threadsafe. */ -int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ +int sqlite3_status64( + int op, + sqlite3_int64 *pCurrent, + sqlite3_int64 *pHighwater, + int resetFlag +){ + sqlite3_mutex *pMutex; wsdStatInit; if( op<0 || op>=ArraySize(wsdStat.nowValue) ){ return SQLITE_MISUSE_BKPT; @@ -89,13 +140,30 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; #endif + pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex(); + sqlite3_mutex_enter(pMutex); *pCurrent = wsdStat.nowValue[op]; *pHighwater = wsdStat.mxValue[op]; if( resetFlag ){ wsdStat.mxValue[op] = wsdStat.nowValue[op]; } + sqlite3_mutex_leave(pMutex); + (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */ return SQLITE_OK; } +int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ + sqlite3_int64 iCur, iHwtr; + int rc; +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; +#endif + rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag); + if( rc==0 ){ + *pCurrent = (int)iCur; + *pHighwater = (int)iHwtr; + } + return rc; +} /* ** Query status information for a single database connection diff --git a/src/table.c b/src/table.c index 235d8dd..153bfb3 100644 --- a/src/table.c +++ b/src/table.c @@ -90,7 +90,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ z = 0; }else{ int n = sqlite3Strlen30(argv[i])+1; - z = sqlite3_malloc( n ); + z = sqlite3_malloc64( n ); if( z==0 ) goto malloc_failed; memcpy(z, argv[i], n); } @@ -139,7 +139,7 @@ int sqlite3_get_table( res.nData = 1; res.nAlloc = 20; res.rc = SQLITE_OK; - res.azResult = sqlite3_malloc(sizeof(char*)*res.nAlloc ); + res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc ); if( res.azResult==0 ){ db->errCode = SQLITE_NOMEM; return SQLITE_NOMEM; @@ -167,7 +167,7 @@ int sqlite3_get_table( } if( res.nAlloc>res.nData ){ char **azNew; - azNew = sqlite3_realloc( res.azResult, sizeof(char*)*res.nData ); + azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData ); if( azNew==0 ){ sqlite3_free_table(&res.azResult[1]); db->errCode = SQLITE_NOMEM; diff --git a/src/tclsqlite.c b/src/tclsqlite.c index a912e8a..3e9c986 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -661,9 +661,9 @@ static int DbWalHandler( #if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){ char zBuf[64]; - sprintf(zBuf, "%d", iArg); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iArg); Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY); - sprintf(zBuf, "%d", nArg); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nArg); Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY); } #else @@ -1191,7 +1191,7 @@ static int dbPrepareAndBind( int n; u8 *data; const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); - char c = zType[0]; + c = zType[0]; if( zVar[0]=='@' || (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){ /* Load a BLOB type if the Tcl variable is a bytearray and @@ -2298,7 +2298,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ } Tcl_DecrRefCount(pRet); }else{ - ClientData cd[2]; + ClientData cd2[2]; DbEvalContext *p; Tcl_Obj *pArray = 0; Tcl_Obj *pScript; @@ -2312,42 +2312,57 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext)); dbEvalInit(p, pDb, objv[2], pArray); - cd[0] = (void *)p; - cd[1] = (void *)pScript; - rc = DbEvalNextCmd(cd, interp, TCL_OK); + cd2[0] = (void *)p; + cd2[1] = (void *)pScript; + rc = DbEvalNextCmd(cd2, interp, TCL_OK); } break; } /* - ** $db function NAME [-argcount N] SCRIPT + ** $db function NAME [-argcount N] [-deterministic] SCRIPT ** ** Create a new SQL function called NAME. Whenever that function is ** called, invoke SCRIPT to evaluate the function. */ case DB_FUNCTION: { + int flags = SQLITE_UTF8; SqlFunc *pFunc; Tcl_Obj *pScript; char *zName; int nArg = -1; - if( objc==6 ){ - const char *z = Tcl_GetString(objv[3]); + int i; + if( objc<4 ){ + Tcl_WrongNumArgs(interp, 2, objv, "NAME ?SWITCHES? SCRIPT"); + return TCL_ERROR; + } + for(i=3; i<(objc-1); i++){ + const char *z = Tcl_GetString(objv[i]); int n = strlen30(z); if( n>2 && strncmp(z, "-argcount",n)==0 ){ - if( Tcl_GetIntFromObj(interp, objv[4], &nArg) ) return TCL_ERROR; + if( i==(objc-2) ){ + Tcl_AppendResult(interp, "option requires an argument: ", z, 0); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[i+1], &nArg) ) return TCL_ERROR; if( nArg<0 ){ Tcl_AppendResult(interp, "number of arguments must be non-negative", (char*)0); return TCL_ERROR; } + i++; + }else + if( n>2 && strncmp(z, "-deterministic",n)==0 ){ + flags |= SQLITE_DETERMINISTIC; + }else{ + Tcl_AppendResult(interp, "bad option \"", z, + "\": must be -argcount or -deterministic", 0 + ); + return TCL_ERROR; } - pScript = objv[5]; - }else if( objc!=4 ){ - Tcl_WrongNumArgs(interp, 2, objv, "NAME [-argcount N] SCRIPT"); - return TCL_ERROR; - }else{ - pScript = objv[3]; } + + pScript = objv[objc-1]; zName = Tcl_GetStringFromObj(objv[2], 0); pFunc = findSqlFunc(pDb, zName); if( pFunc==0 ) return TCL_ERROR; @@ -2357,7 +2372,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ pFunc->pScript = pScript; Tcl_IncrRefCount(pScript); pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript); - rc = sqlite3_create_function(pDb->db, zName, nArg, SQLITE_UTF8, + rc = sqlite3_create_function(pDb->db, zName, nArg, flags, pFunc, tclSqlFunc, 0, 0); if( rc!=SQLITE_OK ){ rc = TCL_ERROR; @@ -3429,7 +3444,7 @@ static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){ for(i=j=0; i<16; i+=2){ x = digest[i]*256 + digest[i+1]; if( i>0 ) zDigest[j++] = '-'; - sprintf(&zDigest[j], "%05u", x); + sqlite3_snprintf(50-j, &zDigest[j], "%05u", x); j += 5; } zDigest[j] = 0; @@ -3689,7 +3704,44 @@ static int db_last_stmt_ptr( return TCL_OK; } -#endif +#endif /* SQLITE_TEST */ + +#if defined(SQLITE_TEST) || defined(SQLITE_ENABLE_DBSTAT_VTAB) +/* +** tclcmd: register_dbstat_vtab DB +** +** Cause the dbstat virtual table to be available on the connection DB +*/ +static int sqlite3RegisterDbstatCmd( + void *clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ +#ifdef SQLITE_OMIT_VIRTUALTABLE + Tcl_AppendResult(interp, "dbstat not available because of " + "SQLITE_OMIT_VIRTUALTABLE", (void*)0); + return TCL_ERROR; +#else + struct SqliteDb { sqlite3 *db; }; + char *zDb; + Tcl_CmdInfo cmdInfo; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB"); + return TCL_ERROR; + } + + zDb = Tcl_GetString(objv[1]); + if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){ + int sqlite3_dbstat_register(sqlite3*); + sqlite3* db = ((struct SqliteDb*)cmdInfo.objClientData)->db; + sqlite3_dbstat_register(db); + } + return TCL_OK; +#endif /* SQLITE_OMIT_VIRTUALTABLE */ +} +#endif /* defined(SQLITE_TEST) || defined(SQLITE_ENABLE_DBSTAT_VTAB) */ /* ** Configure the interpreter passed as the first argument to have access @@ -3713,11 +3765,10 @@ static void init_all(Tcl_Interp *interp){ ** of virtual table dbstat (source file test_stat.c). This command is ** required for testfixture and sqlite3_analyzer, but not by the production ** Tcl extension. */ -#if defined(SQLITE_TEST) || TCLSH==2 - { - extern int SqlitetestStat_Init(Tcl_Interp*); - SqlitetestStat_Init(interp); - } +#if defined(SQLITE_TEST) || defined(SQLITE_ENABLE_DBSTAT_VTAB) + Tcl_CreateObjCommand( + interp, "register_dbstat_vtab", sqlite3RegisterDbstatCmd, 0, 0 + ); #endif #ifdef SQLITE_TEST diff --git a/src/test1.c b/src/test1.c index 8f21660..a87fcd8 100644 --- a/src/test1.c +++ b/src/test1.c @@ -94,10 +94,7 @@ static int get_sqlite_pointer( return TCL_ERROR; } p = (struct SqliteDb*)cmdInfo.objClientData; - sprintf(zBuf, "%p", p->db); - if( strncmp(zBuf,"0x",2) ){ - sprintf(zBuf, "0x%p", p->db); - } + sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p->db); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } @@ -145,7 +142,8 @@ int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){ && sqlite3_errcode(db)!=rc ){ char zBuf[200]; int r2 = sqlite3_errcode(db); - sprintf(zBuf, "error code %s (%d) does not match sqlite3_errcode %s (%d)", + sqlite3_snprintf(sizeof(zBuf), zBuf, + "error code %s (%d) does not match sqlite3_errcode %s (%d)", t1ErrorName(rc), rc, t1ErrorName(r2), r2); Tcl_ResetResult(interp); Tcl_AppendResult(interp, zBuf, 0); @@ -310,7 +308,7 @@ static int test_exec_printf( zSql = sqlite3_mprintf(argv[2], argv[3]); rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr); sqlite3_free(zSql); - sprintf(zBuf, "%d", rc); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc); Tcl_AppendElement(interp, zBuf); Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); Tcl_DStringFree(&str); @@ -357,7 +355,7 @@ static int test_exec_hex( zSql[i] = 0; Tcl_DStringInit(&str); rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr); - sprintf(zBuf, "%d", rc); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc); Tcl_AppendElement(interp, zBuf); Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); Tcl_DStringFree(&str); @@ -442,7 +440,7 @@ static int test_exec( zSql[j] = 0; rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr); sqlite3_free(zSql); - sprintf(zBuf, "%d", rc); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc); Tcl_AppendElement(interp, zBuf); Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); Tcl_DStringFree(&str); @@ -591,13 +589,13 @@ static int test_get_table_printf( resCount = (nRow+1)*nCol; } sqlite3_free(zSql); - sprintf(zBuf, "%d", rc); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc); Tcl_AppendElement(interp, zBuf); if( rc==SQLITE_OK ){ if( argc==4 ){ - sprintf(zBuf, "%d", nRow); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nRow); Tcl_AppendElement(interp, zBuf); - sprintf(zBuf, "%d", nCol); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nCol); Tcl_AppendElement(interp, zBuf); } for(i=0; i9 || n1<1 ){ - sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1); + sqlite3_snprintf(sizeof(zErr), zErr, + "putVarint returned %d - should be between 1 and 9", n1); Tcl_AppendResult(interp, zErr, 0); return TCL_ERROR; } n2 = getVarint(zBuf, &out); if( n1!=n2 ){ - sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2); + sqlite3_snprintf(sizeof(zErr), zErr, + "putVarint returned %d and getVarint returned %d", n1, n2); Tcl_AppendResult(interp, zErr, 0); return TCL_ERROR; } if( in!=out ){ - sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out); + sqlite3_snprintf(sizeof(zErr), zErr, + "Wrote 0x%016llx and got back 0x%016llx", in, out); Tcl_AppendResult(interp, zErr, 0); return TCL_ERROR; } @@ -465,13 +468,15 @@ static int btree_varint_test( n2 = getVarint32(zBuf, out32); out = out32; if( n1!=n2 ){ - sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d", + sqlite3_snprintf(sizeof(zErr), zErr, + "putVarint returned %d and GetVarint32 returned %d", n1, n2); Tcl_AppendResult(interp, zErr, 0); return TCL_ERROR; } if( in!=out ){ - sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", + sqlite3_snprintf(sizeof(zErr), zErr, + "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", in, out); Tcl_AppendResult(interp, zErr, 0); return TCL_ERROR; diff --git a/src/test4.c b/src/test4.c index a6375c7..d689030 100644 --- a/src/test4.c +++ b/src/test4.c @@ -270,7 +270,7 @@ static int tcl_thread_argc( return TCL_ERROR; } thread_wait(&threadset[i]); - sprintf(zBuf, "%d", threadset[i].argc); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", threadset[i].argc); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } diff --git a/src/test7.c b/src/test7.c index 93bf1e4..6ba3631 100644 --- a/src/test7.c +++ b/src/test7.c @@ -315,7 +315,7 @@ static int tcl_client_argc( return TCL_ERROR; } client_wait(&threadset[i]); - sprintf(zBuf, "%d", threadset[i].argc); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", threadset[i].argc); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } diff --git a/src/test8.c b/src/test8.c index f37a28c..2107710 100644 --- a/src/test8.c +++ b/src/test8.c @@ -206,8 +206,8 @@ static int getColumnNames( zSpace = (char *)(&aCol[nCol]); for(ii=0; ii +#include "sqlite3.h" #include /* These functions are implemented in main.c. */ diff --git a/src/test_blob.c b/src/test_blob.c index d88c913..4a7075a 100644 --- a/src/test_blob.c +++ b/src/test_blob.c @@ -16,6 +16,7 @@ #include #include #include +#ifndef SQLITE_OMIT_INCRBLOB /* These functions are implemented in main.c. */ extern const char *sqlite3ErrName(int); @@ -295,12 +296,13 @@ static int test_blob_write( return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); } - +#endif /* SQLITE_OMIT_INCRBLOB */ /* ** Register commands with the TCL interpreter. */ int Sqlitetest_blob_Init(Tcl_Interp *interp){ +#ifndef SQLITE_OMIT_INCRBLOB static struct { char *zName; Tcl_ObjCmdProc *xProc; @@ -315,5 +317,6 @@ int Sqlitetest_blob_Init(Tcl_Interp *interp){ for(i=0; i +#include "sqlite3.h" #include #include diff --git a/src/test_func.c b/src/test_func.c index c785063..2e34fa0 100644 --- a/src/test_func.c +++ b/src/test_func.c @@ -600,12 +600,26 @@ static void test_decode( Tcl_DecrRefCount(pRet); } +/* +** The implementation of scalar SQL function "test_zeroblob()". This is +** similar to the built-in zeroblob() function, except that it does not +** check that the integer parameter is within range before passing it +** to sqlite3_result_zeroblob(). +*/ +static void test_zeroblob( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int nZero = sqlite3_value_int(argv[0]); + sqlite3_result_zeroblob(context, nZero); +} static int registerTestFunctions(sqlite3 *db){ static const struct { char *zName; signed char nArg; - unsigned char eTextRep; /* 1: UTF-16. 0: UTF-8 */ + unsigned int eTextRep; /* 1: UTF-16. 0: UTF-8 */ void (*xFunc)(sqlite3_context*,int,sqlite3_value **); } aFuncs[] = { { "randstr", 2, SQLITE_UTF8, randStr }, @@ -626,6 +640,7 @@ static int registerTestFunctions(sqlite3 *db){ { "real2hex", 1, SQLITE_UTF8, real2hex}, { "test_decode", 1, SQLITE_UTF8, test_decode}, { "test_extract", 2, SQLITE_UTF8, test_extract}, + { "test_zeroblob", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, test_zeroblob}, }; int i; diff --git a/src/test_intarray.c b/src/test_intarray.c index 7235fbc..70e34db 100644 --- a/src/test_intarray.c +++ b/src/test_intarray.c @@ -85,7 +85,7 @@ static int intarrayCreate( char **pzErr /* Put error message text here */ ){ int rc = SQLITE_NOMEM; - intarray_vtab *pVtab = sqlite3_malloc(sizeof(intarray_vtab)); + intarray_vtab *pVtab = sqlite3_malloc64(sizeof(intarray_vtab)); if( pVtab ){ memset(pVtab, 0, sizeof(intarray_vtab)); @@ -102,7 +102,7 @@ static int intarrayCreate( static int intarrayOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ int rc = SQLITE_NOMEM; intarray_cursor *pCur; - pCur = sqlite3_malloc(sizeof(intarray_cursor)); + pCur = sqlite3_malloc64(sizeof(intarray_cursor)); if( pCur ){ memset(pCur, 0, sizeof(intarray_cursor)); *ppCursor = (sqlite3_vtab_cursor *)pCur; @@ -225,7 +225,7 @@ SQLITE_API int sqlite3_intarray_create( #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_intarray *p; - *ppReturn = p = sqlite3_malloc( sizeof(*p) ); + *ppReturn = p = sqlite3_malloc64( sizeof(*p) ); if( p==0 ){ return SQLITE_NOMEM; } @@ -340,7 +340,7 @@ static int test_intarray_bind( pArray = (sqlite3_intarray*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); n = objc - 2; #ifndef SQLITE_OMIT_VIRTUALTABLE - a = sqlite3_malloc( sizeof(a[0])*n ); + a = sqlite3_malloc64( sizeof(a[0])*n ); if( a==0 ){ Tcl_AppendResult(interp, "SQLITE_NOMEM", (char*)0); return TCL_ERROR; diff --git a/src/test_malloc.c b/src/test_malloc.c index 1ea4de5..94a2282 100644 --- a/src/test_malloc.c +++ b/src/test_malloc.c @@ -211,15 +211,15 @@ static int faultsimInstall(int install){ faultsimBeginBenign, faultsimEndBenign ); }else{ - sqlite3_mem_methods m; + sqlite3_mem_methods m2; assert(memfault.m.xMalloc); /* One should be able to reset the default memory allocator by storing ** a zeroed allocator then calling GETMALLOC. */ - memset(&m, 0, sizeof(m)); - sqlite3_config(SQLITE_CONFIG_MALLOC, &m); - sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m); - assert( memcmp(&m, &memfault.m, sizeof(m))==0 ); + memset(&m2, 0, sizeof(m2)); + sqlite3_config(SQLITE_CONFIG_MALLOC, &m2); + sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m2); + assert( memcmp(&m2, &memfault.m, sizeof(m2))==0 ); rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m); sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0); diff --git a/src/test_multiplex.c b/src/test_multiplex.c index 8f204c6..843a92c 100644 --- a/src/test_multiplex.c +++ b/src/test_multiplex.c @@ -286,7 +286,7 @@ static void multiplexFilename( static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){ if( iChunk>=pGroup->nReal ){ struct multiplexReal *p; - p = sqlite3_realloc(pGroup->aReal, (iChunk+1)*sizeof(*p)); + p = sqlite3_realloc64(pGroup->aReal, (iChunk+1)*sizeof(*p)); if( p==0 ){ return SQLITE_NOMEM; } @@ -297,7 +297,7 @@ static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){ if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){ char *z; int n = pGroup->nName; - pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+5 ); + pGroup->aReal[iChunk].z = z = sqlite3_malloc64( n+5 ); if( z==0 ){ return SQLITE_NOMEM; } @@ -357,7 +357,7 @@ static sqlite3_file *multiplexSubOpen( } flags &= ~SQLITE_OPEN_CREATE; } - pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile ); + pSubOpen = sqlite3_malloc64( pOrigVfs->szOsFile ); if( pSubOpen==0 ){ *rc = SQLITE_IOERR_NOMEM; return 0; @@ -524,7 +524,7 @@ static int multiplexOpen( nName = zName ? multiplexStrlen30(zName) : 0; sz = sizeof(multiplexGroup) /* multiplexGroup */ + nName + 1; /* zName */ - pGroup = sqlite3_malloc( sz ); + pGroup = sqlite3_malloc64( sz ); if( pGroup==0 ){ rc = SQLITE_NOMEM; } @@ -568,12 +568,15 @@ static int multiplexOpen( if( pSubOpen==0 && rc==SQLITE_OK ) rc = SQLITE_CANTOPEN; } if( rc==SQLITE_OK ){ - sqlite3_int64 sz; + sqlite3_int64 sz64; - rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz); + rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz64); if( rc==SQLITE_OK && zName ){ int bExists; - if( sz==0 ){ + if( flags & SQLITE_OPEN_MASTER_JOURNAL ){ + pGroup->bEnabled = 0; + }else + if( sz64==0 ){ if( flags & SQLITE_OPEN_MAIN_JOURNAL ){ /* If opening a main journal file and the first chunk is zero ** bytes in size, delete any subsequent chunks from the @@ -604,10 +607,10 @@ static int multiplexOpen( rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z, SQLITE_ACCESS_EXISTS, &bExists); bExists = multiplexSubSize(pGroup, 1, &rc)>0; - if( rc==SQLITE_OK && bExists && sz==(sz&0xffff0000) && sz>0 - && sz!=pGroup->szChunk ){ - pGroup->szChunk = (int)sz; - }else if( rc==SQLITE_OK && !bExists && sz>pGroup->szChunk ){ + if( rc==SQLITE_OK && bExists && sz64==(sz64&0xffff0000) && sz64>0 + && sz64!=pGroup->szChunk ){ + pGroup->szChunk = (int)sz64; + }else if( rc==SQLITE_OK && !bExists && sz64>pGroup->szChunk ){ pGroup->bEnabled = 0; } } @@ -652,7 +655,7 @@ static int multiplexDelete( */ int nName = (int)strlen(zName); char *z; - z = sqlite3_malloc(nName + 5); + z = sqlite3_malloc64(nName + 5); if( z==0 ){ rc = SQLITE_IOERR_NOMEM; }else{ @@ -1004,6 +1007,13 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){ break; case SQLITE_FCNTL_PRAGMA: { char **aFcntl = (char**)pArg; + /* + ** EVIDENCE-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA + ** file control is an array of pointers to strings (char**) in which the + ** second element of the array is the name of the pragma and the third + ** element is the argument to the pragma or NULL if the pragma has no + ** argument. + */ if( aFcntl[1] && sqlite3_stricmp(aFcntl[1],"multiplex_truncate")==0 ){ if( aFcntl[2] && aFcntl[2][0] ){ if( sqlite3_stricmp(aFcntl[2], "on")==0 @@ -1015,6 +1025,12 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){ pGroup->bTruncate = 0; } } + /* EVIDENCE-OF: R-27806-26076 The handler for an SQLITE_FCNTL_PRAGMA + ** file control can optionally make the first element of the char** + ** argument point to a string obtained from sqlite3_mprintf() or the + ** equivalent and that string will become the result of the pragma + ** or the error message if the pragma fails. + */ aFcntl[0] = sqlite3_mprintf(pGroup->bTruncate ? "on" : "off"); rc = SQLITE_OK; break; diff --git a/src/test_onefile.c b/src/test_onefile.c index 6986744..122be70 100644 --- a/src/test_onefile.c +++ b/src/test_onefile.c @@ -595,9 +595,9 @@ static int fsOpen( int rc = SQLITE_OK; if( 0==(flags&(SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_MAIN_JOURNAL)) ){ - tmp_file *p = (tmp_file *)pFile; - memset(p, 0, sizeof(*p)); - p->base.pMethods = &tmp_io_methods; + tmp_file *p2 = (tmp_file *)pFile; + memset(p2, 0, sizeof(*p2)); + p2->base.pMethods = &tmp_io_methods; return SQLITE_OK; } diff --git a/src/test_osinst.c b/src/test_osinst.c index 1701def..4ae23a8 100644 --- a/src/test_osinst.c +++ b/src/test_osinst.c @@ -1131,7 +1131,6 @@ static int test_vfslog( switch( (enum VL_enum)iSub ){ case VL_ANNOTATE: { - int rc; char *zVfs; char *zMsg; if( objc!=4 ){ @@ -1148,7 +1147,6 @@ static int test_vfslog( break; } case VL_FINALIZE: { - int rc; char *zVfs; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "VFS"); @@ -1164,7 +1162,6 @@ static int test_vfslog( }; case VL_NEW: { - int rc; char *zVfs; char *zParent; char *zLog; diff --git a/src/test_rtree.c b/src/test_rtree.c index 9d19fa0..7beec66 100644 --- a/src/test_rtree.c +++ b/src/test_rtree.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. */ -#include +#include "sqlite3.h" #include /* Solely for the UNUSED_PARAMETER() macro. */ diff --git a/src/test_sqllog.c b/src/test_sqllog.c index 4aa68b7..6c0bf95 100644 --- a/src/test_sqllog.c +++ b/src/test_sqllog.c @@ -365,8 +365,10 @@ static void sqllogOpenlog(struct SLConn *p){ FILE *fd; char *zVar = getenv(ENVIRONMENT_VARIABLE1_NAME); if( zVar==0 || strlen(zVar)+10>=(sizeof(sqllogglobal.zPrefix)) ) return; - sprintf(sqllogglobal.zPrefix, "%s/sqllog_%d", zVar, getProcessId()); - sprintf(sqllogglobal.zIdx, "%s.idx", sqllogglobal.zPrefix); + sqlite3_snprintf(sizeof(sqllogglobal.zPrefix), sqllogglobal.zPrefix, + "%s/sqllog_%d", zVar, getProcessId()); + sqlite3_snprintf(sizeof(sqllogglobal.zIdx), sqllogglobal.zIdx, + "%s.idx", sqllogglobal.zPrefix); if( getenv(ENVIRONMENT_VARIABLE2_NAME) ){ sqllogglobal.bReuse = atoi(getenv(ENVIRONMENT_VARIABLE2_NAME)); } diff --git a/src/test_superlock.c b/src/test_superlock.c index 936fcad..cac7898 100644 --- a/src/test_superlock.c +++ b/src/test_superlock.c @@ -18,7 +18,7 @@ ** sqlite3demo_superunlock() */ -#include +#include "sqlite3.h" #include /* memset(), strlen() */ #include /* assert() */ diff --git a/src/test_thread.c b/src/test_thread.c index 2f9363b..a4d96e1 100644 --- a/src/test_thread.c +++ b/src/test_thread.c @@ -608,7 +608,7 @@ static int blocking_prepare_v2_proc( } if( rc!=SQLITE_OK ){ assert( pStmt==0 ); - sprintf(zBuf, "%s ", (char *)sqlite3ErrName(rc)); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%s ", (char *)sqlite3ErrName(rc)); Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0); return TCL_ERROR; } diff --git a/src/test_vfs.c b/src/test_vfs.c index 37081af..a8c6ae7 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -823,11 +823,12 @@ static int tvfsShmOpen(sqlite3_file *pFile){ if( 0==strcmp(pFd->zFilename, pBuffer->zFile) ) break; } if( !pBuffer ){ - int nByte = sizeof(TestvfsBuffer) + (int)strlen(pFd->zFilename) + 1; + int szName = (int)strlen(pFd->zFilename); + int nByte = sizeof(TestvfsBuffer) + szName + 1; pBuffer = (TestvfsBuffer *)ckalloc(nByte); memset(pBuffer, 0, nByte); pBuffer->zFile = (char *)&pBuffer[1]; - strcpy(pBuffer->zFile, pFd->zFilename); + memcpy(pBuffer->zFile, pFd->zFilename, szName+1); pBuffer->pNext = p->pBuffer; p->pBuffer = pBuffer; } @@ -966,16 +967,15 @@ static void tvfsShmBarrier(sqlite3_file *pFile){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); + if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){ + const char *z = pFd->pShm ? pFd->pShm->zFile : ""; + tvfsExecTcl(p, "xShmBarrier", Tcl_NewStringObj(z, -1), pFd->pShmId, 0, 0); + } + if( p->isFullshm ){ sqlite3OsShmBarrier(pFd->pReal); return; } - - if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){ - tvfsExecTcl(p, "xShmBarrier", - Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0, 0 - ); - } } static int tvfsShmUnmap( @@ -1080,7 +1080,7 @@ static int testvfs_obj_cmd( switch( aSubcmd[i].eCmd ){ case CMD_SHM: { Tcl_Obj *pObj; - int i, rc; + int rc; TestvfsBuffer *pBuffer; char *zName; if( objc!=3 && objc!=4 ){ @@ -1160,7 +1160,6 @@ static int testvfs_obj_cmd( }; Tcl_Obj **apElem = 0; int nElem = 0; - int i; int mask = 0; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "LIST"); @@ -1531,7 +1530,7 @@ static int testvfs_cmd( return TCL_OK; bad_args: - Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?"); + Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-fullshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?"); return TCL_ERROR; } diff --git a/src/threads.c b/src/threads.c index 16f5249..4ce6122 100644 --- a/src/threads.c +++ b/src/threads.c @@ -101,7 +101,7 @@ int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ /********************************* Win32 Threads ****************************/ -#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0 +#if SQLITE_OS_WIN_THREADS #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ #include @@ -194,7 +194,7 @@ int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR; } -#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT */ +#endif /* SQLITE_OS_WIN_THREADS */ /******************************** End Win32 Threads *************************/ diff --git a/src/tokenize.c b/src/tokenize.c index f0360ee..78baee3 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -390,10 +390,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ sqlite3 *db = pParse->db; /* The database connection */ int mxSqlLen; /* Max length of an SQL string */ - -#ifdef SQLITE_ENABLE_API_ARMOR - if( zSql==0 || pzErrMsg==0 ) return SQLITE_MISUSE_BKPT; -#endif + assert( zSql!=0 ); mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; if( db->nVdbeActive==0 ){ db->u1.isInterrupted = 0; @@ -433,10 +430,8 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ break; } case TK_ILLEGAL: { - sqlite3DbFree(db, *pzErrMsg); - *pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"", + sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", &pParse->sLastToken); - nErr++; goto abort_parse; } case TK_SEMI: { @@ -454,17 +449,22 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ } } abort_parse: - if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){ + assert( nErr==0 ); + if( zSql[i]==0 && pParse->rc==SQLITE_OK && db->mallocFailed==0 ){ if( lastTokenParsed!=TK_SEMI ){ sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse); pParse->zTail = &zSql[i]; } - sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse); + if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){ + sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse); + } } #ifdef YYTRACKMAXSTACKDEPTH + sqlite3_mutex_enter(sqlite3MallocMutex()); sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK, sqlite3ParserStackPeak(pEngine) ); + sqlite3_mutex_leave(sqlite3MallocMutex()); #endif /* YYDEBUG */ sqlite3ParserFree(pEngine, sqlite3_free); db->lookaside.bEnabled = enableLookaside; @@ -518,8 +518,6 @@ abort_parse: pParse->pZombieTab = p->pNextZombie; sqlite3DeleteTable(db, p); } - if( nErr>0 && pParse->rc==SQLITE_OK ){ - pParse->rc = SQLITE_ERROR; - } + assert( nErr==0 || pParse->rc!=SQLITE_OK ); return nErr; } diff --git a/src/trigger.c b/src/trigger.c index d2e7b5a..2eba0cf 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -193,7 +193,6 @@ void sqlite3BeginTrigger( /* Do not create a trigger on a system table */ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ sqlite3ErrorMsg(pParse, "cannot create trigger on system table"); - pParse->nErr++; goto trigger_cleanup; } @@ -373,12 +372,12 @@ static TriggerStep *triggerStepAllocate( ){ TriggerStep *pTriggerStep; - pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n); + pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1); if( pTriggerStep ){ char *z = (char*)&pTriggerStep[1]; memcpy(z, pName->z, pName->n); - pTriggerStep->target.z = z; - pTriggerStep->target.n = pName->n; + sqlite3Dequote(z); + pTriggerStep->zTarget = z; pTriggerStep->op = op; } return pTriggerStep; @@ -661,7 +660,7 @@ Trigger *sqlite3TriggersExist( } /* -** Convert the pStep->target token into a SrcList and return a pointer +** Convert the pStep->zTarget string into a SrcList and return a pointer ** to that SrcList. ** ** This routine adds a specific database name, if needed, to the target when @@ -674,17 +673,17 @@ static SrcList *targetSrcList( Parse *pParse, /* The parsing context */ TriggerStep *pStep /* The trigger containing the target token */ ){ + sqlite3 *db = pParse->db; int iDb; /* Index of the database to use */ SrcList *pSrc; /* SrcList to be returned */ - pSrc = sqlite3SrcListAppend(pParse->db, 0, &pStep->target, 0); + pSrc = sqlite3SrcListAppend(db, 0, 0, 0); if( pSrc ){ assert( pSrc->nSrc>0 ); - assert( pSrc->a!=0 ); - iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema); + pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget); + iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema); if( iDb==0 || iDb>=2 ){ - sqlite3 *db = pParse->db; - assert( iDbdb->nDb ); + assert( iDbnDb ); pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); } } @@ -796,6 +795,7 @@ static void transferParseError(Parse *pTo, Parse *pFrom){ if( pTo->nErr==0 ){ pTo->zErrMsg = pFrom->zErrMsg; pTo->nErr = pFrom->nErr; + pTo->rc = pFrom->rc; }else{ sqlite3DbFree(pFrom->db, pFrom->zErrMsg); } diff --git a/src/util.c b/src/util.c index 6e64242..0bc1eea 100644 --- a/src/util.c +++ b/src/util.c @@ -655,6 +655,7 @@ int sqlite3GetInt32(const char *zNum, int *pValue){ } } #endif + while( zNum[0]=='0' ) zNum++; for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ v = v*10 + c; } diff --git a/src/vacuum.c b/src/vacuum.c index 9df8e08..adc802e 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -184,7 +184,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ ** cause problems for the call to BtreeSetPageSize() below. */ sqlite3BtreeCommit(pTemp); - nRes = sqlite3BtreeGetReserve(pMain); + nRes = sqlite3BtreeGetOptimalReserve(pMain); /* A VACUUM cannot change the pagesize of an encrypted database. */ #ifdef SQLITE_HAS_CODEC @@ -250,6 +250,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy ** the contents to the temporary database. */ + assert( (db->flags & SQLITE_Vacuum)==0 ); + db->flags |= SQLITE_Vacuum; rc = execExecSql(db, pzErrMsg, "SELECT 'INSERT INTO vacuum_db.' || quote(name) " "|| ' SELECT * FROM main.' || quote(name) || ';'" @@ -257,6 +259,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ "WHERE type = 'table' AND name!='sqlite_sequence' " " AND coalesce(rootpage,1)>0" ); + assert( (db->flags & SQLITE_Vacuum)!=0 ); + db->flags &= ~SQLITE_Vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Copy over the sequence table diff --git a/src/vdbe.c b/src/vdbe.c index 1e0ff96..e47a3ac 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -296,6 +296,7 @@ static void applyAffinity( if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){ sqlite3VdbeMemStringify(pRec, enc, 1); } + pRec->flags &= ~(MEM_Real|MEM_Int); } } @@ -514,6 +515,21 @@ static int checkSavepointCount(sqlite3 *db){ } #endif +/* +** Return the register of pOp->p2 after first preparing it to be +** overwritten with an integer value. +*/ +static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){ + Mem *pOut; + assert( pOp->p2>0 ); + assert( pOp->p2<=(p->nMem-p->nCursor) ); + pOut = &p->aMem[pOp->p2]; + memAboutToChange(p, pOut); + if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut); + pOut->flags = MEM_Int; + return pOut; +} + /* ** Execute as much of a VDBE program as we can. @@ -522,9 +538,11 @@ static int checkSavepointCount(sqlite3 *db){ int sqlite3VdbeExec( Vdbe *p /* The VDBE */ ){ - int pc=0; /* The program counter */ Op *aOp = p->aOp; /* Copy of p->aOp */ - Op *pOp; /* Current operation */ + Op *pOp = aOp; /* Current operation */ +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) + Op *pOrigOp; /* Value of pOp at the top of the loop */ +#endif int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */ @@ -600,23 +618,22 @@ int sqlite3VdbeExec( } sqlite3EndBenignMalloc(); #endif - for(pc=p->pc; rc==SQLITE_OK; pc++){ - assert( pc>=0 && pcnOp ); + for(pOp=&aOp[p->pc]; rc==SQLITE_OK; pOp++){ + assert( pOp>=aOp && pOp<&aOp[p->nOp]); if( db->mallocFailed ) goto no_mem; #ifdef VDBE_PROFILE start = sqlite3Hwtime(); #endif nVmStep++; - pOp = &aOp[pc]; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS - if( p->anExec ) p->anExec[pc]++; + if( p->anExec ) p->anExec[(int)(pOp-aOp)]++; #endif /* Only allow tracing if SQLITE_DEBUG is defined. */ #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ - sqlite3VdbePrintOp(stdout, pc, pOp); + sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp); } #endif @@ -633,23 +650,9 @@ int sqlite3VdbeExec( } #endif - /* On any opcode with the "out2-prerelease" tag, free any - ** external allocations out of mem[p2] and set mem[p2] to be - ** an undefined integer. Opcodes will either fill in the integer - ** value or convert mem[p2] to a different type. - */ - assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] ); - if( pOp->opflags & OPFLG_OUT2_PRERELEASE ){ - assert( pOp->p2>0 ); - assert( pOp->p2<=(p->nMem-p->nCursor) ); - pOut = &aMem[pOp->p2]; - memAboutToChange(p, pOut); - if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut); - pOut->flags = MEM_Int; - } - /* Sanity checking on other operands */ #ifdef SQLITE_DEBUG + assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] ); if( (pOp->opflags & OPFLG_IN1)!=0 ){ assert( pOp->p1>0 ); assert( pOp->p1<=(p->nMem-p->nCursor) ); @@ -682,6 +685,9 @@ int sqlite3VdbeExec( memAboutToChange(p, &aMem[pOp->p3]); } #endif +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) + pOrigOp = pOp; +#endif switch( pOp->opcode ){ @@ -705,7 +711,7 @@ int sqlite3VdbeExec( ** ** Other keywords in the comment that follows each case are used to ** construct the OPFLG_INITIALIZER value that initializes opcodeProperty[]. -** Keywords include: in1, in2, in3, out2_prerelease, out2, out3. See +** Keywords include: in1, in2, in3, out2, out3. See ** the mkopcodeh.awk script for additional information. ** ** Documentation about VDBE opcodes is generated by scanning this file @@ -733,7 +739,8 @@ int sqlite3VdbeExec( ** to the current line should be indented for EXPLAIN output. */ case OP_Goto: { /* jump */ - pc = pOp->p2 - 1; +jump_to_p2_and_check_for_interrupt: + pOp = &aOp[pOp->p2 - 1]; /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev, ** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon @@ -778,9 +785,13 @@ case OP_Gosub: { /* jump */ assert( VdbeMemDynamic(pIn1)==0 ); memAboutToChange(p, pIn1); pIn1->flags = MEM_Int; - pIn1->u.i = pc; + pIn1->u.i = (int)(pOp-aOp); REGISTER_TRACE(pOp->p1, pIn1); - pc = pOp->p2 - 1; + + /* Most jump operations do a goto to this spot in order to update + ** the pOp pointer. */ +jump_to_p2: + pOp = &aOp[pOp->p2 - 1]; break; } @@ -792,7 +803,7 @@ case OP_Gosub: { /* jump */ case OP_Return: { /* in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags==MEM_Int ); - pc = (int)pIn1->u.i; + pOp = &aOp[pIn1->u.i]; pIn1->flags = MEM_Undefined; break; } @@ -816,7 +827,7 @@ case OP_InitCoroutine: { /* jump */ assert( !VdbeMemDynamic(pOut) ); pOut->u.i = pOp->p3 - 1; pOut->flags = MEM_Int; - if( pOp->p2 ) pc = pOp->p2 - 1; + if( pOp->p2 ) goto jump_to_p2; break; } @@ -836,7 +847,7 @@ case OP_EndCoroutine: { /* in1 */ pCaller = &aOp[pIn1->u.i]; assert( pCaller->opcode==OP_Yield ); assert( pCaller->p2>=0 && pCaller->p2nOp ); - pc = pCaller->p2 - 1; + pOp = &aOp[pCaller->p2 - 1]; pIn1->flags = MEM_Undefined; break; } @@ -860,9 +871,9 @@ case OP_Yield: { /* in1, jump */ assert( VdbeMemDynamic(pIn1)==0 ); pIn1->flags = MEM_Int; pcDest = (int)pIn1->u.i; - pIn1->u.i = pc; + pIn1->u.i = (int)(pOp - aOp); REGISTER_TRACE(pOp->p1, pIn1); - pc = pcDest; + pOp = &aOp[pcDest]; break; } @@ -913,30 +924,34 @@ case OP_HaltIfNull: { /* in3 */ case OP_Halt: { const char *zType; const char *zLogFmt; + VdbeFrame *pFrame; + int pcx; + pcx = (int)(pOp - aOp); if( pOp->p1==SQLITE_OK && p->pFrame ){ /* Halt the sub-program. Return control to the parent frame. */ - VdbeFrame *pFrame = p->pFrame; + pFrame = p->pFrame; p->pFrame = pFrame->pParent; p->nFrame--; sqlite3VdbeSetChanges(db, p->nChange); - pc = sqlite3VdbeFrameRestore(pFrame); + pcx = sqlite3VdbeFrameRestore(pFrame); lastRowid = db->lastRowid; if( pOp->p2==OE_Ignore ){ - /* Instruction pc is the OP_Program that invoked the sub-program + /* Instruction pcx is the OP_Program that invoked the sub-program ** currently being halted. If the p2 instruction of this OP_Halt ** instruction is set to OE_Ignore, then the sub-program is throwing ** an IGNORE exception. In this case jump to the address specified ** as the p2 of the calling OP_Program. */ - pc = p->aOp[pc].p2-1; + pcx = p->aOp[pcx].p2-1; } aOp = p->aOp; aMem = p->aMem; + pOp = &aOp[pcx]; break; } p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; - p->pc = pc; + p->pc = pcx; if( p->rc ){ if( pOp->p5 ){ static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK", @@ -960,7 +975,7 @@ case OP_Halt: { }else{ sqlite3SetString(&p->zErrMsg, db, "%s constraint failed", zType); } - sqlite3_log(pOp->p1, zLogFmt, pc, p->zSql, p->zErrMsg); + sqlite3_log(pOp->p1, zLogFmt, pcx, p->zSql, p->zErrMsg); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); @@ -979,7 +994,8 @@ case OP_Halt: { ** ** The 32-bit integer value P1 is written into register P2. */ -case OP_Integer: { /* out2-prerelease */ +case OP_Integer: { /* out2 */ + pOut = out2Prerelease(p, pOp); pOut->u.i = pOp->p1; break; } @@ -990,7 +1006,8 @@ case OP_Integer: { /* out2-prerelease */ ** P4 is a pointer to a 64-bit integer value. ** Write that value into register P2. */ -case OP_Int64: { /* out2-prerelease */ +case OP_Int64: { /* out2 */ + pOut = out2Prerelease(p, pOp); assert( pOp->p4.pI64!=0 ); pOut->u.i = *pOp->p4.pI64; break; @@ -1003,7 +1020,8 @@ case OP_Int64: { /* out2-prerelease */ ** P4 is a pointer to a 64-bit floating point value. ** Write that value into register P2. */ -case OP_Real: { /* same as TK_FLOAT, out2-prerelease */ +case OP_Real: { /* same as TK_FLOAT, out2 */ + pOut = out2Prerelease(p, pOp); pOut->flags = MEM_Real; assert( !sqlite3IsNaN(*pOp->p4.pReal) ); pOut->u.r = *pOp->p4.pReal; @@ -1015,12 +1033,13 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */ ** Synopsis: r[P2]='P4' ** ** P4 points to a nul terminated UTF-8 string. This opcode is transformed -** into a String before it is executed for the first time. During +** into a String opcode before it is executed for the first time. During ** this transformation, the length of string P4 is computed and stored ** as the P1 parameter. */ -case OP_String8: { /* same as TK_STRING, out2-prerelease */ +case OP_String8: { /* same as TK_STRING, out2 */ assert( pOp->p4.z!=0 ); + pOut = out2Prerelease(p, pOp); pOp->opcode = OP_String; pOp->p1 = sqlite3Strlen30(pOp->p4.z); @@ -1047,18 +1066,31 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */ /* Fall through to the next case, OP_String */ } -/* Opcode: String P1 P2 * P4 * +/* Opcode: String P1 P2 P3 P4 P5 ** Synopsis: r[P2]='P4' (len=P1) ** ** The string value P4 of length P1 (bytes) is stored in register P2. +** +** If P5!=0 and the content of register P3 is greater than zero, then +** the datatype of the register P2 is converted to BLOB. The content is +** the same sequence of bytes, it is merely interpreted as a BLOB instead +** of a string, as if it had been CAST. */ -case OP_String: { /* out2-prerelease */ +case OP_String: { /* out2 */ assert( pOp->p4.z!=0 ); + pOut = out2Prerelease(p, pOp); pOut->flags = MEM_Str|MEM_Static|MEM_Term; pOut->z = pOp->p4.z; pOut->n = pOp->p1; pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); + if( pOp->p5 ){ + assert( pOp->p3>0 ); + assert( pOp->p3<=(p->nMem-p->nCursor) ); + pIn3 = &aMem[pOp->p3]; + assert( pIn3->flags & MEM_Int ); + if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term; + } break; } @@ -1074,9 +1106,10 @@ case OP_String: { /* out2-prerelease */ ** NULL values will not compare equal even if SQLITE_NULLEQ is set on ** OP_Ne or OP_Eq. */ -case OP_Null: { /* out2-prerelease */ +case OP_Null: { /* out2 */ int cnt; u16 nullFlag; + pOut = out2Prerelease(p, pOp); cnt = pOp->p3-pOp->p2; assert( pOp->p3<=(p->nMem-p->nCursor) ); pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; @@ -1111,8 +1144,9 @@ case OP_SoftNull: { ** P4 points to a blob of data P1 bytes long. Store this ** blob in register P2. */ -case OP_Blob: { /* out2-prerelease */ +case OP_Blob: { /* out2 */ assert( pOp->p1 <= SQLITE_MAX_LENGTH ); + pOut = out2Prerelease(p, pOp); sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0); pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); @@ -1127,7 +1161,7 @@ case OP_Blob: { /* out2-prerelease */ ** If the parameter is named, then its name appears in P4. ** The P4 value is used by sqlite3_bind_parameter_name(). */ -case OP_Variable: { /* out2-prerelease */ +case OP_Variable: { /* out2 */ Mem *pVar; /* Value being transferred */ assert( pOp->p1>0 && pOp->p1<=p->nVar ); @@ -1136,6 +1170,7 @@ case OP_Variable: { /* out2-prerelease */ if( sqlite3VdbeMemTooBig(pVar) ){ goto too_big; } + pOut = out2Prerelease(p, pOp); sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static); UPDATE_MAX_BLOBSIZE(pOut); break; @@ -1170,10 +1205,11 @@ case OP_Move: { memAboutToChange(p, pOut); sqlite3VdbeMemMove(pOut, pIn1); #ifdef SQLITE_DEBUG - if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<&aMem[p1+pOp->p3] ){ - pOut->pScopyFrom += p1 - pOp->p2; + if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrompScopyFrom += pOp->p2 - p1; } #endif + Deephemeralize(pOut); REGISTER_TRACE(p2++, pOut); pIn1++; pOut++; @@ -1312,7 +1348,7 @@ case OP_ResultRow: { /* Return SQLITE_ROW */ - p->pc = pc + 1; + p->pc = (int)(pOp - aOp) + 1; rc = SQLITE_ROW; goto vdbe_return; } @@ -1505,7 +1541,7 @@ arithmetic_result_is_null: ** ** The interface used by the implementation of the aforementioned functions ** to retrieve the collation sequence set by this opcode is not available -** publicly, only to user functions defined in func.c. +** publicly. Only built-in functions have access to this feature. */ case OP_CollSeq: { assert( pOp->p4type==P4_COLLSEQ ); @@ -1558,7 +1594,7 @@ case OP_Function: { assert( pOp->p4type==P4_FUNCDEF ); ctx.pFunc = pOp->p4.pFunc; - ctx.iOp = pc; + ctx.iOp = (int)(pOp - aOp); ctx.pVdbe = p; MemSetTypeFlag(ctx.pOut, MEM_Null); ctx.fErrorOrAux = 0; @@ -1572,7 +1608,7 @@ case OP_Function: { sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(ctx.pOut)); rc = ctx.isError; } - sqlite3VdbeDeleteAuxData(p, pc, pOp->p1); + sqlite3VdbeDeleteAuxData(p, (int)(pOp - aOp), pOp->p1); } /* Copy the result of the function into register P3 */ @@ -1701,8 +1737,7 @@ case OP_MustBeInt: { /* jump, in1 */ rc = SQLITE_MISMATCH; goto abort_due_to_error; }else{ - pc = pOp->p2 - 1; - break; + goto jump_to_p2; } } } @@ -1888,7 +1923,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ }else{ VdbeBranchTaken(2,3); if( pOp->p5 & SQLITE_JUMPIFNULL ){ - pc = pOp->p2-1; + goto jump_to_p2; } } break; @@ -1908,11 +1943,15 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); sqlite3VdbeMemStringify(pIn1, encoding, 1); + testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); + flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); } if( (pIn3->flags & MEM_Str)==0 && (pIn3->flags & (MEM_Int|MEM_Real))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); sqlite3VdbeMemStringify(pIn3, encoding, 1); + testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) ); + flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask); } } assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); @@ -1936,6 +1975,12 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ default: res = res>=0; break; } + /* Undo any changes made by applyAffinity() to the input registers. */ + assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); + pIn1->flags = flags1; + assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) ); + pIn3->flags = flags3; + if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); @@ -1945,12 +1990,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ }else{ VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); if( res ){ - pc = pOp->p2-1; + goto jump_to_p2; } } - /* Undo any changes made by applyAffinity() to the input registers. */ - pIn1->flags = flags1; - pIn3->flags = flags3; break; } @@ -2045,11 +2087,11 @@ case OP_Compare: { */ case OP_Jump: { /* jump */ if( iCompare<0 ){ - pc = pOp->p1 - 1; VdbeBranchTaken(0,3); + VdbeBranchTaken(0,3); pOp = &aOp[pOp->p1 - 1]; }else if( iCompare==0 ){ - pc = pOp->p2 - 1; VdbeBranchTaken(1,3); + VdbeBranchTaken(1,3); pOp = &aOp[pOp->p2 - 1]; }else{ - pc = pOp->p3 - 1; VdbeBranchTaken(2,3); + VdbeBranchTaken(2,3); pOp = &aOp[pOp->p3 - 1]; } break; } @@ -2159,7 +2201,7 @@ case OP_Once: { /* jump */ assert( pOp->p1nOnceFlag ); VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2); if( p->aOnceFlag[pOp->p1] ){ - pc = pOp->p2-1; + goto jump_to_p2; }else{ p->aOnceFlag[pOp->p1] = 1; } @@ -2194,7 +2236,7 @@ case OP_IfNot: { /* jump, in1 */ } VdbeBranchTaken(c!=0, 2); if( c ){ - pc = pOp->p2-1; + goto jump_to_p2; } break; } @@ -2208,7 +2250,7 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */ pIn1 = &aMem[pOp->p1]; VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2); if( (pIn1->flags & MEM_Null)!=0 ){ - pc = pOp->p2 - 1; + goto jump_to_p2; } break; } @@ -2222,7 +2264,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ pIn1 = &aMem[pOp->p1]; VdbeBranchTaken( (pIn1->flags & MEM_Null)==0, 2); if( (pIn1->flags & MEM_Null)==0 ){ - pc = pOp->p2 - 1; + goto jump_to_p2; } break; } @@ -2436,7 +2478,7 @@ case OP_Column: { } } - /* If after trying to extra new entries from the header, nHdrParsed is + /* If after trying to extract new entries from the header, nHdrParsed is ** still not up to p2, that means that the record has fewer than p2 ** columns. So the result will be either the default value or a NULL. */ @@ -2560,7 +2602,7 @@ case OP_MakeRecord: { u64 nData; /* Number of bytes of data space */ int nHdr; /* Number of bytes of header space */ i64 nByte; /* Data space required for this record */ - int nZero; /* Number of zero bytes at the end of the record */ + i64 nZero; /* Number of zero bytes at the end of the record */ int nVarint; /* Number of bytes in a varint */ u32 serial_type; /* Type field */ Mem *pData0; /* First field to be combined into the record */ @@ -2652,7 +2694,7 @@ case OP_MakeRecord: { if( nVarintdb->aLimit[SQLITE_LIMIT_LENGTH] ){ + if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } @@ -2703,7 +2745,7 @@ case OP_MakeRecord: { ** opened by cursor P1 in register P2 */ #ifndef SQLITE_OMIT_BTREECOUNT -case OP_Count: { /* out2-prerelease */ +case OP_Count: { /* out2 */ i64 nEntry; BtCursor *pCrsr; @@ -2711,6 +2753,7 @@ case OP_Count: { /* out2-prerelease */ assert( pCrsr ); nEntry = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3BtreeCount(pCrsr, &nEntry); + pOut = out2Prerelease(p, pOp); pOut->u.i = nEntry; break; } @@ -2824,7 +2867,7 @@ case OP_Savepoint: { } db->autoCommit = 1; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ - p->pc = pc; + p->pc = (int)(pOp - aOp); db->autoCommit = 0; p->rc = rc = SQLITE_BUSY; goto vdbe_return; @@ -2883,7 +2926,7 @@ case OP_Savepoint: { db->nDeferredImmCons = pSavepoint->nDeferredImmCons; } - if( !isTransaction ){ + if( !isTransaction || p1==SAVEPOINT_ROLLBACK ){ rc = sqlite3VtabSavepoint(db, p1, iSavepoint); if( rc!=SQLITE_OK ) goto abort_due_to_error; } @@ -2943,7 +2986,7 @@ case OP_AutoCommit: { }else{ db->autoCommit = (u8)desiredAutoCommit; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ - p->pc = pc; + p->pc = (int)(pOp - aOp); db->autoCommit = (u8)(1-desiredAutoCommit); p->rc = rc = SQLITE_BUSY; goto vdbe_return; @@ -3020,7 +3063,7 @@ case OP_Transaction: { if( pBt ){ rc = sqlite3BtreeBeginTrans(pBt, pOp->p2); if( rc==SQLITE_BUSY ){ - p->pc = pc; + p->pc = (int)(pOp - aOp); p->rc = rc = SQLITE_BUSY; goto vdbe_return; } @@ -3050,7 +3093,12 @@ case OP_Transaction: { p->nStmtDefImmCons = db->nDeferredImmCons; } - /* Gather the schema version number for checking */ + /* Gather the schema version number for checking: + ** IMPLEMENTATION-OF: R-32195-19465 The schema version is used by SQLite + ** each time a query is executed to ensure that the internal cache of the + ** schema used when compiling the SQL query matches the schema of the + ** database against which the compiled query is actually executed. + */ sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); iGen = db->aDb[pOp->p1].pSchema->iGeneration; }else{ @@ -3094,7 +3142,7 @@ case OP_Transaction: { ** must be started or there must be an open cursor) before ** executing this instruction. */ -case OP_ReadCookie: { /* out2-prerelease */ +case OP_ReadCookie: { /* out2 */ int iMeta; int iDb; int iCookie; @@ -3108,6 +3156,7 @@ case OP_ReadCookie: { /* out2-prerelease */ assert( DbMaskTest(p->btreeMask, iDb) ); sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta); + pOut = out2Prerelease(p, pOp); pOut->u.i = iMeta; break; } @@ -3218,20 +3267,6 @@ case OP_SetCookie: { /* in3 */ ** See also OpenRead. */ case OP_ReopenIdx: { - VdbeCursor *pCur; - - assert( pOp->p5==0 ); - assert( pOp->p4type==P4_KEYINFO ); - pCur = p->apCsr[pOp->p1]; - if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){ - assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */ - break; - } - /* If the cursor is not currently open or is open on a different - ** index, then fall through into OP_OpenRead to force a reopen */ -} -case OP_OpenRead: -case OP_OpenWrite: { int nField; KeyInfo *pKeyInfo; int p2; @@ -3241,8 +3276,20 @@ case OP_OpenWrite: { VdbeCursor *pCur; Db *pDb; - assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 ); - assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 ); + assert( pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); + assert( pOp->p4type==P4_KEYINFO ); + pCur = p->apCsr[pOp->p1]; + if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){ + assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */ + goto open_cursor_set_hints; + } + /* If the cursor is not currently open or is open on a different + ** index, then fall through into OP_OpenRead to force a reopen */ +case OP_OpenRead: +case OP_OpenWrite: + + assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR|OPFLAG_SEEKEQ))==pOp->p5 ); + assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); assert( p->bIsReader ); assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx || p->readOnly==0 ); @@ -3305,14 +3352,17 @@ case OP_OpenWrite: { pCur->pgnoRoot = p2; rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor); pCur->pKeyInfo = pKeyInfo; - assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); - sqlite3BtreeCursorHints(pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR)); - /* Set the VdbeCursor.isTable variable. Previous versions of ** SQLite used to check if the root-page flags were sane at this point ** and report database corruption if they were not, but this check has ** since moved into the btree layer. */ pCur->isTable = pOp->p4type!=P4_KEYINFO; + +open_cursor_set_hints: + assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); + assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ ); + sqlite3BtreeCursorHints(pCur->pCursor, + (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ))); break; } @@ -3428,7 +3478,7 @@ case OP_SequenceTest: { pC = p->apCsr[pOp->p1]; assert( pC->pSorter ); if( (pC->seqCount++)==0 ){ - pc = pOp->p2 - 1; + goto jump_to_p2; } break; } @@ -3573,6 +3623,22 @@ case OP_SeekGT: { /* jump, in3 */ #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif + + /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and + ** OP_SeekLE opcodes are allowed, and these must be immediately followed + ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key. + */ +#ifdef SQLITE_DEBUG + if( sqlite3BtreeCursorHasHint(pC->pCursor, BTREE_SEEK_EQ) ){ + assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE ); + assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT ); + assert( pOp[1].p1==pOp[0].p1 ); + assert( pOp[1].p2==pOp[0].p2 ); + assert( pOp[1].p3==pOp[0].p3 ); + assert( pOp[1].p4.i==pOp[0].p4.i ); + } +#endif + if( pC->isTable ){ /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do @@ -3589,7 +3655,7 @@ case OP_SeekGT: { /* jump, in3 */ if( (pIn3->flags & MEM_Real)==0 ){ /* If the P3 value cannot be converted into any kind of a number, ** then the seek is not possible, so jump to P2 */ - pc = pOp->p2 - 1; VdbeBranchTaken(1,2); + VdbeBranchTaken(1,2); goto jump_to_p2; break; } @@ -3680,7 +3746,7 @@ case OP_SeekGT: { /* jump, in3 */ assert( pOp->p2>0 ); VdbeBranchTaken(res!=0,2); if( res ){ - pc = pOp->p2 - 1; + goto jump_to_p2; } break; } @@ -3774,6 +3840,7 @@ case OP_NoConflict: /* jump, in3 */ case OP_NotFound: /* jump, in3 */ case OP_Found: { /* jump, in3 */ int alreadyExists; + int takeJump; int ii; VdbeCursor *pC; int res; @@ -3796,7 +3863,7 @@ case OP_Found: { /* jump, in3 */ pIn3 = &aMem[pOp->p3]; assert( pC->pCursor!=0 ); assert( pC->isTable==0 ); - pFree = 0; /* Not needed. Only used to suppress a compiler warning. */ + pFree = 0; if( pOp->p4.i>0 ){ r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p4.i; @@ -3819,21 +3886,20 @@ case OP_Found: { /* jump, in3 */ sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); } pIdxKey->default_rc = 0; + takeJump = 0; if( pOp->opcode==OP_NoConflict ){ /* For the OP_NoConflict opcode, take the jump if any of the ** input fields are NULL, since any key with a NULL will not ** conflict */ for(ii=0; iinField; ii++){ if( pIdxKey->aMem[ii].flags & MEM_Null ){ - pc = pOp->p2 - 1; VdbeBranchTaken(1,2); + takeJump = 1; break; } } } rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res); - if( pOp->p4.i==0 ){ - sqlite3DbFree(db, pFree); - } + sqlite3DbFree(db, pFree); if( rc!=SQLITE_OK ){ break; } @@ -3844,10 +3910,10 @@ case OP_Found: { /* jump, in3 */ pC->cacheStatus = CACHE_STALE; if( pOp->opcode==OP_Found ){ VdbeBranchTaken(alreadyExists!=0,2); - if( alreadyExists ) pc = pOp->p2 - 1; + if( alreadyExists ) goto jump_to_p2; }else{ - VdbeBranchTaken(alreadyExists==0,2); - if( !alreadyExists ) pc = pOp->p2 - 1; + VdbeBranchTaken(takeJump||alreadyExists==0,2); + if( takeJump || !alreadyExists ) goto jump_to_p2; } break; } @@ -3896,10 +3962,8 @@ case OP_NotExists: { /* jump, in3 */ pC->cacheStatus = CACHE_STALE; pC->deferredMoveto = 0; VdbeBranchTaken(res!=0,2); - if( res!=0 ){ - pc = pOp->p2 - 1; - } pC->seekResult = res; + if( res!=0 ) goto jump_to_p2; break; } @@ -3911,9 +3975,10 @@ case OP_NotExists: { /* jump, in3 */ ** The sequence number on the cursor is incremented after this ** instruction. */ -case OP_Sequence: { /* out2-prerelease */ +case OP_Sequence: { /* out2 */ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( p->apCsr[pOp->p1]!=0 ); + pOut = out2Prerelease(p, pOp); pOut->u.i = p->apCsr[pOp->p1]->seqCount++; break; } @@ -3934,7 +3999,7 @@ case OP_Sequence: { /* out2-prerelease */ ** generated record number. This P3 mechanism is used to help implement the ** AUTOINCREMENT feature. */ -case OP_NewRowid: { /* out2-prerelease */ +case OP_NewRowid: { /* out2 */ i64 v; /* The new rowid */ VdbeCursor *pC; /* Cursor of table to get the new rowid */ int res; /* Result of an sqlite3BtreeLast() */ @@ -3944,6 +4009,7 @@ case OP_NewRowid: { /* out2-prerelease */ v = 0; res = 0; + pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); @@ -4257,9 +4323,7 @@ case OP_SorterCompare: { res = 0; rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res); VdbeBranchTaken(res!=0,2); - if( res ){ - pc = pOp->p2-1; - } + if( res ) goto jump_to_p2; break; }; @@ -4388,12 +4452,13 @@ case OP_RowData: { ** be a separate OP_VRowid opcode for use with virtual tables, but this ** one opcode now works for both table types. */ -case OP_Rowid: { /* out2-prerelease */ +case OP_Rowid: { /* out2 */ VdbeCursor *pC; i64 v; sqlite3_vtab *pVtab; const sqlite3_module *pModule; + pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); @@ -4446,7 +4511,7 @@ case OP_NullRow: { break; } -/* Opcode: Last P1 P2 * * * +/* Opcode: Last P1 P2 P3 * * ** ** The next use of the Rowid or Column or Prev instruction for P1 ** will refer to the last entry in the database table or index. @@ -4473,12 +4538,13 @@ case OP_Last: { /* jump */ pC->nullRow = (u8)res; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; + pC->seekResult = pOp->p3; #ifdef SQLITE_DEBUG pC->seekOp = OP_Last; #endif if( pOp->p2>0 ){ VdbeBranchTaken(res!=0,2); - if( res ) pc = pOp->p2 - 1; + if( res ) goto jump_to_p2; } break; } @@ -4542,9 +4608,7 @@ case OP_Rewind: { /* jump */ pC->nullRow = (u8)res; assert( pOp->p2>0 && pOp->p2nOp ); VdbeBranchTaken(res!=0,2); - if( res ){ - pc = pOp->p2 - 1; - } + if( res ) goto jump_to_p2; break; } @@ -4655,11 +4719,11 @@ next_tail: VdbeBranchTaken(res==0,2); if( res==0 ){ pC->nullRow = 0; - pc = pOp->p2 - 1; p->aCounter[pOp->p5]++; #ifdef SQLITE_TEST sqlite3_search_count++; #endif + goto jump_to_p2_and_check_for_interrupt; }else{ pC->nullRow = 1; } @@ -4767,11 +4831,12 @@ case OP_IdxDelete: { ** ** See also: Rowid, MakeRecord. */ -case OP_IdxRowid: { /* out2-prerelease */ +case OP_IdxRowid: { /* out2 */ BtCursor *pCrsr; VdbeCursor *pC; i64 rowid; + pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); @@ -4884,9 +4949,7 @@ case OP_IdxGE: { /* jump */ res++; } VdbeBranchTaken(res>0,2); - if( res>0 ){ - pc = pOp->p2 - 1 ; - } + if( res>0 ) goto jump_to_p2; break; } @@ -4910,32 +4973,18 @@ case OP_IdxGE: { /* jump */ ** ** See also: Clear */ -case OP_Destroy: { /* out2-prerelease */ +case OP_Destroy: { /* out2 */ int iMoved; - int iCnt; - Vdbe *pVdbe; int iDb; assert( p->readOnly==0 ); -#ifndef SQLITE_OMIT_VIRTUALTABLE - iCnt = 0; - for(pVdbe=db->pVdbe; pVdbe; pVdbe = pVdbe->pNext){ - if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->bIsReader - && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 - ){ - iCnt++; - } - } -#else - iCnt = db->nVdbeRead; -#endif + pOut = out2Prerelease(p, pOp); pOut->flags = MEM_Null; - if( iCnt>1 ){ + if( db->nVdbeRead > db->nVDestroy+1 ){ rc = SQLITE_LOCKED; p->errorAction = OE_Abort; }else{ iDb = pOp->p3; - assert( iCnt==1 ); assert( DbMaskTest(p->btreeMask, iDb) ); iMoved = 0; /* Not needed. Only to silence a warning. */ rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved); @@ -5038,12 +5087,13 @@ case OP_ResetSorter: { ** ** See documentation on OP_CreateTable for additional information. */ -case OP_CreateIndex: /* out2-prerelease */ -case OP_CreateTable: { /* out2-prerelease */ +case OP_CreateIndex: /* out2 */ +case OP_CreateTable: { /* out2 */ int pgno; int flags; Db *pDb; + pOut = out2Prerelease(p, pOp); pgno = 0; assert( pOp->p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); @@ -5269,12 +5319,12 @@ case OP_RowSetRead: { /* jump, in1, out3 */ ){ /* The boolean index is empty */ sqlite3VdbeMemSetNull(pIn1); - pc = pOp->p2 - 1; VdbeBranchTaken(1,2); + goto jump_to_p2_and_check_for_interrupt; }else{ /* A value was pulled from the index */ - sqlite3VdbeMemSetInt64(&aMem[pOp->p3], val); VdbeBranchTaken(0,2); + sqlite3VdbeMemSetInt64(&aMem[pOp->p3], val); } goto check_for_interrupt; } @@ -5325,10 +5375,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */ if( iSet ){ exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i); VdbeBranchTaken(exists!=0,2); - if( exists ){ - pc = pOp->p2 - 1; - break; - } + if( exists ) goto jump_to_p2; } if( iSet>=0 ){ sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i); @@ -5417,7 +5464,7 @@ case OP_Program: { /* jump */ pFrame->v = p; pFrame->nChildMem = nMem; pFrame->nChildCsr = pProgram->nCsr; - pFrame->pc = pc; + pFrame->pc = (int)(pOp - aOp); pFrame->aMem = p->aMem; pFrame->nMem = p->nMem; pFrame->apCsr = p->apCsr; @@ -5440,7 +5487,7 @@ case OP_Program: { /* jump */ pFrame = pRt->u.pFrame; assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem ); assert( pProgram->nCsr==pFrame->nChildCsr ); - assert( pc==pFrame->pc ); + assert( (int)(pOp - aOp)==pFrame->pc ); } p->nFrame++; @@ -5461,7 +5508,7 @@ case OP_Program: { /* jump */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS p->anExec = 0; #endif - pc = -1; + pOp = &aOp[-1]; memset(p->aOnceFlag, 0, p->nOnceFlag); break; @@ -5479,9 +5526,10 @@ case OP_Program: { /* jump */ ** the value of the P1 argument to the value of the P1 argument to the ** calling OP_Program instruction. */ -case OP_Param: { /* out2-prerelease */ +case OP_Param: { /* out2 */ VdbeFrame *pFrame; Mem *pIn; + pOut = out2Prerelease(p, pOp); pFrame = p->pFrame; pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1]; sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem); @@ -5525,10 +5573,10 @@ case OP_FkCounter: { case OP_FkIfZero: { /* jump */ if( pOp->p1 ){ VdbeBranchTaken(db->nDeferredCons==0 && db->nDeferredImmCons==0, 2); - if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1; + if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) goto jump_to_p2; }else{ VdbeBranchTaken(p->nFkConstraint==0 && db->nDeferredImmCons==0, 2); - if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1; + if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) goto jump_to_p2; } break; } @@ -5568,18 +5616,18 @@ case OP_MemMax: { /* in2 */ /* Opcode: IfPos P1 P2 * * * ** Synopsis: if r[P1]>0 goto P2 ** -** If the value of register P1 is 1 or greater, jump to P2. +** Register P1 must contain an integer. +** If the value of register P1 is 1 or greater, jump to P2 and +** add the literal value P3 to register P1. ** -** It is illegal to use this instruction on a register that does -** not contain an integer. An assertion fault will result if you try. +** If the initial value of register P1 is less than 1, then the +** value is unchanged and control passes through to the next instruction. */ case OP_IfPos: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); VdbeBranchTaken( pIn1->u.i>0, 2); - if( pIn1->u.i>0 ){ - pc = pOp->p2 - 1; - } + if( pIn1->u.i>0 ) goto jump_to_p2; break; } @@ -5594,26 +5642,56 @@ case OP_IfNeg: { /* jump, in1 */ assert( pIn1->flags&MEM_Int ); pIn1->u.i += pOp->p3; VdbeBranchTaken(pIn1->u.i<0, 2); - if( pIn1->u.i<0 ){ - pc = pOp->p2 - 1; + if( pIn1->u.i<0 ) goto jump_to_p2; + break; +} + +/* Opcode: IfNotZero P1 P2 P3 * * +** Synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2 +** +** Register P1 must contain an integer. If the content of register P1 is +** initially nonzero, then add P3 to P1 and jump to P2. If register P1 is +** initially zero, leave it unchanged and fall through. +*/ +case OP_IfNotZero: { /* jump, in1 */ + pIn1 = &aMem[pOp->p1]; + assert( pIn1->flags&MEM_Int ); + VdbeBranchTaken(pIn1->u.i<0, 2); + if( pIn1->u.i ){ + pIn1->u.i += pOp->p3; + goto jump_to_p2; } break; } -/* Opcode: IfZero P1 P2 P3 * * -** Synopsis: r[P1]+=P3, if r[P1]==0 goto P2 +/* Opcode: DecrJumpZero P1 P2 * * * +** Synopsis: if (--r[P1])==0 goto P2 ** -** The register P1 must contain an integer. Add literal P3 to the -** value in register P1. If the result is exactly 0, jump to P2. +** Register P1 must hold an integer. Decrement the value in register P1 +** then jump to P2 if the new value is exactly zero. */ -case OP_IfZero: { /* jump, in1 */ +case OP_DecrJumpZero: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); - pIn1->u.i += pOp->p3; + pIn1->u.i--; VdbeBranchTaken(pIn1->u.i==0, 2); - if( pIn1->u.i==0 ){ - pc = pOp->p2 - 1; - } + if( pIn1->u.i==0 ) goto jump_to_p2; + break; +} + + +/* Opcode: JumpZeroIncr P1 P2 * * * +** Synopsis: if (r[P1]++)==0 ) goto P2 +** +** The register P1 must contain an integer. If register P1 is initially +** zero, then jump to P2. Increment register P1 regardless of whether or +** not the jump is taken. +*/ +case OP_JumpZeroIncr: { /* jump, in1 */ + pIn1 = &aMem[pOp->p1]; + assert( pIn1->flags&MEM_Int ); + VdbeBranchTaken(pIn1->u.i==0, 2); + if( (pIn1->u.i++)==0 ) goto jump_to_p2; break; } @@ -5655,7 +5733,7 @@ case OP_AggStep: { ctx.pOut = &t; ctx.isError = 0; ctx.pVdbe = p; - ctx.iOp = pc; + ctx.iOp = (int)(pOp - aOp); ctx.skipFlag = 0; (ctx.pFunc->xStep)(&ctx, n, apVal); /* IMP: R-24505-23230 */ if( ctx.isError ){ @@ -5750,7 +5828,7 @@ case OP_Checkpoint: { ** ** Write a string containing the final journal-mode to register P2. */ -case OP_JournalMode: { /* out2-prerelease */ +case OP_JournalMode: { /* out2 */ Btree *pBt; /* Btree to change journal mode of */ Pager *pPager; /* Pager associated with pBt */ int eNew; /* New journal mode */ @@ -5759,6 +5837,7 @@ case OP_JournalMode: { /* out2-prerelease */ const char *zFilename; /* Name of database file for pPager */ #endif + pOut = out2Prerelease(p, pOp); eNew = pOp->p3; assert( eNew==PAGER_JOURNALMODE_DELETE || eNew==PAGER_JOURNALMODE_TRUNCATE @@ -5834,7 +5913,6 @@ case OP_JournalMode: { /* out2-prerelease */ } eNew = sqlite3PagerSetJournalMode(pPager, eNew); - pOut = &aMem[pOp->p2]; pOut->flags = MEM_Str|MEM_Static|MEM_Term; pOut->z = (char *)sqlite3JournalModename(eNew); pOut->n = sqlite3Strlen30(pOut->z); @@ -5875,8 +5953,8 @@ case OP_IncrVacuum: { /* jump */ rc = sqlite3BtreeIncrVacuum(pBt); VdbeBranchTaken(rc==SQLITE_DONE,2); if( rc==SQLITE_DONE ){ - pc = pOp->p2 - 1; rc = SQLITE_OK; + goto jump_to_p2; } break; } @@ -5954,13 +6032,29 @@ case OP_VBegin: { #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE -/* Opcode: VCreate P1 * * P4 * +/* Opcode: VCreate P1 P2 * * * ** -** P4 is the name of a virtual table in database P1. Call the xCreate method -** for that table. +** P2 is a register that holds the name of a virtual table in database +** P1. Call the xCreate method for that table. */ case OP_VCreate: { - rc = sqlite3VtabCallCreate(db, pOp->p1, pOp->p4.z, &p->zErrMsg); + Mem sMem; /* For storing the record being decoded */ + const char *zTab; /* Name of the virtual table */ + + memset(&sMem, 0, sizeof(sMem)); + sMem.db = db; + /* Because P2 is always a static string, it is impossible for the + ** sqlite3VdbeMemCopy() to fail */ + assert( (aMem[pOp->p2].flags & MEM_Str)!=0 ); + assert( (aMem[pOp->p2].flags & MEM_Static)!=0 ); + rc = sqlite3VdbeMemCopy(&sMem, &aMem[pOp->p2]); + assert( rc==SQLITE_OK ); + zTab = (const char*)sqlite3_value_text(&sMem); + assert( zTab || db->mallocFailed ); + if( zTab ){ + rc = sqlite3VtabCallCreate(db, pOp->p1, zTab, &p->zErrMsg); + } + sqlite3VdbeMemRelease(&sMem); break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -5972,9 +6066,9 @@ case OP_VCreate: { ** of that table. */ case OP_VDestroy: { - p->inVtabMethod = 2; + db->nVDestroy++; rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z); - p->inVtabMethod = 0; + db->nVDestroy--; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -5990,14 +6084,17 @@ case OP_VOpen: { VdbeCursor *pCur; sqlite3_vtab_cursor *pVtabCursor; sqlite3_vtab *pVtab; - sqlite3_module *pModule; + const sqlite3_module *pModule; assert( p->bIsReader ); pCur = 0; pVtabCursor = 0; pVtab = pOp->p4.pVtab->pVtab; - pModule = (sqlite3_module *)pVtab->pModule; - assert(pVtab && pModule); + if( pVtab==0 || NEVER(pVtab->pModule==0) ){ + rc = SQLITE_LOCKED; + break; + } + pModule = pVtab->pModule; rc = pModule->xOpen(pVtab, &pVtabCursor); sqlite3VtabImportErrmsg(p, pVtab); if( SQLITE_OK==rc ){ @@ -6008,9 +6105,11 @@ case OP_VOpen: { pCur = allocateCursor(p, pOp->p1, 0, -1, 0); if( pCur ){ pCur->pVtabCursor = pVtabCursor; + pVtab->nRef++; }else{ - db->mallocFailed = 1; + assert( db->mallocFailed ); pModule->xClose(pVtabCursor); + goto no_mem; } } break; @@ -6066,27 +6165,19 @@ case OP_VFilter: { /* jump */ iQuery = (int)pQuery->u.i; /* Invoke the xFilter method */ - { - res = 0; - apArg = p->apArg; - for(i = 0; iinVtabMethod = 1; - rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg); - p->inVtabMethod = 0; - sqlite3VtabImportErrmsg(p, pVtab); - if( rc==SQLITE_OK ){ - res = pModule->xEof(pVtabCursor); - } - VdbeBranchTaken(res!=0,2); - if( res ){ - pc = pOp->p2 - 1; - } + res = 0; + apArg = p->apArg; + for(i = 0; ixFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg); + sqlite3VtabImportErrmsg(p, pVtab); + if( rc==SQLITE_OK ){ + res = pModule->xEof(pVtabCursor); } pCur->nullRow = 0; - + VdbeBranchTaken(res!=0,2); + if( res ) goto jump_to_p2; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -6165,9 +6256,7 @@ case OP_VNext: { /* jump */ ** data is available) and the error code returned when xColumn or ** some other method is next invoked on the save virtual table cursor. */ - p->inVtabMethod = 1; rc = pModule->xNext(pCur->pVtabCursor); - p->inVtabMethod = 0; sqlite3VtabImportErrmsg(p, pVtab); if( rc==SQLITE_OK ){ res = pModule->xEof(pCur->pVtabCursor); @@ -6175,7 +6264,7 @@ case OP_VNext: { /* jump */ VdbeBranchTaken(!res,2); if( !res ){ /* If there is data, jump to P2 */ - pc = pOp->p2 - 1; + goto jump_to_p2_and_check_for_interrupt; } goto check_for_interrupt; } @@ -6242,7 +6331,7 @@ case OP_VRename: { */ case OP_VUpdate: { sqlite3_vtab *pVtab; - sqlite3_module *pModule; + const sqlite3_module *pModule; int nArg; int i; sqlite_int64 rowid; @@ -6254,7 +6343,11 @@ case OP_VUpdate: { ); assert( p->readOnly==0 ); pVtab = pOp->p4.pVtab->pVtab; - pModule = (sqlite3_module *)pVtab->pModule; + if( pVtab==0 || NEVER(pVtab->pModule==0) ){ + rc = SQLITE_LOCKED; + break; + } + pModule = pVtab->pModule; nArg = pOp->p2; assert( pOp->p4type==P4_VTAB ); if( ALWAYS(pModule->xUpdate) ){ @@ -6294,7 +6387,8 @@ case OP_VUpdate: { ** ** Write the current number of pages in database P1 to memory cell P2. */ -case OP_Pagecount: { /* out2-prerelease */ +case OP_Pagecount: { /* out2 */ + pOut = out2Prerelease(p, pOp); pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt); break; } @@ -6310,10 +6404,11 @@ case OP_Pagecount: { /* out2-prerelease */ ** ** Store the maximum page count after the change in register P2. */ -case OP_MaxPgcnt: { /* out2-prerelease */ +case OP_MaxPgcnt: { /* out2 */ unsigned int newMax; Btree *pBt; + pOut = out2Prerelease(p, pOp); pBt = db->aDb[pOp->p1].pBt; newMax = 0; if( pOp->p3 ){ @@ -6342,9 +6437,6 @@ case OP_Init: { /* jump */ char *zTrace; char *z; - if( pOp->p2 ){ - pc = pOp->p2 - 1; - } #ifndef SQLITE_OMIT_TRACE if( db->xTrace && !p->doingRerun @@ -6372,6 +6464,7 @@ case OP_Init: { /* jump */ } #endif /* SQLITE_DEBUG */ #endif /* SQLITE_OMIT_TRACE */ + if( pOp->p2 ) goto jump_to_p2; break; } @@ -6403,8 +6496,8 @@ default: { /* This is really OP_Noop and OP_Explain */ #ifdef VDBE_PROFILE { u64 endTime = sqlite3Hwtime(); - if( endTime>start ) pOp->cycles += endTime - start; - pOp->cnt++; + if( endTime>start ) pOrigOp->cycles += endTime - start; + pOrigOp->cnt++; } #endif @@ -6414,16 +6507,16 @@ default: { /* This is really OP_Noop and OP_Explain */ ** the evaluator loop. So we can leave it out when NDEBUG is defined. */ #ifndef NDEBUG - assert( pc>=-1 && pcnOp ); + assert( pOp>=&aOp[-1] && pOp<&aOp[p->nOp-1] ); #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ if( rc!=0 ) printf("rc=%d\n",rc); - if( pOp->opflags & (OPFLG_OUT2_PRERELEASE|OPFLG_OUT2) ){ - registerTrace(pOp->p2, &aMem[pOp->p2]); + if( pOrigOp->opflags & (OPFLG_OUT2) ){ + registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]); } - if( pOp->opflags & OPFLG_OUT3 ){ - registerTrace(pOp->p3, &aMem[pOp->p3]); + if( pOrigOp->opflags & OPFLG_OUT3 ){ + registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]); } } #endif /* SQLITE_DEBUG */ @@ -6438,7 +6531,7 @@ vdbe_error_halt: p->rc = rc; testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(rc, "statement aborts at %d: [%s] %s", - pc, p->zSql, p->zErrMsg); + (int)(pOp - aOp), p->zSql, p->zErrMsg); sqlite3VdbeHalt(p); if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1; rc = SQLITE_ERROR; diff --git a/src/vdbe.h b/src/vdbe.h index b715241..bb597b6 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -213,6 +213,7 @@ int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); +int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int); UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); typedef int (*RecordCompare)(int,const void*,UnpackedRecord*); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 1a7297e..d3955af 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -313,14 +313,6 @@ struct ScanStatus { ** ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare() ** is really a pointer to an instance of this structure. -** -** The Vdbe.inVtabMethod variable is set to non-zero for the duration of -** any virtual table method invocations made by the vdbe program. It is -** set to 2 for xDestroy method calls and 1 for all other methods. This -** variable is used for two purposes: to allow xDestroy methods to execute -** "DROP TABLE" statements and to prevent some nasty side effects of -** malloc failure when SQLite is invoked recursively by a virtual table -** method function. */ struct Vdbe { sqlite3 *db; /* The database connection that owns this statement */ @@ -344,11 +336,13 @@ struct Vdbe { u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ +#ifdef SQLITE_DEBUG + int rcApp; /* errcode set by sqlite3_result_error_code() */ +#endif u16 nResColumn; /* Number of columns in one row of the result set */ u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ bft explain:2; /* True if EXPLAIN present on SQL command */ - bft inVtabMethod:2; /* See comments above */ bft changeCntOn:1; /* True to update the change-counter */ bft expired:1; /* True if the VM needs to be recompiled */ bft runOnlyOnce:1; /* Automatically expire on reset */ diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 21c537d..e03640d 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -170,6 +170,10 @@ const void *sqlite3_value_text16le(sqlite3_value *pVal){ return sqlite3ValueText(pVal, SQLITE_UTF16LE); } #endif /* SQLITE_OMIT_UTF16 */ +/* EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five +** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating +** point number string BLOB NULL +*/ int sqlite3_value_type(sqlite3_value* pVal){ static const u8 aType[] = { SQLITE_BLOB, /* 0x00 */ @@ -365,6 +369,9 @@ void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ pCtx->isError = errCode; pCtx->fErrorOrAux = 1; +#ifdef SQLITE_DEBUG + if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode; +#endif if( pCtx->pOut->flags & MEM_Null ){ sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, SQLITE_UTF8, SQLITE_STATIC); @@ -445,7 +452,7 @@ static int sqlite3Step(Vdbe *p){ ** or SQLITE_BUSY error. */ #ifdef SQLITE_OMIT_AUTORESET - if( p->rc==SQLITE_BUSY || p->rc==SQLITE_LOCKED ){ + if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){ sqlite3_reset((sqlite3_stmt*)p); }else{ return SQLITE_MISUSE_BKPT; @@ -491,6 +498,9 @@ static int sqlite3Step(Vdbe *p){ if( p->bIsReader ) db->nVdbeRead++; p->pc = 0; } +#ifdef SQLITE_DEBUG + p->rcApp = SQLITE_OK; +#endif #ifndef SQLITE_OMIT_EXPLAIN if( p->explain ){ rc = sqlite3VdbeList(p); @@ -535,7 +545,7 @@ end_of_step: assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR || rc==SQLITE_BUSY || rc==SQLITE_MISUSE ); - assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE ); + assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp ); if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ /* If this statement was prepared using sqlite3_prepare_v2(), and an ** error has occurred, then return the error code in p->rc to the @@ -623,16 +633,26 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ } /* -** Return the current time for a statement +** Return the current time for a statement. If the current time +** is requested more than once within the same run of a single prepared +** statement, the exact same time is returned for each invocation regardless +** of the amount of time that elapses between invocations. In other words, +** the time returned is always the time of the first call. */ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ - Vdbe *v = p->pVdbe; int rc; - if( v->iCurrentTime==0 ){ - rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, &v->iCurrentTime); - if( rc ) v->iCurrentTime = 0; +#ifndef SQLITE_ENABLE_STAT3_OR_STAT4 + sqlite3_int64 *piTime = &p->pVdbe->iCurrentTime; + assert( p->pVdbe!=0 ); +#else + sqlite3_int64 iTime = 0; + sqlite3_int64 *piTime = p->pVdbe!=0 ? &p->pVdbe->iCurrentTime : &iTime; +#endif + if( *piTime==0 ){ + rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, piTime); + if( rc ) *piTime = 0; } - return v->iCurrentTime; + return *piTime; } /* @@ -702,6 +722,11 @@ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); +#if SQLITE_ENABLE_STAT3_OR_STAT4 + if( pCtx->pVdbe==0 ) return 0; +#else + assert( pCtx->pVdbe!=0 ); +#endif for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; } @@ -725,6 +750,11 @@ void sqlite3_set_auxdata( assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); if( iArg<0 ) goto failed; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( pVdbe==0 ) goto failed; +#else + assert( pVdbe!=0 ); +#endif for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index e07aacb..2c32038 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1118,7 +1118,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ #ifndef SQLITE_OMIT_VIRTUALTABLE case P4_VTAB: { sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab; - sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule); + sqlite3_snprintf(nTemp, zTemp, "vtab:%p", pVtab); break; } #endif @@ -1782,13 +1782,29 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ else if( pCx->pVtabCursor ){ sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor; const sqlite3_module *pModule = pVtabCursor->pVtab->pModule; - p->inVtabMethod = 1; + assert( pVtabCursor->pVtab->nRef>0 ); + pVtabCursor->pVtab->nRef--; pModule->xClose(pVtabCursor); - p->inVtabMethod = 0; } #endif } +/* +** Close all cursors in the current frame. +*/ +static void closeCursorsInFrame(Vdbe *p){ + if( p->apCsr ){ + int i; + for(i=0; inCursor; i++){ + VdbeCursor *pC = p->apCsr[i]; + if( pC ){ + sqlite3VdbeFreeCursor(p, pC); + p->apCsr[i] = 0; + } + } + } +} + /* ** Copy the values stored in the VdbeFrame structure to its Vdbe. This ** is used, for example, when a trigger sub-program is halted to restore @@ -1796,6 +1812,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ */ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ Vdbe *v = pFrame->v; + closeCursorsInFrame(v); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS v->anExec = pFrame->anExec; #endif @@ -1830,17 +1847,7 @@ static void closeAllCursors(Vdbe *p){ p->nFrame = 0; } assert( p->nFrame==0 ); - - if( p->apCsr ){ - int i; - for(i=0; inCursor; i++){ - VdbeCursor *pC = p->apCsr[i]; - if( pC ){ - sqlite3VdbeFreeCursor(p, pC); - p->apCsr[i] = 0; - } - } - } + closeCursorsInFrame(p); if( p->aMem ){ releaseMemArray(&p->aMem[1], p->nMem); } @@ -2143,7 +2150,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ ** doing this the directory is synced again before any individual ** transaction files are deleted. */ - rc = sqlite3OsDelete(pVfs, zMaster, 1); + rc = sqlite3OsDelete(pVfs, zMaster, needSync); sqlite3DbFree(db, zMaster); zMaster = 0; if( rc ){ @@ -3373,7 +3380,8 @@ static void vdbeAssertFieldCountWithinLimits( if( CORRUPT_DB ) return; idx = getVarint32(aKey, szHdr); - assert( szHdr<=nKey ); + assert( nKey>=0 ); + assert( szHdr<=(u32)nKey ); while( idxerrCode is set to SQLITE_NOMEM and, if it is not NULL, the ** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db). */ -static int vdbeRecordCompareWithSkip( +int sqlite3VdbeRecordCompareWithSkip( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2, /* Right key */ int bSkip /* If true, skip the first field */ @@ -3770,7 +3778,7 @@ int sqlite3VdbeRecordCompare( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2 /* Right key */ ){ - return vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0); + return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0); } @@ -3858,7 +3866,7 @@ static int vdbeRecordCompareInt( }else if( pPKey2->nField>1 ){ /* The first fields of the two keys are equal. Compare the trailing ** fields. */ - res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); + res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); }else{ /* The first fields of the two keys are equal and there are no trailing ** fields. Return pPKey2->default_rc in this case. */ @@ -3906,7 +3914,7 @@ static int vdbeRecordCompareString( res = nStr - pPKey2->aMem[0].n; if( res==0 ){ if( pPKey2->nField>1 ){ - res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); + res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); }else{ res = pPKey2->default_rc; } diff --git a/src/vdbeblob.c b/src/vdbeblob.c index cf1eb59..ea01f5c 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -154,12 +154,17 @@ int sqlite3_blob_open( Incrblob *pBlob = 0; #ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || ppBlob==0 || zTable==0 ){ + if( ppBlob==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + *ppBlob = 0; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zTable==0 ){ return SQLITE_MISUSE_BKPT; } #endif flags = !!flags; /* flags = (flags ? 1 : 0); */ - *ppBlob = 0; sqlite3_mutex_enter(db->mutex); @@ -373,7 +378,7 @@ static int blobReadWrite( sqlite3_mutex_enter(db->mutex); v = (Vdbe*)p->pStmt; - if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){ + if( n<0 || iOffset<0 || ((sqlite3_int64)iOffset+n)>p->nByte ){ /* Request is out of range. Return a transient error. */ rc = SQLITE_ERROR; }else if( v==0 ){ diff --git a/src/vdbemem.c b/src/vdbemem.c index 870fb5b..2fd6a71 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -200,10 +200,11 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ pMem->z[pMem->n] = 0; pMem->z[pMem->n+1] = 0; pMem->flags |= MEM_Term; -#ifdef SQLITE_DEBUG - pMem->pScopyFrom = 0; -#endif } + pMem->flags &= ~MEM_Ephem; +#ifdef SQLITE_DEBUG + pMem->pScopyFrom = 0; +#endif return SQLITE_OK; } @@ -1090,7 +1091,7 @@ struct ValueNewStat4Ctx { ** Otherwise, if the second argument is non-zero, then this function is ** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not ** already been allocated, allocate the UnpackedRecord structure that -** that function will return to its caller here. Then return a pointer +** that function will return to its caller here. Then return a pointer to ** an sqlite3_value within the UnpackedRecord.a[] array. */ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ @@ -1134,6 +1135,113 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ return sqlite3ValueNew(db); } +/* +** The expression object indicated by the second argument is guaranteed +** to be a scalar SQL function. If +** +** * all function arguments are SQL literals, +** * the SQLITE_FUNC_CONSTANT function flag is set, and +** * the SQLITE_FUNC_NEEDCOLL function flag is not set, +** +** then this routine attempts to invoke the SQL function. Assuming no +** error occurs, output parameter (*ppVal) is set to point to a value +** object containing the result before returning SQLITE_OK. +** +** Affinity aff is applied to the result of the function before returning. +** If the result is a text value, the sqlite3_value object uses encoding +** enc. +** +** If the conditions above are not met, this function returns SQLITE_OK +** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to +** NULL and an SQLite error code returned. +*/ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +static int valueFromFunction( + sqlite3 *db, /* The database connection */ + Expr *p, /* The expression to evaluate */ + u8 enc, /* Encoding to use */ + u8 aff, /* Affinity to use */ + sqlite3_value **ppVal, /* Write the new value here */ + struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */ +){ + sqlite3_context ctx; /* Context object for function invocation */ + sqlite3_value **apVal = 0; /* Function arguments */ + int nVal = 0; /* Size of apVal[] array */ + FuncDef *pFunc = 0; /* Function definition */ + sqlite3_value *pVal = 0; /* New value */ + int rc = SQLITE_OK; /* Return code */ + int nName; /* Size of function name in bytes */ + ExprList *pList = 0; /* Function arguments */ + int i; /* Iterator variable */ + + assert( pCtx!=0 ); + assert( (p->flags & EP_TokenOnly)==0 ); + pList = p->x.pList; + if( pList ) nVal = pList->nExpr; + nName = sqlite3Strlen30(p->u.zToken); + pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0); + assert( pFunc ); + if( (pFunc->funcFlags & SQLITE_FUNC_CONSTANT)==0 + || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) + ){ + return SQLITE_OK; + } + + if( pList ){ + apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal); + if( apVal==0 ){ + rc = SQLITE_NOMEM; + goto value_from_function_out; + } + for(i=0; ia[i].pExpr, enc, aff, &apVal[i]); + if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out; + } + } + + pVal = valueNew(db, pCtx); + if( pVal==0 ){ + rc = SQLITE_NOMEM; + goto value_from_function_out; + } + + assert( pCtx->pParse->rc==SQLITE_OK ); + memset(&ctx, 0, sizeof(ctx)); + ctx.pOut = pVal; + ctx.pFunc = pFunc; + pFunc->xFunc(&ctx, nVal, apVal); + if( ctx.isError ){ + rc = ctx.isError; + sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal)); + }else{ + sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8); + assert( rc==SQLITE_OK ); + rc = sqlite3VdbeChangeEncoding(pVal, enc); + if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){ + rc = SQLITE_TOOBIG; + pCtx->pParse->nErr++; + } + } + pCtx->pParse->rc = rc; + + value_from_function_out: + if( rc!=SQLITE_OK ){ + pVal = 0; + } + if( apVal ){ + for(i=0; iop)==TK_UPLUS ) pExpr = pExpr->pLeft; if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; + /* Compressed expressions only appear when parsing the DEFAULT clause + ** on a table column definition, and hence only when pCtx==0. This + ** check ensures that an EP_TokenOnly expression is never passed down + ** into valueFromFunction(). */ + assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 ); + if( op==TK_CAST ){ u8 aff = sqlite3AffinityType(pExpr->u.zToken,0); rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx); @@ -1242,6 +1356,12 @@ static int valueFromExpr( } #endif +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + else if( op==TK_FUNCTION && pCtx!=0 ){ + rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx); + } +#endif + *ppVal = pVal; return rc; @@ -1528,7 +1648,7 @@ void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){ Mem *aMem = pRec->aMem; sqlite3 *db = aMem[0].db; for(i=0; ipKeyInfo); sqlite3DbFree(db, pRec); diff --git a/src/vdbesort.c b/src/vdbesort.c index 5a43a10..afc4d6a 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -291,6 +291,7 @@ struct MergeEngine { ** after the thread has finished are not dire. So we don't worry about ** memory barriers and such here. */ +typedef int (*SorterCompare)(SortSubtask*,int*,const void*,int,const void*,int); struct SortSubtask { SQLiteThread *pThread; /* Background thread, if any */ int bDone; /* Set if thread is finished but not joined */ @@ -298,10 +299,12 @@ struct SortSubtask { UnpackedRecord *pUnpacked; /* Space to unpack a record */ SorterList list; /* List for thread to write to a PMA */ int nPMA; /* Number of PMAs currently in file */ + SorterCompare xCompare; /* Compare function to use */ SorterFile file; /* Temp file for level-0 PMAs */ SorterFile file2; /* Space for other PMAs */ }; + /* ** Main sorter structure. A single instance of this is allocated for each ** sorter cursor created by the VDBE. @@ -328,9 +331,13 @@ struct VdbeSorter { u8 bUseThreads; /* True to use background threads */ u8 iPrev; /* Previous thread used to flush PMA */ u8 nTask; /* Size of aTask[] array */ + u8 typeMask; SortSubtask aTask[1]; /* One or more subtasks */ }; +#define SORTER_TYPE_INTEGER 0x01 +#define SORTER_TYPE_TEXT 0x02 + /* ** An instance of the following object is used to read records out of a ** PMA, in sorted order. The next key to be read is cached in nKey/aKey. @@ -742,32 +749,162 @@ static int vdbePmaReaderInit( return rc; } +/* +** A version of vdbeSorterCompare() that assumes that it has already been +** determined that the first field of key1 is equal to the first field of +** key2. +*/ +static int vdbeSorterCompareTail( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ + int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ + const void *pKey1, int nKey1, /* Left side of comparison */ + const void *pKey2, int nKey2 /* Right side of comparison */ +){ + UnpackedRecord *r2 = pTask->pUnpacked; + if( *pbKey2Cached==0 ){ + sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); + *pbKey2Cached = 1; + } + return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, r2, 1); +} /* ** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, ** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences ** used by the comparison. Return the result of the comparison. ** -** Before returning, object (pTask->pUnpacked) is populated with the -** unpacked version of key2. Or, if pKey2 is passed a NULL pointer, then it -** is assumed that the (pTask->pUnpacked) structure already contains the -** unpacked key to use as key2. +** If IN/OUT parameter *pbKey2Cached is true when this function is called, +** it is assumed that (pTask->pUnpacked) contains the unpacked version +** of key2. If it is false, (pTask->pUnpacked) is populated with the unpacked +** version of key2 and *pbKey2Cached set to true before returning. ** ** If an OOM error is encountered, (pTask->pUnpacked->error_rc) is set ** to SQLITE_NOMEM. */ static int vdbeSorterCompare( SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ + int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2 /* Right side of comparison */ ){ UnpackedRecord *r2 = pTask->pUnpacked; - if( pKey2 ){ + if( !*pbKey2Cached ){ sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); + *pbKey2Cached = 1; } return sqlite3VdbeRecordCompare(nKey1, pKey1, r2); } +/* +** A specially optimized version of vdbeSorterCompare() that assumes that +** the first field of each key is a TEXT value and that the collation +** sequence to compare them with is BINARY. +*/ +static int vdbeSorterCompareText( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ + int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ + const void *pKey1, int nKey1, /* Left side of comparison */ + const void *pKey2, int nKey2 /* Right side of comparison */ +){ + const u8 * const p1 = (const u8 * const)pKey1; + const u8 * const p2 = (const u8 * const)pKey2; + const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */ + const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */ + + int n1; + int n2; + int res; + + getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2; + getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2; + res = memcmp(v1, v2, MIN(n1, n2)); + if( res==0 ){ + res = n1 - n2; + } + + if( res==0 ){ + if( pTask->pSorter->pKeyInfo->nField>1 ){ + res = vdbeSorterCompareTail( + pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 + ); + } + }else{ + if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ + res = res * -1; + } + } + + return res; +} + +/* +** A specially optimized version of vdbeSorterCompare() that assumes that +** the first field of each key is an INTEGER value. +*/ +static int vdbeSorterCompareInt( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ + int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ + const void *pKey1, int nKey1, /* Left side of comparison */ + const void *pKey2, int nKey2 /* Right side of comparison */ +){ + const u8 * const p1 = (const u8 * const)pKey1; + const u8 * const p2 = (const u8 * const)pKey2; + const int s1 = p1[1]; /* Left hand serial type */ + const int s2 = p2[1]; /* Right hand serial type */ + const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */ + const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */ + int res; /* Return value */ + + assert( (s1>0 && s1<7) || s1==8 || s1==9 ); + assert( (s2>0 && s2<7) || s2==8 || s2==9 ); + + if( s1>7 && s2>7 ){ + res = s1 - s2; + }else{ + if( s1==s2 ){ + if( (*v1 ^ *v2) & 0x80 ){ + /* The two values have different signs */ + res = (*v1 & 0x80) ? -1 : +1; + }else{ + /* The two values have the same sign. Compare using memcmp(). */ + static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 }; + int i; + res = 0; + for(i=0; i7 ){ + res = +1; + }else if( s1>7 ){ + res = -1; + }else{ + res = s1 - s2; + } + assert( res!=0 ); + + if( res>0 ){ + if( *v1 & 0x80 ) res = -1; + }else{ + if( *v2 & 0x80 ) res = +1; + } + } + } + + if( res==0 ){ + if( pTask->pSorter->pKeyInfo->nField>1 ){ + res = vdbeSorterCompareTail( + pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 + ); + } + }else if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ + res = res * -1; + } + + return res; +} + /* ** Initialize the temporary index cursor just opened as a sorter cursor. ** @@ -835,9 +972,13 @@ int sqlite3VdbeSorterInit( pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); pKeyInfo->db = 0; - if( nField && nWorker==0 ) pKeyInfo->nField = nField; + if( nField && nWorker==0 ){ + pKeyInfo->nXField += (pKeyInfo->nField - nField); + pKeyInfo->nField = nField; + } pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); pSorter->nTask = nWorker + 1; + pSorter->iPrev = nWorker-1; pSorter->bUseThreads = (pSorter->nTask>1); pSorter->db = db; for(i=0; inTask; i++){ @@ -863,6 +1004,12 @@ int sqlite3VdbeSorterInit( if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM; } } + + if( (pKeyInfo->nField+pKeyInfo->nXField)<13 + && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl) + ){ + pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; + } } return rc; @@ -887,30 +1034,24 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ */ static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){ sqlite3DbFree(db, pTask->pUnpacked); - pTask->pUnpacked = 0; #if SQLITE_MAX_WORKER_THREADS>0 /* pTask->list.aMemory can only be non-zero if it was handed memory ** from the main thread. That only occurs SQLITE_MAX_WORKER_THREADS>0 */ if( pTask->list.aMemory ){ sqlite3_free(pTask->list.aMemory); - pTask->list.aMemory = 0; }else #endif { assert( pTask->list.aMemory==0 ); vdbeSorterRecordFree(0, pTask->list.pList); } - pTask->list.pList = 0; if( pTask->file.pFd ){ sqlite3OsCloseFree(pTask->file.pFd); - pTask->file.pFd = 0; - pTask->file.iEof = 0; } if( pTask->file2.pFd ){ sqlite3OsCloseFree(pTask->file2.pFd); - pTask->file2.pFd = 0; - pTask->file2.iEof = 0; } + memset(pTask, 0, sizeof(SortSubtask)); } #ifdef SQLITE_DEBUG_SORTER_THREADS @@ -1090,6 +1231,7 @@ void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){ for(i=0; inTask; i++){ SortSubtask *pTask = &pSorter->aTask[i]; vdbeSortSubtaskCleanup(db, pTask); + pTask->pSorter = pSorter; } if( pSorter->list.aMemory==0 ){ vdbeSorterRecordFree(0, pSorter->list.pList); @@ -1151,6 +1293,7 @@ static int vdbeSorterOpenTempFile( sqlite3_file **ppFd ){ int rc; + if( sqlite3FaultSim(202) ) return SQLITE_IOERR_ACCESS; rc = sqlite3OsOpenMalloc(db->pVfs, 0, ppFd, SQLITE_OPEN_TEMP_JOURNAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | @@ -1198,28 +1341,42 @@ static void vdbeSorterMerge( ){ SorterRecord *pFinal = 0; SorterRecord **pp = &pFinal; - void *pVal2 = p2 ? SRVAL(p2) : 0; + int bCached = 0; while( p1 && p2 ){ int res; - res = vdbeSorterCompare(pTask, SRVAL(p1), p1->nVal, pVal2, p2->nVal); + res = pTask->xCompare( + pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal + ); + if( res<=0 ){ *pp = p1; pp = &p1->u.pNext; p1 = p1->u.pNext; - pVal2 = 0; }else{ *pp = p2; - pp = &p2->u.pNext; + pp = &p2->u.pNext; p2 = p2->u.pNext; - if( p2==0 ) break; - pVal2 = SRVAL(p2); + bCached = 0; } } *pp = p1 ? p1 : p2; *ppOut = pFinal; } +/* +** Return the SorterCompare function to compare values collected by the +** sorter object passed as the only argument. +*/ +static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){ + if( p->typeMask==SORTER_TYPE_INTEGER ){ + return vdbeSorterCompareInt; + }else if( p->typeMask==SORTER_TYPE_TEXT ){ + return vdbeSorterCompareText; + } + return vdbeSorterCompare; +} + /* ** Sort the linked list of records headed at pTask->pList. Return ** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if @@ -1234,12 +1391,14 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ rc = vdbeSortAllocUnpacked(pTask); if( rc!=SQLITE_OK ) return rc; + p = pList->pList; + pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter); + aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *)); if( !aSlot ){ return SQLITE_NOMEM; } - p = pList->pList; while( p ){ SorterRecord *pNext; if( pList->aMemory ){ @@ -1453,13 +1612,12 @@ static int vdbeMergeEngineStep( int i; /* Index of aTree[] to recalculate */ PmaReader *pReadr1; /* First PmaReader to compare */ PmaReader *pReadr2; /* Second PmaReader to compare */ - u8 *pKey2; /* To pReadr2->aKey, or 0 if record cached */ + int bCached = 0; /* Find the first two PmaReaders to compare. The one that was just ** advanced (iPrev) and the one next to it in the array. */ pReadr1 = &pMerger->aReadr[(iPrev & 0xFFFE)]; pReadr2 = &pMerger->aReadr[(iPrev | 0x0001)]; - pKey2 = pReadr2->aKey; for(i=(pMerger->nTree+iPrev)/2; i>0; i=i/2){ /* Compare pReadr1 and pReadr2. Store the result in variable iRes. */ @@ -1469,8 +1627,8 @@ static int vdbeMergeEngineStep( }else if( pReadr2->pFd==0 ){ iRes = -1; }else{ - iRes = vdbeSorterCompare(pTask, - pReadr1->aKey, pReadr1->nKey, pKey2, pReadr2->nKey + iRes = pTask->xCompare(pTask, &bCached, + pReadr1->aKey, pReadr1->nKey, pReadr2->aKey, pReadr2->nKey ); } @@ -1492,9 +1650,9 @@ static int vdbeMergeEngineStep( if( iRes<0 || (iRes==0 && pReadr1aTree[i] = (int)(pReadr1 - pMerger->aReadr); pReadr2 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; - pKey2 = pReadr2->aKey; + bCached = 0; }else{ - if( pReadr1->pFd ) pKey2 = 0; + if( pReadr1->pFd ) bCached = 0; pMerger->aTree[i] = (int)(pReadr2 - pMerger->aReadr); pReadr1 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; } @@ -1601,6 +1759,16 @@ int sqlite3VdbeSorterWrite( int bFlush; /* True to flush contents of memory to PMA */ int nReq; /* Bytes of memory required */ int nPMA; /* Bytes of PMA space required */ + int t; /* serial type of first record field */ + + getVarint32((const u8*)&pVal->z[1], t); + if( t>0 && t<10 && t!=7 ){ + pSorter->typeMask &= SORTER_TYPE_INTEGER; + }else if( t>10 && (t & 0x01) ){ + pSorter->typeMask &= SORTER_TYPE_TEXT; + }else{ + pSorter->typeMask = 0; + } assert( pSorter ); @@ -1866,10 +2034,12 @@ static void vdbeMergeEngineCompare( }else if( p2->pFd==0 ){ iRes = i1; }else{ + SortSubtask *pTask = pMerger->pTask; + int bCached = 0; int res; - assert( pMerger->pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */ - res = vdbeSorterCompare( - pMerger->pTask, p1->aKey, p1->nKey, p2->aKey, p2->nKey + assert( pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */ + res = pTask->xCompare( + pTask, &bCached, p1->aKey, p1->nKey, p2->aKey, p2->nKey ); if( res<=0 ){ iRes = i1; @@ -1893,11 +2063,12 @@ static void vdbeMergeEngineCompare( #define INCRINIT_TASK 1 #define INCRINIT_ROOT 2 -/* Forward reference. -** The vdbeIncrMergeInit() and vdbePmaReaderIncrMergeInit() routines call each -** other (when building a merge tree). +/* +** Forward reference required as the vdbeIncrMergeInit() and +** vdbePmaReaderIncrInit() routines are called mutually recursively when +** building a merge tree. */ -static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode); +static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode); /* ** Initialize the MergeEngine object passed as the second argument. Once this @@ -1944,7 +2115,7 @@ static int vdbeMergeEngineInit( ** better advantage of multi-processor hardware. */ rc = vdbePmaReaderNext(&pMerger->aReadr[nTree-i-1]); }else{ - rc = vdbePmaReaderIncrMergeInit(&pMerger->aReadr[i], INCRINIT_NORMAL); + rc = vdbePmaReaderIncrInit(&pMerger->aReadr[i], INCRINIT_NORMAL); } if( rc!=SQLITE_OK ) return rc; } @@ -1956,17 +2127,15 @@ static int vdbeMergeEngineInit( } /* -** Initialize the IncrMerge field of a PmaReader. -** -** If the PmaReader passed as the first argument is not an incremental-reader -** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it serves -** to open and/or initialize the temp file related fields of the IncrMerge +** The PmaReader passed as the first argument is guaranteed to be an +** incremental-reader (pReadr->pIncr!=0). This function serves to open +** and/or initialize the temp file related fields of the IncrMerge ** object at (pReadr->pIncr). ** ** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders -** in the sub-tree headed by pReadr are also initialized. Data is then loaded -** into the buffers belonging to pReadr and it is set to -** point to the first key in its range. +** in the sub-tree headed by pReadr are also initialized. Data is then +** loaded into the buffers belonging to pReadr and it is set to point to +** the first key in its range. ** ** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed ** to be a multi-threaded PmaReader and this function is being called in a @@ -1993,59 +2162,62 @@ static int vdbeMergeEngineInit( static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){ int rc = SQLITE_OK; IncrMerger *pIncr = pReadr->pIncr; + SortSubtask *pTask = pIncr->pTask; + sqlite3 *db = pTask->pSorter->db; /* eMode is always INCRINIT_NORMAL in single-threaded mode */ assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); - if( pIncr ){ - SortSubtask *pTask = pIncr->pTask; - sqlite3 *db = pTask->pSorter->db; + rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode); - rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode); - - /* Set up the required files for pIncr. A multi-theaded IncrMerge object - ** requires two temp files to itself, whereas a single-threaded object - ** only requires a region of pTask->file2. */ - if( rc==SQLITE_OK ){ - int mxSz = pIncr->mxSz; + /* Set up the required files for pIncr. A multi-theaded IncrMerge object + ** requires two temp files to itself, whereas a single-threaded object + ** only requires a region of pTask->file2. */ + if( rc==SQLITE_OK ){ + int mxSz = pIncr->mxSz; #if SQLITE_MAX_WORKER_THREADS>0 - if( pIncr->bUseThread ){ - rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd); - if( rc==SQLITE_OK ){ - rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd); - } - }else + if( pIncr->bUseThread ){ + rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd); + if( rc==SQLITE_OK ){ + rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd); + } + }else #endif - /*if( !pIncr->bUseThread )*/{ - if( pTask->file2.pFd==0 ){ - assert( pTask->file2.iEof>0 ); - rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd); - pTask->file2.iEof = 0; - } - if( rc==SQLITE_OK ){ - pIncr->aFile[1].pFd = pTask->file2.pFd; - pIncr->iStartOff = pTask->file2.iEof; - pTask->file2.iEof += mxSz; - } + /*if( !pIncr->bUseThread )*/{ + if( pTask->file2.pFd==0 ){ + assert( pTask->file2.iEof>0 ); + rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd); + pTask->file2.iEof = 0; + } + if( rc==SQLITE_OK ){ + pIncr->aFile[1].pFd = pTask->file2.pFd; + pIncr->iStartOff = pTask->file2.iEof; + pTask->file2.iEof += mxSz; } } + } #if SQLITE_MAX_WORKER_THREADS>0 - if( rc==SQLITE_OK && pIncr->bUseThread ){ - /* Use the current thread to populate aFile[1], even though this - ** PmaReader is multi-threaded. The reason being that this function - ** is already running in background thread pIncr->pTask->thread. */ - assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK ); - rc = vdbeIncrPopulate(pIncr); - } + if( rc==SQLITE_OK && pIncr->bUseThread ){ + /* Use the current thread to populate aFile[1], even though this + ** PmaReader is multi-threaded. If this is an INCRINIT_TASK object, + ** then this function is already running in background thread + ** pIncr->pTask->thread. + ** + ** If this is the INCRINIT_ROOT object, then it is running in the + ** main VDBE thread. But that is Ok, as that thread cannot return + ** control to the VDBE or proceed with anything useful until the + ** first results are ready from this merger object anyway. + */ + assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK ); + rc = vdbeIncrPopulate(pIncr); + } #endif - if( rc==SQLITE_OK - && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) - ){ - rc = vdbePmaReaderNext(pReadr); - } + if( rc==SQLITE_OK && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) ){ + rc = vdbePmaReaderNext(pReadr); } + return rc; } @@ -2054,7 +2226,7 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){ ** The main routine for vdbePmaReaderIncrMergeInit() operations run in ** background threads. */ -static void *vdbePmaReaderBgInit(void *pCtx){ +static void *vdbePmaReaderBgIncrInit(void *pCtx){ PmaReader *pReader = (PmaReader*)pCtx; void *pRet = SQLITE_INT_TO_PTR( vdbePmaReaderIncrMergeInit(pReader,INCRINIT_TASK) @@ -2062,20 +2234,36 @@ static void *vdbePmaReaderBgInit(void *pCtx){ pReader->pIncr->pTask->bDone = 1; return pRet; } +#endif /* -** Use a background thread to invoke vdbePmaReaderIncrMergeInit(INCRINIT_TASK) -** on the PmaReader object passed as the first argument. -** -** This call will initialize the various fields of the pReadr->pIncr -** structure and, if it is a multi-threaded IncrMerger, launch a -** background thread to populate aFile[1]. +** If the PmaReader passed as the first argument is not an incremental-reader +** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it invokes +** the vdbePmaReaderIncrMergeInit() function with the parameters passed to +** this routine to initialize the incremental merge. +** +** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1), +** then a background thread is launched to call vdbePmaReaderIncrMergeInit(). +** Or, if the IncrMerger is single threaded, the same function is called +** using the current thread. */ -static int vdbePmaReaderBgIncrInit(PmaReader *pReadr){ - void *pCtx = (void*)pReadr; - return vdbeSorterCreateThread(pReadr->pIncr->pTask, vdbePmaReaderBgInit, pCtx); -} +static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode){ + IncrMerger *pIncr = pReadr->pIncr; /* Incremental merger */ + int rc = SQLITE_OK; /* Return code */ + if( pIncr ){ +#if SQLITE_MAX_WORKER_THREADS>0 + assert( pIncr->bUseThread==0 || eMode==INCRINIT_TASK ); + if( pIncr->bUseThread ){ + void *pCtx = (void*)pReadr; + rc = vdbeSorterCreateThread(pIncr->pTask, vdbePmaReaderBgIncrInit, pCtx); + }else #endif + { + rc = vdbePmaReaderIncrMergeInit(pReadr, eMode); + } + } + return rc; +} /* ** Allocate a new MergeEngine object to merge the contents of nPMA level-0 @@ -2287,6 +2475,11 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){ MergeEngine *pMain = 0; #if SQLITE_MAX_WORKER_THREADS sqlite3 *db = pTask0->pSorter->db; + int i; + SorterCompare xCompare = vdbeSorterGetCompare(pSorter); + for(i=0; inTask; i++){ + pSorter->aTask[i].xCompare = xCompare; + } #endif rc = vdbeSorterMergeTreeBuild(pSorter, &pMain); @@ -2315,15 +2508,21 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){ } } for(iTask=0; rc==SQLITE_OK && iTasknTask; iTask++){ + /* Check that: + ** + ** a) The incremental merge object is configured to use the + ** right task, and + ** b) If it is using task (nTask-1), it is configured to run + ** in single-threaded mode. This is important, as the + ** root merge (INCRINIT_ROOT) will be using the same task + ** object. + */ PmaReader *p = &pMain->aReadr[iTask]; - assert( p->pIncr==0 || p->pIncr->pTask==&pSorter->aTask[iTask] ); - if( p->pIncr ){ - if( iTask==pSorter->nTask-1 ){ - rc = vdbePmaReaderIncrMergeInit(p, INCRINIT_TASK); - }else{ - rc = vdbePmaReaderBgIncrInit(p); - } - } + assert( p->pIncr==0 || ( + (p->pIncr->pTask==&pSorter->aTask[iTask]) /* a */ + && (iTask!=pSorter->nTask-1 || p->pIncr->bUseThread==0) /* b */ + )); + rc = vdbePmaReaderIncrInit(p, INCRINIT_TASK); } } pMain = 0; diff --git a/src/vdbetrace.c b/src/vdbetrace.c index 507c2f1..c230b50 100644 --- a/src/vdbetrace.c +++ b/src/vdbetrace.c @@ -84,9 +84,8 @@ char *sqlite3VdbeExpandSql( char zBase[100]; /* Initial working space */ db = p->db; - sqlite3StrAccumInit(&out, zBase, sizeof(zBase), + sqlite3StrAccumInit(&out, db, zBase, sizeof(zBase), db->aLimit[SQLITE_LIMIT_LENGTH]); - out.db = db; if( db->nVdbeExec>1 ){ while( *zRawSql ){ const char *zStart = zRawSql; @@ -95,6 +94,8 @@ char *sqlite3VdbeExpandSql( assert( (zRawSql - zStart) > 0 ); sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart)); } + }else if( p->nVar==0 ){ + sqlite3StrAccumAppend(&out, zRawSql, sqlite3Strlen30(zRawSql)); }else{ while( zRawSql[0] ){ n = findNextHostParameter(zRawSql, &nToken); @@ -111,10 +112,12 @@ char *sqlite3VdbeExpandSql( idx = nextIndex; } }else{ - assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' ); + assert( zRawSql[0]==':' || zRawSql[0]=='$' || + zRawSql[0]=='@' || zRawSql[0]=='#' ); testcase( zRawSql[0]==':' ); testcase( zRawSql[0]=='$' ); testcase( zRawSql[0]=='@' ); + testcase( zRawSql[0]=='#' ); idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken); assert( idx>0 ); } diff --git a/src/vtab.c b/src/vtab.c index 00d0882..1989391 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -24,6 +24,8 @@ struct VtabCtx { VTable *pVTable; /* The virtual table being constructed */ Table *pTab; /* The Table object to which the virtual table belongs */ + VtabCtx *pPrior; /* Parent context (if any) */ + int bDeclared; /* True after sqlite3_declare_vtab() is called */ }; /* @@ -389,6 +391,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ char *zStmt; char *zWhere; int iDb; + int iReg; Vdbe *v; /* Compute the complete text of the CREATE VIRTUAL TABLE statement */ @@ -423,8 +426,10 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ sqlite3VdbeAddOp2(v, OP_Expire, 0, 0); zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName); sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); - sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0, - pTab->zName, sqlite3Strlen30(pTab->zName) + 1); + + iReg = ++pParse->nMem; + sqlite3VdbeAddOp4(v, OP_String8, 0, iReg, 0, pTab->zName, 0); + sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg); } /* If we are rereading the sqlite_master table create the in-memory @@ -467,7 +472,7 @@ void sqlite3VtabArgExtend(Parse *pParse, Token *p){ pArg->z = p->z; pArg->n = p->n; }else{ - assert(pArg->z < p->z); + assert(pArg->z <= p->z); pArg->n = (int)(&p->z[p->n] - pArg->z); } } @@ -484,15 +489,27 @@ static int vtabCallConstructor( int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), char **pzErr ){ - VtabCtx sCtx, *pPriorCtx; + VtabCtx sCtx; VTable *pVTable; int rc; const char *const*azArg = (const char *const*)pTab->azModuleArg; int nArg = pTab->nModuleArg; char *zErr = 0; - char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); + char *zModuleName; int iDb; + VtabCtx *pCtx; + /* Check that the virtual-table is not already being initialized */ + for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){ + if( pCtx->pTab==pTab ){ + *pzErr = sqlite3MPrintf(db, + "vtable constructor called recursively: %s", pTab->zName + ); + return SQLITE_LOCKED; + } + } + + zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); if( !zModuleName ){ return SQLITE_NOMEM; } @@ -513,11 +530,13 @@ static int vtabCallConstructor( assert( xConstruct ); sCtx.pTab = pTab; sCtx.pVTable = pVTable; - pPriorCtx = db->pVtabCtx; + sCtx.pPrior = db->pVtabCtx; + sCtx.bDeclared = 0; db->pVtabCtx = &sCtx; rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); - db->pVtabCtx = pPriorCtx; + db->pVtabCtx = sCtx.pPrior; if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; + assert( sCtx.pTab==pTab ); if( SQLITE_OK!=rc ){ if( zErr==0 ){ @@ -533,13 +552,14 @@ static int vtabCallConstructor( memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0])); pVTable->pVtab->pModule = pMod->pModule; pVTable->nRef = 1; - if( sCtx.pTab ){ + if( sCtx.bDeclared==0 ){ const char *zFormat = "vtable constructor did not declare schema: %s"; *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); sqlite3VtabUnlock(pVTable); rc = SQLITE_ERROR; }else{ int iCol; + u8 oooHidden = 0; /* If everything went according to plan, link the new VTable structure ** into the linked list headed by pTab->pVTable. Then loop through the ** columns of the table to see if any of them contain the token "hidden". @@ -552,7 +572,10 @@ static int vtabCallConstructor( char *zType = pTab->aCol[iCol].zType; int nType; int i = 0; - if( !zType ) continue; + if( !zType ){ + pTab->tabFlags |= oooHidden; + continue; + } nType = sqlite3Strlen30(zType); if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){ for(i=0; iaCol[iCol].colFlags |= COLFLAG_HIDDEN; + oooHidden = TF_OOOHidden; + }else{ + pTab->tabFlags |= oooHidden; } } } @@ -703,21 +729,25 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ ** virtual table module. */ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ + VtabCtx *pCtx; Parse *pParse; - int rc = SQLITE_OK; Table *pTab; char *zErr = 0; #ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; + if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){ + return SQLITE_MISUSE_BKPT; + } #endif sqlite3_mutex_enter(db->mutex); - if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){ + pCtx = db->pVtabCtx; + if( !pCtx || pCtx->bDeclared ){ sqlite3Error(db, SQLITE_MISUSE); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } + pTab = pCtx->pTab; assert( (pTab->tabFlags & TF_Virtual)!=0 ); pParse = sqlite3StackAllocZero(db, sizeof(*pParse)); @@ -740,7 +770,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ pParse->pNewTable->nCol = 0; pParse->pNewTable->aCol = 0; } - db->pVtabCtx->pTab = 0; + pCtx->bDeclared = 1; }else{ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); @@ -775,11 +805,15 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){ - VTable *p = vtabDisconnectAll(db, pTab); - - assert( rc==SQLITE_OK ); + VTable *p; + for(p=pTab->pVTable; p; p=p->pNext){ + assert( p->pVtab ); + if( p->pVtab->nRef>0 ){ + return SQLITE_LOCKED; + } + } + p = vtabDisconnectAll(db, pTab); rc = p->pMod->pModule->xDestroy(p->pVtab); - /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */ if( rc==SQLITE_OK ){ assert( pTab->pVTable==p && p->pNext==0 ); @@ -930,7 +964,7 @@ int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ int rc = SQLITE_OK; assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN ); - assert( iSavepoint>=0 ); + assert( iSavepoint>=-1 ); if( db->aVTrans ){ int i; for(i=0; rc==SQLITE_OK && inVTrans; i++){ @@ -1048,7 +1082,7 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ if( pTab==pToplevel->apVtabLock[i] ) return; } n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]); - apVtabLock = sqlite3_realloc(pToplevel->apVtabLock, n); + apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n); if( apVtabLock ){ pToplevel->apVtabLock = apVtabLock; pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; diff --git a/src/vxworks.h b/src/vxworks.h new file mode 100644 index 0000000..45a4445 --- /dev/null +++ b/src/vxworks.h @@ -0,0 +1,29 @@ +/* +** 2015-03-02 +** +** 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 contains code that is specific to Wind River's VxWorks +*/ +#if defined(__RTP__) || defined(_WRS_KERNEL) +/* This is VxWorks. Set up things specially for that OS +*/ +#include +#include /* amalgamator: dontcache */ +#define OS_VXWORKS 1 +#define SQLITE_OS_OTHER 0 +#define SQLITE_HOMEGROWN_RECURSIVE_MUTEX 1 +#define SQLITE_OMIT_LOAD_EXTENSION 1 +#define SQLITE_ENABLE_LOCKING_STYLE 0 +#define HAVE_UTIME 1 +#else +/* This is not VxWorks. */ +#define OS_VXWORKS 0 +#endif /* defined(_WRS_KERNEL) */ diff --git a/src/wal.c b/src/wal.c index 71f4a3d..ce98149 100644 --- a/src/wal.c +++ b/src/wal.c @@ -522,7 +522,7 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){ if( pWal->nWiData<=iPage ){ int nByte = sizeof(u32*)*(iPage+1); volatile u32 **apNew; - apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte); + apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte); if( !apNew ){ *ppPage = 0; return SQLITE_NOMEM; @@ -788,9 +788,10 @@ static void walUnlockShared(Wal *pWal, int lockIdx){ SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED); WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx))); } -static int walLockExclusive(Wal *pWal, int lockIdx, int n){ +static int walLockExclusive(Wal *pWal, int lockIdx, int n, int fBlock){ int rc; if( pWal->exclusiveMode ) return SQLITE_OK; + if( fBlock ) sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_WAL_BLOCK, 0); rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n, SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE); WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal, @@ -1076,7 +1077,7 @@ static int walIndexRecover(Wal *pWal){ assert( pWal->writeLock ); iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock; nLock = SQLITE_SHM_NLOCK - iLock; - rc = walLockExclusive(pWal, iLock, nLock); + rc = walLockExclusive(pWal, iLock, nLock, 0); if( rc ){ return rc; } @@ -1146,7 +1147,7 @@ static int walIndexRecover(Wal *pWal){ /* Malloc a buffer to read frames into. */ szFrame = szPage + WAL_FRAME_HDRSIZE; - aFrame = (u8 *)sqlite3_malloc(szFrame); + aFrame = (u8 *)sqlite3_malloc64(szFrame); if( !aFrame ){ rc = SQLITE_NOMEM; goto recovery_error; @@ -1539,7 +1540,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){ nByte = sizeof(WalIterator) + (nSegment-1)*sizeof(struct WalSegment) + iLast*sizeof(ht_slot); - p = (WalIterator *)sqlite3_malloc(nByte); + p = (WalIterator *)sqlite3_malloc64(nByte); if( !p ){ return SQLITE_NOMEM; } @@ -1549,7 +1550,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){ /* Allocate temporary space used by the merge-sort routine. This block ** of memory will be freed before this function returns. */ - aTmp = (ht_slot *)sqlite3_malloc( + aTmp = (ht_slot *)sqlite3_malloc64( sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) ); if( !aTmp ){ @@ -1610,7 +1611,7 @@ static int walBusyLock( ){ int rc; do { - rc = walLockExclusive(pWal, lockIdx, n); + rc = walLockExclusive(pWal, lockIdx, n, 0); }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) ); return rc; } @@ -1729,6 +1730,14 @@ static int walCheckpoint( mxSafeFrame = pWal->hdr.mxFrame; mxPage = pWal->hdr.nPage; for(i=1; iaReadMark[i]; if( mxSafeFrame>y ){ assert( y<=pWal->hdr.mxFrame ); @@ -2043,7 +2052,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ walUnlockShared(pWal, WAL_WRITE_LOCK); rc = SQLITE_READONLY_RECOVERY; } - }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){ + }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 1)) ){ pWal->writeLock = 1; if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ badHdr = walIndexTryHdr(pWal, pChanged); @@ -2249,7 +2258,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ && (mxReadMarkhdr.mxFrame || mxI==0) ){ for(i=1; iaReadMark[i] = pWal->hdr.mxFrame; mxI = i; @@ -2505,7 +2514,7 @@ int sqlite3WalBeginWriteTransaction(Wal *pWal){ /* Only one writer allowed at a time. Get the write lock. Return ** SQLITE_BUSY if unable. */ - rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1); + rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 0); if( rc ){ return rc; } @@ -2650,7 +2659,7 @@ static int walRestartLog(Wal *pWal){ if( pInfo->nBackfill>0 ){ u32 salt1; sqlite3_randomness(4, &salt1); - rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); + rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1, 0); if( rc==SQLITE_OK ){ /* If all readers are using WAL_READ_LOCK(0) (in other words if no ** readers are currently using the WAL), then the transactions @@ -2975,7 +2984,7 @@ int sqlite3WalCheckpoint( /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive ** "checkpoint" lock on the database file. */ - rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); + rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1, 0); if( rc ){ /* EVIDENCE-OF: R-10421-19736 If any other process is running a ** checkpoint operation at the same time, the lock cannot be obtained and diff --git a/src/where.c b/src/where.c index f45da74..85eb00b 100644 --- a/src/where.c +++ b/src/where.c @@ -202,7 +202,7 @@ static void whereClauseClear(WhereClause *pWC){ ** calling this routine. Such pointers may be reinitialized by referencing ** the pWC->a[] array. */ -static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){ +static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ WhereTerm *pTerm; int idx; testcase( wtFlags & TERM_VIRTUAL ); @@ -255,13 +255,14 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){ ** all terms of the WHERE clause. */ static void whereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ + Expr *pE2 = sqlite3ExprSkipCollate(pExpr); pWC->op = op; - if( pExpr==0 ) return; - if( pExpr->op!=op ){ + if( pE2==0 ) return; + if( pE2->op!=op ){ whereClauseInsert(pWC, pExpr, 0); }else{ - whereSplit(pWC, pExpr->pLeft, op); - whereSplit(pWC, pExpr->pRight, op); + whereSplit(pWC, pE2->pLeft, op); + whereSplit(pWC, pE2->pRight, op); } } @@ -627,7 +628,11 @@ static void exprAnalyzeAll( ** so and false if not. ** ** In order for the operator to be optimizible, the RHS must be a string -** literal that does not begin with a wildcard. +** literal that does not begin with a wildcard. The LHS must be a column +** that may only be NULL, a string, or a BLOB, never a number. (This means +** that virtual tables cannot participate in the LIKE optimization.) If the +** collating sequence for the column on the LHS must be appropriate for +** the operator. */ static int isLikeOrGlob( Parse *pParse, /* Parsing and code generating context */ @@ -656,7 +661,7 @@ static int isLikeOrGlob( pLeft = pList->a[1].pExpr; if( pLeft->op!=TK_COLUMN || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT - || IsVirtual(pLeft->pTab) + || IsVirtual(pLeft->pTab) /* Value might be numeric */ ){ /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must ** be the name of an indexed column with TEXT affinity. */ @@ -766,6 +771,79 @@ static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){ pWC->a[iParent].nChild++; } +/* +** Return the N-th AND-connected subterm of pTerm. Or if pTerm is not +** a conjunction, then return just pTerm when N==0. If N is exceeds +** the number of available subterms, return NULL. +*/ +static WhereTerm *whereNthSubterm(WhereTerm *pTerm, int N){ + if( pTerm->eOperator!=WO_AND ){ + return N==0 ? pTerm : 0; + } + if( Nu.pAndInfo->wc.nTerm ){ + return &pTerm->u.pAndInfo->wc.a[N]; + } + return 0; +} + +/* +** Subterms pOne and pTwo are contained within WHERE clause pWC. The +** two subterms are in disjunction - they are OR-ed together. +** +** If these two terms are both of the form: "A op B" with the same +** A and B values but different operators and if the operators are +** compatible (if one is = and the other is <, for example) then +** add a new virtual AND term to pWC that is the combination of the +** two. +** +** Some examples: +** +** x x<=y +** x=y OR x=y --> x=y +** x<=y OR x x<=y +** +** The following is NOT generated: +** +** xy --> x!=y +*/ +static void whereCombineDisjuncts( + SrcList *pSrc, /* the FROM clause */ + WhereClause *pWC, /* The complete WHERE clause */ + WhereTerm *pOne, /* First disjunct */ + WhereTerm *pTwo /* Second disjunct */ +){ + u16 eOp = pOne->eOperator | pTwo->eOperator; + sqlite3 *db; /* Database connection (for malloc) */ + Expr *pNew; /* New virtual expression */ + int op; /* Operator for the combined expression */ + int idxNew; /* Index in pWC of the next virtual term */ + + if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; + if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; + if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp + && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return; + assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 ); + assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 ); + if( sqlite3ExprCompare(pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; + if( sqlite3ExprCompare(pOne->pExpr->pRight, pTwo->pExpr->pRight, -1) )return; + /* If we reach this point, it means the two subterms can be combined */ + if( (eOp & (eOp-1))!=0 ){ + if( eOp & (WO_LT|WO_LE) ){ + eOp = WO_LE; + }else{ + assert( eOp & (WO_GT|WO_GE) ); + eOp = WO_GE; + } + } + db = pWC->pWInfo->pParse->db; + pNew = sqlite3ExprDup(db, pOne->pExpr, 0); + if( pNew==0 ) return; + for(op=TK_EQ; eOp!=(WO_EQ<<(op-TK_EQ)); op++){ assert( opop = op; + idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); + exprAnalyze(pSrc, pWC, idxNew); +} + #if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) /* ** Analyze a term that consists of two or more OR-connected @@ -790,6 +868,7 @@ static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){ ** (C) t1.x=t2.y OR (t1.x=t2.z AND t1.y=15) ** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*') ** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6) +** (F) x>A OR (x=A AND y>=B) ** ** CASE 1: ** @@ -806,6 +885,16 @@ static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){ ** ** CASE 2: ** +** If there are exactly two disjuncts one side has x>A and the other side +** has x=A (for the same x and A) then add a new virtual conjunct term to the +** WHERE clause of the form "x>=A". Example: +** +** x>A OR (x=A AND y>B) adds: x>=A +** +** The added conjunct can sometimes be helpful in query planning. +** +** CASE 3: +** ** If all subterms are indexable by a single table T, then set ** ** WhereTerm.eOperator = WO_OR @@ -932,12 +1021,26 @@ static void exprAnalyzeOrTerm( } /* - ** Record the set of tables that satisfy case 2. The set might be + ** Record the set of tables that satisfy case 3. The set might be ** empty. */ pOrInfo->indexable = indexable; pTerm->eOperator = indexable==0 ? 0 : WO_OR; + /* For a two-way OR, attempt to implementation case 2. + */ + if( indexable && pOrWc->nTerm==2 ){ + int iOne = 0; + WhereTerm *pOne; + while( (pOne = whereNthSubterm(&pOrWc->a[0],iOne++))!=0 ){ + int iTwo = 0; + WhereTerm *pTwo; + while( (pTwo = whereNthSubterm(&pOrWc->a[1],iTwo++))!=0 ){ + whereCombineDisjuncts(pSrc, pWC, pOne, pTwo); + } + } + } + /* ** chngToIN holds a set of tables that *might* satisfy case 1. But ** we have to do some additional checking to see if case 1 really @@ -1067,7 +1170,7 @@ static void exprAnalyzeOrTerm( }else{ sqlite3ExprListDelete(db, pList); } - pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */ + pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */ } } } @@ -1105,7 +1208,7 @@ static void exprAnalyze( Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */ Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */ int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */ - int noCase = 0; /* LIKE/GLOB distinguishes case */ + int noCase = 0; /* uppercase equivalent to lowercase */ int op; /* Top-level operator. pExpr->op */ Parse *pParse = pWInfo->pParse; /* Parsing context */ sqlite3 *db = pParse->db; /* Database connection */ @@ -1243,12 +1346,15 @@ static void exprAnalyze( /* Add constraints to reduce the search space on a LIKE or GLOB ** operator. ** - ** A like pattern of the form "x LIKE 'abc%'" is changed into constraints + ** A like pattern of the form "x LIKE 'aBc%'" is changed into constraints ** - ** x>='abc' AND x<'abd' AND x LIKE 'abc%' + ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%' ** ** The last character of the prefix "abc" is incremented to form the - ** termination condition "abd". + ** termination condition "abd". If case is not significant (the default + ** for LIKE) then the lower-bound is made all uppercase and the upper- + ** bound is made all lowercase so that the bounds also work when comparing + ** BLOBs. */ if( pWC->op==TK_AND && isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase) @@ -1259,10 +1365,26 @@ static void exprAnalyze( Expr *pNewExpr2; int idxNew1; int idxNew2; - Token sCollSeqName; /* Name of collating sequence */ + const char *zCollSeqName; /* Name of collating sequence */ + const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC; pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); + + /* Convert the lower bound to upper-case and the upper bound to + ** lower-case (upper-case is less than lower-case in ASCII) so that + ** the range constraints also work for BLOBs + */ + if( noCase && !pParse->db->mallocFailed ){ + int i; + char c; + pTerm->wtFlags |= TERM_LIKE; + for(i=0; (c = pStr1->u.zToken[i])!=0; i++){ + pStr1->u.zToken[i] = sqlite3Toupper(c); + pStr2->u.zToken[i] = sqlite3Tolower(c); + } + } + if( !db->mallocFailed ){ u8 c, *pC; /* Last character before the first wildcard */ pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1]; @@ -1279,22 +1401,21 @@ static void exprAnalyze( } *pC = c + 1; } - sCollSeqName.z = noCase ? "NOCASE" : "BINARY"; - sCollSeqName.n = 6; + zCollSeqName = noCase ? "NOCASE" : "BINARY"; pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); - pNewExpr1 = sqlite3PExpr(pParse, TK_GE, - sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName), + pNewExpr1 = sqlite3PExpr(pParse, TK_GE, + sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), pStr1, 0); transferJoinMarkings(pNewExpr1, pExpr); - idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC); + idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); testcase( idxNew1==0 ); exprAnalyze(pSrc, pWC, idxNew1); pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); pNewExpr2 = sqlite3PExpr(pParse, TK_LT, - sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName), + sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName), pStr2, 0); transferJoinMarkings(pNewExpr2, pExpr); - idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC); + idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); testcase( idxNew2==0 ); exprAnalyze(pSrc, pWC, idxNew2); pTerm = &pWC->a[idxTerm]; @@ -1412,7 +1533,7 @@ static int findIndexCol( && p->iTable==iBase ){ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); - if( ALWAYS(pColl) && 0==sqlite3StrICmp(pColl->zName, zColl) ){ + if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){ return i; } } @@ -1612,12 +1733,16 @@ static void constructAutomaticIndex( pLoop = pLevel->pWLoop; idxCols = 0; for(pTerm=pWC->a; pTermpExpr; + assert( !ExprHasProperty(pExpr, EP_FromJoin) /* prereq always non-zero */ + || pExpr->iRightJoinTable!=pSrc->iCursor /* for the right-hand */ + || pLoop->prereq!=0 ); /* table of a LEFT JOIN */ if( pLoop->prereq==0 && (pTerm->wtFlags & TERM_VIRTUAL)==0 - && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) - && sqlite3ExprIsTableConstant(pTerm->pExpr, pSrc->iCursor) ){ + && !ExprHasProperty(pExpr, EP_FromJoin) + && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){ pPartial = sqlite3ExprAnd(pParse->db, pPartial, - sqlite3ExprDup(pParse->db, pTerm->pExpr, 0)); + sqlite3ExprDup(pParse->db, pExpr, 0)); } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ int iCol = pTerm->u.leftColumn; @@ -1682,7 +1807,7 @@ static void constructAutomaticIndex( idxCols |= cMask; pIdx->aiColumn[n] = pTerm->u.leftColumn; pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); - pIdx->azColl[n] = ALWAYS(pColl) ? pColl->zName : "BINARY"; + pIdx->azColl[n] = pColl ? pColl->zName : "BINARY"; n++; } } @@ -1904,11 +2029,14 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ ** Estimate the location of a particular key among all keys in an ** index. Store the results in aStat as follows: ** -** aStat[0] Est. number of rows less than pVal -** aStat[1] Est. number of rows equal to pVal +** aStat[0] Est. number of rows less than pRec +** aStat[1] Est. number of rows equal to pRec ** ** Return the index of the sample that is the smallest sample that -** is greater than or equal to pRec. +** is greater than or equal to pRec. Note that this index is not an index +** into the aSample[] array - it is an index into a virtual set of samples +** based on the contents of aSample[] and the number of fields in record +** pRec. */ static int whereKeyStats( Parse *pParse, /* Database connection */ @@ -1919,67 +2047,158 @@ static int whereKeyStats( ){ IndexSample *aSample = pIdx->aSample; int iCol; /* Index of required stats in anEq[] etc. */ + int i; /* Index of first sample >= pRec */ + int iSample; /* Smallest sample larger than or equal to pRec */ int iMin = 0; /* Smallest sample not yet tested */ - int i = pIdx->nSample; /* Smallest sample larger than or equal to pRec */ int iTest; /* Next sample to test */ int res; /* Result of comparison operation */ + int nField; /* Number of fields in pRec */ + tRowcnt iLower = 0; /* anLt[] + anEq[] of largest sample pRec is > */ #ifndef SQLITE_DEBUG UNUSED_PARAMETER( pParse ); #endif assert( pRec!=0 ); - iCol = pRec->nField - 1; assert( pIdx->nSample>0 ); - assert( pRec->nField>0 && iColnSampleCol ); + assert( pRec->nField>0 && pRec->nField<=pIdx->nSampleCol ); + + /* Do a binary search to find the first sample greater than or equal + ** to pRec. If pRec contains a single field, the set of samples to search + ** is simply the aSample[] array. If the samples in aSample[] contain more + ** than one fields, all fields following the first are ignored. + ** + ** If pRec contains N fields, where N is more than one, then as well as the + ** samples in aSample[] (truncated to N fields), the search also has to + ** consider prefixes of those samples. For example, if the set of samples + ** in aSample is: + ** + ** aSample[0] = (a, 5) + ** aSample[1] = (a, 10) + ** aSample[2] = (b, 5) + ** aSample[3] = (c, 100) + ** aSample[4] = (c, 105) + ** + ** Then the search space should ideally be the samples above and the + ** unique prefixes [a], [b] and [c]. But since that is hard to organize, + ** the code actually searches this set: + ** + ** 0: (a) + ** 1: (a, 5) + ** 2: (a, 10) + ** 3: (a, 10) + ** 4: (b) + ** 5: (b, 5) + ** 6: (c) + ** 7: (c, 100) + ** 8: (c, 105) + ** 9: (c, 105) + ** + ** For each sample in the aSample[] array, N samples are present in the + ** effective sample array. In the above, samples 0 and 1 are based on + ** sample aSample[0]. Samples 2 and 3 on aSample[1] etc. + ** + ** Often, sample i of each block of N effective samples has (i+1) fields. + ** Except, each sample may be extended to ensure that it is greater than or + ** equal to the previous sample in the array. For example, in the above, + ** sample 2 is the first sample of a block of N samples, so at first it + ** appears that it should be 1 field in size. However, that would make it + ** smaller than sample 1, so the binary search would not work. As a result, + ** it is extended to two fields. The duplicates that this creates do not + ** cause any problems. + */ + nField = pRec->nField; + iCol = 0; + iSample = pIdx->nSample * nField; do{ - iTest = (iMin+i)/2; - res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec); - if( res<0 ){ - iMin = iTest+1; + int iSamp; /* Index in aSample[] of test sample */ + int n; /* Number of fields in test sample */ + + iTest = (iMin+iSample)/2; + iSamp = iTest / nField; + if( iSamp>0 ){ + /* The proposed effective sample is a prefix of sample aSample[iSamp]. + ** Specifically, the shortest prefix of at least (1 + iTest%nField) + ** fields that is greater than the previous effective sample. */ + for(n=(iTest % nField) + 1; nnField = n; + res = sqlite3VdbeRecordCompare(aSample[iSamp].n, aSample[iSamp].p, pRec); + if( res<0 ){ + iLower = aSample[iSamp].anLt[n-1] + aSample[iSamp].anEq[n-1]; + iMin = iTest+1; + }else if( res==0 && nnSample ); - assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec) - || pParse->db->mallocFailed ); - }else{ - /* Otherwise, pRec must be smaller than sample $i and larger than - ** sample ($i-1). */ - assert( i==pIdx->nSample - || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0 - || pParse->db->mallocFailed ); - assert( i==0 - || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0 - || pParse->db->mallocFailed ); + if( pParse->db->mallocFailed==0 ){ + if( res==0 ){ + /* If (res==0) is true, then pRec must be equal to sample i. */ + assert( inSample ); + assert( iCol==nField-1 ); + pRec->nField = nField; + assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec) + || pParse->db->mallocFailed + ); + }else{ + /* Unless i==pIdx->nSample, indicating that pRec is larger than + ** all samples in the aSample[] array, pRec must be smaller than the + ** (iCol+1) field prefix of sample i. */ + assert( i<=pIdx->nSample && i>=0 ); + pRec->nField = iCol+1; + assert( i==pIdx->nSample + || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0 + || pParse->db->mallocFailed ); + + /* if i==0 and iCol==0, then record pRec is smaller than all samples + ** in the aSample[] array. Otherwise, if (iCol>0) then pRec must + ** be greater than or equal to the (iCol) field prefix of sample i. + ** If (i>0), then pRec must also be greater than sample (i-1). */ + if( iCol>0 ){ + pRec->nField = iCol; + assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0 + || pParse->db->mallocFailed ); + } + if( i>0 ){ + pRec->nField = nField; + assert( sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0 + || pParse->db->mallocFailed ); + } + } } #endif /* ifdef SQLITE_DEBUG */ - /* At this point, aSample[i] is the first sample that is greater than - ** or equal to pVal. Or if i==pIdx->nSample, then all samples are less - ** than pVal. If aSample[i]==pVal, then res==0. - */ if( res==0 ){ + /* Record pRec is equal to sample i */ + assert( iCol==nField-1 ); aStat[0] = aSample[i].anLt[iCol]; aStat[1] = aSample[i].anEq[iCol]; }else{ - tRowcnt iLower, iUpper, iGap; - if( i==0 ){ - iLower = 0; - iUpper = aSample[0].anLt[iCol]; + /* At this point, the (iCol+1) field prefix of aSample[i] is the first + ** sample that is greater than pRec. Or, if i==pIdx->nSample then pRec + ** is larger than all samples in the array. */ + tRowcnt iUpper, iGap; + if( i>=pIdx->nSample ){ + iUpper = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]); }else{ - i64 nRow0 = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]); - iUpper = i>=pIdx->nSample ? nRow0 : aSample[i].anLt[iCol]; - iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol]; + iUpper = aSample[i].anLt[iCol]; } - aStat[1] = pIdx->aAvgEq[iCol]; + if( iLower>=iUpper ){ iGap = 0; }else{ @@ -1991,7 +2210,11 @@ static int whereKeyStats( iGap = iGap/3; } aStat[0] = iLower + iGap; + aStat[1] = pIdx->aAvgEq[iCol]; } + + /* Restore the pRec->nField value before returning. */ + pRec->nField = nField; return i; } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ @@ -2465,20 +2688,43 @@ static int whereInScanEst( ** but joins might run a little slower. The trick is to disable as much ** as we can without disabling too much. If we disabled in (1), we'd get ** the wrong answer. See ticket #813. +** +** If all the children of a term are disabled, then that term is also +** automatically disabled. In this way, terms get disabled if derived +** virtual terms are tested first. For example: +** +** x GLOB 'abc*' AND x>='abc' AND x<'acd' +** \___________/ \______/ \_____/ +** parent child1 child2 +** +** Only the parent term was in the original WHERE clause. The child1 +** and child2 terms were added by the LIKE optimization. If both of +** the virtual child terms are valid, then testing of the parent can be +** skipped. +** +** Usually the parent term is marked as TERM_CODED. But if the parent +** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead. +** The TERM_LIKECOND marking indicates that the term should be coded inside +** a conditional such that is only evaluated on the second pass of a +** LIKE-optimization loop, when scanning BLOBs instead of strings. */ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ - if( pTerm + int nLoop = 0; + while( pTerm && (pTerm->wtFlags & TERM_CODED)==0 && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) && (pLevel->notReady & pTerm->prereqAll)==0 ){ - pTerm->wtFlags |= TERM_CODED; - if( pTerm->iParent>=0 ){ - WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent]; - if( (--pOther->nChild)==0 ){ - disableTerm(pLevel, pOther); - } + if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){ + pTerm->wtFlags |= TERM_LIKECOND; + }else{ + pTerm->wtFlags |= TERM_CODED; } + if( pTerm->iParent<0 ) break; + pTerm = &pTerm->pWC->a[pTerm->iParent]; + pTerm->nChild--; + if( pTerm->nChild!=0 ) break; + nLoop++; } } @@ -2857,8 +3103,7 @@ static int explainOneScan( || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); - sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); - str.db = db; + sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); @@ -2962,7 +3207,34 @@ static void addScanStatus( # define addScanStatus(a, b, c, d) ((void)d) #endif - +/* +** If the most recently coded instruction is a constant range contraint +** that originated from the LIKE optimization, then change the P3 to be +** pLoop->iLikeRepCntr and set P5. +** +** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range +** expression: "x>='ABC' AND x<'abd'". But this requires that the range +** scan loop run twice, once for strings and a second time for BLOBs. +** The OP_String opcodes on the second pass convert the upper and lower +** bound string contants to blobs. This routine makes the necessary changes +** to the OP_String opcodes for that to happen. +*/ +static void whereLikeOptimizationStringFixup( + Vdbe *v, /* prepared statement under construction */ + WhereLevel *pLevel, /* The loop that contains the LIKE operator */ + WhereTerm *pTerm /* The upper or lower bound just coded */ +){ + if( pTerm->wtFlags & TERM_LIKEOPT ){ + VdbeOp *pOp; + assert( pLevel->iLikeRepCntr>0 ); + pOp = sqlite3VdbeGetOp(v, -1); + assert( pOp!=0 ); + assert( pOp->opcode==OP_String8 + || pTerm->pWC->pWInfo->pParse->db->mallocFailed ); + pOp->p3 = pLevel->iLikeRepCntr; + pOp->p5 = 1; + } +} /* ** Generate code for the start of the iLevel-th loop in the WHERE clause @@ -3292,10 +3564,25 @@ static Bitmask codeOneLoopStart( if( pLoop->wsFlags & WHERE_BTM_LIMIT ){ pRangeStart = pLoop->aLTerm[j++]; nExtraReg = 1; + /* Like optimization range constraints always occur in pairs */ + assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 || + (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 ); } if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ pRangeEnd = pLoop->aLTerm[j++]; nExtraReg = 1; + if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){ + assert( pRangeStart!=0 ); /* LIKE opt constraints */ + assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */ + pLevel->iLikeRepCntr = ++pParse->nMem; + testcase( bRev ); + testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); + sqlite3VdbeAddOp2(v, OP_Integer, + bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC), + pLevel->iLikeRepCntr); + VdbeComment((v, "LIKE loop counter")); + pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v); + } if( pRangeStart==0 && (j = pIdx->aiColumn[nEq])>=0 && pIdx->pTable->aCol[j].notNull==0 @@ -3338,6 +3625,7 @@ static Bitmask codeOneLoopStart( if( pRangeStart ){ Expr *pRight = pRangeStart->pExpr->pRight; sqlite3ExprCode(pParse, pRight, regBase+nEq); + whereLikeOptimizationStringFixup(v, pLevel, pRangeStart); if( (pRangeStart->wtFlags & TERM_VNULL)==0 && sqlite3ExprCanBeNull(pRight) ){ @@ -3383,6 +3671,7 @@ static Bitmask codeOneLoopStart( Expr *pRight = pRangeEnd->pExpr->pRight; sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); sqlite3ExprCode(pParse, pRight, regBase+nEq); + whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd); if( (pRangeEnd->wtFlags & TERM_VNULL)==0 && sqlite3ExprCanBeNull(pRight) ){ @@ -3610,7 +3899,8 @@ static Bitmask codeOneLoopStart( */ wctrlFlags = WHERE_OMIT_OPEN_CLOSE | WHERE_FORCE_TABLE - | WHERE_ONETABLE_ONLY; + | WHERE_ONETABLE_ONLY + | WHERE_NO_AUTOINDEX; for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ @@ -3772,6 +4062,7 @@ static Bitmask codeOneLoopStart( */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE; + int skipLikeAddr = 0; testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; @@ -3786,7 +4077,13 @@ static Bitmask codeOneLoopStart( if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ continue; } + if( pTerm->wtFlags & TERM_LIKECOND ){ + assert( pLevel->iLikeRepCntr>0 ); + skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr); + VdbeCoverage(v); + } sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); + if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); pTerm->wtFlags |= TERM_CODED; } @@ -4005,6 +4302,13 @@ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){ */ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ if( ALWAYS(pWInfo) ){ + int i; + for(i=0; inLevel; i++){ + WhereLevel *pLevel = &pWInfo->a[i]; + if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){ + sqlite3DbFree(db, pLevel->u.in.aInLoop); + } + } whereClauseClear(&pWInfo->sWC); while( pWInfo->pLoops ){ WhereLoop *p = pWInfo->pLoops; @@ -4451,6 +4755,10 @@ static int whereLoopAddBtreeIndex( } if( pTerm->prereqRight & pNew->maskSelf ) continue; + /* Do not allow the upper bound of a LIKE optimization range constraint + ** to mix with a lower range bound from some other source */ + if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue; + pNew->wsFlags = saved_wsFlags; pNew->u.btree.nEq = saved_nEq; pNew->nLTerm = saved_nLTerm; @@ -4480,7 +4788,7 @@ static int whereLoopAddBtreeIndex( }else if( eOp & (WO_EQ) ){ pNew->wsFlags |= WHERE_COLUMN_EQ; if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){ - if( iCol>=0 && !IsUniqueIndex(pProbe) ){ + if( iCol>=0 && pProbe->uniqNotNull==0 ){ pNew->wsFlags |= WHERE_UNQ_WANTED; }else{ pNew->wsFlags |= WHERE_ONEROW; @@ -4494,6 +4802,17 @@ static int whereLoopAddBtreeIndex( pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pBtm = pTerm; pTop = 0; + if( pTerm->wtFlags & TERM_LIKEOPT ){ + /* Range contraints that come from the LIKE optimization are + ** always used in pairs. */ + pTop = &pTerm[1]; + assert( (pTop-(pTerm->pWC->a))pWC->nTerm ); + assert( pTop->wtFlags & TERM_LIKEOPT ); + assert( pTop->eOperator==WO_LT ); + if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ + pNew->aLTerm[pNew->nLTerm++] = pTop; + pNew->wsFlags |= WHERE_TOP_LIMIT; + } }else{ assert( eOp & (WO_LT|WO_LE) ); testcase( eOp & WO_LT ); @@ -4695,8 +5014,9 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){ int i; WhereTerm *pTerm; for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){ - if( sqlite3ExprImpliesExpr(pTerm->pExpr, pWhere, iTab) - && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + Expr *pExpr = pTerm->pExpr; + if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab) + && (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab) ){ return 1; } @@ -4803,6 +5123,7 @@ static int whereLoopAddBtree( #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet + && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && pSrc->pIndex==0 && !pSrc->viaCoroutine @@ -5686,10 +6007,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ /* Seed the search with a single WherePath containing zero WhereLoops. ** - ** TUNING: Do not let the number of iterations go above 25. If the cost - ** of computing an automatic index is not paid back within the first 25 + ** TUNING: Do not let the number of iterations go above 28. If the cost + ** of computing an automatic index is not paid back within the first 28 ** rows, then do not use the automatic index. */ - aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) ); + aFrom[0].nRow = MIN(pParse->nQueryLoop, 48); assert( 48==sqlite3LogEst(28) ); nFrom = 1; assert( aFrom[0].isOrdered==0 ); if( nOrderBy ){ @@ -5927,7 +6248,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pWInfo->revMask = pFrom->revLoop; } if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) - && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr + && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0 ){ Bitmask revMask = 0; int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, @@ -6332,7 +6653,6 @@ WhereInfo *sqlite3WhereBegin( } #ifdef WHERETRACE_ENABLED /* !=0 */ if( sqlite3WhereTrace ){ - int ii; sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); if( pWInfo->nOBSat>0 ){ sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask); @@ -6487,6 +6807,12 @@ WhereInfo *sqlite3WhereBegin( if( op ){ sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIx); + if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0 + && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0 + && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 + ){ + sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */ + } VdbeComment((v, "%s", pIx->zName)); } } @@ -6579,7 +6905,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen); sqlite3VdbeJumpHere(v, pIn->addrInTop-1); } - sqlite3DbFree(db, pLevel->u.in.aInLoop); } sqlite3VdbeResolveLabel(v, pLevel->addrBrk); if( pLevel->addrSkip ){ @@ -6588,6 +6913,16 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3VdbeJumpHere(v, pLevel->addrSkip); sqlite3VdbeJumpHere(v, pLevel->addrSkip-2); } + if( pLevel->addrLikeRep ){ + int op; + if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){ + op = OP_DecrJumpZero; + }else{ + op = OP_JumpZeroIncr; + } + sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep); + VdbeCoverage(v); + } if( pLevel->iLeftJoin ){ addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 diff --git a/src/whereInt.h b/src/whereInt.h index 2ccc6ec..04cc202 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -69,6 +69,8 @@ struct WhereLevel { int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ + int iLikeRepCntr; /* LIKE range processing counter register */ + int addrLikeRep; /* LIKE range processing address */ u8 iFrom; /* Which entry in the FROM clause */ u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ int p1, p2; /* Operands of the opcode used to ends the loop */ @@ -253,7 +255,7 @@ struct WhereTerm { } u; LogEst truthProb; /* Probability of truth for this expression */ u16 eOperator; /* A WO_xx value describing */ - u8 wtFlags; /* TERM_xxx bit flags. See below */ + u16 wtFlags; /* TERM_xxx bit flags. See below */ u8 nChild; /* Number of children that must disable us */ WhereClause *pWC; /* The clause this term is part of */ Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */ @@ -275,6 +277,9 @@ struct WhereTerm { #else # define TERM_VNULL 0x00 /* Disabled if not using stat3 */ #endif +#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */ +#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */ +#define TERM_LIKE 0x400 /* The original LIKE operator */ /* ** An instance of the WhereScan object is used as an iterator for locating diff --git a/test/alter.test b/test/alter.test index ddf1698..ebfe97a 100644 --- a/test/alter.test +++ b/test/alter.test @@ -912,5 +912,14 @@ do_execsql_test alter-17.9 { do_execsql_test alter-17.10 { SELECT sqlite_rename_parent(NULL,'abc','xyz'); } {{}} +do_execsql_test alter-17.11 { + SELECT sqlite_rename_parent('create references ''','abc','xyz'); +} {{create references '}} +do_execsql_test alter-17.12 { + SELECT sqlite_rename_parent('create references "abc"123" ','abc','xyz'); +} {{create references "xyz"123" }} +do_execsql_test alter-17.13 { + SELECT sqlite_rename_parent("references '''",'abc','xyz'); +} {{references '''}} finish_test diff --git a/test/analyze.test b/test/analyze.test index c445084..af277cc 100644 --- a/test/analyze.test +++ b/test/analyze.test @@ -359,6 +359,6 @@ do_test analyze-99.1 { catchsql { ANALYZE } -} {1 {malformed database schema (sqlite_stat1) - near "nonsense": syntax error}} +} {1 {malformed database schema (sqlite_stat1)}} finish_test diff --git a/test/analyze3.test b/test/analyze3.test index e7416d5..d61d21a 100644 --- a/test/analyze3.test +++ b/test/analyze3.test @@ -16,6 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix analyze3 ifcapable !stat4&&!stat3 { finish_test @@ -46,6 +47,9 @@ ifcapable !stat4&&!stat3 { # # analyze3-6.*: Test that the problem fixed by commit [127a5b776d] is fixed. # +# analyze3-7.*: Test that some memory leaks discovered by fuzz testing +# have been fixed. +# proc getvar {varname} { uplevel #0 set $varname } db function var getvar @@ -281,35 +285,35 @@ do_eqp_test analyze3-2.3 { do_test analyze3-2.4 { sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE 'a%' } -} {101 0 100} +} {102 0 100} do_test analyze3-2.5 { sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE '%a' } } {999 999 100} -do_test analyze3-2.4 { +do_test analyze3-2.6 { set like "a%" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } -} {101 0 100} -do_test analyze3-2.5 { +} {102 0 100} +do_test analyze3-2.7 { set like "%a" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } } {999 999 100} -do_test analyze3-2.6 { +do_test analyze3-2.8 { set like "a" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } -} {101 0 0} -do_test analyze3-2.7 { +} {102 0 0} +do_test analyze3-2.9 { set like "ab" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } -} {11 0 0} -do_test analyze3-2.8 { +} {12 0 0} +do_test analyze3-2.10 { set like "abc" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } -} {2 0 1} -do_test analyze3-2.9 { +} {3 0 1} +do_test analyze3-2.11 { set like "a_c" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } -} {101 0 10} +} {102 0 10} #------------------------------------------------------------------------- @@ -662,4 +666,30 @@ do_eqp_test analyze3-6-2 { SELECT * FROM t1 WHERE a = 5 AND b > 'w' AND c = 13; } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}} +#----------------------------------------------------------------------------- +# 2015-04-20. +# Memory leak in sqlite3Stat4ProbeFree(). (Discovered while fuzzing.) +# +do_execsql_test analyze-7.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); + INSERT INTO t1 VALUES(1,1,'0000'); + CREATE INDEX t0b ON t1(b); + ANALYZE; + SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND hex(1); +} {} + +# At one point duplicate stat1 entries were causing a memory leak. +# +reset_db +do_execsql_test 7.2 { + CREATE TABLE t1(a,b,c); + CREATE INDEX t1a ON t1(a); + ANALYZE; + SELECT * FROM sqlite_stat1; + INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t1','t1a','12000'); + INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t1','t1a','12000'); + ANALYZE sqlite_master; +} + finish_test diff --git a/test/analyze9.test b/test/analyze9.test index 8572cbe..1ebd69c 100644 --- a/test/analyze9.test +++ b/test/analyze9.test @@ -1134,4 +1134,116 @@ ifcapable stat4&&cte { } } +#------------------------------------------------------------------------- +# Check that a problem in they way stat4 data is used has been +# resolved (see below). +# +reset_db +do_test 26.1.1 { + db transaction { + execsql { + CREATE TABLE t1(x, y, z); + CREATE INDEX t1xy ON t1(x, y); + CREATE INDEX t1z ON t1(z); + } + for {set i 0} {$i < 10000} {incr i} { + execsql { INSERT INTO t1(x, y) VALUES($i, $i) } + } + for {set i 0} {$i < 10} {incr i} { + execsql { + WITH cnt(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM cnt WHERE x<100) + INSERT INTO t1(x, y) SELECT 10000+$i, x FROM cnt; + INSERT INTO t1(x, y) SELECT 10000+$i, 100; + } + } + execsql { + UPDATE t1 SET z = rowid / 20; + ANALYZE; + } + } +} {} + +do_execsql_test 26.1.2 { + SELECT count(*) FROM t1 WHERE x = 10000 AND y < 50; +} {49} +do_execsql_test 26.1.3 { + SELECT count(*) FROM t1 WHERE z = 444; +} {20} + +# The analyzer knows that any (z=?) expression matches 20 rows. So it +# will use index "t1z" if the estimate of hits for (x=10000 AND y<50) +# is greater than 20 rows. +# +# And it should be. The analyzer has a stat4 sample as follows: +# +# sample=(x=10000, y=100) nLt=(10000 10099) +# +# There should be no other samples that start with (x=10000). So it knows +# that (x=10000 AND y<50) must match somewhere between 0 and 99 rows, but +# know more than that. Guessing less than 20 is therefore unreasonable. +# +# At one point though, due to a problem in whereKeyStats(), the planner was +# estimating that (x=10000 AND y<50) would match only 2 rows. +# +do_eqp_test 26.1.4 { + SELECT * FROM t1 WHERE x = 10000 AND y < 50 AND z = 444; +} { + 0 0 0 {SEARCH TABLE t1 USING INDEX t1z (z=?)} +} + + +# This test - 26.2.* - tests that another manifestation of the same problem +# is no longer present in the library. Assuming: +# +# CREATE INDEX t1xy ON t1(x, y) +# +# and that have samples for index t1xy as follows: +# +# +# sample=('A', 70) nEq=(100, 2) nLt=(900, 970) +# sample=('B', 70) nEq=(100, 2) nLt=(1000, 1070) +# +# the planner should estimate that (x = 'B' AND y > 25) matches 76 rows +# (70 * 2/3 + 30). Before, due to the problem, the planner was estimating +# that this matched 100 rows. +# +reset_db +do_execsql_test 26.2.1 { + BEGIN; + CREATE TABLE t1(x, y, z); + CREATE INDEX i1 ON t1(x, y); + CREATE INDEX i2 ON t1(z); + + WITH + cnt(y) AS (SELECT 0 UNION ALL SELECT y+1 FROM cnt WHERE y<99), + letters(x) AS ( + SELECT 'A' UNION SELECT 'B' UNION SELECT 'C' UNION SELECT 'D' + ) + INSERT INTO t1(x, y) SELECT x, y FROM letters, cnt; + + WITH + letters(x) AS ( + SELECT 'A' UNION SELECT 'B' UNION SELECT 'C' UNION SELECT 'D' + ) + INSERT INTO t1(x, y) SELECT x, 70 FROM letters; + + WITH + cnt(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM cnt WHERE i<9999) + INSERT INTO t1(x, y) SELECT i, i FROM cnt; + + UPDATE t1 SET z = (rowid / 95); + ANALYZE; + COMMIT; +} + +do_eqp_test 26.2.2 { + SELECT * FROM t1 WHERE x='B' AND y>25 AND z=?; +} { + 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x=? AND y>?)} +} + + finish_test + + + diff --git a/test/analyzeF.test b/test/analyzeF.test new file mode 100644 index 0000000..670d178 --- /dev/null +++ b/test/analyzeF.test @@ -0,0 +1,127 @@ +# 2015-03-12 +# +# 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. +# +#*********************************************************************** +# Test that deterministic scalar functions passed constant arguments +# are used with stat4 data. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix analyzeF + +ifcapable {!stat4} { + finish_test + return +} + +proc isqrt {i} { expr { int(sqrt($i)) } } +db func isqrt isqrt + +do_execsql_test 1.0 { + CREATE TABLE t1(x INTEGER, y INTEGER); + WITH data(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM data + ) + INSERT INTO t1 SELECT isqrt(i), isqrt(i) FROM data LIMIT 400; + CREATE INDEX t1x ON t1(x); + CREATE INDEX t1y ON t1(y); + ANALYZE; +} + +proc str {a} { return $a } +db func str str + +# Note: tests 7 to 12 might be unstable - as they assume SQLite will +# prefer the expression to the right of the AND clause. Which of +# course could change. +# +# Note 2: tests 9 and 10 depend on the tcl interface creating functions +# without the SQLITE_DETERMINISTIC flag set. +# +foreach {tn where idx} { + 1 "x = 4 AND y = 19" {t1x (x=?)} + 2 "x = 19 AND y = 4" {t1y (y=?)} + 3 "x = '4' AND y = '19'" {t1x (x=?)} + 4 "x = '19' AND y = '4'" {t1y (y=?)} + 5 "x = substr('5195', 2, 2) AND y = substr('145', 2, 1)" {t1y (y=?)} + 6 "x = substr('145', 2, 1) AND y = substr('5195', 2, 2)" {t1x (x=?)} + + 7 "x = substr('5195', 2, 2+0) AND y = substr('145', 2, 1+0)" {t1y (y=?)} + 8 "x = substr('145', 2, 1+0) AND y = substr('5195', 2, 2+0)" {t1y (y=?)} + + 9 "x = str('19') AND y = str('4')" {t1y (y=?)} + 10 "x = str('4') AND y = str('19')" {t1y (y=?)} + + 11 "x = nullif('19', 0) AND y = nullif('4', 0)" {t1y (y=?)} + 12 "x = nullif('4', 0) AND y = nullif('19', 0)" {t1y (y=?)} +} { + set res "0 0 0 {SEARCH TABLE t1 USING INDEX $idx}" + do_eqp_test 1.$tn "SELECT * FROM t1 WHERE $where" $res +} + +# Test that functions that do not exist - "func()" - do not cause an error. +# +do_catchsql_test 2.1 { + SELECT * FROM t1 WHERE x = substr('145', 2, 1) AND y = func(1, 2, 3) +} {1 {no such function: func}} +do_catchsql_test 2.2 { + UPDATE t1 SET y=y+1 WHERE x = substr('145', 2, 1) AND y = func(1, 2, 3) +} {1 {no such function: func}} + + +# Check that functions that accept zero arguments do not cause problems. +# +proc ret {x} { return $x } + +db func det4 -deterministic [list ret 4] +db func nondet4 [list ret 4] +db func det19 -deterministic [list ret 19] +db func nondet19 [list ret 19] + +foreach {tn where idx} { + 1 "x = det4() AND y = det19()" {t1x (x=?)} + 2 "x = det19() AND y = det4()" {t1y (y=?)} + + 3 "x = nondet4() AND y = nondet19()" {t1y (y=?)} + 4 "x = nondet19() AND y = nondet4()" {t1y (y=?)} +} { + set res "0 0 0 {SEARCH TABLE t1 USING INDEX $idx}" + do_eqp_test 3.$tn "SELECT * FROM t1 WHERE $where" $res +} + + +execsql { DELETE FROM t1 } + +proc throw_error {err} { error $err } +db func error -deterministic throw_error +do_catchsql_test 4.1 { + SELECT * FROM t1 WHERE x = error('error one') AND y = 4; +} {1 {error one}} + +do_catchsql_test 4.2 { + SELECT * FROM t1 WHERE x = zeroblob(2000000000) AND y = 4; +} {1 {string or blob too big}} + +sqlite3_limit db SQLITE_LIMIT_LENGTH 1000000 +proc dstr {} { return [string repeat x 1100000] } +db func dstr -deterministic dstr +do_catchsql_test 4.3 { + SELECT * FROM t1 WHERE x = dstr() AND y = 11; +} {1 {string or blob too big}} + +do_catchsql_test 4.4 { + SELECT * FROM t1 WHERE x = test_zeroblob(1100000) AND y = 4; +} {1 {string or blob too big}} + + +finish_test + + + diff --git a/test/attach.test b/test/attach.test index be5f988..31c24e6 100644 --- a/test/attach.test +++ b/test/attach.test @@ -859,4 +859,16 @@ do_test attach-10.2 { }] 9 end } {4 noname {} 5 inmem {}} +# Attach with a very long URI filename. +# +db close +sqlite3 db test.db -uri 1 +do_execsql_test attach-11.1 { + ATTACH printf('file:%09000x/x.db?mode=memory&cache=shared',1) AS aux1; + CREATE TABLE aux1.t1(x,y); + INSERT INTO aux1.t1(x,y) VALUES(1,2),(3,4); + SELECT * FROM aux1.t1; +} {1 2 3 4} + + finish_test diff --git a/test/autoindex1.test b/test/autoindex1.test index bcde5bc..e2b8b15 100644 --- a/test/autoindex1.test +++ b/test/autoindex1.test @@ -11,6 +11,9 @@ # This file implements regression tests for SQLite library. The # focus of this script is testing automatic index creation logic. # +# EVIDENCE-OF: R-34271-33106 PRAGMA automatic_index; PRAGMA +# automatic_index = boolean; Query, set, or clear the automatic indexing +# capability. set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -509,5 +512,12 @@ do_execsql_test autoindex1-901 { WHERE t1.x IN (1,2,3); } {/USING AUTOMATIC COVERING INDEX/} +# 2015-04-15: A NULL CollSeq pointer in automatic index creation. +# +do_execsql_test autoindex1-920 { + CREATE TABLE t920(x); + INSERT INTO t920 VALUES(3),(4),(5); + SELECT * FROM t920,(SELECT 0 FROM t920),(VALUES(9)) WHERE 5 IN (x); +} {5 0 9 5 0 9 5 0 9} finish_test diff --git a/test/btree02.test b/test/btree02.test new file mode 100644 index 0000000..de7c06d --- /dev/null +++ b/test/btree02.test @@ -0,0 +1,52 @@ +# 2015-03-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 making multiple calls to saveCursorPosition() +# and restoreCursorPosition() when cursors have eState==CURSOR_SKIPNEXT +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +load_static_extension db eval +do_execsql_test btree02-100 { + CREATE TABLE t1(a TEXT, ax INTEGER, b INT, PRIMARY KEY(a,ax)) WITHOUT ROWID; + WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<10) + INSERT INTO t1(a,ax,b) SELECT printf('%02x',i), random(), i FROM c; + CREATE INDEX t1a ON t1(a); + CREATE TABLE t2(x,y); + CREATE TABLE t3(cnt); + WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<4) + INSERT INTO t3(cnt) SELECT i FROM c; + SELECT count(*) FROM t1; +} {10} +do_test btree02-110 { + db eval BEGIN + set i 0 + db eval {SELECT a, ax, b, cnt FROM t1 CROSS JOIN t3 WHERE b IS NOT NULL} { + db eval {INSERT INTO t2(x,y) VALUES($b,$cnt)} + # puts "a,b,cnt = ($a,$b,$cnt)" + incr i + if {$i%2==1} { + set bx [expr {$b+1000}] + # puts "INSERT ($a),$bx" + db eval {INSERT INTO t1(a,ax,b) VALUES(printf('(%s)',$a),random(),$bx)} + } else { + # puts "DELETE a=$a" + db eval {DELETE FROM t1 WHERE a=$a} + } + db eval {COMMIT; BEGIN} + } + db one {COMMIT; SELECT count(*) FROM t1;} +} {20} + +finish_test diff --git a/test/capi3.test b/test/capi3.test index 9f3d6f6..163bb19 100644 --- a/test/capi3.test +++ b/test/capi3.test @@ -452,9 +452,21 @@ proc check_data {STMT test types ints doubles strings} { # types do_test $test.1 { set types [list] - foreach i $idxlist {lappend types [sqlite3_column_type $STMT $i]} + foreach i $idxlist { + set x [sqlite3_column_type $STMT $i] + # EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five + # fundamental datatypes: 64-bit signed integer 64-bit IEEE floating + # point number string BLOB NULL + if {[lsearch {INTEGER FLOAT TEXT BLOB NULL} $x]<0} { + set types ERROR + break + } else { + lappend types $x + } + } set types } $types + # Integers do_test $test.2 { diff --git a/test/collate1.test b/test/collate1.test index 2085415..7cf5698 100644 --- a/test/collate1.test +++ b/test/collate1.test @@ -10,12 +10,12 @@ # #*********************************************************************** # This file implements regression tests for SQLite library. The -# focus of this script is page cache subsystem. +# focus of this script is testing collation sequences. # -# $Id: collate1.test,v 1.5 2007/02/01 23:02:46 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix collate1 # # Tests are roughly organised as follows: @@ -333,4 +333,72 @@ do_test collate1-5.3 { } } {1 2} + + +#------------------------------------------------------------------------- +# Fix problems with handling collation sequences named '"""'. +# +do_execsql_test 6.1 { + SELECT """"""""; +} {\"\"\"} + +do_catchsql_test 6.2 { + CREATE TABLE x1(a); + SELECT a FROM x1 ORDER BY a COLLATE """"""""; +} {1 {no such collation sequence: """}} + +do_catchsql_test 6.3 { + SELECT a FROM x1 ORDER BY 1 COLLATE """"""""; +} {1 {no such collation sequence: """}} + +do_catchsql_test 6.4 { + SELECT 0 UNION SELECT 0 ORDER BY 1 COLLATE """"""""; +} {1 {no such collation sequence: """}} + +db collate {"""} [list string compare -nocase] + +do_execsql_test 6.5 { + PRAGMA foreign_keys = ON; + CREATE TABLE p1(a PRIMARY KEY COLLATE '"""'); + CREATE TABLE c1(x, y REFERENCES p1); +} {} + +do_execsql_test 6.6 { + INSERT INTO p1 VALUES('abc'); + INSERT INTO c1 VALUES(1, 'ABC'); +} + +ifcapable foreignkey { + do_catchsql_test 6.7 { + DELETE FROM p1 WHERE rowid = 1 + } {1 {FOREIGN KEY constraint failed}} +} + +do_execsql_test 6.8 { + INSERT INTO p1 VALUES('abb'); + INSERT INTO p1 VALUES('wxz'); + INSERT INTO p1 VALUES('wxy'); + + INSERT INTO c1 VALUES(2, 'abb'); + INSERT INTO c1 VALUES(3, 'wxz'); + INSERT INTO c1 VALUES(4, 'WXY'); + SELECT x, y FROM c1 ORDER BY y COLLATE """"""""; +} {2 abb 1 ABC 4 WXY 3 wxz} + +# 2015-04-15: Nested COLLATE operators +# +do_execsql_test 7.0 { + SELECT 'abc' UNION ALL SELECT 'DEF' + ORDER BY 1 COLLATE nocase COLLATE nocase COLLATE nocase COLLATE nocase; +} {abc DEF} +do_execsql_test 7.1 { + SELECT 'abc' UNION ALL SELECT 'DEF' + ORDER BY 1 COLLATE nocase COLLATE nocase COLLATE nocase COLLATE binary; +} {DEF abc} +do_execsql_test 7.2 { + SELECT 'abc' UNION ALL SELECT 'DEF' + ORDER BY 1 COLLATE binary COLLATE binary COLLATE binary COLLATE nocase; +} {abc DEF} + + finish_test diff --git a/test/collate3.test b/test/collate3.test index 2c051cb..99640d0 100644 --- a/test/collate3.test +++ b/test/collate3.test @@ -32,7 +32,7 @@ source $testdir/tester.tcl # do_test collate3-1.0 { execsql { - CREATE TABLE collate3t1(c1); + CREATE TABLE collate3t1(c1 UNIQUE); } } {} do_test collate3-1.1 { @@ -40,6 +40,11 @@ do_test collate3-1.1 { SELECT * FROM collate3t1 ORDER BY 1 collate garbage; } } {1 {no such collation sequence: garbage}} +do_test collate3-1.1.2 { + catchsql { + SELECT DISTINCT c1 COLLATE garbage FROM collate3t1; + } +} {1 {no such collation sequence: garbage}} do_test collate3-1.2 { catchsql { CREATE TABLE collate3t2(c1 collate garbage); diff --git a/test/collate8.test b/test/collate8.test index 60a8916..b06c87d 100644 --- a/test/collate8.test +++ b/test/collate8.test @@ -13,7 +13,9 @@ # focus of this script is making sure collations pass through the # unary + operator. # -# $Id: collate8.test,v 1.2 2008/08/25 12:14:09 drh Exp $ +# 2015-02-09: Added tests to make sure COLLATE passes through function +# calls. Ticket [ca0d20b6cdddec5e81b8d66f89c46a5583b5f6f6]. +# set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -122,4 +124,34 @@ do_test collate8-2.8 { } } {abc} +# Make sure the COLLATE operator perculates up through function calls +# and other Expr structures that use the Expr.x.pList field. +# +do_execsql_test collate8-3.1 { + SELECT 'abc'==('ABC'||'') COLLATE nocase; + SELECT 'abc'==('ABC'||'' COLLATE nocase); + SELECT 'abc'==('ABC'||('' COLLATE nocase)); + SELECT 'abc'==('ABC'||upper('' COLLATE nocase)); +} {1 1 1 1} +do_execsql_test collate8-3.2 { + SELECT 'abc'==('ABC'||max('' COLLATE nocase,'' COLLATE binary)); +} {1} + +# The COLLATE binary is on the left and so takes precedence +do_execsql_test collate8-3.3 { + SELECT 'abc'==('ABC'||max('' COLLATE binary,'' COLLATE nocase)); +} {0} + +do_execsql_test collate8-3.4 { + SELECT 'abc'==('ABC'||CASE WHEN 1-1=2 THEN '' COLLATE nocase + ELSE '' COLLATE binary END); + SELECT 'abc'==('ABC'||CASE WHEN 1+1=2 THEN '' COLLATE nocase + ELSE '' COLLATE binary END); +} {1 1} +do_execsql_test collate8-3.5 { + SELECT 'abc'==('ABC'||CASE WHEN 1=2 THEN '' COLLATE binary + ELSE '' COLLATE nocase END); +} {0} + + finish_test diff --git a/test/corruptC.test b/test/corruptC.test index adf6f44..a7f93c4 100644 --- a/test/corruptC.test +++ b/test/corruptC.test @@ -292,7 +292,7 @@ do_test corruptC-2.15 { hexio_write test.db 986 b9 sqlite3 db test.db catchsql {SELECT count(*) FROM sqlite_master;} -} {1 {malformed database schema (t1i1) - no such table: main.t1}} +} {1 {database disk image is malformed}} # # Now test for a series of quasi-random seeds. diff --git a/test/corruptJ.test b/test/corruptJ.test new file mode 100644 index 0000000..c08e628 --- /dev/null +++ b/test/corruptJ.test @@ -0,0 +1,80 @@ +# 2015-03-30 +# +# 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. +# +#*********************************************************************** +# +# Corruption consisting of a database page that thinks it is a child +# of itself. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix corruptJ + +if {[permutation]=="mmap"} { + finish_test + return +} + +# Do not use a codec for tests in this file, as the database file is +# manipulated directly using tcl scripts (using the [hexio_write] command). +# +do_not_use_codec +database_may_be_corrupt + +# Initialize the database. +# +do_execsql_test 1.1 { + PRAGMA page_size=1024; + PRAGMA auto_vacuum=0; + CREATE TABLE t1(a,b); + WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<10) + INSERT INTO t1(a,b) SELECT i, zeroblob(700) FROM c; +} {} +db close + +# Corrupt the root page of the t1 table such that the left-child pointer +# for the very first cell points back to the root. Then try to DROP the +# table. The clearDatabasePage() routine should not loop. +# +do_test 1.2 { + hexio_write test.db [expr {2*1024-2}] 02 + sqlite3 db test.db + catchsql { DROP TABLE t1 } +} {1 {database disk image is malformed}} + +# Similar test using a WITHOUT ROWID table +# +do_test 2.1 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + PRAGMA page_size=1024; + PRAGMA auto_vacuum=0; + CREATE TABLE t1(a,b,PRIMARY KEY(a,b)) WITHOUT ROWID; + WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<100) + INSERT INTO t1(a,b) SELECT i, zeroblob(200) FROM c; + } +} {} + +# The table is three levels deep. Corrupt the left child of an intermediate +# page so that it points back to the root page. +# +do_test 2.2 { + db close + hexio_read test.db [expr {9*1024+391}] 8 +} {00000008814D0401} +do_test 2.2b { + hexio_write test.db [expr {9*1024+391}] 00000002 + sqlite3 db test.db + catchsql { PRAGMA secure_delete=ON; DROP TABLE t1; } +} {1 {database disk image is malformed}} + +finish_test diff --git a/test/count.test b/test/count.test index 3461e49..862b62a 100644 --- a/test/count.test +++ b/test/count.test @@ -191,4 +191,9 @@ do_execsql_test count-5.1 { SELECT count(*) FROM t5; } {1} +do_catchsql_test count-6.1 { + CREATE TABLE t6(x); + SELECT count(DISTINCT) FROM t6 GROUP BY x; +} {1 {DISTINCT aggregates must have exactly one argument}} + finish_test diff --git a/test/crashM.test b/test/crashM.test new file mode 100644 index 0000000..de10c45 --- /dev/null +++ b/test/crashM.test @@ -0,0 +1,80 @@ +# 2015 Mar 13 +# +# 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. +# +#*********************************************************************** +# +# Crash tests for the multiplex module with 8.3 filenames enabled. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix crashM + +ifcapable !crashtest||!8_3_names { + finish_test + return +} + +db close +sqlite3_shutdown +sqlite3_config_uri 1 + +foreach f [glob -nocomplain test1.* test2.*] { forcedelete $f } +sqlite3_multiplex_initialize "" 1 +sqlite3 db file:test1.db?8_3_names=1 +sqlite3_multiplex_control db main chunk_size [expr 64*1024] + +do_execsql_test 1.0 { + ATTACH 'file:test2.db?8_3_names=1' AS aux; + + CREATE TABLE t1(x, y); + CREATE INDEX t1x ON t1(x); + CREATE INDEX t1y ON t1(y); + + CREATE TABLE aux.t2(x, y); + CREATE INDEX aux.t2x ON t2(x); + CREATE INDEX aux.t2y ON t2(y); + + WITH s(a) AS ( + SELECT 1 UNION ALL SELECT a+1 FROM s WHERE a<1000 + ) + INSERT INTO t1 SELECT a, randomblob(500) FROM s; + + WITH s(a) AS ( + SELECT 1 UNION ALL SELECT a+1 FROM s WHERE a<1000 + ) + INSERT INTO t2 SELECT a, randomblob(500) FROM s; +} {} + +for {set i 0} {$i < 20} {incr i} { + do_test 2.$i.1 { + crashsql -delay 1 -file test1.db -opendb { + sqlite3_shutdown + sqlite3_config_uri 1 + sqlite3_multiplex_initialize crash 1 + sqlite3 db file:test1.db?8_3_names=1 + sqlite3_multiplex_control db main chunk_size [expr 64*1024] + } { + ATTACH 'file:test2.db?8_3_names=1' AS aux; + BEGIN; + UPDATE t1 SET y = randomblob(500) WHERE (x%10)==0; + UPDATE t2 SET y = randomblob(500) WHERE (x%10)==0; + COMMIT; + } + } {1 {child process exited abnormally}} + + do_execsql_test 2.$i.2 { + PRAGMA main.integrity_check; + PRAGMA aux.integrity_check; + } {ok ok} +} + +catch { db close } +sqlite3_multiplex_shutdown +finish_test diff --git a/test/e_insert.test b/test/e_insert.test index 0ea4b76..ffafa0e 100644 --- a/test/e_insert.test +++ b/test/e_insert.test @@ -348,9 +348,9 @@ do_insert_tests e_insert-3.2 { 6.2 "SELECT * FROM a1" {{} {} {} {}} } -# EVIDENCE-OF: R-46928-50290 The optional conflict-clause allows the -# specification of an alternative constraint conflict resolution -# algorithm to use during this one INSERT command. +# EVIDENCE-OF: R-03235-45250 The "REPLACE" and "INSERT OR action" forms +# specify an alternative constraint conflict resolution algorithm to use +# during this one INSERT command. # # EVIDENCE-OF: R-23110-47146 the parser allows the use of the single # keyword REPLACE as an alias for "INSERT OR REPLACE". diff --git a/test/e_reindex.test b/test/e_reindex.test index 4b86787..fa66aa7 100644 --- a/test/e_reindex.test +++ b/test/e_reindex.test @@ -48,8 +48,11 @@ do_execsql_test e_reindex-1.1 { INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); INSERT INTO t1 VALUES(5, 6); + + CREATE TABLE saved(a,b,c,d,e); + INSERT INTO saved SELECT * FROM sqlite_master WHERE type = 'index'; PRAGMA writable_schema = 1; - UPDATE sqlite_master SET sql = '-- ' || sql WHERE type = 'index'; + DELETE FROM sqlite_master WHERE type = 'index'; } {} db close @@ -59,7 +62,8 @@ do_execsql_test e_reindex-1.2 { INSERT INTO t1 VALUES(7, 8); INSERT INTO t1 VALUES(9, 10); PRAGMA writable_schema = 1; - UPDATE sqlite_master SET sql = substr(sql, 4) WHERE type = 'index'; + INSERT INTO sqlite_master SELECT * FROM saved; + DROP TABLE saved; } {} db close diff --git a/test/e_wal.test b/test/e_wal.test index a5e074f..77ac83a 100644 --- a/test/e_wal.test +++ b/test/e_wal.test @@ -200,10 +200,11 @@ do_test 3.4.2 { db close -# EVIDENCE-OF: R-22428-28959 To prevent older versions of SQLite from -# trying to recover a WAL-mode database (and making matters worse) the -# database file format version numbers (bytes 18 and 19 in the database -# header) are increased from 1 to 2 in WAL mode. +# EVIDENCE-OF: R-45540-25505 To prevent older versions of SQLite (prior +# to version 3.7.0, 2010-07-22) from trying to recover a WAL-mode +# database (and making matters worse) the database file format version +# numbers (bytes 18 and 19 in the database header) are increased from 1 +# to 2 in WAL mode. # reset_db do_execsql_test 4.1.1 { CREATE TABLE t1(x, y) } diff --git a/test/e_walauto.test b/test/e_walauto.test index b624b24..a1f4eb7 100644 --- a/test/e_walauto.test +++ b/test/e_walauto.test @@ -15,6 +15,14 @@ source $testdir/tester.tcl source $testdir/wal_common.tcl set testprefix e_walauto +# Do not run this test on OpenBSD, as it depends on read() and mmap both +# accessing the same coherent view of the "test.db-shm" file. This doesn't +# work on OpenBSD. +# +if {$tcl_platform(os) == "OpenBSD"} { + finish_test + return +} proc read_nbackfill {} { seek $::shmfd 96 diff --git a/test/expr.test b/test/expr.test index 8d913d2..7d7b8ce 100644 --- a/test/expr.test +++ b/test/expr.test @@ -943,5 +943,13 @@ do_realnum_test expr-13.7 { } } {9.22337203685478e+18} +do_execsql_test expr-13.8 { + SELECT "" <= ''; +} {1} +do_execsql_test expr-13.9 { + SELECT '' <= ""; +} {1} + + finish_test diff --git a/test/fkey1.test b/test/fkey1.test index 90a4c44..0bd4939 100644 --- a/test/fkey1.test +++ b/test/fkey1.test @@ -121,4 +121,34 @@ do_test fkey1-3.5 { sqlite3_db_status db DBSTATUS_DEFERRED_FKS 0 } {0 0 0} +# Stress the dequoting logic. The first test is not so bad. +do_execsql_test fkey1-4.0 { + PRAGMA foreign_keys=ON; + CREATE TABLE "xx1"("xx2" TEXT PRIMARY KEY, "xx3" TEXT); + INSERT INTO "xx1"("xx2","xx3") VALUES('abc','def'); + CREATE TABLE "xx4"("xx5" TEXT REFERENCES "xx1" ON DELETE CASCADE); + INSERT INTO "xx4"("xx5") VALUES('abc'); + INSERT INTO "xx1"("xx2","xx3") VALUES('uvw','xyz'); + SELECT 1, "xx5" FROM "xx4"; + DELETE FROM "xx1"; + SELECT 2, "xx5" FROM "xx4"; +} {1 abc} + +# This case is identical to the previous except the "xx" in each name +# is changed to a single escaped double-quote character. +do_execsql_test fkey1-4.1 { + PRAGMA foreign_keys=ON; + CREATE TABLE """1"("""2" TEXT PRIMARY KEY, """3" TEXT); + INSERT INTO """1"("""2","""3") VALUES('abc','def'); + CREATE TABLE """4"("""5" TEXT REFERENCES """1" ON DELETE CASCADE); + INSERT INTO """4"("""5") VALUES('abc'); + INSERT INTO """1"("""2","""3") VALUES('uvw','xyz'); + SELECT 1, """5" FROM """4"; + DELETE FROM """1"; + SELECT 2, """5" FROM """4"; +} {1 abc} +do_execsql_test fkey1-4.2 { + PRAGMA table_info="""1"; +} {0 {"2} TEXT 0 {} 1 1 {"3} TEXT 0 {} 0} + finish_test diff --git a/test/fkey2.test b/test/fkey2.test index 53b90dc..aec75ed 100644 --- a/test/fkey2.test +++ b/test/fkey2.test @@ -676,6 +676,11 @@ do_test fkey2-9.2.3 { SELECT * FROM cc; } } {{} A {} {} B {} 3 A 2 3 B 2} +do_execsql_test fkey2-9.3.0 { + CREATE TABLE t3(x PRIMARY KEY REFERENCES t3 ON DELETE SET NULL); + INSERT INTO t3(x) VALUES(12345); + DROP TABLE t3; +} {} #------------------------------------------------------------------------- # The following tests, fkey2-10.*, test "foreign key mismatch" and @@ -746,10 +751,10 @@ do_test fkey2-10.2.2 { drop_all_tables do_test fkey2-11.1.1 { execsql { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, rowid, _rowid_, oid); CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(a) ON UPDATE CASCADE); - INSERT INTO t1 VALUES(10, 100); + INSERT INTO t1 VALUES(10, 100, 'abc', 'def', 'ghi'); INSERT INTO t2 VALUES(10, 100); UPDATE t1 SET a = 15; SELECT * FROM t2; @@ -2014,4 +2019,18 @@ do_test fkey2-ce7c13.1.6 { } } {1 {FOREIGN KEY constraint failed}} +# 2015-04-16: Foreign key errors propagate back up to the parser. +# +do_test fkey2-20150416-100 { + db close + sqlite3 db :memory: + catchsql { + PRAGMA foreign_keys=1; + CREATE TABLE t1(x PRIMARY KEY); + CREATE TABLE t(y REFERENCES t0(x)ON DELETE SET DEFAULT); + CREATE TABLE t0(y REFERENCES t1 ON DELETE SET NULL); + REPLACE INTO t1 SELECT(0);CREATE TABLE t2(x);CREATE TABLE t3; + } +} {1 {foreign key mismatch - "t" referencing "t0"}} + finish_test diff --git a/test/fkey5.test b/test/fkey5.test index dc866cb..21feb2b 100644 --- a/test/fkey5.test +++ b/test/fkey5.test @@ -12,8 +12,13 @@ # # This file tests the PRAGMA foreign_key_check command. # -# EVIDENCE-OF: R-05426-18119 PRAGMA foreign_key_check; PRAGMA -# foreign_key_check(table-name); +# EVIDENCE-OF: R-01427-50262 PRAGMA database.foreign_key_check; PRAGMA +# database.foreign_key_check(table-name); +# +# EVIDENCE-OF: R-23918-17301 The foreign_key_check pragma checks the +# database, or the table called "table-name", for foreign key +# constraints that are violated and returns one row of output for each +# violation. set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -74,6 +79,16 @@ do_test fkey5-1.2 { PRAGMA foreign_key_check; } } {c1 87 p1 0 c1 90 p1 0} +do_test fkey5-1.2b { + db eval { + PRAGMA main.foreign_key_check; + } +} {c1 87 p1 0 c1 90 p1 0} +do_test fkey5-1.2c { + db eval { + PRAGMA temp.foreign_key_check; + } +} {} do_test fkey5-1.3 { db eval { PRAGMA foreign_key_check(c1); @@ -84,6 +99,16 @@ do_test fkey5-1.4 { PRAGMA foreign_key_check(c2); } } {} +do_test fkey5-1.5 { + db eval { + PRAGMA main.foreign_key_check(c2); + } +} {} +do_test fkey5-1.6 { + catchsql { + PRAGMA temp.foreign_key_check(c2); + } +} {1 {no such table: temp.c2}} # EVIDENCE-OF: R-45728-08709 There are four columns in each result row. # diff --git a/test/fts3aa.test b/test/fts3aa.test index 6ff384a..08d825d 100644 --- a/test/fts3aa.test +++ b/test/fts3aa.test @@ -16,6 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix fts3aa # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { @@ -221,5 +222,26 @@ do_catchsql_test fts3aa-7.5 { CREATE VIRTUAL TABLE t4 USING fts4(tokenize=simple, tokenize=simple); } {1 {unrecognized parameter: tokenize=simple}} +do_execsql_test 8.0 { + CREATE VIRTUAL TABLE t0 USING fts4(order=desc); + BEGIN; + INSERT INTO t0(rowid, content) VALUES(1, 'abc'); + UPDATE t0 SET docid=5 WHERE docid=1; + INSERT INTO t0(rowid, content) VALUES(6, 'abc'); +} +do_execsql_test 8.1 { + SELECT docid FROM t0 WHERE t0 MATCH 'abc'; +} {6 5} +do_execsql_test 8.2 { + SELECT docid FROM t0 WHERE t0 MATCH '"abc abc"'; +} {} +do_execsql_test 8.3 { COMMIT } +do_execsql_test 8.4 { + SELECT docid FROM t0 WHERE t0 MATCH 'abc'; +} {6 5} +do_execsql_test 8.5 { + SELECT docid FROM t0 WHERE t0 MATCH '"abc abc"'; +} {} + finish_test diff --git a/test/fts3atoken.test b/test/fts3atoken.test index b7722c7..88e3d4f 100644 --- a/test/fts3atoken.test +++ b/test/fts3atoken.test @@ -186,10 +186,32 @@ ifcapable icu { } {} } - do_test fts3token-internal { execsql { SELECT fts3_tokenizer_internal_test() } } {ok} +#------------------------------------------------------------------------- +# Test empty tokenizer names. +# +do_catchsql_test 6.1.1 { + CREATE VIRTUAL TABLE t3 USING fts4(tokenize=""); +} {1 {unknown tokenizer: }} +do_catchsql_test 6.1.2 { + CREATE VIRTUAL TABLE t3 USING fts4(tokenize=); +} {1 {unknown tokenizer: }} +do_catchsql_test 6.1.3 { + CREATE VIRTUAL TABLE t3 USING fts4(tokenize=" "); +} {1 {unknown tokenizer: }} + +do_catchsql_test 6.2.1 { + SELECT fts3_tokenizer(NULL); +} {1 {unknown tokenizer: }} +do_catchsql_test 6.2.2 { + SELECT fts3_tokenizer(NULL, X'1234567812345678'); +} {1 {argument type mismatch}} +do_catchsql_test 6.2.3 { + SELECT fts3_tokenizer(NULL, X'12345678'); +} {1 {argument type mismatch}} + finish_test diff --git a/test/fts3expr5.test b/test/fts3expr5.test new file mode 100644 index 0000000..1e09851 --- /dev/null +++ b/test/fts3expr5.test @@ -0,0 +1,48 @@ +# 2006 September 9 +# +# 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 fts3expr5 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +#------------------------------------------------------------------------- +# Various forms of empty phrase expressions. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t0 USING fts3(x); + SELECT rowid FROM t0 WHERE x MATCH ''; +} {} +do_execsql_test 1.1 { + SELECT rowid FROM t0 WHERE x MATCH '""'; +} {} +do_execsql_test 1.2 { + SELECT rowid FROM t0 WHERE x MATCH '"" ""'; +} {} +do_execsql_test 1.3 { + SELECT rowid FROM t0 WHERE x MATCH '"" OR ""'; +} {} +do_execsql_test 1.4 { + SELECT rowid FROM t0 WHERE x MATCH '"" NOT ""'; +} {} +do_execsql_test 1.5 { + SELECT rowid FROM t0 WHERE x MATCH '""""'; +} {} + +finish_test diff --git a/test/fts3fault2.test b/test/fts3fault2.test index f2d10bc..030ff73 100644 --- a/test/fts3fault2.test +++ b/test/fts3fault2.test @@ -155,4 +155,23 @@ ifcapable fts3_unicode { } } +reset_db +do_test 6.0 { + execsql { + CREATE VIRTUAL TABLE t6 USING fts4(x,order=DESC); + INSERT INTO t6(docid, x) VALUES(-1,'a b'); + INSERT INTO t6(docid, x) VALUES(1, 'b'); + } + faultsim_save_and_close +} {} + +do_faultsim_test 6.1 -faults oom* -prep { + faultsim_restore_and_reopen + db eval {SELECT * FROM sqlite_master} +} -body { + execsql { SELECT docid FROM t6 WHERE t6 MATCH '"a* b"' } +} -test { + faultsim_test_result {0 -1} +} + finish_test diff --git a/test/fts3matchinfo.test b/test/fts3matchinfo.test index 36c9121..2681d00 100644 --- a/test/fts3matchinfo.test +++ b/test/fts3matchinfo.test @@ -449,5 +449,68 @@ do_execsql_test 10.1 { ORDER BY 1; } {1 1 one 2 2 two 3 3 three} +#--------------------------------------------------------------------------- +# Test the 'y' matchinfo flag +# +set sqlite_fts3_enable_parentheses 1 +reset_db +do_execsql_test 11.0 { + CREATE VIRTUAL TABLE tt USING fts3(x, y); + INSERT INTO tt VALUES('c d a c d d', 'e a g b d a'); -- 1 + INSERT INTO tt VALUES('c c g a e b', 'c g d g e c'); -- 2 + INSERT INTO tt VALUES('b e f d e g', 'b a c b c g'); -- 3 + INSERT INTO tt VALUES('a c f f g d', 'd b f d e g'); -- 4 + INSERT INTO tt VALUES('g a c f c f', 'd g g b c c'); -- 5 + INSERT INTO tt VALUES('g a c e b b', 'd b f b g g'); -- 6 + INSERT INTO tt VALUES('f d a a f c', 'e e a d c f'); -- 7 + INSERT INTO tt VALUES('a c b b g f', 'a b a e d f'); -- 8 + INSERT INTO tt VALUES('b a f e c c', 'f d b b a b'); -- 9 + INSERT INTO tt VALUES('f d c e a c', 'f a f a a f'); -- 10 +} + +db func mit mit +foreach {tn expr res} { + 1 "a" { + 1 {1 2} 2 {1 0} 3 {0 1} 4 {1 0} 5 {1 0} + 6 {1 0} 7 {2 1} 8 {1 2} 9 {1 1} 10 {1 3} + } + + 2 "b" { + 1 {0 1} 2 {1 0} 3 {1 2} 4 {0 1} 5 {0 1} + 6 {2 2} 8 {2 1} 9 {1 3} + } + + 3 "y:a" { + 1 {0 2} 3 {0 1} + 7 {0 1} 8 {0 2} 9 {0 1} 10 {0 3} + } + + 4 "x:a" { + 1 {1 0} 2 {1 0} 4 {1 0} 5 {1 0} + 6 {1 0} 7 {2 0} 8 {1 0} 9 {1 0} 10 {1 0} + } + + 5 "a OR b" { + 1 {1 2 0 1} 2 {1 0 1 0} 3 {0 1 1 2} 4 {1 0 0 1} 5 {1 0 0 1} + 6 {1 0 2 2} 7 {2 1 0 0} 8 {1 2 2 1} 9 {1 1 1 3} 10 {1 3 0 0} + } + + 6 "a AND b" { + 1 {1 2 0 1} 2 {1 0 1 0} 3 {0 1 1 2} 4 {1 0 0 1} 5 {1 0 0 1} + 6 {1 0 2 2} 8 {1 2 2 1} 9 {1 1 1 3} + } + + 7 "a OR (a AND b)" { + 1 {1 2 1 2 0 1} 2 {1 0 1 0 1 0} 3 {0 1 0 1 1 2} 4 {1 0 1 0 0 1} + 5 {1 0 1 0 0 1} 6 {1 0 1 0 2 2} 7 {2 1 0 0 0 0} 8 {1 2 1 2 2 1} + 9 {1 1 1 1 1 3} 10 {1 3 0 0 0 0} + } + +} { + do_execsql_test 11.1.$tn { + SELECT rowid, mit(matchinfo(tt, 'y')) FROM tt WHERE tt MATCH $expr + } $res +} +set sqlite_fts3_enable_parentheses 0 finish_test diff --git a/test/fts3prefix.test b/test/fts3prefix.test index e7c197d..e8d2b2b 100644 --- a/test/fts3prefix.test +++ b/test/fts3prefix.test @@ -209,5 +209,87 @@ do_catchsql_test 5.1 { do_catchsql_test 5.2 { CREATE VIRTUAL TABLE t4 USING fts4(prefix=""); } {0 {}} +do_catchsql_test 5.3 { + CREATE VIRTUAL TABLE t5 USING fts4(prefix="-1"); +} {1 {error parsing prefix parameter: -1}} + +#------------------------------------------------------------------------- +# Prefix indexes of size 0 are ignored. Demonstrate this by showing that +# adding prefix=0 does not change the contents of the %_segdir table. +# +reset_db +do_execsql_test 6.1.1 { + CREATE VIRTUAL TABLE t1 USING fts4(prefix=0); + CREATE VIRTUAL TABLE t2 USING fts4; + INSERT INTO t1 VALUES('Twas Mulga Bill, from Eaglehawk, '); + INSERT INTO t2 VALUES('Twas Mulga Bill, from Eaglehawk, '); +} {} +do_execsql_test 6.1.2 { + SELECT md5sum(quote(root)) FROM t1_segdir; +} [db eval {SELECT md5sum(quote(root)) FROM t2_segdir}] + +reset_db +do_execsql_test 6.2.1 { + CREATE VIRTUAL TABLE t1 USING fts4(prefix="1,0,2"); + CREATE VIRTUAL TABLE t2 USING fts4(prefix="1,2"); + INSERT INTO t1 VALUES('that caught the cycling craze;'); + INSERT INTO t2 VALUES('that caught the cycling craze;'); +} {} +do_execsql_test 6.2.2 { + SELECT md5sum(quote(root)) FROM t1_segdir; +} [db eval {SELECT md5sum(quote(root)) FROM t2_segdir}] + +reset_db +do_execsql_test 6.3.1 { + CREATE VIRTUAL TABLE t1 USING fts4(prefix="1,3,2"); + CREATE VIRTUAL TABLE t2 USING fts4(prefix="1,2"); + INSERT INTO t1 VALUES('He turned away the good old horse'); + INSERT INTO t2 VALUES('He turned away the good old horse'); +} {} +do_test 6.3.2 { + set one [db eval {SELECT md5sum(quote(root)) FROM t1_segdir}] + set two [db eval {SELECT md5sum(quote(root)) FROM t2_segdir}] + expr {$one == $two} +} 0 + +reset_db +do_execsql_test 6.4.1 { + CREATE VIRTUAL TABLE t1 USING fts4(prefix="1,600,2"); + CREATE VIRTUAL TABLE t2 USING fts4(prefix="1,2"); + INSERT INTO t1 VALUES('that served him many days;'); + INSERT INTO t2 VALUES('that served him many days;'); +} {} +do_execsql_test 6.4.2 { + SELECT md5sum(quote(root)) FROM t1_segdir; +} [db eval {SELECT md5sum(quote(root)) FROM t2_segdir}] + +reset_db +do_execsql_test 6.5.1 { + CREATE VIRTUAL TABLE t1 USING fts4(prefix="2147483647,2147483648,2147483649"); + CREATE VIRTUAL TABLE t2 USING fts4(prefix=); + INSERT INTO t1 VALUES('He dressed himself in cycling clothes'); + INSERT INTO t2 VALUES('He dressed himself in cycling clothes'); +} {} +do_execsql_test 6.5.2 { + SELECT md5sum(quote(root)) FROM t1_segdir; +} [db eval {SELECT md5sum(quote(root)) FROM t2_segdir}] + + +do_execsql_test 7.0 { + CREATE VIRTUAL TABLE t6 USING fts4(x,order=DESC); + INSERT INTO t6(docid, x) VALUES(-1,'a b'); + INSERT INTO t6(docid, x) VALUES(1, 'b'); +} +do_execsql_test 7.1 { + SELECT docid FROM t6 WHERE t6 MATCH '"a* b"'; +} {-1} +do_execsql_test 7.2 { + SELECT docid FROM t6 WHERE t6 MATCH 'a*'; +} {-1} +do_execsql_test 7.3 { + SELECT docid FROM t6 WHERE t6 MATCH 'a* b'; +} {-1} + + finish_test diff --git a/test/fts3query.test b/test/fts3query.test index 2d12351..06019d1 100644 --- a/test/fts3query.test +++ b/test/fts3query.test @@ -208,5 +208,81 @@ do_select_tests 6.2 { {{ZZZthe hand XXXgesturesYYY (called beatsZZZ}} } +# Test some range queries on the rowid field. +# +do_execsql_test 7.1 { + CREATE VIRTUAL TABLE ft4 USING fts4(x); + CREATE TABLE t4(x); +} + +set SMALLINT -9223372036854775808 +set LARGEINT 9223372036854775807 +do_test 7.2 { + db transaction { + foreach {iFirst nEntry} [subst { + 0 100 + $SMALLINT 100 + [expr $LARGEINT - 99] 100 + }] { + for {set i 0} {$i < $nEntry} {incr i} { + set iRowid [expr $i + $iFirst] + execsql { + INSERT INTO ft4(rowid, x) VALUES($iRowid, 'x y z'); + INSERT INTO t4(rowid, x) VALUES($iRowid, 'x y z'); + } + } + } + } +} {} + +foreach {tn iFirst iLast} [subst { + 1 5 10 + 2 $SMALLINT [expr $SMALLINT+5] + 3 $SMALLINT [expr $SMALLINT+50] + 4 [expr $LARGEINT-5] $LARGEINT + 5 $LARGEINT $LARGEINT + 6 $SMALLINT $LARGEINT + 7 $SMALLINT $SMALLINT + 8 $LARGEINT $SMALLINT +}] { + set res [db eval { + SELECT rowid FROM t4 WHERE rowid BETWEEN $iFirst AND $iLast + } ] + + do_execsql_test 7.2.$tn.1.[llength $res] { + SELECT rowid FROM ft4 WHERE rowid BETWEEN $iFirst AND $iLast + } $res + set res [db eval { + SELECT rowid FROM t4 WHERE rowid BETWEEN $iFirst AND $iLast + ORDER BY +rowid DESC + } ] + do_execsql_test 7.2.$tn.2.[llength $res] { + SELECT rowid FROM ft4 WHERE rowid BETWEEN $iFirst AND $iLast + ORDER BY rowid DESC + } $res +} + +foreach ii [db eval {SELECT rowid FROM t4}] { + set res1 [db eval {SELECT rowid FROM t4 WHERE rowid > $ii}] + set res2 [db eval {SELECT rowid FROM t4 WHERE rowid < $ii}] + set res1s [db eval {SELECT rowid FROM t4 WHERE rowid > $ii ORDER BY +rowid DESC}] + set res2s [db eval {SELECT rowid FROM t4 WHERE rowid < $ii ORDER BY +rowid DESC}] + + do_execsql_test 7.3.$ii.1 { + SELECT rowid FROM ft4 WHERE rowid > $ii + } $res1 + + do_execsql_test 7.3.$ii.2 { + SELECT rowid FROM ft4 WHERE rowid < $ii + } $res2 + + do_execsql_test 7.3.$ii.3 { + SELECT rowid FROM ft4 WHERE rowid > $ii ORDER BY rowid DESC + } $res1s + + do_execsql_test 7.3.$ii.4 { + SELECT rowid FROM ft4 WHERE rowid < $ii ORDER BY rowid DESC + } $res2s +} finish_test diff --git a/test/fts3snippet.test b/test/fts3snippet.test index 415251d..4e1d123 100644 --- a/test/fts3snippet.test +++ b/test/fts3snippet.test @@ -520,5 +520,43 @@ do_execsql_test 2.6 { {[one] two three [four] five} } +#------------------------------------------------------------------------- +do_execsql_test 3 { + CREATE VIRTUAL TABLE t3 USING fts4; + INSERT INTO t3 VALUES('[one two three]'); +} +do_execsql_test 3.1 { + SELECT snippet(t3) FROM t3 WHERE t3 MATCH 'one'; +} {{[one two three]}} +do_execsql_test 3.2 { + SELECT snippet(t3) FROM t3 WHERE t3 MATCH 'two'; +} {{[one two three]}} +do_execsql_test 3.3 { + SELECT snippet(t3) FROM t3 WHERE t3 MATCH 'three'; +} {{[one two three]}} +do_execsql_test 3.4 { + SELECT snippet(t3) FROM t3 WHERE t3 MATCH 'one OR two OR three'; +} {{[one two three]}} + +#------------------------------------------------------------------------- +# Request a snippet 0 tokens in size. This is always an empty string. +do_execsql_test 4.1 { + CREATE VIRTUAL TABLE t4 USING fts4; + INSERT INTO t4 VALUES('a b c d'); + SELECT snippet(t4, '[', ']', '...', 0, 0) FROM t4 WHERE t4 MATCH 'b'; +} {{}} + +do_test 4.2 { + set x35 [string trim [string repeat "x " 35]] + execsql "INSERT INTO t4 VALUES('$x35 E $x35 F $x35 G $x35');" + llength [db one { + SELECT snippet(t4, '', '', '', 0, 64) FROM t4 WHERE t4 MATCH 'E' + }] +} {64} + + + + set sqlite_fts3_enable_parentheses 0 finish_test + diff --git a/test/fts3tok1.test b/test/fts3tok1.test index e6fbbe1..09b07e9 100644 --- a/test/fts3tok1.test +++ b/test/fts3tok1.test @@ -110,5 +110,15 @@ do_catchsql_test 2.1 { SELECT * FROM t4; } {1 {SQL logic error or missing database}} +do_catchsql_test 2.2 { + CREATE VIRTUAL TABLE t USING fts4(tokenize=simple""); +} {0 {}} + +ifcapable fts3_unicode { + do_catchsql_test 2.3 { + CREATE VIRTUAL TABLE u USING fts4(tokenize=unicode61""); + } {1 {unknown tokenizer}} +} + finish_test diff --git a/test/fts4check.test b/test/fts4check.test index c98886c..4ded053 100644 --- a/test/fts4check.test +++ b/test/fts4check.test @@ -179,5 +179,35 @@ do_test 4.2 { } {1 {database disk image is malformed}} reset_db +#-------------------------------------------------------------------------- +# Test case 5.* +# +# Test that the integrity-check works if there is uncommitted data. +# +do_execsql_test 5.0 { + BEGIN; + CREATE VIRTUAL TABLE t5 USING fts4(a, prefix="1,2,3"); + INSERT INTO t5 VALUES('And down by Kosiosko, where the reed-banks sweep'); + INSERT INTO t5 VALUES('and sway, and the rolling plains are wide, the'); + INSERT INTO t5 VALUES('man from snowy river is a household name today,'); + INSERT INTO t5 VALUES('and the stockmen tell the story of his ride'); +} + +do_execsql_test 5.1 { + INSERT INTO t5(t5) VALUES('integrity-check'); +} {} + +do_catchsql_test 5.2 { + INSERT INTO t5_content VALUES(5, 'his hardy mountain pony'); + INSERT INTO t5(t5) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +do_execsql_test 5.3 ROLLBACK + +do_execsql_test 5.4 { + CREATE VIRTUAL TABLE t5 USING fts4(a, prefix="1,2,3"); + INSERT INTO t5(t5) VALUES('integrity-check'); +} {} + finish_test diff --git a/test/fts4content.test b/test/fts4content.test index 6b2cd3c..481c6ec 100644 --- a/test/fts4content.test +++ b/test/fts4content.test @@ -48,6 +48,9 @@ ifcapable !fts3 { # # 9.* - Test using content=xxx where xxx is a virtual table. # +# 11.* - Test that circular references (e.g. "t1(content=t1)") are +# detected. +# do_execsql_test 1.1.1 { CREATE TABLE t1(a, b, c); @@ -406,7 +409,7 @@ do_execsql_test 5.1.7 { # do_catchsql_test 6.1.1 { CREATE VIRTUAL TABLE ft7 USING fts4(content=t7); -} {1 {vtable constructor failed: ft7}} +} {1 {no such table: main.t7}} do_execsql_test 6.2.1 { CREATE TABLE t7(one, two); @@ -433,7 +436,7 @@ do_execsql_test 6.2.3 { } do_catchsql_test 6.2.4 { SELECT * FROM ft7; -} {1 {vtable constructor failed: ft7}} +} {1 {no such table: main.t7}} do_execsql_test 6.2.5 { CREATE TABLE t7(x, y); INSERT INTO t7 VALUES('A B', 'B A'); @@ -622,4 +625,15 @@ do_execsql_test 10.7 { {...c d [e] f g...} } +#------------------------------------------------------------------------- +# Test cases 11.* +# +reset_db + +do_catchsql_test 11.1 { + CREATE VIRTUAL TABLE x1 USING fts4(content=x1); +} {1 {vtable constructor called recursively: x1}} + + finish_test + diff --git a/test/fuzz2.test b/test/fuzz2.test index 4b3fb72..51dfce1 100644 --- a/test/fuzz2.test +++ b/test/fuzz2.test @@ -125,5 +125,15 @@ do_test fuzz2-6.4b { db eval {SELECT quote(t) FROM t0} } {NULL} +# Another test case discovered by Michal Zalewski, this on on 2015-01-22. +# Ticket 32b63d542433ca6757cd695aca42addf8ed67aa6 +# +do_test fuzz2-7.1 { + catchsql {select e.*,0 from(s,(L))e;} +} {1 {no such table: s}} +do_test fuzz2-7.2 { + catchsql {SELECT c.* FROM (a,b) AS c} +} {1 {no such table: a}} + finish_test diff --git a/test/fuzzdata1.txt b/test/fuzzdata1.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d3b20c131ae1da52a4811289a8f7bb80d1fb197 GIT binary patch literal 2966109 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�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

    &Oo%1ocnmlB6~=JI+xr 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

    )JT`TZn4V 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 sFCr+&f&Urs0Xjim!LxY{{{;;^Z)<= literal 0 HcmV?d00001 diff --git a/test/fuzzdata2.txt b/test/fuzzdata2.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1d4bb7bb1505fe63b7cdb1de598812f071335f5 GIT binary patch literal 15739506 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

    esrA7YC`tFU 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

    Xse3CT&plTf7 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≪U4UWwVNYS4`<+T?ZJ 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�E7BC>O7OD>;&`Bb-qk57LvfsqU0+E+h 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

    I);H-n2w$X@rFe9 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ÐG${emez?n<^Y>HSLWr}H?-LGmc5m9 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

    #lx9JgXIqz{WrVEB0xaz4pQ_Flwol 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

    fEB%kzY&=W0XiEsxDrTuq|VmXD;vym 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 z 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

    BM6mkGV{yO97@t4g z_bN{-^RVv^z=0JJ^R2FdKjzxGoha4Mt*3StQ7VLBz*h5$8||NUAcQTiz@i0!XBnIp zTPDT>2@8A9v7dNcPC|RVABbHE&&B{lUvPMdEeE z2EZ~^c<*r__xNFW#G`!hnWZj3I6arjznUsspcoLc3KuYHPY(>CADT+Xr|{_nJ*D>) z<7rq$v$8;6)dPM^@0nlRZ>GZlic3FdFa^&P3&on?eL;s;&G2MzsayaXdM_A3nW)@h zGCZAoYqA$AK$%i;SBz?+qrUhQR&$@O=0ht~%GB84Q4IiCEt3*}D4Yd=gklf|H2HLD z1i$~6&`41~ta}g>>IbKb3dBgTBRI0Lqy^td6&HXM0HcZwg;(cW;h*TsuUCU2jJ5WX z5d8pL{}g{d@LBqGe~A1dkx>x2Z~{BrEAaO7x?$D69;7v7f_GjRqdUE0KtV?fe*!sY zUTjaY=N2OMo#@iF5jjnQ~*;Q}&`{#m#t)jP zr6RAjY(%N}%(WsI<;K~<1qZiHz5a*VskqKeGreZSzZ5TD(ScvokF}o+P0o(^Y5n>I z{V1OPz!#zdJOD`|>$AAmBX;b%-j$ zs4Ac((0tI1@N`R~B?fi;k%Cln55FIp%oy|46@WS5&|KEyqkKSa zbdoV*aY>HPkT8`*K!n>7OIm^Uczbvp25Gqz3{f;3?NRqR4u{TzQ&~Ogj?iJRi;-8I zuI9y;Ushd>zY}=*<$q@bvDVum{qZyE@#mDNuk*lr0yK(j#&tW;su+Q?#BReuAepqp zlt6-!Ari-mW2yY`39xCs1BZ#+_|(^zcqWi0fg1SI8~A#b>@%4xm_SJuzg3<(n|_Kd zB!_q-_wC!)XPG4|CJC2djWbC;g1rc-6@}GLaCQbZ#Rpgd$}L)s;e^XBOM<=pGE?aG zKM)z(malChi>bXG*1>M68;e3!xR?i&rag&)oXTF3yH_30>ut_V8gh2$>6M<;F)N_(AOqvJ1WGIux zx@!<-IO}?`^xj+u6BXE-v>jKMK*%ffN5dFYXv=d@7&L!TnWyp^H1Yg6(}vC7D=$ z>g){oXyp97%=tX{s>kAFjoAH3%;PrvflQx{Qlp(1nXd90dJ)7Lc^v`GS%YP$mEzq? z=T~Q!uvDt{0oi79vc&Uwoyd>hWMv%i@NCjX>#2dlSCfI*)KOj-u5%Oz0Cm9J$ILKp zTs7?3!g9WsC- zfXxUN7*&>RAx|ci*&9&zW$%k~mwoP<4<}DT7Jw7MInQB+mCDabd^30t#MP_2rX(~G zmUv0HaFkRkUgPZRl5W%0*4!T*U@2Icg+{#-eI+Zud26Np*aQ032y~& z+HSf@WXQHl{^yNZI{%nt94REc4j@Lwt&S9kLYRw|oYzp7CHp~uYmo&A6e15aA}p|_ zxcGdfjIKps;i+t$yqh9Wa8X)P)Uskyo9Kous!L}_&;g@Kb$_cWYfCmsC$BHw0gr)n zvV)_j5vt>a5SUx1MRmo+!XlcEbjM3!m@hu_ID$pcvF8(?s zI$?JJikc>*q_wDt4$~39#+zh^J9IB@m9ZCQ;A&6ULB zsz!+9*X)f{*Ot{r&tF$oci8XGu)*XdtpRd9O|K7oaOj8F8Jxq1D#+XJaG9zkCBdjq< zPX(b)7_FdT*BW%?irxTm#&=RdeXTSM7jmQx$R>dMz^#BCh*&kAeCB*a#A?f3R25yq zOWd)V(z-_sy6amIB1qzI+0rA@x+kflvZiV&859PBQtWLMaJ*Ktm5LIc7$S-UyV?4A z$8NTy7**h9O2AIf&!oUCAq_gFgQCLyc8-*0DwokmovZiKhgxZJq-?)h>sWBq-%`PSNJk{8Ng87=Q>b=`Af3JD)#>kI2) z{E{@#%=`Z4r75Hgw6`LUM(sKoom+4y*-Koo1rqk7R1j7%RKlvxT9}(U4RHr;mfTrK z!h$=($X%0P>Y#+jN|K~g#xm7qx>Xd`#Oj)mJ^@;qiRT)ID0OTI4Kf7DNPAU)r5OQI zsnx@XUPyHbDP4D7S=BeVefCbThhi*qUl0DmLrC9So8_GcnGOQl`X#pRt?Uk(?^&-l zOw-T-?zZ}4sq&xZz4Q5xaRDEysQ>O{CJSe82)jNa9WG1dKWbj8&qqoW=*AQlIb#6O zP6tfBeMrMQxTgxB6|K>0v>94jfEl*mu{;~5m(2UjIkiEmzmOZZ@Va$&P<`w4>rnyH^FQRAs;T^Q<_zBh?4Psmc zhS$f`8K_1)>5pMU2%GpIk%Z6uk}bpncc{)j4=#8$M1{&?aG43wn#EHgx_DkDBi;sA zIX*aWDNH%G*nq&x5=MV(V7>;|2l2HCf4EveJ|4T(t3}(r4Y_gpgUR zj)<4y7!=E-VI;Cfx-|N@2%rw6FTlsq^v5)lX_WBzOXq(Q)78htpV}R+6d&uViIku0 zx*WXg=AV*qSL+~@@x-7$7F`FeHJNToxhI2V6Vj{X85#*uGfkc`t0iGZ_xdn%loSaw zhjuv3P$HCn3V+Wpoh2?&Rg;rCdQLGAW*o?XO)g>N_^DD9>OQOpK?=T4jEL_js1vmtg*OkYLP=rO?|=GQ0mz;#W$2fI$taRAem45O8P!c z9YL^?*ENR6L90cmw__(cBkAHhJL`7$aPHjh*o>$V-W&?*kv$qvj&C^x^P6GK@wfmQ zZhs6wuF@6(0sgTZJ9(F{IE{GCmieyf;(^LB<3*Y`Ja zg%DQ_YETp-nTPn0vl6z>5)lE&L71NA(cxDOv`yro9Qk2UGXwA-5BJwFq~xn`j)Ohr z)Oq%MfG1d;@VK=+08sONTJ8l^r&b94;u6-MUxed7hG*Fv`N2o81`$wRQV$GJC8eOX9-;KG3LMR*hHG92ew)sf9%r+{FJ9&e z+J=AO!Z~YyKE8bB!i6ckKX%~*9TzT?@ewY*OYR|lGk^cR`Qkj&{>;~Q;Oz+CtBJp# z(vLko{rEyL%uswzz+ckXj93v^Bj!4>vjKmuhadhBg1sIl4>A=;n@Y4Ib_+eg@ZvNNjy`mNz&#fpJ72&djLflyjQg0urH+hKjnEH9b9A710=E2b zJw6$ynALs&LHCi`*H72DB*i3{x7$xKBi-SbDSD7b?-euxHxNdgYU@!=FT^viXhN5E zavYCYLN{AS=z{ZNINBNbg0S5E7q@hG|DapkeET5|Sly%=W5dd{XyJ3)A1}gZbNumY$hZCRYHuZN zf4tKBZHQYL9{jnQU-`$z9MEV#GTPaeG*FqYbhgqT@BgZKWW!I_fIr?1w^3x!sJRuU zRKU|xs3#=f98cXN(N;Il1baPsApOd=KN79(C=Snu+r&{^+XJa^>LsTQw6_3+5CzlnX0mKpFA zMQn(*VF9PMwneZB%qXy|C4x~)749(Qay$rWYCK|-6ugCqU>UD{k{7PKsx?S35$${a zoG-*55QRE4rv;BzVFh~oBriae<;&Irbz@NWtCZXsciRax0yPRO+w!dK1iFbK+*UY& z9?**(Pi68a*j(&lybzy;e>3q}_`~O!c+q%szs#z5@=NV>=2tr{FD)n+J09kMe|8On zptmdNeisAcGG-3epvQ@yp<~;Rp8&ij=U)tX!BsGxJ1Y@f>8^ zdqrO9u?echc#fyU9OGC%{_F-!bv=K)i>;TJ&z9#F$W0+HPh>2_SumrRFN5UK9na^!(a#(7J`YBQJYk|~V32_^aZRO3DqHX1^t-M+K zm44X-Y^mcoLc@6ygNa>WC0RQZvI#sY2JiC zyV~`L*t|&5B$)-5s7b@Ss+el1DOaMxbJKVXooyJ>38_)C72a3$~(?vv0F4E~^* z(Azl~8utK3$vgS=FX*bn(ZJfR9+6z1ooa3M2ugrCT^w*b+y z>tIgI*1r-w%IEnd;vdhR$!3dC;B@bJjunnT*~(cF+jr3g_T3uTq~mJmkwK0&3URP! zFdwKBF|@|w2M?Tp$To^F$Iw2*#!~s=6Krq!X?Ab2k6)q*jC{AvJy9ybq5;5_2(EpD z9FFz%Rr~r%JTH9OJLoA;*R2L6JC47#3xcl&c9A{(1i%y8I2IQBS2p+Z7yB7AC>?xZ z^WKO*5>_9=mxf{05XuCgM$^N2fSUx}P0R1YkURU>n1baf#OMQGKUGLV^z)-Sz9c7% zAKbQdCOG`_pT{=JOE#R|{S6;N`VFU5nM(kX{Lch_K^W^m7-QJfpJ3y<{nS!PIM8~a zpYc9uG8?Nt&7Qt#l3jcseti$N6&~D42>7l*#dGIb%N)nX_|r;yY+J};5A53+m!>73AKAuF8&<*;jV2CDMDSy2an z4R=7!7QaZa@B$we&;h4M5WrdH3z0eJ{`xUZrr^)l7@tgD&wK)e)ij^fXAq>?T$dze z!8=PfDW4?TMhYjwh2)o?(VKWNq;^jE6m3X$KWf7FrR(K`9hD_MIDc1s^qV$bT9 zkjSL`mGqDf>>HZtmg)=Rs4-OS)x*ct6Fda>^JyfBZKB+8p)D8%{xZ8=r_kk z1B8jepQFIB#PTA3dbE$7(FAHp0bemBEWjaYgc? z>WAln+WJQSpDjy`3G=nhyktN&=5Bf=H3@4o9daTjm{Id7F0Zi)&blUi$1L2V zXMe?1dttR)I&+~gv%0!)B zintkG+T&o7--AlaS9zzF{IieIE#PNvap5->9=Lq@U(h#7#5YI5wj={9nPV*dUfAn4 z$wEO=10rQvnc(}D6%<@Nh2BsEiY?}}P@&sJ{_@38+}0p>*aPRIx4$dKD$wKhaPU+^Hagx4)d`mBv{dsfqUG{(u^5|6#N{HYlk7xhWF(y(8Of%M=M(Yn3M>T+&g@r&Shg}V z5>rN-P=KgswMumx$=O>WGzgeiEOf0D=ZiDtJE5Ojon9#~<6^D&{k`|`Zm;Ncd*_Pf zSooJ@FJzNEB(FaCaOhAk?yA6}ta^IroVA{w`yfF6$+rRce4l*bpXHnQG@5xZ4Uzt2 zn_O5&s}<@6n}(mJDMUwtaNTa%etCyY>yWGu{ss-`;8*?yvk@im8-BtNnE~G8Wf1W) z8ZV0n(XT}c0|`wFLhV~BoGYGLfpayFu!Bih&goYr*%4TA1nUbIii@zjT9LlgoMIP4 zS5UI$!s2XcVS2ta9ZQ1d8-o(=9O&(3c8XhI2hGV89o=Z9NQ9=qJvRX<`l*aW;%_+pPjc1u!WtK}% zjHZUuu=-OAG=bIr*u`}Z<(xRy^lRU_Zm+-J^p<^N^Gf({k+S~FNU_?H+7M_%pcx3D zNg^YA&Zn2>$X(2tm6<1sG}QYj{_?ROK0S{=moI;v-}tZoYK9um!4afAfk*sLbgKkJ z4G0o>i^|X&NmTo z%$rKYD^(gGG|?V`}@Pbf@BK&Zl^+OTd*T2?x5h>wGFEb zWoz3QMfGfL%Q)R#D81nQY4*(OA{hP_=E`O8Q^b;k+)_Dc$1vGhHlQ*5NJy+#FJFd~ zi!P#MuHyc0Kkfv)V84s(I4whKUohM6?Zn7Fa0L^-&Q~XpVNlV`o^@gRg-EevrFibI?GU-U5SG#K?o`B#+GWJ60sTgB%X8Ea7p2$8 zol@uovPuB3%|j6{WKEU@_gW}g7x9`w5l;%aE4WWjO^um=hZru3=)g&bX?R8&P8MKQ z=EF|rjl-Qlkp}Zu9SI;{V%?l})TMcu*hv@K8i*eu>VH51V1Y-Lsba*9A}2wKv=hU*YM`_k(E- zg1_6BfPIkrRW39CKYQ;29oKOk2tMiqM~J~tS$mwHoo84y8qFrzO*Sb}5GgjnCJ74! zs78YnWl3}cXi}g6G}LHFY)Uqek7dVkWGA-AHl-XVyJt_n&P01A$ykvmJ5e_BCL24M zbtYD_ian$F*wNW!$FV0Ld&a%@*1zi2d;MO2@Z)fF-Xy9BvNFy0Uz49wsyJ7@+zU;y}gcR{q|j^ydy-o}3mg_(dl zbpa|;Yj$CAxpv_8tl|<@ z-}bye3;UiG?FuMr#@*WfEZ1pe(&DyEL=|ehofQK9ay$rXYz~c%BcbE2n zvsrko4^l-GWCbepQt!#a_~aS)*m)Ns^q$I{9T_|6PFI!}YQ*ItSMID;@w0mIOXa1q zjxax;J+c0)m04-XG~L&Kg#;vyww@T654zS9u(<54iGf&Y#wAy~*eXq==xjz;MMqss9dKnVbb=x;Pm$1>+dvbzm!wlJ9tzp^*IO?VUu zzW#kv>c13MJ$7pb-43Y&_JIqv6u7r|q`Uy@#qMIIS}RxO8X*-UGYPW#3H~@}fx(o8)rdEv{$8Q|k|C&LLoa_q$KJ7i)iccY?wJOVmADNM9gv*zNhtT$NG_GkHv<}Ct!n3Q18nv+cgg8L0o43c5^V)8hLx_HvPSJL8i zllI7sN-I}Vn0s+^bq=F`8>w^rqygKyy~dq`v2L?-kWq;7!CHl|_^|=0Kp}$_nD5M- z#vin}$hl~gAT?z?0yKazl|Fo=-QEdiNk(&zKThn6Ru#)yOcyEQwN=Dv3 z7TShQHok6d3w~<#4%OHYcKQl>H;|qF|6MTm`iiYhBh!% zFOvn9@5}Y>a9~|!@9y1q6>)*3w~@p}xV>*r_AVv=O>eLGynFv{xc08>9fak%qrGis z;Jz7`^Y-?ppw!+^>Tmk8g|f#0&33^Y*ccJSq?8KnotQ{JaI{{pm)u48ExVO^edX^L z>&1L^(CvZiM^gCv#+$#<<33iZ!f{w&qIo_hU3AFrWt!0Dx zjd5`Q3w*)rZ_Fuw^?_&T7yQMK#XWMLo~j$DJ^-b{fod#wR!aHuGAUF5?B1QhoZg5( zM5jQ~A#?=jpBB(D#e=gA6%SgZA6%r7ZXdhMYDlyb`)Q;(7c?9*Ko?lT^e`@bB@0Ct zH5O3H6AX!qq(JzAq!91sul2kRixA9J6IvP-`RLb{nb1)ImVsGyV-&`_0 zObyg$uBxCyq6PuNx3a7ruGSPck;4AuUr}r;82&Ot!V?dbZ)ZxJ!ZZV6?=h&`WTjLb zIh!|HVDU0E46OkEYKW)xSAb^uN?I$sS4jH-nzpkG-x=|7+OH`zfpgYvfc~(k2bi20 zp5Sw8TM2?MJMbuAC1g)4L@I-il#T)0Oh<(+{=>AzWiD7No=c;#O4{b#j6jaMBjYpU z^;W1v!zk@}^jDCw0I;WLeOi}`sT|F+OHe%iUp=+=F-@Q7DHLyeUympgc`pe39Fb}1_ zjQRE##x-yLHl_&Rnrlo2xf3wh!HC^Ct~ml79k3mi3TT%K*Fe;Q0}gZz32W-NS~ zvFgRk4-!xo<&dbbU^0Nxa&eUID99a!j=)yqj8oP{l>r#G`Pc)yn2_Kr)p_qY#^Ssw zxWC=&6%F8UD7UJN@4&34hKFG#L=#06;SUDDZVmPun{2z#{D5Q_;|aTQXQ;qJD95*okWUg35<2Ny zu%oIXB)sa~_HkX3b%g|YnMkMaCcssmq8ywLAlW&9b9t!Mnjz${WX<|kASQ_a+Z$Tf5@aX!5^M2yGNa2=Ll2K$V$mfkvAv; zElYYHf-}S8d6dyKA&`FmX_M9OL!lwEg5veGvK(JP<63nKTd^-N67`03pK&P zff2(hso;KHN-^8w$2*kS>@g*_sL=WzZ2cU|Q&UlZC{vxB zI5PH_fjB>W41j#-@+el zoTf*G)3^3GFC+eDcxM%Psp7($EuFh%HBt3SHL@WX^NhG<9V(m zdSMxxWAEv*I|D2psEd;$VsAxumCMWDBQFt2$HHErTvs!qab}1PZ_ly(OKb7m2CNH7ak-Oj}09j=JpM_uA=2$bK6(j4rRuYoV3Z9~k-qsw;t_6@ohtCe|( z1YgLnmh%C{Eue}Yi{*F+Em)@N_2-}e)91rpFM1<7jpu1w)FuI+I#mNXcxI?b`guek2BccdvbhRKe%N7f5%h3cVq?=gW!Dv!UoANK3(T1 z+T_(A-vMpB49$r5rfm(Q+JC;KcjzWKQ+eADVC>Y<9sQ8>u+vMkfZsQu|A~|1dqK75 zBv?2Q%K;#n7s>S!y{W$ojTd+HssZHrS6=)hyhC;;z6|$OhlGBC{Nhh>9DjfF7vbmC z7hi<+m3(0WoTXski!U}BFP6jw$4S$~^xKP-+U&wi`3iW?np&7)VK4qNe|Yi5qxA9j z;r1Ic6rV=(C!m1uC)cg?_Tr!8hcDvKHc`s9Rj2nPK>dfF>nV(g*B`%#`HO2tq=lg8 zM6mKO0oRYZm#UTJMeu;UFkJ!{8Q{Ey#Q3EbfBCQA!5JTB9W$5OesY{6K*=OZ-Dxsb zm7{~$#E*zeADs=iu=@1DST4m4ifd?JD(0?rCVYA9OLdtHhifj|N3btdEFP&;+O|!p z5Dt1m*pzloD@(-{Rgm|wDLuC_r`KeL8fa76U{%y6d~9|mB{U{{T@Q*`k4UG91}hjBj6`!JX@1S03|#?TGR%UBuqX1mwfXZ5>se!>B79!^Ys)xazL^bSyEOaL9j;N|mt|Irnzt#6kgb&jZ z;*zKzH!nibBJf{F%}>OCy?C-c+-M6l!)B-vrmhzRGt>WxH667D-NsjZ%$-aZ>x=hd z4=vxQ4s7F7yxUe9vH22{U1M%!1c#*!uu%Oq%}SLPEQ`lf8_GoW zofffz**8ToRpqT}ECU%Ed87qfkKM!?&ZDDS8Cx*1#&$4>jSE(6^@od`!0DP>u=RX? zEiBmTb(PUE3pQYengtuyOkCQu$4XuhRikc_)DIO%(;9k+g`CqF3%Tznyqr>4_budn z^zowAVGIdvA!k`q>#&6!<4Zmka*nkVC1ulm)43*>fTD8 zcQ~j`@{XPA@KOI4+h8XIE82e@1YTXa!;K)A%Oma%B%e7#Lqt3~7a&}DOjg~+2ema? zuW(i7QsUUjopxksl|ir!DUmJ6BSJVc!snokJG5@_%XgJQwgNPl8h_@T27o4UQm?~^ zvq+@QrwJ#MC=r?tx{iO_aDk8LB2%_72g2kE=)2uXW%HWW=)>cuPmdI#%Cw$X5qfE+ zzz~F7*45T*0VqsGe~BWbx=1s+yomM-DspI^hyYcL4iJu{l;bZP$vE|&)d7LGo}P0f z#Zz=QK2fa%OF~c!xt2f2mcIdWcJo`DLgbDg7sP?pfL7@1iZt6enAxj3?{mU!@8D$0TR}hxjg_A>tKHn=c7aq^1`t$lH@(ldw8I z@=A>o`bhf*=~u#3fdQgf6f^4IMx%YveR9pMlz88fqi6^#CEzgT1jbfNf)1`xm$l?h9x#Lx zwAr~msHL7-ln&=7NKsQLf$O6%P_F7*XwW(eiM5k9PPbxZ#AT^f3pP#%ltY;|nlBwW zRI`@a*lV5Fu)isS4ZO9n)_Ewp{~S&llE?V0b^7?vS>x>m9#dl9btxQ(pfmCM8OE*f zRq3+O2yD=1jiH+qa?KyIjg7R0{+QM+@`dYUenBq8k9JLwb#(A9dc#raGq^8q%`2g6khSWd>HA7s(Ui%Q}8D#PKg0qeJi|gt6@9j+`TqmCc?U3-v zN5;f$v?k=2Ph-Ta`=eA{`*8v$XSi$YE+-JzYmRAkd?ek@;x=lda0q26k2yr!@`68y z03sBZWm0VG=%Ryh%>)|thH;_5C0IUW4<3V}(VGKYglXUd*Lli81P2D*xnBcGo5k1$ zvVPB-ZoUzOe*|2W1*Ep#V~Wd0nV;oZ9#ph+7q|%lL_&U%yN#V7v;8eF^HFUfZeo6? z_=L!N9~}WDzc*M5L9tc~2zudmCpQO0^8d#89@K1-MzWcp{Di!eoLI@i*n~e2+TbrA z_nM##DtWNSTf9MABt-fmYq3H=z$*ENSU?FfC8_GWWWm9XW=Zm_=+`%XUG%NiOi3=N z=PY%^+u2d%4;?loIn0;f=;UE5n36DOjYu@A%*EFwX+@!NIlqkL3@MZ;iKaU0q^Sor z+lx&-0=&P4F!fN^L$uM9ntFgRJ;RONqK@R$%)`eSlEwgS!;BUIUiMHLhLN2<1iMdS z{E8cgWT^@*%3`P1MU?Shn0LS^*+t`!zmX;)EgOeWL%e6@SPQZyt&DuT#Oj6+~g zJU5;@NmrXtZX#3V$i^X08&Z|9&K*U|+wK^Lm=tDx4>@F8cZpatB!Qh9$6>2iGY1mV z3;^WSXp6d<-#LwwGwB!G$>St~2ZUJEy@?OGfu>HXCUcW7>S7mBa5qA&jO?i84A<;t zfvzXIwx~-FZzb^CRVmWKtGz{CDt7Y8oR~<;>{a}MLDjmuym&2&%Zmg1rOyj?fZ1Z{ zQu)FXjKqiC1DSo|T(i=0t#aY9()9B3ynEQ4U4X^oc{r}LG$)Qv0`)K1E1S3i9x}k0 zBDj4g{R!DJJ*p$&R!a*rmHDZ;%2XobCfx*-usb_A=+b43j;Gj1%1Ebg4_!t!dwV7f zTuMdulR|hkj^{`7z=uv0#_54~r|`f#atPjGcfY`s2QRGs+e!+&OKY_$cl^N#mLbFk- z`v{?bJE=vRLCZpJO)h6jLNUgKQLY2=6+*2$K%}6G3lH$-S==B?%3_w)%=*>Y=6kXm z;_<6DN8RX8&dt;C0c#q+svB_Q308O^{J7vTF{0VfOeD{P(0RMMe}FbVL}!LeV%^-c zf`h9wa8U^49*ZV686TyoFgK6d;JX5uWL@7do#G3;)|si?cVg9tV0}o{<8&+`*t;ND%%z7`~q` zw}#!p@NUK&?<1^^6pplD^Oj1vD*n>yh4+?9cP7g8E;;}w)rOg{#+?br4UIkQ8<6oIQZJSsM{dSsn4UZQinSSuxM` z;)X$#U^!M?dhRAc}xzsxI&~PQ!euw+AAYan{pX9wCn^| zisdr>NFi-zYdh+whpuX1*X2^{)iQVdh+#Ujld(+M7I-5i33c6qyBwJT%U*J-BT5-p zC39L6VHd>086m`UM%bl-BVm8xkqU|Exl%B6a$Na|wu;w`?@r{7`JXGr#T-RAyUk<4 zDwzS`Uz>uXq6a2&>N!)`L;_tb+ZD2(f?1m?=TA*?_XtL|D3C$6{PLJB@(+^aJbcJY zObA#7SRZWFpkOt(rqmXH1_|9+!J_bJ78T0Gnl~1?bBhWFuqy2E!x3~T*GKuK%S?vQ ztvWeCcN<<^j-r3^Q5!HP23R#FR)?1rZZ!$OawduCp-Sv{BAAgaY?$5q+qb*(B{;YX z9Q4u=NL8qWbI5QBDWuMIj|>7tzuL=KgAoPkJ$yE;wXj9Vi{PVyw=0}Q7g+&=9SqG~ zdq*fhw5!_vUQu@rP&vs>N%awVPjLPM#)`aZDh|BV#*W;TN3as-3)YibZ?~V++N~KG z0Yp<2kU0`ITbc@UwN1XXyQ&jY;5|+o59;Hk6d4+Hr&RO-6H8wk9TI%iWui zvBpL)g2(MiKlWx-x2(x9-36VLHcW%%K#H9LGMNh?Vhj7S%1A8^=SXcW4d=+)XoYA$ zCzNd&zmb-?8o`o69h&)pE*xWv_G*G z_ZzmrfH2PKjaKAzb(BerQf~NO|3N@mh=GO@0^5)FI8KA?<`bi8C^t{EN8&FTdEK+L zr#@A$V5g-$M-_=Z^CEK$x=4mzBq?@@an4(N=2A;a8{q_);!&QD%A_lP05tVd_!HRDx~a!+3c!tL1H(dw#=U$_ zMN`__WG(vKhO1) zkoqK5KrkTBYB<{6*GDRBWOLgRbc-3@HC}p2^b!&jfJVnTDvr9utO5I`jru{^E1lJH zi9rfbii8;yFzE4SuA_xtbo2KO=g$-&c&K**X{F{Kq8D^rxOTZUI8?oI5ga-0hLFsj zbUK?xkA{}dgZ-ucRR2`J+uwf58N{FCX|-nc=I=`3rW`bg}Ps&CnBCn^rUe*joH=8W+liU8m6`3^Z>52K z|G1sFpV_|s>`4CH_U+>^_YlXSLog-%7u`ngYni`za8(<`>xUUTb(#X1-pOlwN`zlCW})71$qQCsy_ z*8qA*8$(5eTSs0I-3s7!wG6caI0lQ9{SFx0ZgbQ<6y?3^avcj-DpE;#d!vt&kYhC3 zB2l3HuDpItKEe|a;h%{4HIgK~3=$X1s)B}*xN<7JzX22KS_w{o_mdNx@H?S*d@u|W zIPm1|=>iyv9+-T(fI;@^D~G_R3%n+bQ~kSuTiP=v4FYt^Im#&q2n#3%C|T9BRp-x7)nbF_>dYO8LmdbHn&!BtEE!2_9@+>LC zN(k)^USYTe73CNpeC1=akfzEKL|>2jfiRlXSx?Lll*!xmAefn-;`#fj^uzxbYTkE-tCM+s*)h^9jiJqn#^Hwr(>Q37?+MKtB8Tv!F z{dN!)?J}`GSvCueSw~g!4S0%K2cL8Bc?*B<39I(lJgj3iuPrw&|kql3C6-6#KApg`wcsc*Z1aj`y0F}1X2AHlq!1Wg5#)Pht_xx{gBwwe!`b58NOvz37|Do=1JCD`+91qqD*>RlfJNO8gUN!& zl9g?Fknrn9SPsKZr9M19I*N{OP_gkICiJ>9;Gbc>G)D{x;0wf=JU#ZnA;s*9954Xb zuRTTVt3Io&1wjDYfR`B5PgR~-oL#sy04ol#Osp>?`;{E*iumvOrAo8TL$L{RZ4Hp}crrXqMr7DGR?FaxoZH;Ka@((0ocU zDdN^zMXMc@&$6&#O=Mr%6{cFEv}VafX(B~?rc-OM0PVAmecP&&>P7RZRcSsYo_tNJ zcnr(3H%D;@(<)E*E9Ot1ab3{~q5DCP18=L_%x*X29?zr2)9dfgjSLSB<;HTO=kEvq zqIj_v=%@6Z|9Zkb0hY9$IGzBOy(iog&^-4Rl2|hBAV5Q(|2*dQd3wtjrf~<;vH_hL zXJkyc$`y;ubc9Uv9lf=sY@$+~DOV5Al$WOIBCvFdo91qG2hyCrtatZ%yLMi06>hP< z-)%A7#!I$u{;7=z92Xb-skhn`GH&G>NcTKL552&}Y=ZP(+|6==Af|&Sm(ama_UZPsL9GNE54k z*tK&7z2h?<`8e;KJaZi9y0x@BkuSOf*RDOX0WJ=G(EV!ANBvv7HM0BBZZ}t-^g8I| z?PD^mG%zqV0Ea{11&ybv3=U@2P~;6B9~99zIN}!k8VkhX8Z{P(!{KR7V#NY+x6uqd zyh8%<&&lDy_7n@m6f3bnET|(Eh_{YF+*olO(Xi^nRrMwK*+=yB1pl}vq^kiIpu>v3 z`_@qOjfLB8kCmH0|5&))Ky4Tcx7}_G;M^S&ZY^Vg8Wan+6dSQ{E2ttCZnutb%NkWx zxYD4jqPd$sbX7!cJ#!1(VTD`eoZu~O%CN25!&H;}W6f<71hLQ8p>UfFhnaPVbsY$| zw{!-rwT*i5p&=G-DJEj!mQ%#FSh!th;r7SkE5<;Kf$ISS#@tTuV0?I5^N^?WKEXHE# zQu)FXIGsL>?q4CeN)leKELRswa~I~}?DfNyix-8NJwHn*QA)W}rZs(rThm`HS1VI< zm8nEFy$@W>?k4}!X>eaCz8pxuJv|5+90#}4%y132PjI*tSXl+kodAmK>McEe?u?YI z=JE#qlI0IU_jvjogdO>9t4^O+@R0J&c3lV4=XGup7^32}A$^=y-hNAY4u1TJ;Lq}F zJbf0ph^NoLz;Us*I|0-c9NTkPDVIYZbiW$(QU4aU*fox)14-V(it_3S5I3BRvduMU zi|fi#cG$Z+WTrAbI|I{$^bm0nYug+>l2i8PY{z?Gbb2 zfWfCN(yI{Jwk4LHw37x8jX5&M1iQx^xw$lTU2$Y0u#+EE5HzSJ%IlV(ux5ic7r0lO zOph8XD7drp>gZe_d_|l_>796wz=zYh;_xYVAdQW{#QkJ4{e+x^c_vsV6tN@8rD}Aa z=#Hs*99HuH*&Dv$bd5ZHaKK#BQ_k0Ob~w%e^>pXfX6MTZcL0uV?GqRHrQCJ?#|H-c z7tRmC8JUkVZ+1K`S#`|d!sF}L=IZMk7<5NR?#YwmDD9_a-cOExeiHqs{7+9kuL$qN~+K*cSTxkaA^^R&16#OV4KOi z*VUBBm*%2;=rUuE$v-Cl4Yeq@emYvp%J4VVU`Sjv)qrotr;w$tbuO_QkEZ(jFIFq_ zt~dy?=4P`QVtN7AE-4wVoL=cVjyMn0H!?lE5;I^1HGO@e49LsPz%@8IHZndY&b!3W zL!?aKB(0}#vRU6_I8DG>FGUm)x+X2aC9spt-i1fAYA3hct{hg#PO>#lDa^=I3il^~ z6l&m{A!R?&R&LA6B&wCiXJ=9_OEAbc!(>wK06iIaWbCASv9^SHzL(`W3&;2>!CFz| zWLr2#xc`yzT>V)7#CRc}ScdpU0$Lu1&nr1S7^Q$Z9OLVP4~Z#vd4W`QwrEr*HQAP=Esh#s z@wQN@g;z+yyGi*U0BGJV@NUqc>>mUh2=7r&Q{rUq)*q}irJ&cu$2CjcfM|Rg=>}HS z4mOh6M|A*aNl6V@a<2s-oDvpk`bUi>HM^HYg+}6wDv8(Y&uR=JWRrWl8m-GO`eUn> zf<8y+`VEw&G-s9 zilqnmH_Gt%*on~*IH}O6$!s0Yx98Q;+J=Z2l!Ejj-kU`bhX^F>;Qs7in`KXD@#)X^ zdIS^+J*(~Ggb!(ysBosEIAl~*n$d)VDK0Ly(namL22le`A*B&hUWmYO{@Q~>Cj4G* zzh6ll1=U95Op*p$U^sTxiL~uyfxMu~BP$I%{fPmE5TKVU70g_JFw!W<87t{E?^9?^ z6-22JgCB*cU-I_T$nu54GyF)!ahx4clEw>o?+EBkTCH$wZzh_3N=_P}Pl^eIr+-p8 zfkQxW;DfVPhtTdwIM7!CPPI*I{{6NY$=L|Gg{~FEsGXa9!p*vDC8$;f*_6v=?z5NE1N-AwC!;R7Z zRv=NuQf6FSA3 z2obfhsj{Z|9-Xnt~IS|9}P!?5{`SsP#{-4pXu&A0;9| zr^dsNbY(o0<1Mcxf!}DVkrP6V>>UrYQvCOkBb$$hY8JG$G!iB%VZD3FSka^nt(r#d zJ1k;#oTS{IvhxLEgHg||AR;h+*&0K7f_649%lF4Xo$x7LiR`aW)FS)H?xd5cOtGo#ez#Cm z>2NfsB6|Y{kJzgG;fRubM(i@e@WX7G&@;37FQAe3@K^;o3-ple5)GBTK) zjpnr}xWNb`&n@^8pq#l#L$LCS4j;c2rm zNP!+*4>Luu=z2t-m%z5E>j|P|P?C}HJxtX+ScmS$`lKNvC>$q3fACdHsuFCN@xg3@ zcH5Nohg+GJBRoF|*B?lW>vXwb6_eUn@Ap|Bw#iYVk8JR@dX2A2NrH|6KFh$I(dpP$ zn#s9IppHzn$BD!$iR zYLneJ%t+^v+OPvh7^PapxS!PE5bSGN zAfqDVV9;v)6)|!09riq;ot%0GEL~}!c&u-5_~YDeTeFE(+pG12ftspNQK}RVx;e2@ zg{-zzq1)Ot)3h>ovV~)E|js4EzMRIh&ef- zdP5a@RgU7e1?|R)L93z1b(;w9KOK|J0009)SjTE#%Sue(C6SIzR3i^Z>nNKQ@)N}Z zSXH6G<%h@6ZMZpQvmFkpd?4fZ$Yx}qTAOhwm{#qy|1+CH;T_Q^)34WhM*Uc!<7?O& z8iyb`5%Sh)yyFTT*^dI4pfe@Qn-JT_rRuuGhL;*Y+0b6t<> z^92=k=3K+3J`dQAxaHL6Tzfv=MBB(mI57f7Q!6u7a#Ok~!AuExXnld0z%j zM=C3@%>)>(58q~+5l0hXl&x;9%?;ZSV2rw}<20XRBJnAjImy2KA}b=G9kM3mtO%i= z@muBJt!U=#;tip1s}2lj>Z*9e>PF3oBF?HJYbyxd#>(@}r99^ps!*|qpElt;_Fh91 zaan=f6+2?PgyGXg+g6@8+3ME*6wuT0gSu#QhI7i|en2uZrK#MFZd1a!ax2upHP}x9R-F&xD1&H((;rsg7Cxtj^ zDiO#rfS^$0n;`2pHx39P-*jW2)Y{57q*FyP4p^UkQsW-uGOOe`BwHF_O;s)v5 z5nI*I-=LXi&``zfnA#-_k1kuKx*&}E8A-*9SjzmzLLsD+UqAjD`JM?We{tT~O=mc* z$^4qWDWo*y(?#1}#EPus(RSu^e(u}W4iKg}=sZ-`{uS8&Hu{|EBe63auRQNFs>0g) zRwSu*l{|#OD*gsTPSc}0M>d5O$=AueFc#Q>)kLt7MXt5A1a|4D%`!G^0D&F)g}-#- zot@z{&obWl^QKm2X8}uxOj7q!<~LWLNLJ6h&On|nd>y4dpcQ&d!KP0ZcAV>o1+~#`T5#`VO zwcSBXbF-jM^w#J(>ZU0lusA(-i(6br8=0no0j-AH$h1#xWO8l*H@ZW;_Wew0d30Ac zQK`<9tJ84)*T~p}Jg6(p59S(3uPkMUao^PBnd7-)-mRtGiG0zWsZ7t#xQE^JkmHwf zdfH86_Q`azkxU#+(`zTWVTNZ4xs#`JZmm4Ocwwnlsg~Wt`!YjX=yT6K_w(=@7HX_MGkAVsRLl_9Q;Xo-P2eiJ?PqD(XuYpSw)ijF$8%x>$~rw zeV4IUg#$!K(fV}@op)^}$o*QjGvPh>f6M^XoRfE}Drp_{xfhpJ=Ck>YkPj&CH9 zq#4uY0@G>}@wTyof)_JBqjR+rh4Ir^)pMuv1u~60ohuHXatG2V`Z94XnM^++g=mj} zd_oyEl3Xep9v_`_$J9Iyt9gLz1m95HCQlz6Fi)D^FK4Z;Q!df7uWP$qa0Zx4rre|} ze)Tssf~&>TzPRSWcllg*MO}n`hMR;H;r|~h!0Qu6GyHI|7 zPYKmZE-BJbEs^Z_^bw=d)8z5=dR==(BQo}vbQ$Y2by)So^{X)oOZ8h`Q*orV}10-I3OEix>_#P%5JSRH3z?$L}j7urus|$ zGnM5jm$9PBv5|Wx^MIG7@?3ek<{lrJD2|K`7n777)-tJt>+p}6!SOM8{e}qGbLh}M zcQ7}0T=uWb;9)4j9WTJ|k^W=-DObq=ReH!qv&n3BJ<1GQ=-NS9bED#r<1e5toTYT8 zDR}F9NaJK-eDVy?jr`C)fjG{pqY{Wt+y^CbYa)Oh$*$0ghMteo}dS6A&fDlXy6i8$Na9tJrh> z{@yV@GA2=}M9dY7nAo0yES={Y7+uM>weoy3prEtQ>?Z2_sFIAsNy|Ud-*tHJWrgb% z4urRq^0rg+*EkZLpw3b5e_lDmcr7o4fl(Mqw06r zFxstoBLxq1Tgi{FmHk^R_XEcAP`jF=i%DU(OukP@QodrqX7S@Y+H~7l;1=jHyALIu zyRp%~BZ8OQd8-M5k{yD85&Q9N-H)%Ua4H{Z82YcZed8_A$k{YXBttbt)@JkL3lqrz z2CQ_x*pKfckxto_9E=MgvOmRsd@WP_Xrh@#o3e{f?}Pd$7wOnwCEElf6AlzAMm%0b zCgds8-P{JM!KZ6zf@DpPU`k~it$HN=8~pqsT6w*{;0yV;<&}Ut^()V9b;r8(!uUDO zJHUEuan%SxrE|L?(MLkI=Aw)dHYx;f2b=+-WTPbHu*4ge3O`+p40@mm`{L#=zX%aMH62Z(3R4sDZWP8763gpiO`Q1SK_4}JpY`f_A8)wf=ewj+#C zW~&V)+6-&G=lU93(R`kCym7>Esg>zvWyC@<$QwutjRTZo<*Gr_vg3AaUgXsd#%@zl ze1c|)r{A5Me(Pj5A7u?;i@HtyXuaO{^xL0#d&VC-i{lf8W}{jcr{5n6BUP$!Mw&ha z&TL{iLOO{GGcydSwlp-g>n%rwn6wD;nzm@6LI`(i=R%jQ)U}pZeo!Z9)FE6~D_m?;hUbkUBR0>N=n4c=~o8f-erh}0k_5W&=-+P}>P9VNcGO@Z9y#l>a?(h={gnK_-GPO*Ri{K$93Ce!@tYQW)RqYMDRD>PmDQ#Fri!7UZ5(XEuFVT z1B4cZ_XGV!H0Zfl^C2ms|4?bSsS7xh(Fie4u|vTSkO zD_Vs3Huey11Qv2BaFwnVFOrPP{F|!DtX%60nySz?np5)AI@R^;MN&6sQ^nfuJ;#0_ zk%dx;!{~V*QRN_o6ECzdct>&G9o{eG9dh?f>=%;we~kS?KD=&zA#Y8C3((jvWOSEJ zUG|JnX+TQkfFWYh9K`|F3PrqU&u)0 z8#!|9b+40N_mV;Q4?)l^c(hzUhowPv-5&e#HPGWPj;xCp)0X^Pw@cog;MaGB^W?pz z-NNRsS+IhWI zxW)Q@x5acDFWJ702U1js5=MfXjraJqT?|~icI|iI@7lEwlHZ6wp9vrTrfq86C)F3f z=TET@zv366>*2rE`4S#)l4YaOB*JF-{M$A_pHTxt5rLYZ)6Z8sm*Iz6%IecRl{h7c zxYrymx>wMRFC2J<&V$jJx_ji|xrNDCmAQ=%fCvMJT$ROb3#@ zeN2Xx1_q`E4!Z~Ng07-_@00Tj=8+rxS5#`HIgl;pYSr2KL}m}TA5Zo7o38q^*-R!y z{(&=d;cvR=_GQpjy9lVcJfdHCN{bH}^tm!Qyt)}k2|lyI6FGC3Z4^P`=(*HPFf4H( zsHKvKqxS@brOiCJQ}2G&Wj6s;RM~NapYXoEY!<3%xPreUEt}BU;qWYB^VEDf;SL*^QtE1bZAGzHAf}K$(?KQ;Wf3x+z*qTMdsO=@TX6d9gOZXnK?q_G)hylYw zbi3H*#t(UZ;a!%O*3L%q*k(Bz-mfJ>kavVpi?r)n{`}C;P;Sioqy)-G8Bt5+@^C>E zy_Ot#BrR!MdCSCV9h!wIaHz>TTL}v$HUwONd<70qog3;`1yTHQB9}pufg3q2HI?1B zKb3W77uZ6`t?p87IX{76H+6T)eLp>@JK@eATPUZN$j{k49gpW4Kq?S#QcL+U3?bq7XISJ|2z~sT5!`d|( zFY}s_YK|Dy9AT&;xTQ&6ewoDd!w8fY0TXAig|;Xr6w;&^adxCKKJ8(pZ;E?L$RZuk zbLtUq6H`*3SDRj=eU+_b!Gr?(tzuC06K)oS3+NYCIL34mwluHaE3r*y9LE7rp-WZ> zXbQ-r>mXUO{`%h3k_tD19R>`Z9Oy?wht?@&Bv&oNsF92nDk}|K#$rw~7US+sy2-s) z{o0xKJ3kI~$Ye+`;j{8PR9*@E=?G9etS?b;Xn`RX#_24Q@Vb^+T{%VYfIt5HnuBIE z*ts%cMKAv&Wh|js5RJ-N7xHJIny28;&Xm9HINyd5WW=Z4eS6IY8!-f(yUruW1V>QK z0=voCqwq66z5rDP)6^_!Gx+gx6>L$z7Sm~-BV$NmX<#EMk-@=eN?RZ@c<>6+ilb%4 z$u9hesUe}go+c$Az}US3(vfd(1J3Kq7}}7OI95EJ@qYg%mX%?h7oysmRvE22-5yA1 z!R&)TMWTcfK&>@kD2HM3s4ARJVz#x6!jMr;4IDlYTtiHQJnW25fgB#y?$lVtg4qyk zg; z+36d>Gn(kl!`ne+QU1fDLM3XCY|4BchfJ~vx^reCnG| zfzrUl`L~r;S6MpY=Fq}~lr$T<@WWNBZ&Q9kQWt1wU2LxSII?o}T%1BEEn8U@Mho|lh4Pb##|HubIZ&psgd1pkgF z{87J4i}^9~mZ-R%3JgI%1M%C)4?ikQGNH#tgu~Y9Q$N6~g?81FBvoi}1rpN;HoO`jH!cMR>f3?3K zw$a!!aU?f7dj5U+ljq0o=H>|bN8Ne1=2!gt926}<55(ELvH)50G+WgoLJ|N2W|65 z<%AE{DVLZv+HTiX+=Qgl`!eVU!+Y%kFAx}-89Z`?AFBs%-iR0ik@IkSl0ytUB7atIEB&MxFxSaI8YQM$QGkqOkt-ID z4WGK_t28?v*>>kZ9N~GYSwk46X%>e;jZq2Y0#F8Qv+o=(NUT@JG#pgiwHgAD@wz4C zA<-Gy?^(QCZI%UuD7+l^&wf789AP?)@-fkx|4^9X)ifLGM0zPzP9!2 zLwxy?_MxNKAG@=Qnu7mZg(0glUC|fhNAuvx(}fK}7m5El;!cpct=pZ+l8p%<_J9*L z8VF`pt^+>p22mF3-?h)3Db?@o$Dy0QErDoYj?n(1k1^<@B;xA@PJANS1&KF?L~uy) z&S!`K#_Q&m2wL@;c7Zx_=lxnd0 zSehcf8ok z@e~9-%s^0DMFNFS#BLTW1B+$%xG>H^RPxcj=pd5W5G zoW>F%pGXV)uIdV2-MR?IMdM~7nAcjaSqh$W>tdEw?(~y^J13EB zR%x0ee4QGm<>^H%O>Y(24KFe(ZYtzl+R z%UX18i)g-hc*q=nXm-KO;YdF%n1ayh0--u*_J~$Lh{&hX{s@539zE%CnAu<*A2D za6||mYy%c}nsuYimXG8kY)5^-u_de(xCQGa(}eX`Ef<5AmJ|&{tt4lxNGuN_zjsTU z*JyAn#*5&j1Gn^tG+q=E9a~Lq&4zl5TjA^ExMAMn-l+7-Fuk$Y&vaes_v_jlLs=3Z zQg+!Gvr3q&c6D-%v+G{RS#^Tv%s3B+i$`YDZ81#{Gk%N&bN>_Qvvk8u_z@_$IPmS& z)JF%=M5(axO~sRp@Y>e{D0YJFXC_FjyIK}rO#1+LR#(xnM&T7)V-vGj)zZwgYn>V< zR<%U;xUkup%BuWqV#IB;TRNl|aU0?ZY-NJ|xhdG-i+h1_aSnI!PNzzPgDx(tj87Kb z!uYw7<6>5VI}qW(UtEQ|>@|fE?)z$Z>zK%h&IU{GSom z?85vMd-;F}eC8Ppo`1)Dc?gz-aFb}S^6i;t>f%jLbH6ps$Nx%1XAgQRpOStWBYR5v z3pFqKRSi|1?Gd1IpPPRNkM{4#L*0n_R}g9h@dR-9RzUfPk9raGW0dT4%m=qd@K;$X z16p8EP{Z&2o&i03l}Y7y9WV$N*~vKY6s`U=frog4D~4ZLncn8`fXQOYD(PwLl*hsWu4j^{v&kekSVLAm%he%wHko)Q2q{g<+(6x>QA zsqg1YkCm7Hn8bsJeV77Y9-C-1%B9DGla?Sw!JD*6qTtU64$1RGr@)C^lgJ4q)}ZMQ zKVDvPoZbYSN3#msNO}|7$jLNM9>_o&F6jgyx1|j2-n|6Na{R;x*L`%kQY$B_rG=Tw z{M1}!DsjMl@=5o=V8EtYv9knrx#osX9pSrN=~6qcQKN|^-HVEE7wN84`WfE&D)y27 zcGHW@c&7Z0+hAoe^l9i+?kre;8#`DeYCK(Iq3kZrm*(cc<^T`|XZ@6`H8en|!1-gt zqp*MNY(DX>CZFF$uDPq=u2ysy9fCVxUo#xIa|A6A_j+KkbWb%a(f2qtV^@)665Its zblB^phuo1?%#)oP!1!2bGYoxkS}K*YiAr^*T%88m@KbH9EMIqr@~_|VlmRDicKWPuuForju`#n3);f;m^vtf-FU+CC%}(#!5@&sb?RI>g ztfeEY>v^)YgKIt90%F*pP2QKoR^@$cVl5E?I!O@Hr9`K z`893_!hHt8q?ppKaSv#tO8!F?ot&?6O`_6E8#ND+G;U|IQ&pLHg3boFl}BwRBA~ZF zL2br#IdrQ{1g6FcYOI*i3RP9%xk{+KI(G`Z_T$6pTygjmn6n`0Ok9KQ^-nAjl^D@k z-T7d$u|jG_e@-aFMslS=KMs$NPP$`i9*5ODAQpT>4H$X);DD((Rdy^h)z@O_Qu)FX z_>YC$R4u>Se*D-&%N5(WhrgB+4aN|Pc)0NDZV#FtAf(+ zy!z_r;gzh*Y3=iJI!#+Ctz|cDw$iJAspRJKIRB2-hSB=t>E`)5f8&$it18q^qnPtk z9%rQTcz*))#?D9rXqwUJ@#87W;6wU9MrEdm~(-_O0 zh9ecm!QI%SbJd!2VY)KE2xMJZtj$&yE-WvV;q13T;o8CapjFO@@%P5Ne0@niiUZy4 zCe5D82iIb@1GUhq^y;e;RPsbCb;$@dUOknXoFFX+%R#t`rY^JHkyacFXv7Q5r5Sk{ zpt9FjUimMt*ht`o7hV8jF)ssj_9|-N)LN%YTGW4(B^E}HnY3C2s5o5VftFdm0;yY~ zZHlZ`aP^88Wkm?;0Lt`kEK#F(Wq~h_g>Wc<-8@G3ZXE?C20Bo8UYQL_F5O~<1}0-f ze({SMS2OVAKc*-V1rkG!DXufpWOVGpxFTw)0FIB*2AC-9`Gq0f9svz$N^{F)YTALv z{YVj_n9sM0lY?LUV#LlOP+>e+F=GUpuW{SMT+1UhjRdzn`bg?X+eeWWS!46TpYwlm zH(QmyM{Qe=piIlyBqn8-32I@jFOp(UO%l;~2(}(q9STWHmT^2+@-jO;iMR#e0 zNf+~?J2S|~8RVWBlH$?_H;=iqi7SJsTuE>>T4vA%mm%OnjwzrLS9WCvcV^Ob-xTac z1697^^2_mgY8yi^wB}oc&QeGcfsD!5GZw_;OScPceI$d}}v4X*{Y>cVk&Bqp7)C zS~`fR-m=b@jX?6MEQ_u3GloN|Ft^^anBx14O>q{h!jEh6KJeO_+P5#YA5M4N?d)(I zI4pACz9*kNh@RN-g163HMwYx7TLGEO0b4MJ!KVWU$aXvbpIzA}aW7tf|HW!$9wxXB z-x-Rg#SoHauR|k8U(nRLp&ufq`zOy8e%}+bY9KQ zQ|RlvEt{no(-1ucX6j7>l}*XASh^odiMkP3yveYneYCFq3<+48R(Idxf^kHk_JcG; zQr;>Q@~noV-Fu*pi9Gdff8f zkyaecZH*!Q)mNJhk(=*(xIz7^WS~@s$9PaLx;Aa+Mjh0J!n4_+Ziqy|uOY3(0y_>X z!4OKKY4&-gf^1zBk6{||wruM{0sjvH81i^)P<%`*l<N)I6}MaSyB-I>0mhYdn;D=9!r9yKN3-G2i#6urGd*aG7th7~bv}^Zh~|y`>nQ zSFStJDTstx_~s?FW|_3d_s4Rh=kL!CZ5;Vnt8R2`bVFWgi%)9xvAncUMaX41H!++$ zo+tSQTAUe^qdzwwh#=iLy=ST2yS|2{c&%eTPt6vmT|Usp;n!}bg5iT4D8|8 zoBw5eFPuA>zQVSu-8$`_UM==6Wk%sVu;kue&=z{svBMbu9^BftXU}`~?13{tnHG~P zOr2i$$YBbA2Z`Ev*N z!BJ(q$^V_1L4a?E2fmuyC)4V>Rj%g^h*8M*4v&vb6bo=%W|0EUAZnItk!ofMR6bY( z-E5!8;&V)Wyzo)C+!xx`lwM4m%_z2;u3M|rN^=RUorC=y0HlOn zLVVX|LS)NCuoj3EI2E)96xa99gd`aG!>zKaY~`<9ytq`ZEhR422B`%RbcS;eo{ZDiz3rb{|Gsl*BOfgGgTNqq!A7qxjFXc3xv6OJ$)}UZ|yDY@-J$yNi`-ty~3r zam|%xCQ+?CJ_~1$Ow$D7;P4D|vg&djF7W6I6W&!}2neZyl)+wk6{k#Mpw{D|!t8d-DRIWjGzyaOm#YGTy zGlK-kdh`63jQlxz-ZNWQAaNH(y_;vb;FD#|z<3>)_Ada_o^qEL<^bgsuWJ79BrWzq z1&|NpbIAO8GD19$lvlyu1Jnac#i0UAWzQmXjsXoXAaeZ-HRzrzUHGM4gD zjrLzL7XHs0(?LuJL4>nIl_vCl zV($(}W3vmF$h<~V7iSb_U~4u5d0?tue;#B{I(ex+fbwhkUqSIlpa0Y6`Gq#k^!eZM zpk{ZcVZ?xJc`0sBPtW%i^VLCo==qU1;qM#q2PaUc7!2+rLgN0I{leII5l&Ja)YB|p zhP3lg+~t*-MNw>?N8-4BsIUU^_MISayBxGPlQ=hi-Q{t(`ex6u(flf%0nVIsAKM1H z;pt(V=_Q#5cPxegTp<-zYkTu|8x&YtNqmMQC-a3KhXxn1+Q;*dgO>JWVSMroO9;0& z_Q2#4PDxN8tLHgJ3D{5b3)UTR`Oy)}j|jbR#IW<+HaP!MKtF{3=QZfx3Kii9p-n`g zfF^z-#pwM=dtdE{iv}3g$QaiRIF-;34zvdj9 z=gP_lINnR(S+38NR~LVhF1|JzO!cPK-n~fL?v$tPzVe^H($e+XSH1$ou=*8A4G$B1 zK0$D^(pX%U6%j;8%L*xz<;@9;1G0Lnx?&AL$5>zV;;L<|6I45l3>nc>$srKX3Y2Inb;7kogQ@-VDI|14 zAGD_tUP>qo`eO-O`T#(Ul&tXvY~dTfo^z*i$1nrEmqOdGA3$(mQ%}$9paz70f~w*& zcBgVLyGF)FiX*wv(epf@7wU+$Vf1=H=+}MfHKOwBwLvuS9~TdzidHXCLH2<4!G@)r z^}9FUgfBOL4Ss?;CL(aLehzVX`NNE5d<6B9oM!^!4ziBEOtnp%9Ej!;$FqxUM5t7I z{;ucd{}0QRH-y!%W zsKzJS4RBIdsZJ~OEM)*nB%C;?U_rx$gwBf(LC;8zpLupbebm6C!6 z8~Wd;(lZkT>A7k2SBOWxop=Yf#~rNL6&LFQJr(H2ca1?vp3V&v2bHI!OuEC_p#dXg zH9Df*21wj_USkTm9S&xL5E!Fg&jWQ;GVqQdD9gr@ADra0E|MP-o?GmkJd7HR(p7Ke?Ekn;f|N5_$nPDg)eR(BD~GeDpaTor)qaMUw%^ATQ(xAOWQw$k$kYo%ccg4iWw4f`mdEjRvT`Xp55H%P;}vHJ5zY^x~w= z0CtGV*UnCu|v?_yWZtI zjS4E~D_=n@{3?%u_xGzW%JWC$^FREhXzpu2EhSbF=$xZlBi)}RPxa&7{WC!qe1h4an6gP;9g_&=+&r`Ww-w_Nl5FT#rV-gv&{@4}?Tlc)SMRH3%I*gKF@SFf3+bT>|(a^jPx{F}+x8`*JhJQ>Bs z-qvsqw!94I?J3uHI>r<>NJj1Qrfqm?VaMEm{>_bW=3Yyu;wf!pJT~P`bX%9cGo%6Y zIL~1p=1F5)(o+~(W&&gOasRnCr%%RxPSCJQz1+cB+~@R@r8d2HzTiH`&eLq_RLB_J z*{h%=%Y%{P@7Jy*QnGpGcHu?n)YNB55nZn5FT;aS6`zzo?b6#6_5m4ezo*<>=Cb+h1JX}|mAlP>YFgkJhH_oTBKd`Kt3?Gg!L zcYMa{J^t5Y^3x9Ef--jP2FFh_M${+gD5fy7C9eQfW_M$ifQ!zeuvWxr6x4!L0V3>0 z(6i*rPWqSyg*~|Q@nT>%#Q>{)Wr{cx%I?aRS-Rg>5B!qPE5FUYlN(29W;cNdA%qOi zl5cyn!+0zLLdjuCX4B~bIIh;)R>yByMZE1|DtPqbKRyPl7~c>+fA$MSbJyYiQolQ1z2ytP z{)I1mL2>q9BgY$H?Xa>tYObtV6Jpuni#$)UgpL0hxyS6rnEwS6GAouRv|Wwx)GXb+rFyp#KH&5n!aWHyfN(?>7&L zuE6;Sp@ri{$9PNAj)A+ltR3TH68*o(AI)aKcK}xDtWYy6yWCH&=4?Bre~xVRZX#aL zKa9LcE}3TIj^wj%!1xwEOUDX>&uYYF<3=Pi_G97QjL^^72Fzr(zZE_U#tKl`+nJaF zMY9n@LgIx(soT80%jeX+rUl6o`VWPt|KfRcDvxrAeBtHNmu@=LH^;c zdHNF^h6Iws>_TR6b|KNr?%;Vbi|=UUhBx}0rD1#64MJ-oyB=+s4&t@Ed%CWzyQ!2rzLSHi@L<7_Pq+_GV-bM5N2DA(gbkv|ml z(f8Y@`4=%NgRAz!iQLF2IS3i1|0m!eXY>ce1XUQeQ5`sN?b;)qyGB~gibF5&18}*s z7Z;Z2=7_v^tpQv4<>%n1h+y11nJ=7=n5LEJ4Cv1)z<*3Wmj(u=1`fM$Wa@zf&`i3_ zrZ|q>#EWq6-FQo9or5TN5sn^t$Bi6pW-~1>!u{o|Uwid)f55Yjb`N=$q8Cex-k?nt z65Lvbh1aXEex599!r_VB$ceSq444;&ILlEp(zLhG`Yf5=?7lbf{ISQYue|a~hYbsV ze6coLS-7ygRPOk>;;+#)N99~`zLd&|vqSBkUjKF{-QGe=Z-1&Z{jeq66J!uGkn!yt zOIz|@;}PHSLJL!*`tFTwda#IRL{9`uYHt(UE)d{ZsuetR|<(y&va1`TqVR z{iVb3^Yt4Y2cO9w3GL5~9fx;(W*@ZgFtk+1q^f298%<0E4-rKtRo{-_xc5F-?2BK=-gwhoXHizC3>UZUhj zl{)Z>(>$Zsi5911*bFJ5D$y>cNUb!)@Ot81$6o~4c_w-WS~)DYt%&QR4(nrH(lTq! z5vAUnBMlHq6Lv;%JA)9Yht%_2Emte(2|NLt2Qq_T%asQo%R@t4VGd8Qzhq?Wc>X?koXDNc zp8@4T(Jh|F^Xi=&94Bn%khhUVP)R}$rNSq{D~waO2EpK&mEOS>R=4k=wt;|&QXxN4 zba8Hlcp1wTCkt@C`U@|N<>(9eAQvC$H*a|EHj++_%JccRBs2VBnQM_OSrsQ)3d=W3 z5P&q)%k~l{=~1Pu8jm(Fsn9i`NF8h_%;PdEo^MU0QaqQB(FHYJv3=NIS7sWr-N$gNdp=ZT@FvN0r`PA8_sVe|v=iWeH8p3RL; z<|h(rP=4&Vs9>=$a`I%p0DDW)>0|j5c68bgfUD)LAcp(EMd+fYhGB;c)ZYR;q2ilKq=D#}wTftm0(aj7F?oGPMy}jVD zr@xquHv_NH`yj{_gk#zPjYGxF?K<)yNB$2gvJ9`5LwKH24r0&Pva}T?#bQ` z7ym#4Fe4)XUz_EV%>vXs9V;JSLzQ4JfL5tl!5g>&yd5YWRK%`J1Ic#P+Q%O*Xg)>^ zI(acVvA0^&O0NkvYyh_iFQQ-*6CpP5rmlb=L18%XzF@8+Ii|@z;R|S)81 z`E;R20|cA90&C2Y2)Z=73E6U#@DSMsllFXI4Wbt!V?j74&9F!LN{zVSj2m(O~0H3)~}{B?=fu0lQFlw6v;g zj}+h4L%Vk`fxD-n-Am!NZu;91^Dp!7fc?Or${wDaJl*>YTv_~qOAW3sR2E7YK#iOS z?wl{rSE}_p$sRr$-T!xXVZMp&oJfm4m(_CNgB6@-S_3CHI@HUoqG2E6^dpOvi%a!d zI&lS%&cYur&0Q!h*DCBg7$v#jr#GF3$>O%$$TSJN)zGofq1NFoA1=G*t;O>r_i&j8G;U1s$Z!na5{lvx z|0dP1X>)M?&@qxB?!p6TB@|keUTnc?b67VXGg_x=#LS5LulFIyc=)CAhh*Seiy5Kh z$T^%33C!}Lkh0zADfBMpl{x&%6;h85fM0eYYC>})&wB~YKNC}&=TTV7%FD`j=t zT&v+R;-&75x>nzPol|#JbY0azZDw8eW^dRCx*MW_ zEkdlh`vPp|3Txb{usDB(e7vCBd|cq%B^Z-Bp@h#>EXRge+K@+ZFk@tQsaCznoVUGh z=aRc{{=t6@$7tO}^4@v0EJ>iIfdI$3@$1mZNqzxN?s!2wFY1ztmz5*#=3vK( zBePKaSV>nu<`ZPg^YGl?O2P6vw<~#_+d-w?Ln`K5YJXO%IJy_=B~FHP^YQ)4StoWs zkIEq@`^ny$l3P<)pY8$z+ATG?HcaVr987kbR~QQZFcSYzxQddXgNB)?0`kKMFYC--@$d$ z-$BSBVa*oDLrYbp8bkDch-E1RZxpvObqON+f1@DkV1h; zxxm5ZK5+p9$z;S^lZQ;^K$95e=YSOO=>VQw*}02&yFZi}6x&?{&xBL10MYnwP&p#9 z==MSTC;@nuc+?}p-CkY_@L*+UO`mOJ4V*;9LFi{Afu72>CIb`!ndqQGI%OM=HQ8-h zadgsa;z@l7DBE$Go#nk>arx?TE#e-}pU6#)78AS2CPzo{*eIvh`P-#lzHyBn3bhY; zVg5Wan}PjwGoP^;DzuY?u>KUH?&6i(a4owvEkR-nFHI=j3&@PjCrd7tAeOPum(X}( zgB1@2wPsfpB0Stnk^#uRA9>OCyda(9psf{HFD)@&=vY-k++ZxW4 z+~M(A{T1FeM%6rEc>*lRvjjyZnE$;yST(?Z)_CWy-f*osK4WPwo>bl~Xs`rDqBNPg z-;<>TOVB234pv!9MJz!^-TV;MPM$&RfaV*MuNUvndV@S6miDv+8BM&=n}gNTQV~m# zQ8!G>oN>U$I(?p?ILVFWHPcZWL;AnBbmWsR{9)0N27wKNC8c~}>u#{&BGB^qr z;Ww-Vc^Hk=0JL$M^Wcb6X`d$R1~-#FHfddKzZP&TK?YHE94R))x<6NDrFOhFJ_wAP z*xSs{dV;i(M$*6*krYzb=GadiKC;Z;!{csv0XXe>cZ0W|a7&?0B7uOXg! zo42#xs?X}L-nS+ZEah2(3{t~V{3Mg>%x&V}(1!Nv2x~x!r$*s;kgo^{SB6ns7%CZ} z+dRV?)lVwl7w`_$gn!EJKF;IeoNn1WOQO5RB=IjE%7YFJsU+g=Iju1Vxx4 zC?0{WCY@KLJM?U#o=SrdD>q+`yH|t_C&+%TJ2mA_AB5j2cPyVP?1dnFCia@}umb`Q z?>*>3R1C&1N7C-QrtE1wonL$M%F_JEvj z`?nuj`?*WdTteB~YhcZI4Ua_OEq}uu2Y?o(YjpB}X}l`l&z|x*VL+eb$z2r8-q&4P zo`Q`OiT)$n1!ntM7ftuoYbV-^l4~az`+^axW8kUrzo<7q3%)&AJ^3@>MU6=1tby{xVBH!bs~GcpCgflupMorBD$7&uy$_eF z;OYxJmLGkX zE1@TT4PHN~2fh6A@0tPpeJ=Gfv5!`=bLaR+|NAFje%1dY|MJKDLA(3Ij#{CSlVe(J zcOgOe_9V;c50|g?^gW)mxD- zcLe&VgpPoY=1&xT`_q@d{7na4bUB$6J zZS2Hf?9Ik|m$~=qudBMNXS(MH7?9H>rn{@_=hb_!UcGu%^~%H$p~L#@Pf^xX{Fo8j z3ifaZPy^xNA+#vDDTtnw9bypyfO^;KpneI^$}#$1h%{=o#1Jrmej<_wyZ>ddXn|w3 zU42=ST7BMg>J4AU^nK_Jy7xqf!*SGkz2er6UXqlZ2UKR=)`LHPU)yAE3u!X3KlTC& zN10Oxq=U?B+a5w!f7>8q1%3Io|0qgaj;%#!Pp0kI+SdsT@GbnY6SVu0gXZPeo_h8u zx)O&(nyDzM?Ah*?^+5oN_r9_*m&t}6Qm7bgXGGl@bz6g`>C1QPaJ?3~J#hoZpL_Ce zN1Sji!;@#H0{m;)=`QDw%^3VPW`d@q_c+p^Oin^iYlwNz(>Z)waCWWX+Bo^~u^AurkYNqbAH@v|^+HS<|oaMVk zPjaC4s+lQ|B?upequG&q@UQ%5Z8=REXGoA#)Y9cX`pYRVfHMFD%Z$%+Z01)e*~+_UbMwAs~Q`-mcdMT z&(EMdWM(+l# z+OTDuCl_|Wmf@ih1aw0cY1UUTIB*B-Ew{XJg9$1Kn@r86-5k_9eWQ~g$~Mx>T$^G= zQu{ZRoBiQ=n^rOt4Fhmi*x|Xf^qzFg&t9!uZT+SxjvS92k0lO@c*mc8R>pCs!FSj|Mcv?N=gj45qmwgnDZE5E&ZsIVX{y+n6VC66Y{@ zYgutlZ^VNj8=e?xNk=fg5gBk2kg5TYCa{~5G_Gx<6qbSpq%i>l1m%u)hK7>KdvOn)&WXyY6XM9~N_oAs6j2uy#NzP;IMNbqmmrky zfU*hTMPxI@&62g}^jI$KoM8+{+}=AZyayfY;Ds{&@CX?>JOamWYK-?G^x&ZJ6J^o& zx9c0A4z6L7R~nh}C`G=*njp*FlH2JG=|_iJ zf-;^IO*`7)DO%u&#{Grjf4$#d^!p37XG1lhp$^%oiG^ zb@neSSF9SKOZrCv;?O9@{%I0v*-UlH=Th0Z)FiI<8e9Wa#5*Vm&I2#F1oK-o9@rm9 z7gMCM@(9P#OM0pt8cZ|qAROd#ZNL#8a;trDZ!@ie_Aq_%rjo#6DNwJ&D_SnO!tku- z&zaNOiz>diU9~P+{RHJ*i3HI`NfBotDw?9&s1zfCt1_-JrQ)30VLt&Foqyk3+;`wHFhak8c=MlpTtt&V}ur=D9`8uy=f7mgp28!GkzstxKfo~eO#u1t?e*)IJp)c zgcpCK5%RTfKdrqPUJRvMEr8_CrnQQ>bJ@xFev{m8?Dv}_Yo7+Z?_85Kh>X^P47Ca# zWGM1y3}GRII@SqdkJ|8JC57wJX@&tnJTgDyRt19g(<;oZfLP5bCBZ6@7YB=_M_h2j zF3#~mZlUX_lJP+W`Vhcddr7tMRk-Fkyi3KUk{w$ro-EnRhLf-875YZ zj*oK$XR?`mCN(|%==14Qk7n=ZKG4R~PmvW`O?@U?JqKj>HK) zll^)SldRDkOBZ6GITmb9$`T4{F=}Tf`zgmF*@6|zV6Z|^jPdE?1Rw@Eos}aa1M#$n5h0;ZPEfS5A2XeDB6gav(i9XGw@{^~@{zdnp zcSjXx&%IyA{rh92QYbBzS0Yhz5d2zz7lJUA-8RP?1$rhMI^HPYE(ll(FP(Y(ICthz zP?oeww#VU9j9{}o;UQM`qS0!&Us zxFeBeD3k6Kfl}8?)W=A%=FL_3AbA>mkhpSH)60GL=(R+Et3JE^naHw=!pDiF=ATn4 zLtURdX@UC_@L{4s%}SLR5U{F%xhsaX=NQoQaz_-oJ}zDU0fJ|<=}M{14^-Mai zQ==N=0WB#>Zbc4Pd^7~&4~4^3l$haEIGR<4SC%nZ-Ej|LF1qSmN%nZV6Vlof`l4_b zwpU?pjY7|_?)6qza|7g5`=jQIiVZ`V9C!Z2-{wX`rJYyq(B?@+$R@C=BRNaeCly9} zPpQT!+PKkN#HL>;D`Quv(hVAh5Xl;0Xp8u!>|$FISSp_h;k=}F z+zrGR;!MGVv4`?)k810$gM3EsU3wFpP$cPmhvc)nx*d?uRiy>+hFW_<(R@_0nEPK3 z?*Z$Dkk_1zJo5T#Yhs(G3Mso4>UB=YP+179uj5kZ5z&SaXm3065wb$fR9megVnJ>? z4UXwR@1ae@tOGR_=bkDkWd#%Gmzn0~7UvWdUWwr5akY_32_6W!N&{4IMJ{-BX6(D_ z;nB**1ZK3N3`ZZCFcxT8hKCU0RJq=p$HrQ#;aEhMNJ@`lY8tE;QAL_N11iCR6CTdw zPb+9;P2VLsTagFIpq6!`B_xpEYAo>Tskn&ZbZy5Z&OI8rnK9fl-86(y$8_dgT!%mQMvQG{)YW6XZ8HaQ?OI*k@P;GQ6 z4h=?bwBky8<&UE8HIcsgSi+(D+q8@JT_U+-N}<6XhVoZ&1aSUr!T8rj&rhnPQ5lC~ z)~(;U#(^-tYCLLpYcpPQjb$IuMrm(HYoAbV_{M6Y%>f=&_Eo3y`4mngTqrKv_Z*JL z?_Vh|*(X-)m2#za*J5Gu3H!tvEcvpR_LI~cVUOeKN6t*AGTA{sy#S*Gm^xwK4qdqt zDSi}YC(qSY9r!7{W0Hek+;28Nyo1XYt8Je)*IX zBG+zU0DDtwoigXf7fqqEn}c9&XqE+8%%i3w>IlW)=6BGB!KSEr(RA6 z8KR?+ovLeVpj^wbFPQ|l59mR`8fJTxs^I+rH>zptMP&S>6JKm;g3W;}10{XL+1%wx z8XBhNd!}R^2G?ZUlEsue*>lTW!y{B(>Lb?-d9b5aw%dq>bw)^RTx=AGuD@rxFb5TA zWmlVJO-Q#HSOjpIdzp>mF2%S6MO|fcByuHIt}NLVdn!E_+c%$#C1cj!yS0Tio1_|# zER`4WER-wa6qH=%)am>|aJb@JusS0icQ3m!B#prGn*H$wW#tV$Xoamj0pQpwn=6E` zv5AlDC$qV!bdH>S6gELHFk<`AZDkSwVozJe(#n@s9^6u|7i#L8_WTj$4N@+wJh)^}1!j`=2>s&ePAbM?>LTPT{}m#DCihTcvWTfPYw^SkcsRgzyqm z({Q+qDBVy`@d@tcdVY3mD{K|FwyBCheR0M1C9x(ITAe!n8i_?eZx8-CaIhjUsR4&< z>Si_u7X3970X~H#!Z!2SR+IJwHTVLrX2+_yBYegy(Ucs0qH|2K+wLa1B3xK?sM+SX z@DdV8v~sQ1^hFW=@V+g=-%m1Lzrsh5#mtBOP7V~jmb5O){?~dZhs>k4;+@cM1Ovl; zCyMt~r*?-Vyw*9Cs=UY|&DAi$NM=b0Uz@5nn8QvthklPt>Da5o&bIlm-y`>XQXjuR#c8^n$_g8gEf(%Ed8@Zl0k8*d2W61^&7S)ugyJ-;UEFgkN#RTk5rS`oqECK5BhW$55vbC;04f&?6f_PI@Mz zxBcXYqlzbQ+}}Wo5tx94rEn23a|RpMnLB52!9lpU<8pC{%_SDebY>=#C!^_j;$S=x zOD2v+2YI9`GKvL(&IDtErvVQoI)f`-m9>?3Fu_@Xbp(&(W8hE#@7mnyEH*>ow;;Yh zw%;&8s(l~zPM~Vvk0{fo1=o~mgx76>hC{)pa@#5SKKL7kPtdH`DK>DMp)c$>n}uOA>>OwFzTx2qXERwyGJGGVq^aST zK0rhnhM&YiBoDY*Q1Kqa7kI7~F52h+f?cEI`jSvs(Q^e43rwF%!xH5s`&fePr@Jb_ zvqfd?MEw(=z$GS$`0?0LVA+SMJDUAnyr#OCx5zpZ%cXI3EW5?hIr#r5c_{rTZ=A8| z6f{xzjb)*=?vLL>n1O%iB}{2HV8J8?});?4sHprfJ!MQ3=?eloDa`Msy_`xKVChDIFJvB*3P3e8h zCG`dNzt;yNNnrfKGgj6Rh(+^ zN0$r932zJ$Qn-8(&|I#5F(naxc`-5;U0YdYbfNBMs`0}5mGME^H*;rOW?CLryl}yu zM5{#UKA)wox$0Qh7)hK+T&_kEZ!1>|OGx5Gtag$WK1SEdU%WjL1s!gZnL3sX10_Bv6Z51dQq*)m9Sf{Y!d*SNL8))G1q8$R9L z@T=d)S-%gB!iO7u+<|W`ld3BTk$RAEsh!NpbFQwmvC+q)M6x?q%L0jVW)ogs&#T+aos_EXBvZfxQ z!&26_D+<(oxYZ|bkMu)a+rn-`vj-nj9KGtNZqVJ<1g)%iVh8$>MLQ((91R^Ox3x@V z=JJ{BWPXIu)2OS77+CB7YlWNGtK<-vY+}Pd0A|_+YPC%yz{BzgS}dehze=|S&1NCs zTYMvwNH-?aVJ^;F49u@2m7O}2M2jO>y~%6zdg-;-*+Zk>FFPNXW3SPTRHxCcGBwIX z$g=bKwb%ZG_fkK1^cirXz=2t7g^RL!9A*I~I;YK?%8FNU|84Q$zBjFwJ3%kJdr2ms z+JWk8+`?W2G#$VDSNyft-u&CwUVF)1VyEf8Yg+oQ0n|+~d~Zl*`2G?`a;`Vw@g?V# zJ((&0>T9pH*y48$LU#?IZi?Z1NXozVnwiXy(>9S=sf0i5J0O)6xVGuBr>fsGof07b zB{ujXfI-dMy z(c|9|)b1y(fy=Kw_3Tkxb_t1egQ;>@ROr=<4_5DA;`0u(=+ zn}MV7t1B>ad6PYc zs=ULI|;0pmXb1M|#Y64a+x7wnT`NMAEwK8EkPmzS_bkdK8WV}( z`!cYq1GePhZaBJohOO6t?O__)1921;>%@`jirLsDLpF_W&BuOU)^s0I3?qmNw&Hv)A! z6&>n!fRLOjA+X+bzi{L$U-^n#>4!zx>Xu`5%kaJg-*CmdkAu#hVb~8WzA5{L^;)|i z*FUlbB+%F$4#Wjq-~Mfwg={EyoA52#L;Djxfs`dWA=AZ4x&DOD3@{_-*8nn$;>)XO z>pLBGw$(&ql0v^z~ zu@YB}QFmp8ooNhTQd3i8a&~%t2Hmy6+LZX&c$`e7A4ttl=gIytaCy`qiJA`FF{$bH z`K9}DENYQ}`>|;!zF*`zMqZ*$A0cw!WVAXm8LtaHMh^-SzAzHh&&!n)R}O$DN;V59 z{nNQET#8>nyi%4wF0YEm&<=!m2) zFKa1&%BrjH8|sVaSuhH}J0AVq82)cyK}Mz|r*K(XGEz89&=((xJ4wJ#-@<%qg=9D* znuxL&((dJc{E#S56iZ9?6?^H#!a>ZO8=S6S0pKGttK|=8rK>sna)qTu6E7lf3VaNJ zXIxPQ04xdstsMuTENXbG4#6~numP4~;J88h0_VCLIF10vS$nD=phWQk8P;1qnT(vq z^2y@wkdiAg|A3f5z!+u}z%Dwde_USHCO$sH-|v^y6<;Q?7$utU)Ma?pq}9%to0 zk^$TM;EVkh1hyh$4&L)OAbmduyDhkQN9pTo0J<#m6~B5k(P$LTjR5C@2!)f1eWcul z=B=VbX!v1dSt&Zwz@xyHLR8b2G1eovMTaAuO_=KvOGrS~ZqS8bH=s>ASQm+P8P^_( z)gIQtjkbSWC^y^`T;H!k~VOth_4VzvV!B^oTu!TO{#d5@Q1-M^Z7JTlE zw(C7ui+@)&sdYO-kJI_Qm4?)~#hYYheM1P7ooz^F%&iK+=V%u_gE^GECX71bxic6g z)#3^}r63V?Mjy?4A3xDVHL)KO64~iTeo`tvAyxkIQ$$huVJs4l+YY^G0cUt;z&qG8 za(sgl5<1w_w4B8U0rxT=wLw0%XGvNzQca?d?CE)QvQ{ir?TeLSwRUjv348I$@Uivf z2976tt5_*(8GC?@dV!QOC}FbBuC@yjeRlxo->B>z@wvwNAXG|zyW8Yi1gdD&mQ9^ z1|(=I{87T1rq?5&%g>`@aMr*u^_QnO!ApW;JUlK0j|y>|*~{wOs3Be`kNOg_Ke2C z6=5Q73Z3%%;1fNa3z;BXbaScZP!s6pm|;Rqxi-LG7qgyXM|39OY!LWINa4@|KC!cu z;Hka|4EG#8ga=|m42X$@CKOy(YMzUe8e>BqaQ=ul7g`>+mjoPc#3HinY5SG{G|Hj@ z$LZB-5inX?3FpBB2jQd?a{uVT18_`_-U%rC;`weLQYo*OmLik$xm-G%KcCOcq+=ku zp@S9zH9?+z7R3m@A55h2=A6P}?KwS`OAqh4uU_W|3k}~3hYB6Th11nz!LHYXM1$%@ z508+M!y_PUG{O8Kdl953m72cd8D(sgfW(%fQ_5--z)wlhif1;m4$dH{wKRwZCXOA^ zj-{Z`HkV>Z;i?KfSjSZf=o7+&Bmqb!@AZM&iQ+l9>bSDATi;#8{LSXl4}juOvVR>e z(!X{m22wo$HZqXsB5PbPJq72>#MV}-3I1?(nZ93L&dyGyA6Y7%#MkU>H9J4eo>%Zw z9$u%@aN+Q&bHYNGiU*p}31)5i2js?kHaOaEsl1})G;^CLr?YBKdS|I@Fok^@i{qX% z!nBzPY0VSHV8szPcv+_WNXEy{r6%!kCta-OE{ZEXb4DCz^$GDH@9dl`pI^{kHndMN znS9VbKk>v_*ZZz`O+PV$*UrLP3|PFxe4qz8Z{&JV5;rdQ`Np3+@Kpij#TO|d`ajni z2Ij7{3ia#L$3V*%SPGbu8B?iz1bZr+#*xpZvU91)d}cN~pN@`)Rsp`_y;SKN4SA_) zTY3(Nhkmqc0|OJ*4%MUI{j`Gkpkk_(y!&Z(4g*2y+Uwm<$ll5m{j2)*r*PrKWy!u7 zEY0k^E3gXN{B-5?K0IGJ{~}CXf}Lmy>_606v`j9DvzF;0&g>{=IJY~?j6mb=Vfpjv zQ;%lvPi0fndml@Wr=KD#)D)qc2^3dMDL8?A@-#SkEH2yk+yyrD`&Y_K_K6jHrCh1q zRV^(3u>FH;FwJT&{Rq6Dd1f(dpJ4C%(QDJ|jjtv6{HqVH*yD|hSuDUjH_!Gin(e=% z`9i7idV##oUOiIJgTt3PN9sP~6bdoqv#$uGuD(s%T>*`k}k$9X-!8973eW&XU zV#(1Xu_UakSgXRsWi0V_f{cXIHPqWR{K~1DDme<%O|w}Lb|>P_(R>z>bL$D5aZ^66 z!Lynk5A;)zJ(t4e8Bjh<^ECtsKzQ^q4%0Z!vH@8Bh1zrm3n#iHtZpFGg%jdbL07f- z)RdZwv)*D4`2<*lbrGz%-LY;=otjCJ3+0MkyjVK_q+MHsgMA(QF@g!f91IuuZ;QVboageRYNjwx!Qi{h%L+$-}U41}><@^qnkz z@)OBn*x+YE=G5CLR0j@@CKLCb09J)L|F^yR>cQlzvSj&?NJ0yq5U-zxhd&fAdo1xJ z?@1lQh*Us0pg=C2($Jl}17W3WtrA|k9%OXoRBldF#x;o~xk%?)V0t}yAZc@KND$o* z{5!q*^NEUK;1hO@w18o@0tza7oHH?GCF#iX<@|a|!KPBT6_`izuiH0R{i^1wSQcz%3c8SbDeN3nV-=H{vcco+AsH+|GFK7gFy{PI3 ze!7;`50F{EuVBt$oUX8EAgR@aJpo$5lay||Rcbk!PB@#)T;9uGMSFR!|xbn|@` z1~3Gu?A2jU6Hy%Pt1z^~XMG)IcgphJRAF|%x#ij!r6mH2vPPCq!9bs_Lvg*jOUG6-PC+?~G=r3gS+Wh<+gHSTT=>84tP9tT3jx*Kf_p zusallFi1ONwkc8EsR#`*h-4FU+$7v9=47ELLdBX4Fm||gaZOfOYC7GzU_wdG5%i}! z2G@FpKe4T~Ki%QBtYS0ft+>}a<5oMvzCAz;YPVxybtX0%CDB3p zIy*Cy$&bs$qolB~D7Rd5KVWg{un^Xpfr7J~zbcpWJ4^U+{qG=mO)ofi8>@pm6X5zPY)t_9AgUm$*oC@s zhXP`M0#@G@ggy^+j!=Bq6{>4xv7YzcZxZmIL8zM@^rA67$emy~9~yldIm{BV^=D2R z5w2urD08178U@A(30-L1un1O>UV#@q7j*$U4QVyf-9n!*G6=6`U1b7{s4?K(iZep< zDG~|C&+?JTVi{aGmZ~vQEk9|OidSv2TCP;>3iL&pta`dfq*8vm2>zIP0_g)19Cq!m zyl0_Ss};y<%_h9eB}ax6dz0r`c@IQ$;>fck4-wU&NHqJ!_O9Qe$pQR)IyKc^R_&(# zwJ(0r+S5WNZ`@#6EhKA{WDjT%{QGY-ir4?v90R}7JW8V&^^JPH(f3~aHqk2pv6kI3 zG}L8P+ACh1^GWbDjzj3;om{~7vN(xSa3p7uOY9+!rx(qF2wQc87xf6A*x)+qp8pw= z-NRy62^Dv%@VgEoRTF==-F90ljUEhA(_AV}SOa$sz{N{);$wO!@zUx?@NN+*pE+cC zLKr~L&`9OlD#WDGL5yQ=^qL=dt9WF0A?+o6nEx!h>h-17pMZDP4=|vyd@Be_mLvwN zO;LhXs@e!bDwU^@0P?>_E0^~tfGoT)@6;r{Dz+PY?+b#x`Ua~N!(Jx4PHD+ehm{nl z19A~W)tfir?>q1Zui5#0I>#Q_@7Dz;b$opZFPa^r94&#eQl8Q^w_3ZIp*TD1WGC{X zu?5vRRc2?GuzL-NokO^#$&b+xAp+4i;>%56haZuX z8wH4`4P+&TwM*+1Pt*gp8(-{iv0R!dhyhfF-m4{aTEC()Ro*jU zXXm1oJ&-LFEw!(Qg_rM|y$|V!;@_(YjVdiiXlOzPy-zJ1TRI4otlE009D&y3Mh=C6 zHJ-+;N5~#3TYz~|F3}`KA>&_KL4k3&gVeDA^MEVMB`5*fH*O$8E}f+SB5vvBBbTV} z&wLoLm8PYGW)hk2>$u27DWVJDU=_Ver5|~U!7K!@tEpS?Rj^anaI%x#2(eW5rafzi zx)H%=j`YyDgNfGhdOerQ%%wHaTKf=L#nem={X)|VMGei{EKP!UBi3736QlxycO!f( z1#bMYnDW)Cy{0P@(tYB*DnxMG^02W*LN*^~n!fB%!tfhgL;c6Mx!h3eRz(HM#MLfv5`6si-Bj^9GZ1{t*8 zvAxt#n-%?WsE)1kLcG zv)TDfyVv6(GC1qR^~#tX4tX_f`8y&!k;OFQpVZeuv+=e!$K-|-?}{bF+wM6W?}qV0 z2d$nhwR>L^pW5y#dh41=MruGT%P+}Ji zguK893bEc|S$aevNINkMYHAtiLIiRy6Ue3*Zs?_t;jiVPS1?nkPanQr(=e?Ly#m=3 z<IT1x`mb)_b9Eh9-QXB&#LQu5ZMI}>9S+2e(y?`iZMI^? zM~mwf#85(x?|e)R$>Xd@$D(~}K2m&@~=z*F3 z)}jrjqrL5*$(-u+ws729qZzympTVo?GkC#mkS<#~EcK8)oa1U?SnEo#_Z2!XpNKZ1{;u1t5UhcyyEOei>r<5gltC#bBn+z>H-mmZ^T3m+#40QHNGMZkz3|dr}=1 zcTtrC7dp8AD>T`hNTg zygUMWMe}Ml$PhCMvYPGL9vkHQ4Qpk14~*Y$cmttnb9aKQkn6#J{LY!EWnEFSX8>KX z+`{;kbuy?cc5(dPXwnb5ZE-nmD9VDwdUA;bXd^x=aJy?Q|G#?nVw2O%FoKKL4SQSY zNXw|{_5MZP^;|n1_lZG`^5G2lV z8Xt#~dFYAmu6TIlm-QBJal|$h$Vzi%9RyNi!q708Ac{gRUd$NFYZ1^CU<{ClN6rAg zu{?%JGu{M@^Yb&~6yI_48GLt-I_#o5>JXk6z-0p6ut8GO({N7GG%ScC<>C@~AU8Wh ziex$i?k~t_n)*6{GqH|FktH$G6&b~XKsfqmDxD)IA0-K%CNX~P7dSXbijgZ(&3Q-{ z5jyDFEPlixE+KQtXNai!5S`aQq?|>0?AT z{lu91Ha4ccCKCGl*w_gB{_yE^7Ma)`-}OFra7-^uEerD2bJwD3aEv8f`6R{;K!j$s zIilz9F3 zm$VQyeb_QZuI6;=R~;Hw4^gszJp6)x&FZe^;KWt)$6AY67%m`4(@^}P#&+_+n&~Mq zuE@z-Z$J8|DH`XX#}sb@I)BQBh13m&UQ2-=R#yRqe;GPX^t{|9IdMg;Foqk?0)pL4 zA%ALN+s3Z~1A=e7xDj7k!D%5GKRA(0p236hCK3mz<7*5Mj+tec`W>T!+cFua4rc-- z8z*N;XeMe(c&66~c=Lli(WM%eeohU9=Ml)=DGxs$n6nw=6bK2W5=(}eAgARts&0Gm z`a{PN>|ZoPfJCi`7z&>4mf(FJQrS~7UMQM*cz%a@$ODg08}tet6i00+5fYUWk6mlj zL1joM+GJ3CZe#VKTC8SN+Jca!3@ZX#lEG9~r*x?#s-fy-OiR zZG=xBDwui0sU544lg68az?-@5n7_zPeb$FCZD`A_sCoSNgTDoF1H@=7`3) z^5YK1O+83gIxzM#2{2wzYbeH(e17m7mbxfGD{ow%IJsu8iob1~%t~EQx(Y_sHci1udnzhfU zOc%wxy?UcqwxbrsM@P!r8gbrn&Q zfymvXH0W%UPf!K#f(hmPO}_G*z$T5@vR%4ZeIjx)I=nC(gLmQ+s>K^#8Mc>4$%RUJ zg}@n@)~%K}_KqAv!FdAwSfDElQmquhjZ2K>4ka{7gw8LNL~t@Af&_o|SQM6j>^J~x z`mP$~Y|T_2PN_Lf_FpJ2+xOfB$35P^QeLu8tk^5%O6{)2!r~M5i8WX&Z!hh~b@Z<{ zy8ibDA6Fh+f#W6FiG+h&aIM(jz0;b6Eggg7gA9uO_poB`p+#Y&t*uY|_w4TdEtXck zwDREA*5{N@HTryo{(i-H$;~@cx!E&tLJw{h$~-{Qk7VZZbEN9Goygfu1jo?9ZlXcH z8|m*V#j3HK5P`p?#+?Et(fri$Dw&JH(2f^XtQMyJ+`qhLU%c4zrV#A0 zdwJvAyi(rUZa;6dNiZ*YzVa1l$fjTn>jJ;|6%{nRz1G@Z>MkI}zuH~EeZQ^yqx&mg zp}g^J9;4sZd!T3jikAvr0`~hC-0s{tb*e2P;U&-Y)xUJ1hrk}+gw{5~f;1~V`-YnS z*5`cncK!TlP~0<-{o{`EKKT&QcKCk*uRo{P^z_M;>GK0HTA2nv0DSBKZUl1aY-%P= z^0S1jJ+)k{TIUzbE2}V`Dz8?H<!&um@y@c=g`9(D8Z;X(J>&^}3Cur7DL+!3(u1wNJj&R z73Q#&!WFQC#ZJb^2#Jm0uSz?OTvhN{AwCkx7>O9#uO`?no)`(7#1I#7 zKbwW@PME&QPbv#Ff+?Or$RMlxm1=SPGzGU=yiSAa#+wNP?O?}MpEfXK5yr@VsBaVU zNieUvn9Go(FC&sblnue8ZD7iUb2o`mXtvJoO)@v&tgYfKFHzdSj3Ku!VW-o0aG`xS z;DE#E=J|%~5Q-Y2G43MVs0^s%$6j=EdcSWI3LA)gM`Q)>hTY86Z<7gBOF}hB*;6pI zhwdSxhRa?Af`Ybg0>-CJw*_=#y@55uHUz3m{B#!7CYiTM&Te2v=Bcz(ocD=pYeoX08A=B zPhB`lOUzoWwD?4&Tq>`xIbmytFely#m`>)CuuJxZ!uoRc{GzcmLtyJE4Vn1`b*Pqp z*<<)_sz>XvDk)dP(OKfIL$pvJ3CVFBlD6PzyL5?;wjbK62ekCZd@m{kPS}kg+!j2v zTSH!t)?rmr_9oY(4_*mm2mvnBgcjS4n4+a`?Go9Siy!N=F(-&Z?cQYLpp4TNuP9gu z*>NZ-+rpo!E3}bOZAbMsPOG*^A@t04^he1vEkL48)Qla!Y1rCOws*;{aMZ0QAbvUVrim%tnEW_ec`P+J#3> zq2~geupx!Z7pWJ6)MW^#&*kbDQ-#Yk1`QdDuB}`h9)^jivv;Ip^Z0c7>^wZB_t`P@ z_`bG6zsd*vnBKQsIxN%i02-J6oW~R_Q!ErA!TX96URT2t(Q>u0jBvubW)9pK<%x^8 zC!zoV&6F1R1ppI)!vb&_h6_wa1)ys_otnazf7LQwHmy2Gr$81~A{$9atXS4w>+Bk> z)PVyBMh2e~S4+qjwPN-2MSi|DZ=s0RFdQGMJO)j$YVckokx5-7aJ z_zQfbr;yJ=;=MVYK4!{s%M|z-S0HN~z*$I9`1Ydn{blD-efll_@`q|*yU&|VGx!CF zvFMFu?KLwZ8sqeq%;<^XNQ}E#1R#ct$rf$EnG)so%A$R~xHN&}63N`60r`2aU~0I3 zOnH9pQ+2r10PWfGYdsQ_qn!D;Y-j*<^v5Y{33+D9`B`X}n8R$2<_8*Zn`SFZG5ISP$V3fdQyj`2{l6m9^|{ zkQ+WsS>hMyZ#Y))5zbNGi7A+@j|@{30+jE%Jma8_;?M=0=M|AU9Pq+YSO%guRMaM+ ziwO;E|KhnSoK7(^GE(0Z>XprvC(w{&G=az+xc{3SD6_pHQ`5NM6i2Ji}Dp8@Z>}-0Gl4RNSC=zv5YCk7r^#2 zQsH7FUcmmINJ0zLO`(&s*?K;gf+ISql}>5u%~eEZx23RrK)dMRdlS322mA-$yr`dl zDpa7esfUg&*={%E#V_B)stJ}r- zs{J8e-F=Jq+6)EqG88BA{!d1*c!~ozWfPQ@qge z(=*FqTF{xf%{WG*?U>PZPc!l zA*m3f+2fK0F^rb=Uwh@7-o&5t2AM;e51U?j#k(rtPt2JaLVfc$#O-j9dyuWId!P%0 zP-^`U@Fka8jG$bSX@k%XE+9}jQn%`;Uwoe3ynE8OC*pz>ssw9@Tmy2>+%P8(J=xXa zbGX)NKD`W0a3YgMTsSCjhG)_7tTXvWs^CdOU(Gh^>=!YvX1h>zR+r(v$>(6nIUp8A)~RFBGET)E^jIW-13DBYj$-la-kY!!(1o{hPlGi55L3eXT@*f zBbA!!w{WWkzlE;+x3-$OIF!B*sc*YYmcCRj70}nB0vot;)L`=zBm%qzesD|mnIUaY(RAuo=hPbP3gT`BYdnqz}c=a7{SvyVVEhtg2U&0nhv6I zd_8{#T}9wz@myNWBcC8g@oM-HK3f}uaa1CZ@?1)PZ|BX@ zO*%=(q(dy}VrfD+AjX4*V#5dHAI9q!>96?tw0OWfS+@Vmdw~y5@Ow)v>1OPZaza!b zPZosh2pk`ujM5$(&h&-=?d=X4hy9GU1B(i+@p*xUP8h$*K&{d|)LuppXlv_mT2oZ` zI}1|j{l1k}>YN;nt8ef;`gS<&Dv=x?EJ~>GVH5s7tA%)8KBk0NWRIi@f_^lLAJaQe z0g6mNJ_&&`IE7VSt)ooA*oVz1!x&F1(OzKB?x5m_KRv84$6n#fEIiwo+KSjCqC0-S zXjg$HITl9YJT&?k!C!o1Or(ng+k3%XE#f_`fJxg)i-Zj|Tc`JE4j=x(Q$5x+C&yqW4D z%9$0^Rt;NkX0tfW!R_hdoH(*rUN4~mmK~2`2G=nOOKZIE$z!x2di;uW+6HWC z>I&|>)ppACelwi#;W^#oxTi@;l*QDu_9SM36_UwVa#SKs9t?SCY-}t>+ZwbtI1r6J zLt|r26Bq>!medg=$Tn#Gwy?z?X_hf$?a9Rx24LusBwRA858TbZceh>&*Ypg;T>k0g zn@74mW4-=y4ay9>5VXZ>O;BLn>+G#=n}yPwP0@}7Ja{W7n6Nvqf_I}Xd_71 z66u36ThGZ&S!dA<#NE}{j?v}-yX&H{h{8^I9Hu7esa^&$c{Y206sEWJsGbHDwDe}h zBu8PEl|<|{PypQ96z@I+=XBqP`&tgeBx?Z{B%aIU{P&8LOI5p6g^h{jC+!j(dO}vq zm8xBFZ>UK`D&?oqqy8dG;JD!jm-&_TQmI%%|Lu!0}y zeYokS@4E>uJd#{MF;6a(SS;AchN<~?j3f59bu`lkMKio0M4wTv4}az}48pw@gU}Og z8Ww>jzMrBYHJ_i&WPuQ{F+A3->JEp%VW8@k-F1fQ>r~-&rf4x%7fw#2Oa)YDDUpD1 zsdRoUAQNn;On|ut1<#>eU>Hqs_ae-^9lEe#tY#NE4;U|S>(yzmwQ;8f1tx8u^Pnk( zZ(KLB#-m_=7^c6p2PG@9o$_0Rg zp05Z!Y2IT5VhV;A(p)0v0TpaQcsgLogNtNMnA z?}I*={n1U~XO%-?y7-t#Gzb0keP0uxiMtmfnGw{)6I~?3`-9MtfFVfM7oYfxCyd3D z!S@X>xe{WA`Fv{f^nLi}E%z~+R^*Sd*^Yak=t@aCn97H+8Bnr%AyabHi_+>0vCi_C z4Py!B@gh@}{FG9npa;uy8;}yH676D&)=ER4s3+ca{3*x?OVC||>zQT^P4b3{C-JP~ zOG7J19>2Aj3*^j-^zv@ORB9W=^|_F@f=;z~!7HZwHON0MJ{y+<2ZW)TfHVM99h9m zOy5thJY4Ka|0M%&{HJ9b>@$&a=_#^ysj$2Zu9?ByRa7$_iz}zY@6=v}7wa!}ZcVw% zsm-r%*D|&L)m>1BS8{*Uo&OHKdwtscp1RuhT`iy+~b*Dh}tXd%n#a1#kx z`fiMVdy7E-22a;HIV%8B8-Gu^q{02|KlgK;s_<`$`nGxJjn~@KW-x<)=})(oSqD;ed_Z}72Y_ldi|&po|7ojW zwVaN!ePgC?Iqyy-{4~$VEk2YzHy!fF^gHe%_`9VWH4~1lv=@w;A8!NEfjQ1BRoW=I z&7|R_N}C0WNlP9Mqr(S-@yP) z@!+2{gh@m?8M~$i%}ps9a?m`Teju+{x7ryrGtm4eKNSN)D>iJ{yO(WRdltcE!&Z*r zwP0_+71!Q?Vu`yeFVL+5^tDi0DzCh`raNw7zLRkG0eD)XK1m#pE;59=cwsTPvlsY8 zz}E$CSA3Qnf}@A|+23RI9X!R1jgj;tlj$>gXhPFzI3{Q`PG)mc=^Q!vC`pjX+39I? zFW3MYck+0<8S?6(`+e$~9lWzAlj4Mg?)eNiC%2GiKRe;AcP%ZT}Q-f1wE$D7BCL|7~&l+?BwCbWi1V&Kdd1+qYfG< z6494d)FLq8;1y&v4P%Z*;|`WlSSTS?gPNx4XPUEK)1$%6F$j%U0Zc}tF>)nJQgh&__*`mwK0OC`B=gzKY*v^$ zBUcV2qIV|Z^hk74j1F=W=*3ETeHG4AE-eqp32S6pFxBARl8DNSS~L_(C{7|(cTHPQTaWA-(!SaT3;^0d_bXwd*a0YS@rgnOr46~7=5Qtu3Kc5#6?3IvIuX>* zSO+cn*w_g@0Q@BC-ciQl%Au=^l{8L0=>CAO#5vY4RM(P`l|ps#35ZiFFBaBpQn4@C zl~^rC9+=IgGpDlTq4cAXE3sOXd&3_wmJwT>zJ;)xrXL8_F$TC!&4`4ifcxcw}{#& zR7|lREuTwe=Teh-7|sRi(L{%K(dp5&T-6f9b1Qu(P1`XL1th-rRzR%g6l7T0{ELId z(jx)jhJ!kaRU5{|E33t2yS!R0mP_X^+IXxN%g{lsFTCP|FWjlg`S}@L9cc>M_Zsw= zMtX|?g5AxaI3T>2YD5ak&dmNPyTo07(;mL+xiA&=GAYaWCi?3y2n|{8Gda1N($@M^7+e!#r5@-6YLBSI9wtH?klxnQZ)`%6~2)@FZSpP z1B)C7jvWJ&E*P2N|5zM{TCm;D$~A}|r?E2GxwI0Cn`5pp`%E?NDYhFCPNq*~vg3nO zuo?~qmSO}?o%a)ZsLY+m#|JseiY3sSSKzFH!ZOEP722P@O%48y&c?Ot@YU@l z7~ek#S2{bjxv^Rwyls4c{o9-S{XSTOgRrw{aP1j-mLRX{UZ^UuegLy^s%rqu?GaTu zQLk@EXtm$n-RZ&(9QA&o>07rA2~7bA6XCj7A$ygT`__P7rA&w6+WA3qhbttq+lh*O z+$;M8IK6TA!q>5o>t2+rnC#e4yKfBu(?|$wfZx=C90T{Q0TLDP;4ub#wU?{`$|RkE^oZXfug@wiO!8!faZ3`&Cv^N{^PM=IoK1A}fG#U7bmUaVu{+%3XEX1smDZw&h){0 z-g2o5(|b`d!3hpD_E+W>YPDK{tbVLkvq`yD+ptz^`E(^p2H^U^82-NFrf&@lT*jO$ z?}5k=Z?(2syP1`T5%~4i0s8IIDvN`mv-A0M4(?y$QOJN8CDF`yDBMJ_sDo3ImglAQ z8Z7K{ASCz4F^_lP53RdTI{ZGn&S1F_U+Co&YVFah2ZjE?>Wi!<$5$_{FRfy&H?W8! zq6i?-l7*-q;j_FD<(XOyCfLihRhyirfCEKDX>flld&ay>SYnX<5kztzVjMFU|{ZMhik}V+8PC6u}e3*zTqJSgP z(G6~6Jc*bU6rY9$ayFZvg}Bf_{){&eh2nzUStWQ?evIGOmx?X`oH8q!9PDP80ck2I z3v$q*KNR6Cxvx@=WE5uynhN-o1}rGP@Z;o@Zq`PE-1HCcxPcSKq4*e;xQ1L1Zc{EO zu{fCX%9Rqp1IBOXjf%DW_q$m+qf{n)>P}=|bK_#bzIDLq9)$eLWHb3pYI^z|0?!oE z8m>)HuYm!&F+>V4UV9;O(R(XofHnQDWqsFAux-@qbxbKJ4Kf4McwtyXlnvs36%`2j z49OqGJt`(p>W=icZoF?WlR~MiF+vSMLpeSz#FfCqdZ%(yaF~bci3g0mhSm+bBpo--QzhzJM zm@QsQOi-f8vGyRwUUGH8WGX#3De?ay$V{OjMJyui-PQMri}nKh8ubFxnTKGTL4KC) zooYEb!`6~zQ3Y!-vqyz|RrXVyrW>^7ahl%a>N`0Rkc$-&GB0Jw;|!Baf`4f5%n<16 zv{)ef1wL@KySCcDrk9Ea#~>Gt0ncM{i!NR_iY=AF97vriurN~Abl|&b;5DW^waJ*n(dxYhvtr4Z+|Wszr;ckK3z74kIk_jC1HaO)-P+@=X` zqjf;wc@cMum3`0ySymUfgf71mu6y43PTDX`+@RInEfR8A_0y-hP^i@&m(uK+ODGif z@G5Gpc9V}IINhLRnhjZJl$GNQ_8kGv=Q5{GrE_weK_d#WiP1Efd(+n;#El4*^cxaN zp~SnS>SY(osXigPVdyLJne3j~bwR+TT20fXc=n*$ZeDUz92@hbRMD#mr7?eb(Wfy7 zVt78Jf|_G=vlfn+aw!?JTuMj*p(+_Hej`-=3&4S(1N5V3k*Uj$G$hqaVr&Yk2yM~D zxe=$gh%|!pRv2H>OAyx~KbF$l;<7K|m}cJ>amd2ERm90YsxRVLm$Q8$4pA>8>zg;p z9&Qg+pl|v*4n<_&jw+}mm8v1HV>H^S|KouHr%$_UkJMFQG*PEQTPns_QLbuK!D3au z0D6WPO=J!^AB9?auNaP?&54bp`Owp-f>0nQG(iB`)mDD$rZ>x)vL-e z2vVraGnd>W*=s~6Mmo_N?&c0d44ikDPOLVOp6M`DQ-v}b2Jyyw096DzLfT)D^Enr1 zq`udD)%2n94vkY7O^zv|@Vo*Sb`q(5rD_aE?bIfJgJYh*zWVhGAsaZOpN_zL&bZ&tnL7z<$eWbKpfZ*EvF$rX^&n@`reoO&Ew$t=0)DW7_ zEx=UpdI`5W0~%_(dv4*s-7v7Na|==hh29TT7;CrBHSlQ?3#>La*~6QKrq@ZkJj@~( z+LzQxHC5himZNq*mb+F)c;jJBbQ#Qis*PzZ%V5LbhAyb)bZER?V#E9hLnB=P;EXyp z>I0!h9jqUmCUn4IO@KtCdNa$LN&F=#29Ow3;1#aIc<(P^@CN~)+CKwkOYfq6Cj@AM zdGOmneM92_A!7gpkl4!LkAUB@z3zo5^QrsDgcHqgT9i$(u@b42kCSuf`FLTD4WfS7 z6Nimv*>IEY*B|&aR{0MHo@Ms`pWYp_NEF%IYS%RP6No#w1aq=C{6!vG;Nx(W2!bux zy+3s$(dsjG(>J3qsiMxq1Tv!tQGb47E@SA@YJKzKe$bJ@d5XT4((y>ly#eN73m*|a0TYqJGIKbC z%QDw&>Z5~e#Y0i%eHh)$c)pB>jDMk0rVeYweQ?d|z9tcOfYrx4xB|r0-5!Z7&eCO^ zbS$Y&K2hp8E@v9A`+S_@|?^0d??y*ypwNlfg`9ql--e5B>XPRDnT`_9l-fA|> z^lHc&$LW*j!uXw-enoErdTZBWMS1GfzBlun;8(e zVZpllVB*BV&PyCSt+88uLvUFDcI%e(fj(@PN_8(8{5zuUm+IFNUg@IRATo?MMA5uD z+)-{TN`IJb!)aFm`DBN>fO&Q6jag^%>nQg!z0=$kwI;cQ+&Xh6faLP;D3v93X6XDI zbjxyHtSxPqu>O5}`yFL_y`t

    BBbnifBh~tyk;=?`gEapAl7P^gS|MPtb$QB9kaJ$-|>zF z0&A?a{Ql@5h%L=ul?C$4;i+VWYT2**y*?Gv*L|?mS4e%Wfnpq~^3?X3X|`Pi?c{#V&?9++sn~$6>#`}qTpV^{-xVX`S#dE(7tTuU z!+511$;{>F@CiF!Is&?lU8xbmK8o%4aF=nMtq00tNA(e!sGJIs4=j0ZwOBGv>?IQ6 zCd-)5lQt*I`c6`=f}XX#PEv&YwyYc8fKALUzXX57mlH!Q-915_Zkti|G+Y&X7MRxP zyA@=h8-7<*O;wbvu8i%5-xb)UvLSZoxcvdlNiQ7A90{A7;`qL9{jPwMm4Vr7YHjq{ z9rC-fQHO5D5&pX0l{?7D;jn&JHhuiAbY*QcUr){UcXf4bG+W3j_Ohw_BkD5M=Y)#(ACzew<-$Y4(=$?9K=u{%e7F>sTvAN6UOn1>5Td>(-`#%F1&kNs?cYt$1@H0nzN6Zx93#H?i51DK7F2= zz%A}s$K=!aW6t_x*6BEuQgmtNpi%c*h~DL1;JqdmD|AolVvh@4)$I>LC?elYWf`CB{Jr&9lDdziR{Bj_Cq zb>5kV6#7Tn@mxy9u@uBG;QW8^`akHe^MkR6d=# z{qX0y5T2woEDRug=%}@O7ZxaY%h67T52D5B=n<+m(|(Y~9r!lhaJ*wM+{;y7Q&X51 z=0U5xiX9vELU0lgEzkm=x83>Mk8$-MD% z;{1)W@v4`Y^^Hyvb7I#xf7{kw%ZX8EaRagJ0^ff;F$L={GTF&I87>URh7ZO+jMp#H zU-9#4@ql--Z2y(_f}O|_Vi8MjYd(}rCP(A(#6kKWUf?>COdd!^A3mMVr6Cvsw6{BG z9QHHX4lF9P#^(hZI$``K1GP%?P_~zQZG8oO4$^Jc!79Dqx6(?T0bScxdAcVZNu*w* zZwFc>lH-F#i3EJugul;fA)c3yDIpedcD*B}jz;lg4-j0|*~FG1C^VtqtaX$r82hjp zWf0v8J_cIkEBYvsWedwlR*YI1&lW^fCxB>uqV3O0t&h|14Ll;>h;Wg$f7TOp%E zNi|uTt6Ux~zdtV{>JKk$ZR!E+?N_&6R)S0AQUU)EAE`W?W^;P~JuCJ~xl+4lKS|9I zC93fe@bIOT2e-EVnetUari5+zlIZoJqr^P?+1V_14caEQoSdoYb~HNMB(IAMm(( zv2uTg1~qOT5CvKYL%1N43-OIWa0+c&)o@Z=QrjtkKebVilWEgTps*lu7)%m_AuuP1 z=cykrHwf`$eHznPf+wmJ0!#HdPKH0b^%A}`;%q0fcw$iOUgUUD z;SEvs2vKiw4@?Dbwvt-}8_+!cSf^=00wPC#gkY=do%LNkBpn_Vi7M2kZICgj`{Xfh@Ldt5f`Sd;;7%w}u zwj#sQ`<6@aepLi4L%>8P>qQIJ<&ddz^XV97l1V@dv|P9}U__#HEUFY6n}-UhmBW-k zjbB8Jk;M2(hcdyc9qUZB4aAi7ZOQ>E|EM(Qb#wS6b(yhWB3iDJl+KVEk_44pq+D)H zQ$`;oJB^2&lw|}Lkl-B)mwe*_0>FFWBBZCle1UV54=@V1Dr95)ua{>)ZX}_%$rx*s z3_e4AU=KZK+4j6RwXC;T41n(86o(Uxb2%VQa0*x#WLbM2XwnjHX~RjW+(ubbCn>M< zIP^KO#~YGP$bt(okqt1fhcK*uCbsSfu~^1P{nm+Pfv-2hZ#fy7KI!~!BR zoC-m$us)EdYl3=-32G3LKr0gqpxi`)xJ5VeOmIo2FalZmu-4*sT0$FZNBfc%tEUST zUOgY|sxnjM(*O<3Iy-*>1T)f&3XCiUJz8ZI^^D!ZR1dN+^PJOTs`Pw( z7_>`hGig^dVcLe%Ww90|nA30x`#04{x&Rc`Hqkvdxy6u*E4artwK&Gma74DT%frKgOz54*~^9xlv`RQ zjML_Ke#GiqQ9e#;tD@cEz^2kIk^rs1(8mPPg{TYA^xJp}9p8Z?-17%p>95@N6? z#C$vB2hsAmfurs5Lt6uAP%nZs9-|I0A;)_y8Fre}In9(BM7pp}QDp|qLfK-e8r?rW z&ekN1pG=?1WN!z{8`E{9GUQ~yp6D8!cZbNbXhEb9Gs8~NO$qEj6Y8BC?b@9BCpo|p+MlLN8jS2H<3Jj}d3Tnb#9#=_ z?ZBM6SUBWftJUEpL;V#cp%$)gBlnBe8icch#DV;R$QY^A1Z+jyBZq>qsf1nNPTrd$ z$Y0<&nPMjYglB2Qj&bS7vFlKCZnUr*5vb#oqZH*ff0W;MR22evLM`V0j$u)E4=v{I zsAkO<&F>CE^#+v4+fC(=XbX;_=TcL8qb`A)2CYx~wQi*KbV4};Fr{87h~z?iBM>Cj zL|PhP>?8a;8W4U#5EUd2gGbgVL`^z@Ov$1~1V~&-@IQ`R9)*GUB+inarWlDdxm)z2vlu&BZf+S>;y+W|nwM*b& z-0#prqLDu|#d}8xY*e6+_Z4Vo!zL$(Lns$v+~0SH0*z3s0;d~$89S=}?kY4(X4z3@ zK$N+d)o96MsP&WHy-^pT95kJCp_OUB){S(}PV`v-rbM_PQiyJokqm#ER@J|oP}{%A zP*Ph2$a@|~HzXl3X_+t>{{JcZ&UC#Yb5y=+K z8>LfiimV{0f`}nd)Cn0S>k|+>QSA_5(%RFXrjkL(v7OVae@!Ap)YO-FY4Br#;#FVL zad%&@zSi|>gF#vZU8{y^-iBr4*ioGqL{-BXgx-J>QPx!8al9&uqD!#$MqQd=TvmfV z1gQ0ou@t&;r{vOQfzoHRl9JCU{7rnBw0w*l;-Hy z-#0BtLMAa70&~}u$`aP=)wPQpFRyz;`rO}NN#ZY={N-o}@n$rHkM$My&MNHvegWB7 zFl?})tn5^~=})m~*Dhf83TJP~R%=c#`*RSTbbKjg-;R#Qka?T(mgI0h@z5J}>G(*8 z*W0hwjfNSW&v;i1@3og&y%Q%>?PNU~6KXrZj81xd&x z218)36U3ACF(TXxo~Tj?Fl8npEe$Z1C-5G$N9!;7p|~`3oqg`#y=%IHaldT2PW$3d zO{I=#W?sH=GHsfPairr6bgV*k?TT=M`0h7Jb~X=w&bg=cg6p-kR9*=XWnsB|DUz@* z+m$tN&>o3C_uO+!^{O37fJ?mRNTq<;usHG=oQsfH{18M)L=&-nc!#H0;?C!uBjh>u zOn)K$0(!_v#NLikPEF4ej8@r+GM^(800P2Uh(7m0GHau2N!KjUXk5WH^EIzJl}BVV zr}E(ZO}d?TywNA(@wf~Y32pF2|8QzrhA$QtpJ3kW;X?xAv!hrD9MdwLMi-b@$eCPb zCY5`XJd}PEAmlrYpDrw)hm?y?u9jh!`1oKZJD28%*Fh?BE;T)$o{LBtEky2)$D`5l z@1>i_J<;dV(`h)l!xf!8kei)>+{OvPqgV+UB_oI3B?U~HY(44SEhkMJ!=!VmbLlg) zaGoV8mtdmLg{ffh9~nigYH^=iE;FpU(R6Iq6Bjt#9GC36$^jua>y2=zW67uHle053 znf&3w95`G(nVNivA`$oG6{k7>sn-x z#o{r^VtKuUCn-gXRe6Ndfb=$wW%KM3BT2{=lhv&e%bgE+1;?m|;JY`UBeV|2eDJik zF}TnryN(d$v?i}ii)Hg^Y_4aDQo#k879&?78$I@Dq!1$uPVl)*`e9Ot$4BwpA>KY9 z1|C(l0KT5)z)cTp(xc>5Zg&0*Ir%6lK$Css%ybHRc<_Y?`ZPRe2YKRZ;?Pxa`U5#0 zS{dZhfN2A?6e>Ut)lL-9{W|^))8ABfianDg0Y~8wi)S|)JDzZd9D#tZm@n%_%bJj% zzA2xK4=*>rUZGKb%8B^L&SS$T&W0k+@BIJly$yI<*L5KHop#!7vrYSb z8ShLpNt?FcbUNG4&UV}BI$yipO`BPdn@p$EO|$v7lWiO9Irs0~d*6Kz4V+;jiV`AzYp-JhXvzpaJoFF&Wh+TNadX8oDYu2;HzT_i->*wP&k%w853 z7?lbxHF7nY4n&2fd$F{vEdI@ zSYagd2=ivc@#zP%(^<6aXR0o$TbkJ%dWE@=r!JKF+}u)~%+KYg&yuBj?O42$ zN+n4>RRJAEog9HkT-6^MN|K?a{rvi`Z{ELuW)@%m{_pSsUfIL`k7D4r_E#!H!C8HH z|9;HiTlrFjeE!NPQWc)Jq9r6hI4sm6dXx35couM1d6>d)8fPz+eu= z$~xr0vUm%;Emq(S6F%!s1B8%R#Atwl>9eFkArgu4ewUYtEegw@i!cws)dqWRG|*Kq zMT$|C#yrew!5YN^Sud|F+u+55y&RWij^EcHkQZZfPPf>kP0B5Xp|66IKxM-0@80O&E!;~yX5KckG^NjsG zRB8Dmw*f(6p}EUI8zvg7siXSZfhM&nT($4>$}SbG3WUA-oW0IN%q_!=EPDjJcX z14E8zTcLEo+$DZOSgP3+7^sv#=$1*nx(t5QVYDe|72nua zzDGr2NVP)Rhoq~ZKopT%i%9pr$ZZGng0NkcJ^eP_Z_|x_n-1#jZw56==t}`3h@DfT z`m(1T*&{o4(4t|O1WEJB4??dTeeiaID@D-;Z;k`>(Fbol1Rfh*N9l5Y-DmuS0dj^n-tyJh+7oXn}`N) z@a@w_p@I5H0*b99_#_VB-_;@qHGxvX-M)!~O{lcBbwom|L7BCkG zqxSpX4Z9B?T&eL>u;2C`?N2?ZQgQN2wz7IqlC7AI!~Do= znN<&}6o9 zP2hOq?P)moHkE%Q7Zb7hIXHeI4$j{#)aqbJgBsRgMZikX>4}FPd4nCB6HwXi@-Q7c zTX$02*kL=ZQurx4ASM>QL)UE?Q28)gJ_)w3LO+KZPYL~q$F<4wQh9x4h3;jfOOben zG?`-P^jTJ+Hdb)kBid!*c2y|qnVFVonL&DLrp1=oTU8@1{AG+;Y>8q$<(OhU#Ud?> z(1Pgk&)m7(bU{1adCLk%lyt3sNNsnQ1XAx-5!A;N!w&sLd8Q-v7v&d?eFg!O zCXrQC?KE2GoS~rvZ|$`M1-=JW3P4_eQGTp@8)1TQ9EpFTun8Tk;S?c#=r78XEegqq z1l!A`iNt$b-7f)!^gv{VfNq=O>;VK3`6C2S$B!sAbFe=0h8@TPEGcG7AyAz`ka`CCy%vb}J82q@O?kU9s2T zm|{w{zl6|VLg2?$eL947q}GNAjVjLk&14H99kk0HR4GWYLN%zb)wa@VcV2n@I&vV@ zS&?A$p|8Adlkys+1@BhUL=s%L+zf<{l^%#&y@2-L`Z~T1XM1@+asMn%FP0hmYK_rO zdLYY!aBP%(;|5IK_*-b-s7Y7Ga{)x?0l5vbZtXRS>SUDAgDM3eufN8(N7ndmlEII` z==d6?eeBkuMSpRV6STi%vE{9NmZq_lpeW5s&)=`OD03_~cK0!Vy(S&LwU06^Xm>0h zD2~^-frX_?)m^?^zVxiysG+Z6X&R58VNA!bf?rqekxg?sEY26QQ{1U|gG}bmWap;} z;IJ4BE}Y4M(S?Z|Sla_{#R&pl(B{ui;^D}-TtUQygK%0du6E68Z#)0egDUQPrMdz^ zk1QhIJ>xo$D+0tHK}r6=hXLA0HO zgV`*y`2D7MfO~rg?;MTVIp1T7>nTD8=|A|<@1fx`HhaLhkiKOSjG;rKI!>y(#kx!C z#f2641Dl1o3Ujap9@uJbwGM}5>lO6H`h0O^-K~MS9qpSpw5Dq$5iYv{7i>s%y!$-}MAfxIc^I!Kx>HD)-=1xub)FhlhtBo;m73yr3)$M~cJHdGmO9IErcY>bJsw~l`r@xhi zHxPrA2M139HQ{<-xxBVsKR$ZQ@1%>%>{O}qOaP)3naZEb7f8x(+hIX~ zcLKoB>#CUQcCNe637J@5UUlPSD3i(j?VI5o{ymQ`3?)eU@iAW3gUpHA zYJl==CLctYNTiv1fE1yH7q!?}KuI@8K?`lf#;~$=)0WFI-IfdM*|@{q_M|5eIa=4X zWjXDYWbeA(6x4Omu1b^3TFgUdviT{|!Lg3bXtz-E;L$_8sZ(49^rsLps57K_i2ihw z7bp5r4LA@oOv#wl`*MF5DHMZ)=|q>Y8?_=rF$k)NMW^Tl-F|#H&h1|fRvEU;AU;9g zqVM~DRq4_Q1(wR0U+LPsQ%Tznf!l1Mr%=*$AQ1g66h?eQq<0(vnFb` zV30YMAm2EIc7lwj=nxQkN-{ZbKP8E#gf*$o(JnAkV#(WfQKw1@SEh?cIB=#`hz@nM^X1PG>SB$C5Bxm`R;X zfyq{Ug79Oi%+fYNTKE|XGSqZDaRVK>Y2ZcXOuq^C*?|gxmWr;d!pf_nzFRF6+hJdJ;~rf42ya^z6$P*7fuT!$z*22+%(WhVF}b#DI>QZZW%&Yb#Rp zwWnJ_t6uPNMUO@lavZho?7W?wHY)D@h9!o~+s0gC5QR*pFmyn0IFYuIU7Deg1UD3K zQo^clD;Qt}$R_RkA_BzSqL}NSf`PKlZ5U~l=?dQ$5g_gY5;o@8!<|tsJMj>!j3OCC z?G$Dcqa+;xDhpd8i$tEx=_qGknIb^kExGESdd3$%q?tm++*O)s$57mR-SHaiqjyW+ zTW!4i`U{Kvebrs9K)_;g@fi_e2p8O6e|`1gRd+1h{+v8=As%?r{}bMS>-C=zq00Ra z*mFN>$?Ju zE~DZNt;WHq=qmnO7y4%!SnQ>9-lEKD=iAr+-RnOG*>~0+{vb+Q^0&Z0VaWyy`htjZ zyi?m)R8Pe>lBAI&Y_B1{Y$QNr=zHkd7WGtT=hKtF1e)?jvp1BvU1MC13 zui_DLkSU$Sb58UZK8gDuB0kH)#wd(KdYKaAU?9Jz zlO^^pl9MC2D2L#T&F0QetrAw?30W{p3DF#g!j5Cz<}4qC1+$;^L(C5bZ-tNtIV4%e zZ}ij`-=;PJ^#Hg-FeR}fs`vh>{LfN6eF9GrvpQxca`HS`*U(m1$#xL2M;t&>2&_n! z-9%Mrc3b7)?Adc!MD5PC;x1HT50R|j5TEzSuf5+8`&5lgRrkmlJpP-Xt2=xL2kq>F zItl32bfrf*7H!?k04I;<=kn8MNwr>e-S~0}lpp-VtuCqp1o5~lZQ;i_og^b9c?{z5 zqkvrbsn*Br2}gNK^t&uGfrk$A=|UC^f*zEeBx#Blx{pUEM&QZts(F3j1318XK1G;V+V> z1(+A_$)MCLR{@uHL@f>bzI>EeqK8P83sk!iGD z#k8SK1_yv`gG@(_nauHY0#f6KOkI>KXYl!u&@C@kO3UTT)xuV_s zJp|{Deh(4R8Jn#&wG-CwA$DyKv75Rrjin5=>1*0Y`%7o-Ip4qf80cf5kAdBe0Wm$l zRIeS28zy4=KBmnsp|j4QBOIGWTi=cTOvG_EUwe(fb_VN;Oei!W2g`kz_)*ZO$rSUA zle07D3A19A|HNLoQb#tb=D}*k3Zj_eD{fp`D_(XlEmqdcb%MrwxANt&jUCISgL*`P zb_}lUG}DL2#t1y3L7v0vDj+=HBbNp5!7m9kLK#ELn=xuJ*|T_wRyGT;XBI7Oj#HDB zhOJC;cmxW0_|PG|O~UW#T;Z|YA-s;$U*qR}?|WZ+pR{~)(}#IMt?72FV8TGK@AZ9X z;98dzis7$aZLna+j1}y(rG{;y<905@h^P!R!gG2bd|xBoEtZqO$QCn>5TpFyKu2mEc|UNzD4^AY)k)Ri?*bd z#b3GuQcH^byi&HP9t{dDUs>x{(tGu9Szj(qG`;D#Vy}oxx*9rr!O_U-+VYB9S*tHs z%9rSB($G-iWbDugm{7Z3i&4!PG}ltm0UaB96gbr2ztSgT_l%@cX_^q?HdsQ)=6B%j zLp3lW&rCp_vD(OgLRzsG`nwj8rX45i%^(7)tuH`-jutJzrUmPHLDxS$@z5jThV5yl zW>+XmRC{MyX&yjT1ThE+1H@2Ok1OZLbaTw;;>9Iki#=AVtS=DmfJGRw7CSh}YH@=a z?cknW(#bfH+dC1S(NP@uAP&H)SUNonyH|)FB{4G%0S9ENBcr2f81y6n1$P}f>{GWp z3P@*gaK(^%GIlyfW@hOo!x1oHhNMxypk5<`#+Aqz@nQJ$>HEi(^Ek?mnEnNQlLWoWbvO&fc z9e|3gJH5BlbZlkxpi0F_TR~e06QdwCi~p#;_?~aUEi`*&f!s$cOF(B#xg+ahpn~n>{@k!edabjrE)*bp zL6Jj$Ygek2b{t2lludnvgtyF&hU3bC+HII^ThM3Q;B8B@Z8*=C2L%H%VRLJ8;tghK zPR6KVckhEf@g|bUlp-KfhU75JBkCD?1u-bp_nyt7;Ha7!dG=SPHh00L8kI65WMTZ6T&Evt5gqylE&j2P_;D})1a1WbkAe9)GCe;vC5y`h zC#R`-alYgNA-Qws3HM4jibfl_^cK4eB3Al1gJNTpTMqNXc_J828y4?v5#7Y%ec|y_ zoJzv7S%Z*q9gm|S88pU6z?nFso4s7W_wpOs_9-Yb;a+eAZoyiSZ_6rJ?LZ~X* zLZDP+q)w1+^?l+YR8>HG;F}Lc{{DLuH{V{ltu`7#ZjUk8xWXp=_b8Q!1Xe}!KCUWW z59^;)Em0N{>ymGCsJVt}grg)e>*2Tdu$2CchpZfrcRY=7N-T8p-Spd%$kY#u;G6|69uou1216u^D7so$l!gI%HIWKU1!2sM=2 zP;|lB{8`lhs?fKeDZm3)A3?1Ho1Cy`f0~rtt4E5UDWqTrJ`|~$6yw$M*r>gSAZ7FQNGg%kU;U{#$LP_Ls^??Kg)6p!{MIt{jh6cfZ(O3&+Px--x=)H-E;_iK+h>ToYHJ#k9P6NA)v#oAr2AFn7UHKO6GaPdf z>V?eBu8)fccIW)l7DMPeuJ!!z&5tA?B;9DE#`VX#(QlE~mhNFnZS5*9`Ll>9?rM~F z+LD^Cr!5i+vPd=se6_+*gNPEV$J~tQQ8^klQwaK)0yjo6xEX`=%U?O%L$50z%06P> zz-hHe7FH??_y^OHa?Y8omzTj>AGkmUzlm`%?+%;KSL64m6W|XyeL`Hr;^D-J1nzLg zIcUp)RBv{Mdq-Bs^#Q{aMe|AXZp{H#Fc6$Z}0dy+w zHeA!%Vk_X)<~PY3qKfKW$Cs_T-N^-VX2ts9Mow|4hRjlB1Ys~byFlK4-6rFx5 z?-4HK%)oD31X^iMVxCslHvId4I^CxcgR^;rfISN%R#{jeh z_-{5k(IzdQLLvvGlI>S)#@ahFVmq-z2@ye-2`n$zf#dR4O2@9rOM7twn)WzFVp(F7f?9NcC@+zr>BM42 zM+>AwB&l=mw&7)eC?7my<{vOhvbUah=?|hjiJ`ZLZNp4|DBmB-N9*2-p!I-a16!_i zZ9~~7uIyTHVe?9y!2ScY=)AZ3in~}Rpuc3NaN`R%k(MUe$w@LX zGqrGT8g^j7-VijWBa)G!QE(a@lw=-~ERxw=c1nrwj*bQ<&=*SNn^<*uRfdSwMs{-U z2K(@7_{?3Ed&bE$Z$z+0d7b4EYTHUbHTId-*RPsU{(}sFgC@R9e#D2L(%#^O0cf+U z#FoO0FK9nW!3#VZ3sUAsZa_-PVR28vCY0;wNaewm{krkf^#klgX{T*G@ByKpI&X zJgCjzTDFMnYbEf(nt(Hn-nA$PZIpp5Y(#{ef&|QhErW@(gnDiUx{E^YVgY&-XETRe z7I~L45-*OxcEV&F&#b5q(hd7n@atY&SaC1az`6BmaU3^u@-2*fQ{QT_R(Gp(2PA}y z5An_}?YVOI<#7hKCmUVcY;HPx4&a(0PZyt-rK2zG#b@Ef51ilOR=l`-?0M>Kn|_;} zfxUD3SLVhVz6OTt2vtsnC+>N?hraLUr zz8&s~mU+YR7|8pc*x?wSlmR1dtl&e36kBWe#7=8pPjJ`*48(DJa1UbnUL{yT)J9u& zx`YMc$W{xTyo-o5GT~2zUJ|U#A%A92ga81GWksnLeCM7jlPxE8d_{w>7CSRLa}GCspPikVKTl3SPOiDt z3T^_5qkfqf*4_ymZI$1_^x`PIlPl{h%f&KSyX2-Q)hK5CbmHAg2I|)lTAY$Ll^#te z4k@umM-M@H+)gA!%yBr=2!#rj`ii+yFue%sXRL#kd~|eN4@mnC%_?Idz9;(BA{^5! z3{K39&1Em3xqkZcvi2ry`l~Ut2wHUQW#;9H86#jOtSlq0Kk>^G=#McPBr{zG{N;(R zXV^w%UPh+^a0wX3#`a}-e{^`{a9el@&nk5hvOSb>Gim70U)DP4dzI5Ai&a&F0bxy5 z8)&CO#o^NYLO%Bxc^(dr$V0RB6r2`010ujVNL%nRe)wPkP6`BIrGDD z)ru%5jU#%NlP#a9X#=3Z(j%82kcX&=2k4xw!dopWp!5#1g^3WnB4XWAt|bUu&Tl!} z7r~oApT?H9(gD4;OpI>O7>!%Nn5w4BD&;U1+aF1WmSES-{qKfqKDY||g2$Qj?RPI0 zVN5k%d!|@*OVknf>tWZw4*BStc2UNcAxC!TXteM5`?vL3M*o}a`?_aLmYX8$LC${g zw-6#mwryn5gDM5tZDUaNpuje&YmIt~*k#k|E~d8FwCwINq_;~v*TLEgXp8!>+)&$q z;Y=@4AEkxvR?^5yggxwxA@gpKCahNaH<1H8AsbQ6=+-U)V_X?YK0U3rSqtn`BV zhRjKB2mKvr#0aOJ%`ZhSth)wDa1_UT(cJ87drPh9OU`JLv-|dXwYIohm5;t&2zIYE zN=14J7p*LdKFM)@z3Y<&k?0dClBRF|(#~CxfZgeCXT8=%!}|v?~y)5)-Eo5;R|0d&GFsqH)&R{U zKTs{XRTq|?l6TL84eq3K@IIJ$_DpnL$88Ix$|Be|BO3{B&kGEwJybZ%CfE5d8s-p)3 zu7s5;-q@xp0`H_m(wL;_h5cwzWm6z3I){ zqJCHscKZ|t9Hsl2k^-_f_|Ol$eIO-p+cmMbd-)I$5Mo$Z5gEe%@%FJB?Tq0^)A{;S z55SzekDYd4>cJdx>zjBLv%m5@LFXP7zU$9c*Dlpwef8C!g1>FQUfObrKaDxKsgd|q zoXy2qVSe7S?qbF2m8wg|N77?TsE~otR6H4*Kge^p@ZL(s@+7UI8Her7xsMP{)B~<1 zSX5Pn`1<%9Gw_FmnFrWHL0FhKu`MzZcl_E4Qy2%XR?!flgBWqwRT_bkeXkg%^a*ZS zWrQaD*H8DFgH^(cW-dff_ zSUg}hlKVtErFmPaVzY&CuVOJ*JGwtq92#=TcP|XZo5k4tQjDG1Pc~P{#LtFYa1Pb< zI*NXQCT6D3OywsEU_$5o6nJKW^MKF^>gUEs;v3f;bYR7oWxx2foA&zKo3>{CinW1( z)v&9LeEL!Q7>I;{MR2o{7h@02tPJfne$d*XXo{cL-Ov>NAA1DokCbVS&(UNJOH@k` zFT&qV8fEK6u#fFzrw=f!9jGiZ{Hs?g2U^3R%tU!$DPB@SECU{UF0HHWf#c<`R~Ewm z=ms3?-{(bOPpvaIQrHk<3-glUSN^7xSVZx_*T26f&>omb$?ke8^uVNAnWAwlQCjKx z9co*O31tWDb}WK(OJTl)6c^xCSBcP+4%L)q!N$Sq?8GBz;0faatz=wd=i4#moKL;- ztXp2b=EiHwt7|JR*v;9N+`0(bUPH+CAh?^vw@%O1JK&-nB9-2T>isq}XbOuRB2333 zs^5mh!J}=H|IRHXvOl8rh#I?{+6z5wUu64D0d&w|bz6zLrP`3LRcdW$PiU#TybT$? zSMK#&0PNVY+0Ee8%()|pR^Np~oLkAD56g)9h9t%2JGUZwOLw3KQEnmW*{^CV49vEQu-CtL zQ!LtjHZI8CNQgf#S_EHY`e^zHBtJO}*HLZL zFgQ>{e_yk?GdXZbraVsM=3ugxhqD)O*O{B0&7PjhC24G5C=jyVX*wXsGNgYQ?_~}2 z`xI9wea*(#T6THA2+i9f40k!ueeiZG209)uS-K&6f8^<2qF?etZl&J56?S$jE>1EQ z(fWD|@q-nER*@n9Xu1hR+!dP5eTsh`eYfgpI=+z@1IOBPx!D5x*PbEu(X`NH(1WBA zee`cHc+Cs0+FXV!nOZ~G~ z!GmLEmHK@ID+B1P6+E(Xr>w&EK+YDJxhJ)O_Bij;OmjwlL2t5Di&%(}Sd1#WvDnGj zgYZ{`KWa+jp_6ambI>0$UlDw7@)&A1B1x-kFezrh^AK4%w>gdo!>mfOl-S94iM+i) z4~Pbcks<}y0M1eht=n^=NafCwN*rV-+QNg95wAUDfPr33e^^%djpDtL@oTAq$T9$p zv6B}Cvdp`V9xKdk5#Iuw2aN`!3T z0cbwCHrrrm?X2wBnoy2&hr?MjpysSH0UueVP&)0S;!ISMNvvf3%$VNA_)Uj!Z|gU` zej#;^zOr+U^gv}Z6u>>KzrogJN2{4po!cE};B9yQ^}qnltNKKv z!M?4%cfGU*an=Y33yjQzukiZ-Tr=~9+$`Mx=q>mL*MF*i^>%v5O~6)t;>N(8f5|=$ zG_SK0aPSfGbFZwkYzw(+fYO74S%Y2S{?w(%X@Kv=6m2kbMpXP@4%k}g#NOh zMdjJ@NG_vK^K>$uAZyOPx;rqiI01O85A)HHb8289^>I9+*I0821q`r@pzsLzXpewj z;QBUpqrc~Kn_w<}5k_4N7Fw@V-1qEr0E?ADyz;{S(!|8Xe}KP<5;!PNAod}?q(lp} z-$C>Ky?;0`P=D@OcN%tqbF}{%W(0{}c*?z(k7{NYMTw^Y_w!J<_p1@GFDyKhY0@0k3#ew$NTw;Eg-yfij#53qS=x7C(r| zs>&uBUChYg~EY9fHB_wuqxk$^wuI>5mj-k&E|CnEA+j{ zc2M(EL3#34O;Lymc#FV?nTN6$V3h(N2M*F-tjnfHcutf>1auJ~p>cKtYcfIBBL)>B zqxTF-DkvQS8C2(`4j2^0gq=Yv3WFk#g)rzjfReG{4l*c!2rXEM0>+1L8)!oweaIq@ z{@*)kM%yNj+9mgGTqH%6N5SM4LQZzV!SW~)xxvuSH1NcB$fN7cV0m=qN!~=bZc(Xv zLiX!DxxQl0_5b+}dw4sc4(-X+AK*^9jI2vssnRg{)Nq`GEs{1G!2P_z3r@HqQHHIm zx(tW}fx2tKfe)pPeFwBd2o&pk;kMm!g}jn;#f>2R3c0Lv1!` zD~BJ^Q!~h~3YCMS2B+sJAXn6G_d@{GGc*|F&r@6#VHr}nF@POAmc+VYHa8Aw8cj^( zlkc}-Qc_!Aji*`NQMUdAMw_}4KP40vS`_LW0|T_b=iNOk2jKPeg~9w11^irYx&V4- z_4}pFXUtxQ~x{89@t&2HTKD&X5pQq)OFLIT|B|&iIpN^!b75GTFXXdRQ;)y5 z(Z~V0aF#|@as~$>kN*{R%gq#UZI)-aCMJWj^M#rG7*2l#cWaFCu?dS2HukO6`MHzR zzoQIn7-2qfKp#|tCV@DhtpE$B?XY-_6h=-v*BwVpbBHL4(g3*m7(*Zb_+{&a4`$jx zjMK)6<%G>tX%h@l75dw5{_z_i+Bcun?eW|HMz?GN9|g=OS=xd+pTwlERA9ZfYY{BK zvd9+$9g%zY57(9Xr0WA!T2uBTdpT$iq8m}WWHcn3%NAJVZwxS$stPN7{Nq3V1IOz@_&|B3K&Q2LdL4!z)P$6WEL=!oy+ZW_zd*jG!Fl90Kd0+oshth z=zGn%KCJp3Y;0$YO|L244DB|=Oos{#VO7mKO_&ZJ8{BL%8Z;V!`Ze0={}ZU8((ibq zS4Qr;CuW6)CrL~43!c6(F>?-dGSP8;T_KgF^CzC-=!1R@<`=3=<$wm3b$)b!(yGc7 z0mzrnb6``7Da8PDQX(<%3iExZ-=xb%`)T98^DB^CNEuBuaEforCceT1 z5U#gPe5b;*$oP%M_rhca-$-AptXCJ^OUuwk8}8Er9d)HbAh7%z{e|q*d~S|OhsOIU z8L=`GElHSFt5Qlby|m!)T_%d#{uhO*>4l|z$qKp z;78tvA}7l^Z%bO+%Qme|DK6`)0WLvyrnS9sWqqBpkac}g;aSdnD(Yb3>wQhyG0X~T zQHoxZ=mq7N_FRkCWzR(sBq#1Z)%A<@daw;;;t^yX!Sx#q%}E4)-tPC9ZkA)Wb3jLqiq)04T2gp7?{$WF}9pBvLNoV_eA z*gYu+RKAC2ZiXuty%O(_9(B*e^bs{Y;8(*x!`Iza^OoSYA0b{LrONukGsP;*&okc* zJ!(-GcNZ>q0Gjrx(=tV$d^&wr(msXaab;m2uFO3bdksJ}<|Kk{5ED+|^n%U{6MWyFY zCF>Gz9cFgEU}5 z@lnQxqV;qU&l`f7gQ9N>v^?jSOeK=>5&C;fdB%k+`pO@q4^Yhy&uVdeW_oOJ{ya<~ z=EU66YOw~hA!IIB$B^+M2I)!VI+sJc<)jA38K+4K%*H2%2ALU$a&gri9|FL^hC@KE z1(qwN_yhc6Q`8I>m>+?qH+n8INip#dEaVcJ^{47-$eEKJtKwo6&YT$=%ud0So3Lb` z2BQ$uSpnvAE6ZbJulcV3-50Xc0bdpX3?C(UCK1o^;1NcB&O@>Fp-)kuIgC<%dLjw) z8$^u4#Q8_Q8LCdOb*waCoJN+a6>RGm{dxL3IsH2LtI?g&1p5OtBIA z>S+TOEH21(k8r>vzkk>QDh7T0#&z45Pu=*85?rp7i};7NXQFWEekT0xrvgujYJC(= zj{dpwRYInO-FQ9tY6CGUkv7!qwP(X6(QN+gLj@r{2QlU?NGJ_K_+lWb9rjeIAo8^m zoqpUxL0+aUGl^0o0juYq*K`XO;@z}y<3lpN{=i`S1Pu)L*Cp%IDq5i9S5|Tem>y^? zQ6^eJMHi8fgN?v9z?t?>VD6&HdnKW;x>=FqM}@BY)T)0(0@Kt4^LFF=-b9Y)KSLm)s3Fc}Pu@9X_=@qFy<8NrJVA zdk<5S59!3o*r5?pDmH2{(9TYJZ*ZJ?D*s3>b_VP`pw%ed-UA+nMm08e61G||)ao!% zo=hjRrgAr`*b8%R!!ePtVj|C)p$#*lnRAO*swKAy-ZpWe&NGJMS#?Wo)-n^gdd5|9 zNIjP;z?A*sa*2$S)EM0$VN1EVNK*02i>2YzaC10*f?K_~hu$$mu8D&hzILfruT)(! zK9U~OLSKFL)t`dD!0VIhm;XV1kK0J_C1BSpRdYrTE$ zVM3rSGDhbf3n45*0B8u8+CX57jHAA*&q@o0;D?k?w2f|S%Tx;Y9@`R}Ub1I`D<> zz>^_~TD@*7K6X-4b;@fJxt50(B=L3~z4FReZ*N73S6=B9#C~(o+PNfDzc~O$asA8e zxI5)FiCoJ=mzx7`Fxx7jEVX*(nYJW0o=>$P7lZz#3=iz(WDN1}^_6hW>P;tn-Bb$OTy~cELfN3i69d#`zJdGPeTF^>wf_nJsvn7`Qz^MmO)wl^ zbW5$#WvzNT6>k9l<}QL|0Wkgv5Y582XRtCLjD8l6Y$VCTk&VGKvoq&_j$qYtjug46 zQ1-S!?S&rMI9WW>;45TtNOAJ+;sQsJS$L`kg)f+eGc%+|8sh**%GX8}i)g%!mfWS{ z`pV@?tNzAW1Qb9HoB|Am%gU;yP8wV)G$XSLYhU=H=rK#|V>E9qHY;?47YfjDl8MO) zSYdWA!%|`660A)xJ}V_TgnwL_$h~IHQ?V&$H42a6O>Ob1EH*6&GfvSW|D;)x_U`5G z1p_GXzwBH0@nQr$8Ix@xx#;uJMmm4p5R>4?n=Pgfn#I4w1B`4!if0KvgOlYgV~Ns? z+zlW#f`&)s8G5Ma(W4ReBP{tJ-7pCoQt0X+Ch8-RV_r`C`;jPP&N{H}qZtc-i%+lDkzQ zg2lE(#SdOZHLTz#EkL3H&v6XmXS}@B@;mz=eno^Z3~S|JLM=dM+^XP!?^_#z6V3E8vPnMqk%V3b~5~=+EgL`stw6grOvOcnSYL(&GCu{LYQ1 z7r8ZaW)wY1;yipohR@7S!rq?KkH;1gu~;&zSg^nBfW`a6+@?KUc7c_b%kT&Pi?Q)o z>;d+qeWE8_Ap}6sk)xa@;>a;pT`cA*LCrO`*c4zB7~feFC(eJXy5jqh(b3UlY?Q7I z!Qu~C2G69^MqJP%{U$NHTt*-~esBV#BIv{E1W=1OA`+T9pP7ymZgCx|o2FZsPUi}b z<#N-p(=oLBe%GPHG!z~wiJp?7nL~#TkFXz>P(<+(Mu?(j5(J?HS(u0#CcrY3YD#^C zS$J_jmI;WHJd{aLraFvKk*=9znG6jS;XzSE-t10Od5O>IsS&@3aI|L+JGbKa=V71b zpcf;+3WN^QK!$>TKK|_UgCD~R!ERQ5ARwnkVG;X9CaGX0+Z|2#gr%}2mtyIprnfg^0>CNmr#(Nk-&<^@=52<G^tNhrgy&d+v&oBZ@){I(V}9X7~YDiZF}L_2Bd%OtH?$=|_lSeiwQ& z8A%fS8`_7dAzrg7qOupMqot{byA-H$qq;H&YO|+Y6v%#p$_Fi9sCWDK-woOWPbCy8 zo~({{Yx=I$>G{hrJ)9&(yeBQtOU)<l(p#Z#g@&QwrJw4t)HcBo_&!a#kwL2l=$EcBKtf` zfl?wP6Yw~^u=ssSVN{?D({WZ&NsCb>JXuxrun%4-B2%*lM?{{vDX8gfvy)6f!|5p$ z&}xo0FayhOnGz##=sr4V&Ug5aqiy?qNB72_finj{BFUw7+K=@oDfZqZMYKVwayD+K zX7IYl(OqR+-%R5!g%jq@Zn;^&Tdu;&BpN>M%(Q1TiQ*j@af)?eGz?CF(DTlRs3%i+ zgPCgW_t0T-n1#ZbdVX=UV(h3pZ+%@8@;mvb4#jS zw4*qhePFq~wq94(Kgb|aKH$L*FX!G$R%3l6XbN9nWXQxKEi&NLe1F{nGa`SJ*)HAGKsgy{9x=`a3x{$2C7d- z=%xTNGfOgQP@NJ~zk=#ho?zPn;3Mo9IH`{25dgj_E=$0fY8>H8 zPsfjBXeIs*w`I^Le_fy`y3geAVo97YZ#6jc@AQb8rZt!dWCW~xDv}0_hjBnNq5w8z zWDcE%trseq0V!hc4zvZ9CZN*oA==I}99Fs=h7k}qhXCKjyi{exWz^A;uzIN<;ao&ankVpohmRyAQ3;Y- zzHg;Ow5pyMb03EbLC5D6{Bw&K^!U)wx=VbVq3lAm90MAMt^D$o09!s?i!T#;#s|(| zJd%4{J^QnU8~?dsgNf|i1Q=?A@{UZy4-Z|V)()1(*=p*TEu0HMoQO$3Fb<6d`kK3_ zHx6t%xZz4p92#fL(FA^$7nf15mzXvTBbn)rK>BA}5Mg|XX8-Y;_+(As!FjV4> z;!lQtxraSwhDFFRgodWT5J(AvT_ok%(x~)D#8XP7;pvR$T?z(dE>B^J?g0o81OPaR z$y)%JNe#0)vr6*<>CIj$)D6D2j|o|jK#dFtD|tu|ghF&&1ur6cTGG!-w@AQovMSW& zXc0hrL~02I)(kk#&P7{;1{qmlR~wtk0@@;utUo0SvW2|5MI6kqBeX!e9`WcFvJK;O ziA=LG?`md>M4p?5sU(f$gCrKn*}fnFZV=tcO+)j(Ala5)sV_(X19)}0dx0GNN+vCc z{pcMvjqS-a8il^Lkq1+tRS5|l_)S_ZtR?NA;il?8C)*k%NTF%d4=70_HYr8al8jM8 z&j=V&(@Y}qrk8a~0Wc4tENgO$y+d$PKg@_P9H|={w3_z?Q@;UUAdR~^9sb=I)iMx{ zl+jiO7%fOh1L*t%&UTzcoUjG#Z)Gfg8}DZcuHqd$w%Y1OtO6Q2@hsBEI<`mdQ^Zc1pAs zTJjRB*F^@ET2(*jSoxBP5tjd^0)m!5$D1wxI~-nzSsLkxL_+2th}!7L@oG7fdJ1Eo zbYaWo*x(_3AAxdg$TIa~w*X@`=K)#s^<2Kg9_)1lnTJV3<5H%H(D)@cB;(8FSUn^k zG(F=_0p-r-JbN-}qa?Jz4~dM8|7=F|&VP+7ha9ZAPU0`qCGyZL=%(=qWyUqK_1h`Xpe?* zu+IMmxxdx}?iUqccVS+jC7a1)TGhUKiA<#fGz)cM3i^2t$W_RW z+M8OdfT5`|;jgD!ESD;)3oDg{_`SX&fmks6lj)guj?S?~yHi#~GC5a#LYLKiZWn=Oj_ZD|mlDgc~1x-zSr#-%zT zQM?NK)lSV{q?`fUNTSVJF)s#w+|GjGv?`oZI)mO3xsFMFO5y>gX;OBt9w~yxn2en-7NG#v^jZ92R!lBNcIFx1wr^v=Q_^=6&APbb1 z;=njAv$e}i#ldd5NZITqXd_^yN7Vsb`Z2z|R9;`oYjH;K~i-TFQ}*vgE%m`~7M%zOhMlrfG* z=jgWa@z|XAs5~9c$Oviqq9G6VE87NM3(!C=WYJBPKWF?B z1bE9*Pan>-LP}Tj?`mefN5-IM6@zXY9ZtspV=-gHwlD+_5;9D%*l$Ke5vdD2G=VqY+n{_}nyt_)0x zXV`nqtIEgb8JlEW6g-&jy@qkJKD@H90;jV3VNQ8!5 zLED>7x3Up(p<_t+=JSrzYluoKCuM!2uY6I6KCnO6zxo*HW1u@2Kqmye8GC0d>G={6 zhIl-se*F3OuPBe}Zf#wLue++qHZov|zG%Hbh3R#{AFvi282D>}U-*Y@0ND=0HWb_z zuC@)H-9VBLAp5Vsf5l3gT>{`saY8UqcS`@46u&C0(4nR1A z8=SW|yD1J(!Ra`9rZSzt-HM>f8hU10Ike1|(u(W#%BAOvi|gyF<0Ibe26Kd)j@w+& z)Nv0^9limT#B2z6oEulx^KZ4sCK$a`>RdrbQw#bCd^X4Y>5#E8Zm>pIVrN$_^DB2Q ztLfxDsO}kZikT(p?KUR79m=Xqx4&Aj}h$4es{K3ADGqvtr55X z0w<@vM3w@Ay)9cJ2Lz$X<$zBi!5&y$dI~9P2R>OU^@&%0$P(ICP}e%%md>Qx>M6L> zOIj5xh-0nPkEptVimkRlOmV-Qvr0+MbOHQamM;dw-8G%&Lki##;eHf6W;h1{wSNlN zJO{P3Tq?WC((>uDyF!-SB;fV#nsf!4OV$%$mXN7-`RRNipPia|{KL7kk550Coo1E= zbI*}g(4kHJT(Rnb$-!ntYooz+n3AqM>y~lr-CCtucdMY6>pR}!Y;6%Ngn+xoa$PPv z!ff_X^@)W>qfsPl@avLFqd}atMj=;CkO8>9`|bGqwmbiNV1VXaeFCCEJQjQH3cq8d znR!?Sh5H)=pTk$U>JHJsg2WJd2mLl6V0N5?4#FIe^Obd0oPY?X#4-Kb@FyxnyhKPL z3MFgKzIwU()!S{=xp(c#dT9+SNwIlMKt{(pkjW`$;M)cUq${a?pr9>IAjXGbw+(E* zn}MV+aBQwoRMD(zUq_hP1?klb!FrEEKT)D&9)@$og;xVcY8n*_8MIzd%KTh@`s@IL zj91g4H!J?=mw`VwkZTZtMe^csmJ=ZJ0ik5uBd4cw!05v7);{OUEw6nn#`3juf}cg^ z2G?n1k_^Nln9R=>=Jz=S*0&@n%{T}pg>7^C>=Bg-Th<~P$?F66aCA}p-zHyFPE_dV zYgjK_q1?pV=7-pK!I-RtDtTIo3Tduf`9a1&5ci;HrnFJq`4tGVvJ?kplgKvCu|3ri zqw`saga!HYNjLFJOejnJA z7jlWM4`34a_kx+L@e~+mLRaBAGK&orS;o>(OQ#gJ3F#wBRfI%uNoE_iWG_H4*a`(E zL3$jLL_zMdO8KCs3Gh@JiuA7oF7SHe&Uqnj!ismIt3K0rL&a# z{qVKsekw8$5XRfAa~NQVq*{d1r$x!l$KI*})0#$_)VRlvbOd7-6&0X3{bA5jbp;^j zz_VA1;rk!&_5g-~1JzS}u10=VzNBc4WO z;l52knnGtQ@+`?*U{WQS(F7PoRPB|xG(`)`)WQ#1BXtgOijOO#Knx zh4oqbs_)f`W?Wk}}qKl$z$#iR zg_oFSDiH5ncO1T!fs*pj=g}$R!T939-}^6won1bJya=T-dE@J=P&N2=Iry<_Rj;^{ zvoq&q9-e9-2?vz$s|Jx}=TZRDkS#vY$eDCC8*}!wH_lvW-A%Ts-rj=^BoLYE+Ic6*yms`;GeEj`br zDa=VXr_b8DJv{HsbrH(SY zi3n{78zgH=g`5jWM2Q)oXn=^Zj;m?IKg|mfwdUO~W$n4h4JR@y8?SeM| zP=EuvQ9q~2f_X9CfD+XG`<3BmincaFRSs>e8LFWmcS|TZp`h+$W%*fmr2*R(*u34l zfSJSeR;XC3Nh!!Rtgq#$X}CgDpv`B~cJZ-T4qH^TQJSWBSydE7o~L|*CE0?|ZuGtg zXmko>gng(*g`QIm^AjBch7pr_* zeZMa{AaEPrIRZWK5&{UHyVDmb^NPEoFN$H+;Oh59avXG%^hLZMWm8>-C`Pp&ErpD9tb#0JiMYbwxczU{kcObe^imI)aN_KHmP-0!#1>FC9GD+WJQfRkg|l5~dT11Y2al zkh;G7UE>`vmq4;2iq6^GRA=UJjndy#eANIDgqT-mEzYQy+Vv}OltGMtsB|W9$yh8J zU>$jv@(z543(>vEmyCHm&82b{(TZKh1w0+b({QRRZFzeN1oAMET-x%J+J>WMGq~Gg zGYb?y*ZC^(z|uF^2;eDgNgWFQCf%T5aOX8%PqvzHxpEnXZzDiep#ta_*ivG(ILFhClP_&bbMYfn*h52$rSt}US=KV zLGwzp-(l4am+FrW4L!f?mws8TxvX&fPFB z;>XLOs9K_qfnf!-MXj2vPS($i4aVrNPD{lCxkk&a91UX!yx@?Sdfp4qj6s0+4+BIL zC0IEZCgKL3L1Pi37DRKFAa!=?t-TVhb=K?Z;eel@gU7vco}A+_T1-8uM-42m z>*x1aHS{8VEYM>Zd}jy^ABa6UC8(GYm*>;yHqH#32V6)lCQC^-xs<$|d?vXJ(v=UO z+0nLorr21a2LyeQ+3E|Lq{CjE)HA~RQ93!2JeJHPk0(zg?@iv99EF%-qx9e;Smc7$ zd}^Dh_T0*H9juJji@0@K-Q%o&8N864n$OL}hw7Q3B>WUtR^Sf43g9AXdM6q7LVv+; zMT$T$m@Q4g2e@IM!2uvV=hb2j#n52Xf#va3M4ub*ZnKNg=2Y^XwVUqoMD+~EbiBguDNWzO| z!A;xQUc^rAJ9|0cQ#cABLL2s-zt6B7ua^XG)(W*z0AvBk(LlaxL6J2_8!m0OqSK14 zXl`eHT?gCxhY_^aGi+XtECqKQ8Db^au6jxxsEx+M$ zilu!5EskezVqiGtdlJhqEr;V1|tuC}Cluo=AT<+XVJ` zOpekj82Iwm0|)khP5U}c-$)<_g~9JtNua6Qj0$H0p-E7^K%9eto$eq8cvGF;a=~Hs zv(YS|XcRYXHO{}XT%iqi2k{V4=i%8y}6+%YAG&H=g!Q`<^&_u z={yD%nT9l{A`m5I(GRni&R65(ZXj`>8dQNq=u&vr0@En_X6{;*M zqf|xhRAC*bXMY0})^1gisjl9niaAXKXXBtE<}?ixEPUd|qVD;JcVTlwy_<;{7(k=_ z&OzUCGB{p*|0keo4c)+yAlP@{X%n&El}}Z{u})#X$k7JyzfL~PricJ{bUUQdkd()N ztUQN3zU4rtO1K%@vWYE(>Au|xh%M01 zbfYv{)LA67ln82)HmwsT0&!-N4bkyDv>c+t;q_37SF;H9x^0M#6K{Bo7cZpd;feYA zbL`cactZh)^U?3eyFRBJ@J7r-ug1HwMNVH%Is*G1P7cF$R9j8*ZIA;C)yL9WsN4`H z4PWm^GuG+DalU!((B*1neeDt~6f73&@$}IL6Y8Ej%QiVooy@T7a5@KzAdhFD2dili zk0`D|xNYmDO4VJyT)y`&kSDUaEC5L{zU}5qcUzmif^>`sp>%m2B z!f;7HnL88c%6@uMH4~V-6pPJ+mFP$3bFi07xM^|*(O3jG<_P;-~NgZW?B$tUf|49*(3 zkdj%Tej9y*)kjuG|A8e8ft=BR+}Q!+kd5t#F3m?wIUq>Zb4;fkrL8m3Ahy)N)P|DC zG+)Vwei(;df?<{6B&!jxm&jWhXOu=LBAkhGt~WJ1334L}pBa-NTaH`-j!pR#eBRYN zr5$=En4fbK3%bJU&CH8pn+81xtZ)Fs&IkFjaxnOw4L?|(W_&NxXcC&@{6F6bH>H#= z8;6$0cEU|G`$fLAZ%BFe?Sf~GHf>^0+vF0+PGq&X5ucrTEW!9Y5Mh@u17j;F^NcO{ zt#lzW1Denw$yyjmYeJFFVLMH+=g4kG*TE_nx;va0O&L5JAH=+d1xRLD*xRP~d2-#U9W;fFdv7SS=#4<2AXwPG zF!i`8ZO@-a)Uhjo73ka!wt3uj~VR`rogjy1B{FfWJZ%TSOE%AmAd(w6@Ip zX<@CR#i`KCv>3mDh2TI5`2C(NQsTf?JHX`wAoBTKs*)wCYUf)*>>M8z+q zq5`)miuxw$kR_-lX0_?V_?`a-u)UC7G#i^mx=p^>sWRrb_cort8MTBJLp zcKtmuNhi8MoE8u!>EzrS4i9Koqzq5#u*~x@H;}^|0tN@(uofd}W8%ouBRDpen!XB| zj<=&q(>HOu-Dc`+N(WX0aoG!lQ!79_)q|iii-QylnOcZ2xr+2Y)naOa@z17<;9T9g4oA=EUJ!PQ9&MiRoh{4Y$MN#(Ay@Zvgu;Aw z6@<}%zX`g&9`qqJobPVw!fi4?SIAFK6xzsYOjw>#FrPm|au*@1IZ~H)xlV4H+@R@i(8xPd5%70Hk(YQSTLxsWrJl4JX`ZM1`$ZjNI zM{OaL`_jzBoE`+$1N9wony+Q*kBN1&#f3#M zb4C`DWYOFS3ZJ+o7E6rWx$~qjn?H-YN#9$Hl8ekl7(y$%SC2r^c!T2ch9KmoCw0>_ zkT*Mv%(mtZGb=V8aAQvr_8nHz=Fr~S%rt?o5O_8}jccUR2Ah|r9atQqeubAVt#bt#53}2!6R;b1$9wM~ zPgu=!$&w`@T17(#Zo<&|X$X33eiPGD^M8i>}g=r*i zGFQk>Jfv36dv48NB5p_g^$Q}kc~|(0eUjM=%=@WGBeq3F8{ux)Y_N?eHjVXp4fL|; z?SBwslnM+Xx$kLhq z>y^3-V|2p~6rEmZVv)=`=Tv^8z$P4G+!Y#*obU`E9CQO1-$G4E!5b!g)}4mE7LZuP zXslwS2CV}1qXvobewUYtEegxuhk?}w1GdpvUU300V7m&d;*IAj4ZZ@sK&@La*KJ-= za@;3zx-4`2zQ*cN+xH(QH1}o)pXbsF%Sw8tez^W&N17zo_22b=hl`B8;9)Dht|*#!WF4K^B!(7Aq4o=g#E|DBB^I$SnzAe4;BXg{-rv^&~~= z1yn;ZXHr%mW7ShConJ`4l?s*0>cUE80hlSh87Kp2H--rFkpp-SF4~7KO(H|SD~#zX zKe3qwL*FeDdj{siihE%pFb*`}`sYo&XwO`mcaJKUykwn4=iua98EzD=PV z0>A5e$47auxy3deI+hcKGf_^v`-cO@ayUYfnq5e*(3vvLRV7qadn;=68Y?P1RhlD+ zn$Ui>Gf|@$>5U|6q(T*_G^5Uy_vvDgIiI-*)1G@u=shx6ToW@r{(i;6-#ayJv>FFn z@d;05)YLekXL&;{tqZ^2?LjJtFM%{`&)I6c+HZPdQc{eT!$w~Rta8lP;<*k*$0AWi zUsV2z;hLh9-R+yE+=QsYTyswKBNJ_%C|umq{D8P-$r zQe_dRgu(O;ceO;oEDx-V!jy1|x?TcLO8CltNs4Cx-!~Ge6!p&3d?B8RLm9)V;pXuD zPYyRX(b$lGVR_!Jx2+Hvxns1vqwycdFp>^%O_?_S(fFT&>o|BjvjE*_MFCJXxQ^gF3 z_FfLTFbB2z!9=4pYsm(;asCLXjL9>7oLnc|vX%F(fceCk%;lX+qXj zv`3W<-Y&lm5BG%}Z<}f>kE%fQR>>f0J7946z8aXVu z>4pq^`k(q3=phCwJsoAl{q zEK@i=@z5i0cxgo*<~=(-$&>T^WVY5a7@+C28jIA{7i#q?E@HznHY*@o*g61S6`k80 zN3Cy3)Yl%!(J_27)`*Qk?GOtO&umUhG+Ap*k@cLcn1`r`;gBe10d;~CMJMskk64Vr z)4ox>*Gp_tfMq74GKhFOeiLDs2gWnMM$KDh*8*}SUTffF#XCk+U~$TaP)sZF+JM)j z1HQLTUbK-w;-JGkIaMw6wPh&6dJOCz{vpMyjp10B1zd#^0!sC6LM&NXB2dYo2PC($ zs4QEBR6Lsy2V(=;CQ6ol);8MhGEm$JF~B5RvVLYv@0;%R`liS7g@?#8dKrRa)^V}* z0d}*34;eVt&7CvFHx8u}_oP#7W5aS{kcV&Z05X-wqYopgv3`E@xjERK)g%0Al(Lo5 z!?L^03%oAZ!4qkA%2pR2$6YKCKgSIkir0M}b92S3xL&VZdcL^0zP>u%k>MhrA*7CS z2{owHH~G>xf5eYWY}JZOun82)m)&UcrQa6%ZK2;5cw_aOKVr7LEN!{NAioIs^Hw?a zz#4+;8R`qLN28(alQFXL zVB$l;Q;U`LvhJOk3?~Wm**u(V>8Y7)#Zz-K$W!w%#Zz-fzG%5sf8$t6xTT^e7U1+< zk=vpMyXC}L^DIz*_uHuj>O22>Kw3Ihtxdl%@Hu>itL_kLR7Ww-454?>Z_)vu;~aEU zE7L9PUy}#Zn7)1c*R)h-paf0TIQ#15>Q`^)=DxK;Te&(o<)D+dv^W6dInMzz*oqNl z%@-4zg|1Xydq@p33idCddTuB!F)PW>(h{bgE=XL%)q+t!)Ij?P38g8 ziZX;`!0xB+qaMXsESZ7fC&D}+<#U(zWqvJA46bN)@hvE-58T5_gI_?=ZSsXXQnR2) zBOZA{xXQZDDKxP34cMazWk02r4XM8Ax5=L%*Sr$H8z27!{)8cQ?^FFHcE*^wqt={r zZOwCMH#`Yt^@~IOwgJVpq)D@`I~EG_La8?N(dwBLa7y&u zbEm5^G6T$X^r8B_Y`YbjEmf1QeP_! zN1QqT%IpB^$_G5|Go3lVUw1RJ30)t0HKVR+2L?P{MUlQ1rWMYd)sBy9eG+#;P4Y>G z)BxWU&OzqR?mS21?94nGCDg$3JV1%37M`Hq<5%LAK^@{Ce5_K1_CNhQMk&;7DsYOS zf*i#T2=FCXB&eD~0(t&!-=sMRcA!c`apED0v)~$(Unuacb+kgs+{7w=XR=gpwCl%G z_xQG+UDRg?V>aO%4`8);Z-Y>eCs87PUw&GxhQ(#^mi!j>)e9tzWI08>NGE_6cuB`q zeh15U!Dp$>Gk>6V(=l5c9)vJ0UKUPSyYfS&HGqAJ_*%ZwNX&$~ zh)^OT7AV*rt75^l{qolIGoJGiuQf4Gz6GT>jq05CA8{R3HV8Tj20674n0OqZeyqm_rACBSZ z-u+}sd^m+alEXLw8mp_iRWp@-qL^Ldb`%qzUrW390waJ_M-uCqXp=#YfYf@l&gHK4Pd zrEVJf8n7oBcx&;R1I0G|@tOk*6Zkfm5l5*M^*%kv*;h??e$xGX`kg_F5l9YaVs=Vn zb0Odi?Suj&Vb*y>)oWis5E~7y*UrFOXhsJ#1sU=Ws{AhNNt`VW>uw)tcdq3kL#q@} z*aPTOEm=;SwnuqgP=*%No(GxDxeWx4IoEOuIbj>-S}JD$)dmON9n68E`H8!ye|yRh z@#b23tqh%o0nB-vPS$!XDkP#fJqBf$*J@;R}Nb}Hyc}-ooio=(+-^e zFv9IFF>aYow1{!qp>Km2H@lB6DH1}Mh`UXU-*jWzwpy$*@gtB#@4cQfhb~Dj97<&d z9$>7;;lNOBUVugmQW-Vi<)ob2U+$nw+}}inZZ-nM$}B~ZMPpYpFeqZ%cqVBS~Z^P&S(Y*{^EZ#EhH z2)?!%VYJZ@)id{Ypl7Lx2XYgSzzV!7SW0Wc{_OOWwqxp8+S{GPH$Ih$_2NRY=8n%7 z&ZJK)fG0zX`VqwtP2&G&?_HqdI<5o3rewimgix4|?2I=Pmpf9>09#Zy34JJt6q~>!*&@(@ z8V!o_4{o3vV3PnE?rxB5+H1gZES)&EBV`=R6WTsmC%egbbw=^n@mf0EWH+{sJ;{u- ziDf(SIh^=JiRH|!>^Sir=QrxTw|=jx-h18e^@jw&_ek`ss#l*|w{G3K^}F|bULQap zZ)^lHZZteKF-tPId?Abt9YRYYH4i^jLbu3U~KBZ;1E-A zgn2VtPUzysoM<+Vauy(4RBZ=G;~Ml(68L$L6Apl8aCA#lW1XT4Py^8KOAcwEGMsH4 zSb5VPiwpcJ0P0s(4;*MoP&Pdsh=CDz(YPDs^6u{syu2HYj@1%nW6^hU_rSm_1LZPO zj%vFM(hCxNd;n5oEPTpkQYo%2=NAM?4oqbS1||o9g^joAG^!`IKMOKB+!5ni?S7N!UkBonM0O#5l<>@;CU! zclNdvuW{GJhgV75%(*)nZ8T85r1ltaC5Otj{4#=@jFW;DpN&T0qV}0ta9Ot(;}%@g zuC72BCWC4mdGZbAaIkPlL~byqymS4(hpZx=0v>3xOMyT zYC2O|tsS+Fr!%ilWl|H5zR4Q3-a%H9M_6U{?%g}w9~%M4h^PajH^22d!U)jB0Im65 zlmK~tK<-~m>Cucjk%cq)Rd4c=6vg0`S+V>D^sEEeT_knhclk_Dg3ZI!4u#sG&GboJ2`q3 z3t@!j!2vtwG!{pp4^C4yAIakw(hyV_Yd+J?c=O5NiMlc@W3dCT;K2J20|Ox!kW5WF z^5<`0E^rU>;gAbx@`lL-Z0@&1xB$xETyB4PcX?Bp8kQFqtHoLsriOA-DCdOAtYLtP z_EFh|q=OF2I-|W|2`p;k7^g^%b$}6j+7`J9BphEycc?|_1!G30ED9txsv~3AptIBC zc&Qpb%~-->^C7Sz9l?+M@KCL|vNl(RGe1RgXn#_uPGX^-{`99m4uAfh-*!feID?vo zoUxzF_>@*x==<{JI)7h&TsV|>{W8u~AmAHHAUZ$F{E*F;S02*8)h|D$2T0%hsp}*3 z7gElzJhTEQs!pZGKve0MvCtubY88!xcbR1!1Wda;o|Xo@bacz zi0%5V%g@-J%d6$pJpN%$Oegu^{VTSiB4eL&tc7`bY84;vC zzFWbWZAj$|lL0!Tje6gB_ecG9Ti8V~m+yi)YG6Lj>Q@r(wr4R+IwXUOrRC!NKbJ@( z9$bOT1&5fh_;U;Sg*O)uRpFjzu|Ne!hrtPF0F}SZZ12^weJsClM$5MG%@<#K@ypJ< ze1#N8gO{dc{Le4G_!aOv!T$3^!UHEd@GpK-$<4#L^3Z0(0CUQT>j3$-hB~RC99q(u zJ4)y+aR-wIqyuMa*Q!$G!&38fq~VY!NM!;@IGMW{<;v&n40ztRG#a-! zig5(I>VLa z(oX2Zj!olS4zb&7t5aILwCXn2gMAlBqM?BjjmMK6OBq9xWbC5hyLI z_PXRKNE-MJ53J0jzH>7dHu0Nor1F4bKpCw#)QSYIb1%bhB9@Pnd5}`LG{=O^kpL(@!$78fPj`G54F=}8^;puE9=3-wiJsMAlcO9&#Dy$tR!uDEvM7G(+5!RGwiq5D5smt*K@+g} zpVX4QZ;$5n4<=tX%Z+vV~_DdZzApM3@uhT(2uV*@T1ZZHCc-`Mc*8`)*V zjB;Cx-5j&$fP)JQZ)b{^_*KC&*TaN5N$CAWaiy_EE;QLmp}r}b8y3)v4F|glshF{M z-L-(ODsMt=)0=Ar2S-u^wBFV=55I-t>*kugvC{pkX$#7|E6pj(j7H_P7$qzkg*zeY zCAf~SfM9-jGf6+0OmDb!{j%9LzGATlZ{L_F)YbbpzAjpQ$hc@#+CPME?$Lzeu!*FIrb0ttL>W-&d;v50u-aj=5Y$gc^cy!g}r#` zbp7AXAQ|E~<*u9(YIW}WS3Y2#MG}5-MDNog0N(5b6FZjewvqb63vzRCJUcbbk65IS z5$kk%CO1PokASFR0-gX7r$2sJDb?Hy@*n!F8r5ld`-|#lH+K)Jlpnw9R+7IkXBC|3 zM4N5j2Kxc8l(V+muECtm^TG?zyWD~?tOxYwRg~ZGE!lB2qu2EWWNZ97PFabKW(rd zaKE$1heHduE=U)TC&Uri8%{d238ot^)OylAaoAIKbdqx`;JY?}+2Xp#;MD?>;Gp+H zO7g_4fZjY2sUCjR&JyN~$8j`F9(4-hu+NWP^*r;)@(XtI%z%NPsWL*%x??QQQ&!G1 z`r1J)Eo;~~(~prh$E21K^@vkkOubOk-0XszBQTvwTUjS5^W+8yKB)jw*~LrOl`HCj zG@3L0md<3l4S@nctJ-(HZ0HYewZD38Nm?|V&ldB5S+<>D$F;4b36-d{@(%kgA|n75 zY%TItT9P|kov~F?xF3z(HFnazR3#W{`^RGKJB8Kaa&e&s7pvCitF;QKLyY4ct5U6~ z-Lc{~lO7zpBMHwCoXUtt=c6PVrTR>x(ZdkJ{@9x8;lCDsxA#MEH!KhPQFbadmiZOq z@u)HdEv_CNML=qBVNAO+Ig+reryu!%11GCRQeDX}vm+tq<)z3?{Q@7$^7PlviRyYFQLM zHNZ|vDzW%bR3;Y%$rK*tVP+yO&CG^(berN7t3>f&S4E&qep1nIqUa$#U?P3eieg{E zN5K_fO>{NT?+Y4!P1@b67RVx7-vSvx7;!u7x1B7IxoWe&Zh`F^HR?IYotXI<-qI${ zy!5E|G`#2S)uMp^wZ-@F^OnOvXFc#QZH@k0&d6X-dzx3~TdsXWfIZ)ck@5j-R#2LLJWi$2r&?1AjH58 zfdO;$5B*)m!1ugzyXKPt#ipXZN4pgiGi_IuNzXHdJ)z2^){2YN7@^7}xowKdXSS+p zpzEk&<*BWV7lbX)BU`&$4qAGsGHEtcndC=VS5WxU8H_3Lm} zufq^paLC(2-sVdYW6yXSSMTUw%VRsb-B?#?C*_Ty6>dZ^DJj(Xa&2(M#DQ2I6+&64 z+;=*go=jyQB`2*%LCbKQ%x2)Arz1rob|FqK#z{R+j!l71#N!!E5W5(!4}r~#V;0!G z7_&er16X>&S@HakL;G+skr1kS4e49pps%~of6<8U~!bplS2ePkqc*vV2v^l zK8WlU&np}fq%$)X*KP%XUF-7w!S65De$QGu($82^lcW}B6&^j7MIY4t0EE!f^ZO1S zJh*QJ&k2*MEE!4Oxt|QdVdB^9y>nz_@7_E2k0j|wcFy`x^k|guulCX63H=DWV)X}? zN5IhNDgDZ)en-8$S}U$1faP<=)zYORSu0m+#fnKU$ylX)p;U;I1(sk)5Kl5r1}kql zQvaoTo~+gD^&%

    l@!)tLLoB5b1;Gr{nm0+b!Sk>!UeW-cql#m}_rdFRVd|H3Id= zq&)a6e`C6-SbEmLFUh^g@e5j+iy~c zMid8^>~iVU#KfamFNUH1{(da5Ke7v4@_}rq7P-DYp7ReWg4BlKI99ckVU8vW`u+># z<=XlH!P{i~tlbwNlUWT*g(C_=jMgQ*b>XeHE+YYf%s298P1X-{_{K!5fRgxDtwM79 zj!wY(A@84~W&@RTQ;>yCDtZIGp|9_+Z=-K#1yWVD|IOd{ESf&$mZ^V!4B(!ow9)Zf;t(oLEe;Wu<~h# zL?>edj5zuf4yAM=*2T@-Vx;fGEHCWdHsq{<4yeo#!O#f8L1a*=BN5s_kzL2_?rWCZ zHx*$_3k%*uOZT8m&X*V$ELS4CY_gLCKFtuyqy>d}?};slioyHmIsd-HsKQ$Pf3Fu` zEgOh4zSTv`iD$u`-^Lq6ZCETxu;N$AVu?LyY&aOApo)9fKr~sagL>K00vMeGWn0kf zkTxvj6D1g?TQH;_mh4*?=Uq!Mkr6ZzKBGDe=3Eae6td&*(%Xmi!ZV4$Y zO>}UDT>mX?YKBnR?QVJH$8Y9Mp>@0W+k!#MZl`x*v)kDKJNY6E5}R3Tl*=vlF!dGZ zfXRT=#-#sD@f^7+5@F3%r$Y_t-)P7&2OW@7A9sF)<>gL#H9^W`4Wk+T0GN_!TPU+$ z--H^l;qSJ3y#e}Qq0be7igrab5QN77Ws?D-$|9WbUb%%Al)psgQb$!BO2&m&nCx!r zE{do<@7o&kT!vjrE28J2!Dgi?eF_k2RfK?G(7%e+zlUnFVN77PGIUDe17}2Iw62{x z8bYSBaqIP`DBasKDnq)AU@!^Ein$tZWo%=D)VJ6Jv!vvm^gj=~xHsfG&&qMVNH!irN>msOh$!-b>Yb;;lOc%n z2(l$Gju@nirnG^Pr|R{0(qe3~cj=|KyaZ7NJ*kYG(E-d@1XXcvUnEpTj)N&5iJ%%C zLwsL*D`r!u*R>hJ#;ynsAjr?o8VMekV&P#X@@;Tk%Ct+}kFg(gJWY7+w86nStyBE) z`4hU?8-51F8Vz$AgQWcPp7PuVV1l+Qf+2XQ(y^7Y zX^gj08EO}m`PBA%i(C7>ivvD&k6>2NhvyV##kvTe>E4RZ&Ggsx=bn4+aSiWA;2T%|^qXpLop~89y*aNx>#BM!;AEi0ara6|T-}@HhGc3@c})#^s>p z&DGV}GhZ9Amxbze`Haf_F7(iQ|HmJt&C@?rt9c7aZ|fWt6eDTT(d_51BN7GRt*V2&-o zXvo{mYH1_yhu|cu>!9&u5vP+wLU2Hk;t2O87iod90Ou~9jd9k;RyRh?A@ z4Z6;8yS;Fvua|OK!Xm&)vy4ROf<}LOmpxCElu8Bm<)l-}(ik-6RIc|;wIz5IL&3vq zY-}ob+~JjKhlFQZ)T8TyN92gvS3@Mav`D2wtvzr1k;4^Qbv86u<^ zHC6D?$I><=y#2n{Oq6j)SvkcKla7s@EzE6#e1Ky(X4m&^U2xIXL+H>-K@sv{FBj&r z)`XRsvHJR2EzAL-6#E#FW!Y>AGF{tC_cfXH>9To%1FzWDD5fNk9bZR zSphn2xXrxew2TW(C^6Ax9&(D(5-;E)6{Jv_*M;(%`gEcEkemrUOBQQYWgiMo5!CX_ zbJEna(rQpY?7jD*;%O$a;jTQ^Kr97Osasv>f$!%4bkwiRS_!QeivDeGVIP(Imkg8I zq$_fyf+b-mZ8qUD(SvA$VS_H+K5wt(QWp~zab2ILYG(nCHiJ4W0r{V%4MOK$2ytKE z5AcUJ@sd4Jqovl1qWeEaOQ$ITqZ&RjwN7(ZWvHsmh#@OD)MHONp*9gXLe$v6-XOGt zvz7kW=z;~K`wzjP1seynIQHX0_Y0*<6j>Mnp@f85!F*n7cLGVwn+?J@QX#1%ctoJc z3(ttSQIN9$K|zq%YkGYMXIpP!`)+qB1j~n-c`+o}GnUtjZTr5(9{?YRm4LUIv)_ND zM`ILZ71xHyC4`?nv|8T;w`f4|!Dv9eQ&A$KB#(PPP5I^Y0$T>SpPe!g*^6l%Z;V5* z0PrYnCPq+ayD_!_lr~Loov}@#nvZQiX`|ZLrc-2(wpzk4suR9Vtk-qZ={?SVfb`FJ zrDs2&s}AFG|5-9_DRS++ohf_V?PvoFIi_6KY_@i^*@MEh+srFLp}pA5i`86~ znH+n054tQoAty&nOtY>^WiSwbZj5cxe~Lu@$!nXGGpYZC(!lWAMLe^4zZkp}X~3R5 z)Se*uee-A67Hz_!y97f_LUp9HgV1MvKrz42TKUhiRwWGjgNE z2ridXA(c+y;0*mqdv#j?t<7|5#TA^rr8BIiSW)fF$wAy=V~;MUhzPEGAEid$ zp#?_!@0TKNVXd^fg!ZgwEaUk3J+=mQzJmnvGZi>v3pitTx#U1{*6AGNrN`e7mmF~q#HL%yAdO9FpHlf_DT1tgVtj6^_th4>D3>V~E=F;EslRa$uIumA-Y zP*55oCi&%5c13lc?cEnoChv}eHWK`2|4=ti15x5hjK>p$i#uh2XB4uWuh!;DtJPwq zHb?bY#D;h(I}=FVJbSxjjAs^3{aOZ|v1mbdP40uFT0%W>>i*FYbkKnyd7z#y=`YsA`Jh_$K&%Yj$y9Fa1R2~Y zmv?`E;N{(*QwX%(lp$j{IV5%eEbbl{cx9km#?^Z*ye4$Y3_d;psWBElSA7y=i(T9o23^ZuOnFLGmcz2ur|f}D!SEiy^Z+G`QN zq&;x*QbZqsXn0mJLn!mY%Tbb{v5t2)yl4>U-dir6D=ybTte0_~eDcYU!rzlmK7l{< zlpi|ON5(ZACByIVIvI&VMU4m$;>%;R*-a~xn;Qo-4#+9{uv)xtH?CZ+E)}b>A>T=O z#9wtwa9{WY#lRnK`6o~x-14>Y37{KwJHvK4gP#0tJM1I2GpMUDoEQcTh>hXK1}?PH zCpJ9%#^K>IxHHNUAiYhC43sIXi486+yqzQn#Nv94$_va3_Qn#ia-}dl-0+nPO?Gm) zae^Kfh6TqW&rmOn0HDM7zf}cvc(@&#x=Kv}_!in9y8bx`QUHUUBBcZPcgeK0={suP zF4QCtD*B;ihwsK8=Ro%yiMRwl_uL>0{Um$+mKo=FS->aQ>(D!^Bb3OID)HYib|mKd zfGKU=owUUgZXSCje{pUtzf_!CD6g;92n_q9{=Q5+`X+01CUwf1hBNfJ{!D7((VX${ zt?{dEJmYAZAZv}gCjF`%nw>bB8aqiwZAeIt7R#bccztG|+4;D*L}j*jEv_=~<+*TP zn+AWoy#5TsT=3x%)ta0pqbY29papocQ=SMfM3nR{xwj5_zW0v=!XLCGc_=B91aKJi z+cafUtmzpkQT671UireDE=4-x&;ZEjo9N(2h1?^_P|Fg;pb)|%oJH`CDIM93 z!XYc#%$oK5z&N$6+Ut^|u(NGJ{gIK(q`q@A9a7-(7JM7kcAD?rZx3L6H+@U(GzZ*Q zcFcy&0CVi`j-M~Kjcbc;nrB4#Has?JqZ=Xyf7AV3BaC`sT}9b0-Ogk_tVQ13Wd(f5nZ z-A#yzpxh_n3GUE}#HyTMdIK$5--G5bK?J#FO;h47Y-=FJZm+S++j_;497(2e4_R!0 zFVdaubf&agJ8B(IXI?MH3+o+ZC3%EZX7Ap;!))`N2=pl^^--@QF;@)Gn%@N#4zO8I z*NePcMN*W=l8!(SRFFP*JGHHjCv?2Be8ZZx0_S4RQNjF$_<~Sy{GeOcf zkDEG}k~5&2%*oD6>6;!-DbGi}Pb>ztG{*)c&b8wNRexid+V z9{Y5iv5e9)rpUL2)W;=yhDIu4fym}##=?$cD!=l;DVq%7`~nE`Gd6MhcLkT>p6iAT z*Nr?Jyr4Tr&#}4m-qM@lUoRsnd!iA}yqygH14s>BmzP^f$4-mN=Aw}}jR8t(N6fnh z_C_OYE7}(GhLn2>@B!{bkpfBJ`E~A7j?7e7OKWSz8XTDcVjDa#C=bpgMdB?5{1c)2;S&%ZFkyk6u~Fd-^D*R3ftgp4I++^WDvEyTD12 z`3`o@&xwJjkH)K@MQ(b`x>8sz#+R$~S|<&?v|QZ>BEfR?CA8+|`u!y}bC|iDP{BsWHWcC$Bt@abDNc zd%Zc>%li_;06pDEojQL}@WY+k{1l%XE?LcFci|4tGraE6_2f>xVMt5d>Y1Rgy^NGp zPkWN}0rj-Fpnm0~Xuvaxih7{PW--q%E4~|^-OI_?^(tEeO{?C$`T=HFEATU{ zAoO$>5z0}$&7f{d2C^wAxdHAL5rO7K+JTV~swfO87ydI+2Il}rv^#OLXpU7HMMcyj z>D&oYid}?rp)+vTmS5w7W1^rg22@k=d%&@ady_+VfC8&8xIAbC#wGX*U-*+RL?W&q zl)(R}xO?FIqaNfLiR?NJDv0Le*{R8WdFtTaaqgXhFBrrlWV2Hq2}F9#C{BOo*~`xQ zz9wlu*ZCtWle-p`X@-c->(Y%JzV0UzXnDPIXORs^5ik}Rw9Dp!_5BOGLfIwH)+OGEPf5j!eVijAcw6Q)uq`|c{A;~qh!3!o&O zF6MwLtN5_X96UY(+FYr^but7o+*Dq{OdVs5uqU3hl4R)7k)cshjQ=7YY_|wUO#sd~ zVQ?w+i$f*7KJ=#U{sHT5`Tf=Ys{gXDF;XZM0WCSTr*TqhL2xFaVP&<8+V?05&^Q%> z4)s#4I9DmI=2wbywMuDesaS~((vy6N3e|6Z@#Bfe9)3ghfd?J{bwCYx`FudDSp?Dq zNZ~KzpZ62Z%8a{3J3TmvCw2!tA9fBOj*hye?lkO#YX)s2*flptpn|SQL}`tlVra|( zhQ9!J4EakdV<|P3Vc^J3bxIS!_u&S>`Illrslx-J2mH2yS`EYPm9-HKyk0T=0%7)< zEz(td@hI%{PK@{s;h1Yy(zAZ^Y97z4jkHwTyuq}(bms9wmwyc1r%|;pk`8&B)@Yr! zftH!>=`?GtZNcNKd36x{`I$T1pr##xox}|l5OrArQK(PBolAM>1^T#uj^rBC zlh);jk?2j_9qLmsZANw9LV>B6Wm~AMx>5Bh$P4JcjQ3&xyVm*u?%Co>BtvaklFvrB zzjP<+vc;r40hZ5qDCM!qysAF4+iE65DKC(e=PJ4d2y9LHq1LQxX@@G5^0t%Ktm~r5 z=^jPTX(V40S8eVG)e?L66EKgp_fGznjwp!|yl3#D_FVRON~8qamk5IJ0ci$}ZuIKnT{rhJf$`TMOltwbF92yjClfSLc>M zjUims^MznNKcu482o`&4Hh8kVWOgb&A%Z@vB3Z}jTcP@_UjSw zdXa$ctd-7;Tc;V(C>=sZY}yJ~mh2GBqNXcRG#Y~7%B$}yt`ayIw-Q4Qhk$3-1lZns zr?RPp?nf?^X&vzp3he|M5;hw}vfzybN@edC97W>;-qjvvC>~4AjHSk{j;eic(`vKs z`*sAcUjJv6TFZ;P8@PikX@K%aR(&7-~a4KFc|cvm@+^uokG-f4;tQm;4UWCS(7l`V#_F%CYO+tKAzUACerHeZ$f6lm$+uy`PHO`^jFby&RjA+5>y83Z&36k#a@okI*4D=oWrE z4EIBlb2EIe*jfKO(f&UMJr=97(eUiKfQhCI_pM-w&x7G^Z)V?UNFoxWsia}06$Oop zv1nT{`^aV_!YIIlclV6h%hAli?3;{u*PGe9k8y5-n_z6vwKu646+Z%EkV-4cn7AqU zA!RtaAa}}>y|$J!n(!|T>#lN!DtYpu>nHeV?PutEoQw8y=#nf9O?4~WCT5CvTD{iR zR-4Li3Z7-3Y$g-V`j82=JW&MJP$Bv`r9~{$TSoLVIEd^_w&BrszYG$4>$amN(R(B# z{_ zybQ-hp9H+F6R^e#>{4JN0NqN1S(m?LAJ_z0iNeh%BiSI65uNc0M&wZv%=uSwGSbfY z^u!ZuPjvpM__4W??>QK-F~-bP1}Q4N`U}NhK%%o{y&e$+5&*CepWLZuvtYjV#4%!v z#{Or)ekl~`W;;-5=k)o+6P;72J^E|YjX?&kgjOEgmDmolmtgX?t%`P|b_8>yALTm#XP>u|VkT1APL1N1h zVVjZ`lgn@@w+FSByC1MY5qVW40zA`gmt)g=mjikuGTztNz0$D}!akMjb*6+C#_6Ka22tU1dqgF%1eNi^}HKxSy0o+1?ePK{l&T zS=4>aLhf&=JfyP`S4@=an<(4;RIS<#f#RBq6xgb?`v67%xZ1=p&ah8i9%p2m2b)X< z?cxUz`d`FJ9+kS?x_Fa~Oi1kP;twAuZqs>N=;BrL-Oo8YR{Oc^TDY@!6jU*IE;P4T zfeW&cY47(oHaInisaDoHZk?X4Td-*~ZOM6)Y(w{c+Y&T^DB3iX%)n3@C%5Z9Cxe~a zh+|hVoRc*fuRO(yHnuRg9RvNa!a&108SlibgUk7g+W`pwiw=SpwZHYgUFT$y&-Qk# zRJSI2C=SC|+%0if8z$e~{xJDIF-)50XnL||0;iVLgG(hj@L#X}t{|(DrkJy3I=9b7 zb91g+bJ-lw>x9Ciy==V1Hal*I$-@y%?Ad@`T3TJArew*ceo9a=k;#uB7vM7?yB(x3U zeoB3w`P8SLLw^KjzMuM3d9|3YT__)|foiYB;8Xl52#50ijP@uWyqq7lKfGT$pAoL# z5Ds{|Yrs$<7|zBXBf$2)=c%WbT%XUoK9R`hKW`^4JhaoFKW$dQlg&Q%{M!Or@Esl= zZk$M9KY}x{MR_LHCS{B@+!((9t;3BCh%BCyjp|6OTqz90N52{Taro?D4D_5{!vaDK zgct}h5MrQn4D8@>Xe(6hdtN|*G}YLkvleT@8q1MFd7)Hbs%`ufVD zq?`%CG1&&X#aS2YMLu`t3foL7|+xz7ye#+v8^1Iv@D#Sm4{Yfj&>?F zHak1nkJmIu_+8B(cK3OqYtMLkCYR2POj98~3s~J+0Eu$N4 z*YxWxKwF8H`C+A0%a31G0pLheUgECnZ_+Rtw+CRTFgV>^tgkck4nnqK6GGSMR$u4< zGe**DhbXSMKYVq9fnN)s8x8{>yy0pbRyf3f#DL8%HGKe~v}BCr9eA&u5D=gV|JYF> zHeYZAw;kZD_P1N*)dK-Ll=E95y~%fH6E=y=KJ~l_yC~-)#oPR^iK}I;TSeH4h~iPzpYt{vJ7LcI-#h3FH0d9-A}I4aYe1%E>>~4gny!oJ`~COY=HvJ()nd6)EG@0h zoh#O>pl{4&jp{-JbpOCH%PcIlk#Xx-YIY(=z@~cEItEK{nK27iV5o8;Mx(5YN7l>7mMID!*UT8 z>qZwUaF_sG+#f5$g5vtaLF;jGc@>VWS641UkpPqK0|@zdEPAWLY(pt(;lM0Ia0i$z zlFt>M>MwomG${6721JZaWsaearzEx`G!8F$->emfOJoW{Apn!qigDDNQ(bu)@hlHP z{Bj+W$7i)>29ni@{5}VfujDVzt>u^SwDLOK@rUH2ocvpSp^J_)sZ-YU6m)`qT!qXT z&lUDuZR3H?WM#9~xNFj{+M(Hrqp7izWOP(QLUOcJ7G=WgvmeM(M;CK{(vv)esKn`_C}QrAp42SFFitA_cT5n{FUA zC2*2^o=1_yKysE;XNDj*ey(nh;En;=^=anza>CEb?BMuFKjA&y$>;BmYwJfo%rZoE_e5~UmjGE+gE^u@fq+=vC zrf?lvFw33sDVrV@n3@-_L{ywQwv`XudG!w+xjG~1tkkpX@PwbYGvImO(rDb`D5kA| zRybrun^|9LoSNld^`>AOSIu2dYonRk1P5$c28S;;=qa=na742QG;W2MRBM&RT4|*i zBZK)nCb{#rg!v2(9gc!7=|a9`=`oX$t%^c|%K z9iq|0m;wJ2KGZD_X+$u-g^z!t*~viqnN-*30e;jD3Hl)o+4)|@1Y}`c96f( zPXpM8Zd>M%MB{Ks%YF=A2^#~?fK)=5I?wAfRIYt7B@@vKwZ zzmA9|_#s8Dwv^4sAYh~&;4|CO`~r3Wq{{mor0G9^^*TY4^c|XT?6L_*@74%e2wN^> z;|Git;Fz5pJ&L@YaZJ!R&N?!X<|5eDLz-tDTXtkp5F^kTV+4xM^61X7B4i=mx4kFF zIO(8GrE_Uq2xf8sEEChQ3>!VeganLlx0Nky5M!VOBG`6@Afp2>Q?rQtWgcU`H?%t) zz<`(ksGRu*m_Go|u!V|{TwmUO$T5I*FrkV>8jYoxo};CBTUgz8evT-Kn>poJt3|>A zqMPH27@u^eN4c6QnnKA4N+`XJh7&+KVjdg{CxF)Na{ZuN(wpzG;*-8(%7_Wj4VWk! zS`rq0nLp;zz`#In%;`xPOgchgEGfBiD`8AA6YV&FvRWk7mHhHDtYbmLmsYFAN{xW0 z41294a#KH80Rf|gge;dY6e}@ud-9GXJQn;7!Ah^ox-ef01{;RTO0c~qOc#*tRb+M9 z*k$Qh{mfRCWxk}6UoDhZVz9i;vh!SqW`&bVEIt&K$;BGAT)1wLT!Jhe(cYko1JnUr z0wLlpsw!6MF`VMTfwvwO${PvGX7I?C2pf`PgtwPXV4?xVyG28aXyPp~EYg|H`;Z<$ z_i3oN5r0c$6bn}#M| z5o&s`3>g>Cu1EGnB5U=WRT&}>g*=$Vh_~Sn$Wd4h0LsgIS07D!>#dEATjBW`{JE9T zU-q-0xLurNX}LU44Jwkg$gWzkuWw-tv_RE{xfZC%k-omf2g_hJwI83fP?ZL&41a7Hwy&@D4rbbv8)f|q%m@;{^KHd@`6hjKL6mqDa5D?o zdowF9pG%*z5E(@R*rGts2%tBLL~*_ovZMuIsY8`KppT{fD+;G*xU)8POq>n;?j~%$Li6Frgz3AxD5-gkO;<5=$P5WpNkKlz{RlsnJ;$8-77sIZa4w z!Y$Jx{QnbJrqv_8jmD%TgtllAhW{Cx3u=DED^G6k7Ac88l#5#`S~=nzS#jNAg=l4(gg zd;n-h(qRo^O$MODv%R821ep?^My>(a!DH_1psi-O>DIsVd|q<@^7lXK9^TDR%82`c zhGu7I=T&>7940s?j=)gD;w!&e(s~_G#;HV-ARppbQ&iBd3J?)+WL%o2WAUj868q7i zVg*n8fi;IcG>5+bA!$%FBWLL1mY7Qc4>NXNe_N4|h?P>fWR8B>MM;fOv6lR`&IfMa zSmd?TaBNfBM}8@3AM3soX`iEvH|66tI}eO$#N~(4W_sn(rvxR~nBI5PB0v|M(*ZUi z`UYcieSJTJyp9s+MgyJri1Cuq$OS4r*o_>yDFUJx|!W>1jR_mi#7q1u*@F+-!`Pwx(o2w_qtndhE~JUFed!yT=^|rTt%X~pZ9T^ z<.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≀r|Hyc^m+y8ugtZM@J#azqp?n)|Bw?gEPDF=s}1LWzp)7BwfxKyQfL+ z6AJsuh}7oKbocKY5jjGxydM5D=D@_E8la4MTohyavr4hlh`>=7BLecYG(d#e8ORbw z34~PwiI66hyEd5ZSwlP!ydi)x;?WvV2@r|Wp2A{--NFz9>_jlSRbsZX^dK5s$=l9F zlmd1k?2NG~SAjBUGz5<&wOtfc=ZSfZk|oi4nxOCj*t6=x@Z$ikm8lD*-rWP)AKnz4 zQtayNPjnB#`|f<~((<{Z7Yn7MtHpSg{?xu`ohh87&XweGFccF1dyJH^JYtJe@ z6)PrrJYKajm^mvV`3OKzGrBXd>v)nZ|M{P%vfkd1wR$zJi@s3VXxSB z-BhTXSN!NCg)0!We~!;G!n=B2LPo)Zu%oLQCY?3FbY?x>AwPGtDbj2((gql5wa$oN zJ8C-+X9DA#L++$AP8>udjyJ)Q68+#nR&wYB+Nz;zsxdNg-74Zmw-g|OQc4lqtSQ>) ztZkCL2N5+kvHwY?q;}jOHx*e@U3;wAUQT0gZ4qNLiyYrgw7j zgHL;t$(}7jz&b*UnXUcnep9{1H#LWxDG=>kL_;L*0cbCH z4Lr9FdbS#*7zY zvS?!xc|Fhn;1EbRBzDe<&sN{u4ri8aA0F%WB)^T$3KFJ}RMFX?#ChYc_)tmO<-C)p zgdNUmS{<$IcJI)}g%e%f<5nyrg|nJ)Ruj%@#GQa}k2@3V?yM%<yW1@!hRX92DHu8yFK5z?)|bgM`?N!YdhY+av}fT z>{f>R%;7%sw!g2~!xb6DiYeE@VXN8zlc=Y2pr3=jZS5MT($*v7d;%?+@3J6RK}Odpjya?dLJ5-6x3i z2sQnY2WzGy`ysD8kBqQ4I+J^yZVVoQICrWM+!C>fG#19kywL-0`V51{2*^nUo>BwB zJv<^HxqNx#GJDYU>#5Y(?CfN}XUOHtb^guydcP7>T3wl6dC17oyC6H$mYF~ye&R4# z>X#dhNCe#9P+&vnN0}eM{PM~}`nUS!$MgW{W95E?`duq1W6JupipIecRSE#6EK8*I z220?*ye%4-(~W+?$Z5#2TB|J9N-M<}8O+}?$(^^MSpn@C96B7`yPp*D^=cGUrySNk z3QzKI^bQ{9a5OrRK54-P9fCSx=sQX~aWr}uGvI&1Hv;21GeFx{S9YFb?_|CGSj#@lwMoBN|Gj zFsRCcz`YL#+~EhcL0BiT{oqy7xBz!2PayMcG$2!3ZV<^$;uY}`guOGx5eYj&D4>*Y z;ZX7oF#=8MvVc1H$%|Gi_V}GGd|&l zVz{9gZYYKuia-O#mGQ1znpO7`Z^$E)QY(sf?y>dJN#EMo+E|C(#z!c9U04YBNn93+ z!~1yG=eA25{WCl@8AP3%*dAr~leV4OsIXu9>6cG*T_@3X@0a2JWq41P@~myjxO%hm z%#h(zK5l&mPTW4&p1b`$x+j}VIBk>d#x0t}X<<{ziSF1desH$lL&)lz2#Ps5bC>rbYzo8C6-(Hy1Vc>1 z>JM&w*9M2;vBAWL64byG-+>s1y$Y-`x!6xnu*7)yMR7!i9M4Y8PLrdLl8ZzA>~PD) zLxY&#BZK`@*>N~D1K;@8`7juXh(_t}Tk(Zna6qZ$Zk1Z|C^b8cC3dkeuY#bIrSPpVu8sd=KK~u(4`H8&Oy;_^z4E3vDJ?(z!2c$ zI9i(ute2s|faZ3@wz@9n>#Uh) z70toX1y)aVJCuyHy_bb{m*~nbY~8msiq`f`wx;*Nw)0Byb>GXnaW(UV7W2gZd;2@I zVZTH@mCU?lch7!=d(7b;bGXMGa;R#}Q;1V!<`Z4iT9!;Gmbp4#Qhm>Iyp}ucr0E`lE?7Vc^Yq%hNB+?&%X!E^7Ug9{<%~7(;X?jtB%$q2Ag8_0E zKrn}4=NH!;D0IUtwqNKRd5ellfJFd6BJx%-b^bjLu)74D%oiIZ5GErBIi#`@*myh_ zS>t$3tJ_yHiP8~x}r7gHQMary421t1TK*0ADb?jD1BJ% zXV^!3uV{7DseAb#2ZDxMV#GQZ@|`>hz`j(RSQ;R0M|Z_BL#)#yldzexJ#^e zD_x3pRRdm+=8X93>^`X04^bQ}JAh@aWMI>zj?S@!q)~C9a-(2_sZkO$$Aa}@HI{s% zxoN3bJJ3hiWGoK~C}5LwI-5E^nIif1T6yk#eqnum<y_2~GW(p%&Su6^Im~!da3x~Lj-nlC23cS3+t8QT%ovJtQA3>i~O*VUsyO(oFo3DLu~Ba z%~H63Q+9>LK^;5ji?-99Ypr7*oL7n$eNcqQAl%1N`% z>DZub?;lpiPLk2lnbaw3dMcgCk=zx0uF_{>;%Lh4^RdzX)I<&rM{%SkN!H4wCM}Yi zBBc6`{EP$d9QHuyX0JiYDyxVNvpJ~#(E~NwtdKP2< zfG2S_ZEK1J94WWyyF;;8IXqo@frcN~oc`d27h1Q-Y|swpT2z2Q+9D!;J1w$Zd5Ea9 z>s#R=-hAS=u0Jkpq|1EbPo33mO_VxIbntx4QXd7Jg>(?&B+8bV1+9{=fvwAILajs_ zRfOd29xMKuS~R!=U@Ovp3Pv`dNnL7E^zJ#NCU?Q5i&E208nXj5g*t#mlC8=?Ds(N^*%bO?z?Bg1ie3?H=EC6ee$B!?f2lVP%0DX$RQVnLiN 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

    &*5Jf6v& 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 z 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

    3`#D_J3G|-R-T5dCntG!*TeKt1cZrJ?# z@YMR;4HLriPht&lxHaD;#vGe8??D;VFC})oW-~F3<8|%S(|+x7R2{)I*1;7Y5mC{w zCa_7H6~2S7T&8hSOqN+F3GcBy4I!I`oK19tjY<%Vj82H0zK@yx5Fh?E83{q^Ny_MX zBI60b%!fda@?zy$M%7d}{HQbshT)o}IY{k?$QnCAf`TS zPNOF*Oqgkfxg1vZtL=P7+h@BnxqT2y9e?JSyd_X>cTNO5^tFPPBQ$6oR&yFfL>Cng-#!X8iv%Lm zESZ)!-H1SyjYptixc_-{z2c5naZqXE+TUxscbi=M=_augEwBQHvlBK%$=RS8X2{P* zPa|`NFt&#a5%c&>ogP|*_e@bJhrowE0V32)zNC_}039;HPUJ+F+lC{TXrxe+(7OJu zNWI24ilq*N8v>B~S1~qEmkJ4Epc$_MikF{(i6=R>lUA|{)HX>8Oqp{LebKB887vGj zokX~!jE&L?TFSpY_U2S0Tqh=y(FxWtEoLLite;ny4F?({`;)Tzv3#2BxV9}M??LTB zdJhh#l3}kf^XT!#9r5&96RFUwo4r|nJYlm4Wlh>JgXbBZC~X+(HtgRpgZT{8mMEYn z<3Q?hcAI_vT{>w^$tiOPkTl<60C<|^7nOTLqvy2w_Z9#Sb(u4DaCY;>D(P%4+yH

    ~TXe6~x=p@X+Bp{_PiC4+S~n(~ib)N)x@?sUc2L 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 z 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 z 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 z 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%0AMK4(}H~-dR7-gu@ev<9il$=_FE9| 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 T& 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≪^!XFVE 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

    1&&lT5p3Gd32BV+H2F(=kh_p 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 z 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

    Z0Ql{o2jPcv7jT;T~t(+({}v8csFcO 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 z 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�fmDfkb$Jm=CVKQMtwO{ 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%0DE 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

    $G#8PSt{xqIr)cabjnvT! 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
    iaO zh6Kxm+6b(GPd_vzX#Y5mJ|oMUcl!odM;Pi!u9s_{h3EO_pa0jxXKyKht2g$~^vKF1 zF)_*yt^wdlQ!|Bw;XmOjQPIkVQb!A`>=8_^_JuUy3Sa`bXqWBRBo-F^b%7Aa%hcKl zN0xkdnyeHSN=qYiXHlmEY_}xl@(@as5F4Oq{?lXKla;xWE6rYn_Mjiz5!%04y{#D{ zZdc9uUd2NUUSFG21zHPIE1f4(w?*@r;(W|4i$!U>w(cfpmlm4&`O@+^umveo{w zL9LO2y|2USydVp9!RVJyW5ZV>hd^LcV`0Prvub?TXlAC7n6pF(X*b&CwIpel>($13 zasmvsW+omJ4o467t7e7cc{`4xp@8Ngf~z}h6Kl=4A37v$p+PdHQmb!p-;%EfpTu=`K=lFaYiJ(-~=7@1W+ z48Em`_H4qpebWsSUlk7ccMlZ|W+ z9)DupU2inEo){;&MWP{V4aRQO7qK|EJNp9|7N%T1)_@^JyC)MB{9~Ho--l)58f{Fc}FB`UOVtljXz;8*a^E3bs(AyOIA;?4HEi=G~6r(!>fPNm`KPPG}ik#Rn@ z9~j^MD4-vIG!6_cz$$;`DiIt^O7u-P6$KI0WlnBBH+TI8$TP!IRG#Kv$j{|-i(n)0 zpupPjw8Gy;Plg^hlY;9bm8;lg4^)o0L>?S6Z5=wBj(GFd<+zj>=}T(G-oGxPF7roM@WSj&_Gc0Ak%HKiF)HyyM3* zUTa30XOOe`3x#=ko=UOgmW?vW^3;T*`3At#Rn5FV`VP1^Da|3YZOOr8u7=T*(aoL zRKrN7dRn%=HM5KIS&tXgjL`a}z(EN|I;G5Cg?(Sr@)A!jsM%OA|f(Z239#pMlpEwIKh{2*>l7 z=&d*K812an+>ih^J%y*WFS^af%35OuUJ>~e_s(G^Or;T{%&`-YNiTCM?SY{ua)7D^ zR)Kmy=_8dkEryWl!;(}61u=TZq~LoLH8rw5TQ*6&11+0_P6#G(Hh{#MJE9PLtzCOk z;9%6NbI0zO#BFxTRtrK;QMH*8=C12OBusYiE+OV zHkX{spU*ALl~~*04K6GjQE-T?-bGgEP=8} { + do_test incrblob2-6.2b { + set rc [catch { + # Prior to 2015-02-07, the following caused a segfault due to + # integer overflow. + sqlite3_blob_read $rdHandle 2147483647 2147483647 + } errmsg] + lappend rc $errmsg + } {1 SQLITE_ERROR} +} +do_test incrblob2-6.2c { + set rc [catch { + # Prior to 2015-02-07, the following caused a segfault due to + # integer overflow. + sqlite3_blob_read $rdHandle 2147483647 100 + } errmsg] + lappend rc $errmsg +} {1 SQLITE_ERROR} + do_test incrblob2-6.3 { set wrHandle [db incrblob t1 data 1] sqlite3_blob_write $wrHandle 0 ZZZZZZZZZZ sqlite3_blob_read $rdHandle 2 4 } {ZZZZ} +do_test incrblob2-6.3b { + set rc [catch { + # Prior to 2015-02-07, the following caused a segfault due to + # integer overflow. + sqlite3_blob_write $wrHandle 2147483647 YYYYYYYYYYYYYYYYYY + } errmsg] + lappend rc $errmsg +} {1 SQLITE_ERROR} +do_test incrblob2-6.3c { + sqlite3_blob_read $rdHandle 2 4 +} {ZZZZ} + + do_test incrblob2-6.4 { close $wrHandle close $rdHandle diff --git a/test/incrcorrupt.test b/test/incrcorrupt.test new file mode 100644 index 0000000..eda65e4 --- /dev/null +++ b/test/incrcorrupt.test @@ -0,0 +1,127 @@ +# 2001 October 12 +# +# 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. +# +#*********************************************************************** +# Test that "PRAGMA incremental_vacuum" detects and reports database +# corruption properly. And that "PRAGMA auto_vacuum = INCREMENTAL" +# does as well. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix incrcorrupt + +# If this build of the library does not support auto-vacuum, omit this +# whole file. +ifcapable {!autovacuum} { + finish_test + return +} + +do_execsql_test 1.0 { + PRAGMA auto_vacuum = 2; + CREATE TABLE t1(a PRIMARY KEY, b); + + WITH data(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM data + ) + INSERT INTO t1 SELECT i, randomblob(600) FROM data LIMIT 20; + PRAGMA page_count; +} {24} + +do_execsql_test 1.1 { + PRAGMA incremental_vacuum; +} {} + +do_test 1.2 { + db_save + hexio_write test.db 36 00000019 + catchsql { PRAGMA incremental_vacuum; } +} {1 {database disk image is malformed}} + +do_test 1.3 { + set stmt [sqlite3_prepare_v2 db "PRAGMA incremental_vacuum" -1 dummy] + sqlite3_step $stmt +} {SQLITE_CORRUPT} +do_test 1.4 { sqlite3_errcode db } {SQLITE_CORRUPT} +do_test 1.5 { sqlite3_errmsg db } {database disk image is malformed} +do_test 1.6 { sqlite3_finalize $stmt } {SQLITE_CORRUPT} +do_test 1.7 { sqlite3_errcode db } {SQLITE_CORRUPT} +do_test 1.8 { sqlite3_errmsg db } {database disk image is malformed} + +do_test 1.9 { + set stmt [sqlite3_prepare_v2 db "PRAGMA incremental_vacuum" -1 dummy] + sqlite3_step $stmt +} {SQLITE_CORRUPT} +do_test 1.10 { sqlite3_errcode db } {SQLITE_CORRUPT} +do_test 1.11 { sqlite3_errmsg db } {database disk image is malformed} + +do_test 1.12 { + set stmt2 [sqlite3_prepare_v2 db "SELECT 1" -1 dummy] + sqlite3_finalize $stmt2 +} {SQLITE_OK} +do_test 1.13 { sqlite3_errcode db } {SQLITE_OK} +do_test 1.14 { sqlite3_errmsg db } {not an error} + +do_test 1.15 { sqlite3_finalize $stmt } {SQLITE_CORRUPT} +do_test 1.16 { sqlite3_errcode db } {SQLITE_CORRUPT} +do_test 1.17 { sqlite3_errmsg db } {database disk image is malformed} + +#------------------------------------------------------------------------- +# +reset_db + +do_execsql_test 2.1 { + PRAGMA auto_vacuum = 1; + CREATE TABLE t1(a PRIMARY KEY, b); + WITH data(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM data + ) + INSERT INTO t1 SELECT i, randomblob(600) FROM data LIMIT 20; + PRAGMA page_count; +} {24} + +do_test 2.2 { + db_save + set fd [open test.db r+] + chan truncate $fd [expr 22*1024] + close $fd + catchsql { PRAGMA incremental_vacuum; } +} {1 {database disk image is malformed}} + +do_test 2.3 { + set stmt [sqlite3_prepare_v2 db "PRAGMA auto_vacuum = INCREMENTAL" -1 dummy] + sqlite3_step $stmt +} {SQLITE_CORRUPT} +do_test 2.4 { sqlite3_errcode db } {SQLITE_CORRUPT} +do_test 2.5 { sqlite3_errmsg db } {database disk image is malformed} +do_test 2.6 { sqlite3_finalize $stmt } {SQLITE_CORRUPT} +do_test 2.7 { sqlite3_errcode db } {SQLITE_CORRUPT} +do_test 2.8 { sqlite3_errmsg db } {database disk image is malformed} + +do_test 2.9 { + set stmt [sqlite3_prepare_v2 db "PRAGMA auto_vacuum = INCREMENTAL" -1 dummy] + sqlite3_step $stmt +} {SQLITE_CORRUPT} +do_test 2.10 { sqlite3_errcode db } {SQLITE_CORRUPT} +do_test 2.11 { sqlite3_errmsg db } {database disk image is malformed} + +do_test 2.12 { + set stmt2 [sqlite3_prepare_v2 db "SELECT 1" -1 dummy] + sqlite3_finalize $stmt2 +} {SQLITE_OK} +do_test 2.13 { sqlite3_errcode db } {SQLITE_OK} +do_test 2.14 { sqlite3_errmsg db } {not an error} + +do_test 2.15 { sqlite3_finalize $stmt } {SQLITE_CORRUPT} +do_test 2.16 { sqlite3_errcode db } {SQLITE_CORRUPT} +do_test 2.17 { sqlite3_errmsg db } {database disk image is malformed} + +finish_test + diff --git a/test/incrvacuum2.test b/test/incrvacuum2.test index 6e8e1be..2219d54 100644 --- a/test/incrvacuum2.test +++ b/test/incrvacuum2.test @@ -188,8 +188,10 @@ ifcapable wal { execsql { PRAGMA journal_mode = WAL; PRAGMA incremental_vacuum(1); - PRAGMA wal_checkpoint; } + } {wal} + do_test 4.2.1 { + execsql { PRAGMA wal_checkpoint } file size test.db-wal } [expr {32+2*(512+24)}] diff --git a/test/index3.test b/test/index3.test index a9f9b7a..0cdc6e0 100644 --- a/test/index3.test +++ b/test/index3.test @@ -51,6 +51,6 @@ do_test index3-99.1 { db close catch { sqlite3 db test.db } catchsql { DROP INDEX i1 } -} {1 {malformed database schema (t1) - near "nonsense": syntax error}} +} {1 {malformed database schema (t1)}} finish_test diff --git a/test/index6.test b/test/index6.test index 8414b11..69fae49 100644 --- a/test/index6.test +++ b/test/index6.test @@ -296,4 +296,35 @@ do_execsql_test index6-7.4 { SELECT * FROM t7a JOIN t7b ON (x=99) ORDER BY x; } {/USING COVERING INDEX t7ax/} + +do_execsql_test index6-8.0 { + CREATE TABLE t8a(a,b); + CREATE TABLE t8b(x,y); + CREATE INDEX i8c ON t8b(y) WHERE x = 'value'; + + INSERT INTO t8a VALUES(1, 'one'); + INSERT INTO t8a VALUES(2, 'two'); + INSERT INTO t8a VALUES(3, 'three'); + + INSERT INTO t8b VALUES('value', 1); + INSERT INTO t8b VALUES('dummy', 2); + INSERT INTO t8b VALUES('value', 3); + INSERT INTO t8b VALUES('dummy', 4); +} {} + +do_eqp_test index6-8.1 { + SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) +} { + 0 0 0 {SCAN TABLE t8a} + 0 1 1 {SEARCH TABLE t8b USING INDEX i8c (y=?)} +} + +do_execsql_test index6-8.2 { + SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) +} { + 1 one value 1 + 2 two {} {} + 3 three value 3 +} + finish_test diff --git a/test/index7.test b/test/index7.test index 0f341a3..557fe21 100644 --- a/test/index7.test +++ b/test/index7.test @@ -21,6 +21,31 @@ ifcapable !vtab { return } +# Capture the output of a pragma in a TEMP table. +# +proc capture_pragma {db tabname sql} { + $db eval "DROP TABLE IF EXISTS temp.$tabname" + set once 1 + $db eval $sql x { + if {$once} { + set once 0 + set ins "INSERT INTO $tabname VALUES" + set crtab "CREATE TEMP TABLE $tabname " + set sep "(" + foreach col $x(*) { + append ins ${sep}\$x($col) + append crtab ${sep}\"$col\" + set sep , + } + append ins ) + append crtab ) + $db eval $crtab + } + $db eval $ins + } +} + + load_static_extension db wholenumber; do_test index7-1.1 { # Able to parse and manage partial indices @@ -37,6 +62,15 @@ do_test index7-1.1 { } } {14 20 ok} +# (The "partial" column of the PRAGMA index_list output is...) +# EVIDENCE-OF: R-34457-09668 "1" if the index is a partial index and "0" +# if not. +# +do_test index7-1.1a { + capture_pragma db out {PRAGMA index_list(t1)} + db eval {SELECT "name", "partial", '|' FROM out ORDER BY "name"} +} {sqlite_autoindex_t1_1 0 | t1a 1 | t1b 1 |} + # Make sure the count(*) optimization works correctly with # partial indices. Ticket [a5c8ed66cae16243be6] 2013-10-03. # @@ -277,5 +311,9 @@ do_eqp_test index7-6.4 { } { 0 0 0 {SEARCH TABLE t4 USING INDEX i4 (c=?)} } +do_catchsql_test index7-6.5 { + CREATE INDEX t5a ON t5(a) WHERE a=#1; +} {1 {near "#1": syntax error}} + finish_test diff --git a/test/indexedby.test b/test/indexedby.test index f95c167..413bf07 100644 --- a/test/indexedby.test +++ b/test/indexedby.test @@ -1,4 +1,4 @@ -# 2008 October 4 +# 2008-10-04 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: @@ -9,7 +9,6 @@ # #*********************************************************************** # -# $Id: indexedby.test,v 1.5 2009/03/22 20:36:19 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -58,20 +57,45 @@ do_execsql_test indexedby-1.4 { # attached to a table in the FROM clause, but not to a sub-select or # SQL view. Also test that specifying an index that does not exist or # is attached to a different table is detected as an error. +# +# EVIDENCE-OF: R-63761-48810 -- syntax diagram qualified-table-name # +# EVIDENCE-OF: R-58230-57098 The "INDEXED BY index-name" phrase +# specifies that the named index must be used in order to look up values +# on the preceding table. +# do_test indexedby-2.1 { execsql { SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'} } {} +do_test indexedby-2.1b { + execsql { SELECT * FROM main.t1 NOT INDEXED WHERE a = 'one' AND b = 'two'} +} {} do_test indexedby-2.2 { execsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'} } {} +do_test indexedby-2.2b { + execsql { SELECT * FROM main.t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'} +} {} do_test indexedby-2.3 { execsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'} } {} - +# EVIDENCE-OF: R-44699-55558 The INDEXED BY clause does not give the +# optimizer hints about which index to use; it gives the optimizer a +# requirement of which index to use. +# EVIDENCE-OF: R-15800-25719 If index-name does not exist or cannot be +# used for the query, then the preparation of the SQL statement fails. +# do_test indexedby-2.4 { catchsql { SELECT * FROM t1 INDEXED BY i3 WHERE a = 'one' AND b = 'two'} } {1 {no such index: i3}} + +# EVIDENCE-OF: R-62112-42456 If the query optimizer is unable to use the +# index specified by the INDEX BY clause, then the query will fail with +# an error. +do_test indexedby-2.4.1 { + catchsql { SELECT b FROM t1 INDEXED BY i1 WHERE b = 'two' } +} {1 {no query solution}} + do_test indexedby-2.5 { catchsql { SELECT * FROM t1 INDEXED BY i5 WHERE a = 'one' AND b = 'two'} } {1 {no such index: i5}} @@ -82,11 +106,26 @@ do_test indexedby-2.7 { catchsql { SELECT * FROM v1 INDEXED BY i1 WHERE a = 'one' } } {1 {no such index: i1}} + # Tests for single table cases. # +# EVIDENCE-OF: R-37002-28871 The "NOT INDEXED" clause specifies that no +# index shall be used when accessing the preceding table, including +# implied indices create by UNIQUE and PRIMARY KEY constraints. However, +# the rowid can still be used to look up entries even when "NOT INDEXED" +# is specified. +# do_execsql_test indexedby-3.1 { + EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a = 'one' AND b = 'two' +} {/SEARCH TABLE t1 USING INDEX/} +do_execsql_test indexedby-3.1.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two' } {0 0 0 {SCAN TABLE t1}} +do_execsql_test indexedby-3.1.2 { + EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE rowid=1 +} {/SEARCH TABLE t1 USING INTEGER PRIMARY KEY .rowid=/} + + do_execsql_test indexedby-3.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two' @@ -184,6 +223,10 @@ do_execsql_test indexedby-6.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid } {0 0 0 {SCAN TABLE t1}} +# EVIDENCE-OF: R-40297-14464 The INDEXED BY phrase forces the SQLite +# query planner to use a particular named index on a DELETE, SELECT, or +# UPDATE statement. +# # Test that "INDEXED BY" can be used in a DELETE statement. # do_execsql_test indexedby-7.1 { diff --git a/test/insert2.test b/test/insert2.test index 6876d53..977fbc5 100644 --- a/test/insert2.test +++ b/test/insert2.test @@ -16,6 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix insert2 # Create some tables with data that we can select against # @@ -275,4 +276,23 @@ ifcapable subquery { } {1 2 1 3 1 4} } +do_execsql_test 6.0 { + CREATE TABLE t5(a, b, c DEFAULT 'c', d); +} +do_execsql_test 6.1 { + INSERT INTO t5(a) SELECT 456 UNION ALL SELECT 123 ORDER BY 1; + SELECT * FROM t5 ORDER BY rowid; +} {123 {} c {} 456 {} c {}} + +ifcapable fts3 { + do_execsql_test 6.2 { + CREATE VIRTUAL TABLE t0 USING fts4(a); + } + do_execsql_test 6.3 { + INSERT INTO t0 SELECT 0 UNION SELECT 0 AS 'x' ORDER BY x; + SELECT * FROM t0; + } {0} +} + + finish_test diff --git a/test/insert4.test b/test/insert4.test index 889d5e7..3eece87 100644 --- a/test/insert4.test +++ b/test/insert4.test @@ -560,5 +560,10 @@ do_test insert4-8.25 { } } {1 3} +do_catchsql_test insert4-9.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(x); + INSERT INTO t1(x) VALUES(5 COLLATE xyzzy) UNION SELECT 0; +} {1 {no such collation sequence: xyzzy}} finish_test diff --git a/test/jrnlmode.test b/test/jrnlmode.test index b1007c4..2ba56f2 100644 --- a/test/jrnlmode.test +++ b/test/jrnlmode.test @@ -555,4 +555,18 @@ do_execsql_test jrnlmode-8.28 { PRAGMA journal_mode=DELETE } {delete} do_execsql_test jrnlmode-8.29 { COMMIT } {} do_execsql_test jrnlmode-8.30 { PRAGMA journal_mode=DELETE } {delete} +# Assertion fault on 2015-05-01 +do_test jrnlmode-9.1 { + forcedelete test2.db + sqlite3 db2 test2.db + db2 eval {CREATE TEMP TABLE t(l); PRAGMA journal_mode=off;} + db2 close +} {} +do_execsql_test jrnlmode-9.2 { + PRAGMA locking_mode = exclusive; + CREATE TABLE tx(a); + PRAGMA journal_mode = off; +} {exclusive off} + + finish_test diff --git a/test/like.test b/test/like.test index 923272c..18a01dc 100644 --- a/test/like.test +++ b/test/like.test @@ -749,7 +749,7 @@ ifcapable like_opt&&!icu { count { SELECT a FROM t10 WHERE f LIKE '12%' ORDER BY +a; } - } {12 123 scan 3 like 0} + } {12 123 scan 4 like 0} do_test like-10.6 { count { SELECT a FROM t10 WHERE a LIKE '12%' ORDER BY +a; @@ -790,7 +790,7 @@ ifcapable like_opt&&!icu { count { SELECT a FROM t10b WHERE f GLOB '12*' ORDER BY +a; } - } {12 123 scan 3 like 0} + } {12 123 scan 4 like 0} do_test like-10.15 { count { SELECT a FROM t10b WHERE a GLOB '12*' ORDER BY +a; diff --git a/test/like3.test b/test/like3.test new file mode 100644 index 0000000..a1faf76 --- /dev/null +++ b/test/like3.test @@ -0,0 +1,112 @@ +# 2015-03-06 +# +# 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 file is testing the LIKE and GLOB operators and +# in particular the optimizations that occur to help those operators +# run faster and that those optimizations work correctly when there +# are both strings and blobs being tested. +# +# Ticket 05f43be8fdda9fbd948d374319b99b054140bc36 shows that the following +# SQL was not working correctly: +# +# CREATE TABLE t1(x TEXT UNIQUE COLLATE nocase); +# INSERT INTO t1(x) VALUES(x'616263'); +# SELECT 'query-1', x FROM t1 WHERE x LIKE 'a%'; +# SELECT 'query-2', x FROM t1 WHERE +x LIKE 'a%'; +# +# This script verifies that it works right now. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test like3-1.1 { + PRAGMA encoding=UTF8; + CREATE TABLE t1(a,b TEXT COLLATE nocase); + INSERT INTO t1(a,b) + VALUES(1,'abc'), + (2,'ABX'), + (3,'BCD'), + (4,x'616263'), + (5,x'414258'), + (6,x'424344'); + CREATE INDEX t1ba ON t1(b,a); + + SELECT a, b FROM t1 WHERE b LIKE 'aB%' ORDER BY +a; +} {1 abc 2 ABX 4 abc 5 ABX} +do_execsql_test like3-1.2 { + SELECT a, b FROM t1 WHERE +b LIKE 'aB%' ORDER BY +a; +} {1 abc 2 ABX 4 abc 5 ABX} + +do_execsql_test like3-2.0 { + CREATE TABLE t2(a, b TEXT); + INSERT INTO t2 SELECT a, b FROM t1; + CREATE INDEX t2ba ON t2(b,a); + SELECT a, b FROM t2 WHERE b GLOB 'ab*' ORDER BY +a; +} {1 abc 4 abc} +do_execsql_test like3-2.1 { + SELECT a, b FROM t2 WHERE +b GLOB 'ab*' ORDER BY +a; +} {1 abc 4 abc} +do_execsql_test like3-2.2 { + SELECT a, b FROM t2 WHERE b>=x'6162' AND b GLOB 'ab*' +} {4 abc} +do_execsql_test like3-2.3 { + SELECT a, b FROM t2 WHERE +b>=x'6162' AND +b GLOB 'ab*' +} {4 abc} +do_execsql_test like3-2.4 { + SELECT a, b FROM t2 WHERE b GLOB 'ab*' AND b>=x'6162' +} {4 abc} +do_execsql_test like3-2.5 { + SELECT a, b FROM t2 WHERE +b GLOB 'ab*' AND +b>=x'6162' +} {4 abc} + +do_execsql_test like3-3.0 { + CREATE TABLE t3(x TEXT PRIMARY KEY COLLATE nocase); + INSERT INTO t3(x) VALUES('aaa'),('abc'),('abd'),('abe'),('acz'); + INSERT INTO t3(x) SELECT CAST(x AS blob) FROM t3; + SELECT quote(x) FROM t3 WHERE x LIKE 'ab%' ORDER BY x; +} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} +do_execsql_test like3-3.1 { + SELECT quote(x) FROM t3 WHERE x LIKE 'ab%' ORDER BY x DESC; +} {X'616265' X'616264' X'616263' 'abe' 'abd' 'abc'} +do_execsql_test like3-3.1ck { + SELECT quote(x) FROM t3 WHERE x LIKE 'ab%' ORDER BY +x DESC; +} {X'616265' X'616264' X'616263' 'abe' 'abd' 'abc'} +do_execsql_test like3-3.2 { + SELECT quote(x) FROM t3 WHERE x LIKE 'ab%' ORDER BY x ASC; +} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} +do_execsql_test like3-3.2ck { + SELECT quote(x) FROM t3 WHERE x LIKE 'ab%' ORDER BY +x ASC; +} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} + +do_execsql_test like3-4.0 { + CREATE TABLE t4(x TEXT COLLATE nocase); + CREATE INDEX t4x ON t4(x DESC); + INSERT INTO t4(x) SELECT x FROM t3; + SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY x; +} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} +do_execsql_test like3-4.1 { + SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY x DESC; +} {X'616265' X'616264' X'616263' 'abe' 'abd' 'abc'} +do_execsql_test like3-4.1ck { + SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY +x DESC; +} {X'616265' X'616264' X'616263' 'abe' 'abd' 'abc'} +do_execsql_test like3-4.2 { + SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY x ASC; +} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} +do_execsql_test like3-4.2ck { + SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY +x ASC; +} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} + + + +finish_test diff --git a/test/limit.test b/test/limit.test index 5d6ef33..d727497 100644 --- a/test/limit.test +++ b/test/limit.test @@ -251,6 +251,12 @@ do_test limit-6.8 { # Make sure LIMIT works well with compound SELECT statements. # Ticket #393 # +# EVIDENCE-OF: R-13512-64012 In a compound SELECT, only the last or +# right-most simple SELECT may contain a LIMIT clause. +# +# EVIDENCE-OF: R-03782-50113 In a compound SELECT, the LIMIT clause +# applies to the entire compound, not just the final SELECT. +# ifcapable compound { do_test limit-7.1.1 { catchsql { diff --git a/test/lock.test b/test/lock.test index 6ec85ee..f785c4b 100644 --- a/test/lock.test +++ b/test/lock.test @@ -241,6 +241,9 @@ execsql {ROLLBACK} # Test the built-in busy timeout handler # +# EVIDENCE-OF: R-23579-05241 PRAGMA busy_timeout; PRAGMA busy_timeout = +# milliseconds; Query or change the setting of the busy timeout. +# do_test lock-2.8 { db2 timeout 400 execsql BEGIN diff --git a/test/lock_common.tcl b/test/lock_common.tcl index bc1eb86..a758e7a 100644 --- a/test/lock_common.tcl +++ b/test/lock_common.tcl @@ -86,21 +86,51 @@ proc launch_testfixture {{prg ""}} { # Execute a command in a child testfixture process, connected by two-way # channel $chan. Return the result of the command, or an error message. # -proc testfixture {chan cmd} { - puts $chan $cmd - puts $chan OVER - set r "" - while { 1 } { +proc testfixture {chan cmd args} { + + if {[llength $args] == 0} { + fconfigure $chan -blocking 1 + puts $chan $cmd + puts $chan OVER + + set r "" + while { 1 } { + set line [gets $chan] + if { $line == "OVER" } { + set res [lindex $r 1] + if { [lindex $r 0] } { error $res } + return $res + } + if {[eof $chan]} { + return "ERROR: Child process hung up" + } + append r $line + } + return $r + } else { + set ::tfnb($chan) "" + fconfigure $chan -blocking 0 -buffering none + puts $chan $cmd + puts $chan OVER + fileevent $chan readable [list testfixture_script_cb $chan [lindex $args 0]] + return "" + } +} + +proc testfixture_script_cb {chan script} { + if {[eof $chan]} { + append ::tfnb($chan) "ERROR: Child process hung up" + set line "OVER" + } else { set line [gets $chan] - if { $line == "OVER" } { - set res [lindex $r 1] - if { [lindex $r 0] } { error $res } - return $res - } - if {[eof $chan]} { - return "ERROR: Child process hung up" - } - append r $line + } + + if { $line == "OVER" } { + uplevel #0 $script [list [lindex $::tfnb($chan) 1]] + unset ::tfnb($chan) + fileevent $chan readable "" + } else { + append ::tfnb($chan) $line } } diff --git a/test/malloc.test b/test/malloc.test index 8614567..dbf4699 100644 --- a/test/malloc.test +++ b/test/malloc.test @@ -923,6 +923,27 @@ do_faultsim_test 41.2 -faults oom* -body { faultsim_integrity_check } +reset_db +do_execsql_test 42.0 { + CREATE TABLE t1(x INTEGER PRIMARY KEY, y, z); + CREATE TABLE t2(a, b); + CREATE VIEW a002 AS SELECT *, sum(b) AS m FROM t2 GROUP BY a; +} +faultsim_save_and_close +do_faultsim_test 42 -faults oom-tran* -prep { + faultsim_restore_and_reopen + execsql { SELECT * FROM sqlite_master } +} -body { + execsql { + SELECT t1.z, a002.m + FROM t1 JOIN a002 ON t1.y=a002.m + WHERE t1.x IN (1,2,3); + } +} -test { + faultsim_test_result {0 {}} +} + + # Ensure that no file descriptors were leaked. do_test malloc-99.X { catch {db close} diff --git a/test/malloc5.test b/test/malloc5.test index 6abedf7..c046499 100644 --- a/test/malloc5.test +++ b/test/malloc5.test @@ -71,6 +71,23 @@ do_test malloc5-1.3 { expr $::pgalloc > 0 } {1} +# The sizes of memory allocations from system malloc() might vary, +# depending on the memory allocator algorithms used. The following +# routine is designed to support answers that fall within a range +# of values while also supplying easy-to-understand "expected" values +# when errors occur. +# +proc value_in_range {target x args} { + set v [lindex $args 0] + if {$v!=""} { + if {$v<$target*$x} {return $v} + if {$v>$target/$x} {return $v} + } + return "number between [expr {int($target*$x)}] and [expr {int($target/$x)}]" +} +set mrange 0.98 ;# plus or minus 2% + + do_test malloc5-1.4 { # Commit the transaction and open a new one. Read 1 page into the cache. # Because the page is not dirty, it is eligible for collection even @@ -81,16 +98,16 @@ do_test malloc5-1.4 { BEGIN; SELECT * FROM abc; } - sqlite3_release_memory -} $::pgalloc + value_in_range $::pgalloc $::mrange [sqlite3_release_memory] +} [value_in_range $::pgalloc $::mrange] do_test malloc5-1.5 { # Conclude the transaction opened in the previous [do_test] block. This # causes another page (page 1) to become eligible for recycling. # execsql { COMMIT } - sqlite3_release_memory -} $::pgalloc + value_in_range $::pgalloc $::mrange [sqlite3_release_memory] +} [value_in_range $::pgalloc $::mrange] do_test malloc5-1.6 { # Manipulate the cache so that it contains two unused pages. One requires @@ -101,8 +118,8 @@ do_test malloc5-1.6 { SELECT * FROM abc; CREATE TABLE def(d, e, f); } - sqlite3_release_memory 500 -} $::pgalloc + value_in_range $::pgalloc $::mrange [sqlite3_release_memory 500] +} [value_in_range $::pgalloc $::mrange] do_test malloc5-1.7 { # Database should not be locked this time. diff --git a/test/mallocK.test b/test/mallocK.test index dcf00da..65791e7 100644 --- a/test/mallocK.test +++ b/test/mallocK.test @@ -134,5 +134,42 @@ do_faultsim_test 6 -faults oom* -body { faultsim_test_result {0 {12 13 14 15}} } +do_execsql_test 7.1 { + CREATE TABLE x1(a INTEGER PRIMARY KEY, b); +} +do_faultsim_test 7.2 -faults oom* -body { + execsql { SELECT * FROM x1 WHERE a = (SELECT 1) } +} -test { + faultsim_test_result [list 0 {}] +} + +reset_db + +proc isqrt {i} { expr { int(sqrt($i)) } } +db func isqrt isqrt + +do_execsql_test 8.0 { + PRAGMA encoding = 'utf-16'; + CREATE TABLE x2(x TEXT, y TEXT); + WITH data(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM data + ) + INSERT INTO x2 SELECT isqrt(i), isqrt(i) FROM data LIMIT 400; + CREATE INDEX x2x ON x2(x); + CREATE INDEX x2y ON x2(y); + ANALYZE; + DELETE FROM x2; +} + +proc str {a} { return $a } +db func str -deterministic str + +do_faultsim_test 8 -faults oom* -body { + execsql { SELECT * FROM x2 WHERE x = str('19') AND y = str('4') } +} -test { + faultsim_test_result [list 0 {}] +} + + finish_test diff --git a/test/misc1.test b/test/misc1.test index 173b77d..7ae50e4 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -13,7 +13,6 @@ # This file implements tests for miscellanous features that were # left out of other test files. # -# $Id: misc1.test,v 1.42 2007/11/05 14:58:23 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -621,4 +620,68 @@ do_test misc1-19.2 { set fault_callbacks } {0} +# 2015-01-26: Valgrind-detected over-read. +# Reported on sqlite-users@sqlite.org by Michal Zalewski. Found by afl-fuzz +# presumably. +# +do_execsql_test misc1-20.1 { + CREATE TABLE t0(x INTEGER DEFAULT(0==0) NOT NULL); + REPLACE INTO t0(x) VALUES(''); + SELECT rowid, quote(x) FROM t0; +} {1 ''} + +# 2015-03-22: NULL pointer dereference after a syntax error +# +do_catchsql_test misc1-21.1 { + select''like''like''like#0; +} {1 {near "#0": syntax error}} +do_catchsql_test misc1-21.2 { + VALUES(0,0x0MATCH#0; +} {1 {near ";": syntax error}} + +# 2015-04-15 +do_execsql_test misc1-22.1 { + SELECT ""+3 FROM (SELECT ""+5); +} {3} + +# 2015-04-19: NULL pointer dereference on a corrupt schema +# +db close +sqlite3 db :memory: +do_execsql_test misc1-23.1 { + CREATE TABLE t1(x); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE table t(d CHECK(T(#0)'; + BEGIN; + CREATE TABLE t2(y); + ROLLBACK; + DROP TABLE IF EXISTS t3; +} {} + +# 2015-04-19: Faulty assert() statement +# +db close +database_may_be_corrupt +sqlite3 db :memory: +do_catchsql_test misc1-23.2 { + CREATE TABLE t1(x UNIQUE); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE TABLE IF not EXISTS t(c)'; + BEGIN; + CREATE TABLE t2(x); + ROLLBACK; + DROP TABLE F; +} {1 {no such table: F}} +db close +sqlite3 db :memory: +do_catchsql_test misc1-23.3 { + CREATE TABLE t1(x UNIQUE); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE table y(a TEXT, a TEXT)'; + BEGIN; + CREATE TABLE t2(y); + ROLLBACK; + DROP TABLE IF EXISTS t; +} {0 {}} + finish_test diff --git a/test/misc5.test b/test/misc5.test index 14ba44e..30176b8 100644 --- a/test/misc5.test +++ b/test/misc5.test @@ -583,6 +583,24 @@ do_test misc5-7.1 { catchsql $sql } {1 {parser stack overflow}} +# Parser stack overflow is silently ignored when it occurs while parsing the +# schema and PRAGMA writable_schema is turned on. +# +do_test misc5-7.2 { + sqlite3 db2 :memory: + catchsql { + CREATE TABLE t1(x UNIQUE); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE table t(o CHECK(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((;VALUES(o)'; + BEGIN; + CREATE TABLE t2(y); + ROLLBACK; + DROP TABLE IF EXISTS D; + } db2 +} {0 {}} +db2 close + + # Ticket #1911 # ifcapable compound { diff --git a/test/mkfuzzdata1.tcl b/test/mkfuzzdata1.tcl new file mode 100644 index 0000000..8af45f6 --- /dev/null +++ b/test/mkfuzzdata1.tcl @@ -0,0 +1,113 @@ +#!/usr/bin/tclsh +# +# Run this script in order to rebuild the fuzzdata1.txt file containing +# fuzzer data for the fuzzershell utility that is create by afl-fuzz. +# +# This script gathers all of the test cases identified by afl-fuzz and +# runs afl-cmin and afl-tmin over them all to try to generate a mimimum +# set of tests that cover all observed behavior. +# +# Options: +# +# --afl-bin DIR1 DIR1 contains the AFL binaries +# --fuzzershell PATH Full pathname of instrumented fuzzershell +# --afl-data DIR3 DIR3 is the "-o" directory from afl-fuzz +# -o FILE Write results into FILE +# +set AFLBIN {} +set FUZZERSHELL {} +set AFLDATA {} +set OUTFILE {} + +proc usage {} { + puts stderr "Usage: $::argv0 --afl-bin DIR --fuzzershell PATH\ + --afl-data DIR -o FILE" + exit 1 +} +proc cmdlineerr {msg} { + puts stderr $msg + usage +} + +for {set i 0} {$i<[llength $argv]} {incr i} { + set x [lindex $argv $i] + if {[string index $x 0]!="-"} {cmdlineerr "illegal argument: $x"} + set x [string trimleft $x -] + incr i + if {$i>=[llength $argv]} {cmdlineerr "no argument on --$x"} + set a [lindex $argv $i] + switch -- $x { + afl-bin {set AFLBIN $a} + afl-data {set AFLDATA $a} + fuzzershell {set FUZZERSHELL $a} + o {set OUTFILE $a} + default {cmdlineerr "unknown option: --$x"} + } +} +proc checkarg {varname option} { + set val [set ::$varname] + if {$val==""} {cmdlineerr "required option missing: --$option"} +} +checkarg AFLBIN afl-bin +checkarg AFLDATA afl-data +checkarg FUZZERSHELL fuzzershell +checkarg OUTFILE o +proc checkexec {x} { + if {![file exec $x]} {cmdlineerr "cannot find $x"} +} +checkexec $AFLBIN/afl-cmin +checkexec $AFLBIN/afl-tmin +checkexec $FUZZERSHELL +proc checkdir {x} { + if {![file isdir $x]} {cmdlineerr "no such directory: $x"} +} +checkdir $AFLDATA/queue + +proc progress {msg} { + puts "******** $msg" + flush stdout +} +progress "mkdir tmp1 tmp2" +file mkdir tmp1 tmp2 +progress "copying test cases from $AFLDATA into tmp1..." +set n 0 +foreach file [glob -nocomplain $AFLDATA/queue/id:*] { + incr n + file copy $file tmp1/$n +} +foreach file [glob -nocomplain $AFLDATA/crash*/id:*] { + incr n + file copy $file tmp1/$n +} +progress "total $n files copied." +progress "running: $AFLBIN/afl-cmin -i tmp1 -o tmp2 $FUZZERSHELL" +exec $AFLBIN/afl-cmin -i tmp1 -o tmp2 $FUZZERSHELL >&@ stdout +progress "afl-cmin complete." +# +# Experiments show that running afl-tmin is too slow for this application. +# And it doesn't really make the test cases that much smaller. So let's +# just skip it. +# +# foreach file [glob tmp2/*] { +# progress "$AFLBIN/afl-tmin -i $file -o tmp3/[file tail $file] $FUZZERSHELL" +# exec $AFLBIN/afl-tmin -i $file -o tmp3/[file tail $file] \ +# $FUZZERSHELL >&@ stdout +# } +progress "generating final output into $OUTFILE" +set out [open $OUTFILE wb] +puts $out "# Test data for use with fuzzershell. Automatically +# generated using $argv0. This file contains binary data +#" +set n 0 +foreach file [glob tmp2/*] { + incr n + puts -nonewline $out "/****<$n>****/" + set in [open $file rb] + puts -nonewline $out [read $in] + close $in +} +close $out +progress "done. $n test cases written to $OUTFILE" +progress "clean-up..." +file delete -force tmp1 +progress "culled test cases left in the tmp2 directory" diff --git a/test/multiplex4.test b/test/multiplex4.test index 9c304c3..2caebea 100644 --- a/test/multiplex4.test +++ b/test/multiplex4.test @@ -59,6 +59,14 @@ do_test multiplex4-1.1 { multiplex_file_list mx4test } {mx4test.db} +# NB: The PRAGMA multiplex_truncate command is implemented using the +# SQLITE_FCNTL_PRAGMA file-control... +# +# EVIDENCE-OF: R-12238-55120 Whenever a PRAGMA statement is parsed, an +# SQLITE_FCNTL_PRAGMA file control is sent to the open sqlite3_file +# object corresponding to the database file to which the pragma +# statement refers. +# do_test multiplex4-1.2 { db eval {PRAGMA multiplex_truncate} } {on} @@ -84,6 +92,16 @@ do_test multiplex4-1.9 { db eval {PRAGMA multiplex_truncate=0} } {off} +# EVIDENCE-OF: R-26188-08449 If the SQLITE_FCNTL_PRAGMA file control +# returns SQLITE_OK, then the parser assumes that the VFS has handled +# the PRAGMA itself and the parser generates a no-op prepared statement +# if result string is NULL, or that returns a copy of the result string +# if the string is non-NULL. +# +do_test multiplex4-1.9-explain { + db eval {EXPLAIN PRAGMA multiplex_truncate=0;} +} {/String8 \d \d \d off/} + do_test multiplex4-1.10 { db eval { INSERT INTO t1(x) VALUES(randomblob(250000)); diff --git a/test/null.test b/test/null.test index f3782a7..e8eeb97 100644 --- a/test/null.test +++ b/test/null.test @@ -278,6 +278,23 @@ do_test null-8.15 { } } {1} +do_execsql_test null-9.1 { + CREATE TABLE t5(a, b, c); + CREATE UNIQUE INDEX t5ab ON t5(a, b); + + INSERT INTO t5 VALUES(1, NULL, 'one'); + INSERT INTO t5 VALUES(1, NULL, 'i'); + INSERT INTO t5 VALUES(NULL, 'x', 'two'); + INSERT INTO t5 VALUES(NULL, 'x', 'ii'); +} + +do_execsql_test null-9.2 { + SELECT * FROM t5 WHERE a = 1 AND b IS NULL; +} {1 {} one 1 {} i} + +do_execsql_test null-9.3 { + SELECT * FROM t5 WHERE a IS NULL AND b = 'x'; +} {{} x two {} x ii} finish_test diff --git a/test/orderby1.test b/test/orderby1.test index 6674e32..3e785c5 100644 --- a/test/orderby1.test +++ b/test/orderby1.test @@ -463,6 +463,9 @@ do_execsql_test 5.1 { do_execsql_test 5.2 { SELECT 5 UNION ALL SELECT 3 ORDER BY 1 } {3 5} +do_execsql_test 5.3 { + SELECT 986 AS x GROUP BY X ORDER BY X +} {986} # The following test (originally derived from a single test within fuzz.test) # verifies that a PseudoTable cursor is not closed prematurely in a deeply @@ -495,5 +498,34 @@ do_execsql_test 7.0 { SELECT * FROM t7 WHERE a=?1 ORDER BY rowid; } {~/ORDER BY/} +#------------------------------------------------------------------------- +# Test a partial sort large enough to cause the sorter to spill data +# to disk. +# +reset_db +do_execsql_test 8.0 { + PRAGMA cache_size = 5; + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a); +} + +do_eqp_test 8.1 { + SELECT * FROM t1 ORDER BY a, b; +} { + 0 0 0 {SCAN TABLE t1 USING INDEX i1} + 0 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} +} + +do_execsql_test 8.2 { + WITH cnt(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM cnt WHERE i<10000 + ) + INSERT INTO t1 SELECT i%2, randomblob(500) FROM cnt; +} + +do_test 8.3 { + db eval { SELECT * FROM t1 ORDER BY a, b } { incr res $a } + set res +} 5000 finish_test diff --git a/test/pagesize.test b/test/pagesize.test index 0eebbbb..8800530 100644 --- a/test/pagesize.test +++ b/test/pagesize.test @@ -216,4 +216,22 @@ foreach PGSZ {512 2048 4096 8192} { } [list $PGSZ $PGSZ] } +reset_db +do_execsql_test pagesize-3.1 { + BEGIN; + SELECT * FROM sqlite_master; + PRAGMA page_size=2048; + PRAGMA main.page_size; +} {1024} +do_execsql_test pagesize-3.2 { + CREATE TABLE t1(x); + COMMIT; +} +do_execsql_test pagesize-3.3 { + BEGIN; + PRAGMA page_size = 2048; + COMMIT; + PRAGMA main.page_size; +} {1024} + finish_test diff --git a/test/pragma.test b/test/pragma.test index 09b9b6c..587a03c 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -51,6 +51,30 @@ ifcapable !pragma { return } +# Capture the output of a pragma in a TEMP table. +# +proc capture_pragma {db tabname sql} { + $db eval "DROP TABLE IF EXISTS temp.$tabname" + set once 1 + $db eval $sql x { + if {$once} { + set once 0 + set ins "INSERT INTO $tabname VALUES" + set crtab "CREATE TEMP TABLE $tabname " + set sep "(" + foreach col $x(*) { + append ins ${sep}\$x($col) + append crtab ${sep}\"$col\" + set sep , + } + append ins ) + append crtab ) + $db eval $crtab + } + $db eval $ins + } +} + # Delete the preexisting database to avoid the special setup # that the "all.test" script does. # @@ -59,7 +83,11 @@ delete_file test.db test.db-journal delete_file test3.db test3.db-journal sqlite3 db test.db; set DB [sqlite3_connection_pointer db] - +# EVIDENCE-OF: R-24197-42751 PRAGMA database.cache_size; PRAGMA +# database.cache_size = pages; PRAGMA database.cache_size = -kibibytes; +# Query or change the suggested maximum number of database disk pages +# that SQLite will hold in memory at once per open database file. +# ifcapable pager_pragmas { set DFLT_CACHE_SZ [db one {PRAGMA default_cache_size}] set TEMP_CACHE_SZ [db one {PRAGMA temp.default_cache_size}] @@ -71,6 +99,8 @@ do_test pragma-1.1 { } } [list $DFLT_CACHE_SZ $DFLT_CACHE_SZ 2] do_test pragma-1.2 { + # EVIDENCE-OF: R-42059-47211 If the argument N is positive then the + # suggested cache size is set to N. execsql { PRAGMA synchronous=OFF; PRAGMA cache_size=1234; @@ -189,6 +219,24 @@ do_test pragma-1.14 { PRAGMA synchronous; } } {2} +do_test pragma-1.14.1 { + execsql { + PRAGMA synchronous=4; + PRAGMA synchronous; + } +} {0} +do_test pragma-1.14.2 { + execsql { + PRAGMA synchronous=3; + PRAGMA synchronous; + } +} {0} +do_test pragma-1.14.3 { + execsql { + PRAGMA synchronous=10; + PRAGMA synchronous; + } +} {2} } ;# ifcapable pager_pragmas # Test turning "flag" pragmas on and off. @@ -620,9 +668,10 @@ ifcapable {foreignkey} { } } {} do_test pragma-6.4 { - execsql { + capture_pragma db out { pragma index_list(t3); } + db eval {SELECT seq, "name", "unique" FROM out ORDER BY seq} } {0 sqlite_autoindex_t3_1 1} } ifcapable {!foreignkey} { @@ -631,9 +680,43 @@ ifcapable {!foreignkey} { do_test pragma-6.5.1 { execsql { CREATE INDEX t3i1 ON t3(a,b); + } + capture_pragma db out { pragma index_info(t3i1); } + db eval {SELECT seqno, cid, name FROM out ORDER BY seqno} } {0 0 a 1 1 b} + +# EVIDENCE-OF: R-23114-21695 The auxiliary index-columns are not shown +# by the index_info pragma, but they are listed by the index_xinfo +# pragma. +# +do_test pragma-6.5.1b { + capture_pragma db out {PRAGMA index_xinfo(t3i1)} + db eval {SELECT seqno, cid, name FROM out ORDER BY seqno} +} {0 0 a 1 1 b 2 -1 {}} + + +# EVIDENCE-OF: R-62725-03366 PRAGMA database.index_info(index-name); +# This pragma returns one row for each key column in the named index. +# +# (The first column of output from PRAGMA index_info is...) +# EVIDENCE-OF: R-34186-52914 The rank of the column within the index. (0 +# means left-most.) +# +# (The second column of output from PRAGMA index_info is...) +# EVIDENCE-OF: R-65019-08383 The rank of the column within the table +# being indexed. +# +# (The third column of output from PRAGMA index_info is...) +# EVIDENCE-OF: R-09773-34266 The name of the column being indexed. +# +do_execsql_test pragma-6.5.1c { + CREATE INDEX t3i2 ON t3(b,a); + PRAGMA index_info='t3i2'; + DROP INDEX t3i2; +} {0 1 b 1 0 a} + do_test pragma-6.5.2 { execsql { pragma index_info(t3i1_bogus); @@ -676,8 +759,10 @@ do_test pragma-6.7 { four REAL DEFAULT X'abcdef', five DEFAULT CURRENT_TIME ); - PRAGMA table_info(test_table); } + capture_pragma db out {PRAGMA table_info(test_table)} + db eval {SELECT cid, "name", type, "notnull", dflt_value, pk FROM out + ORDER BY cid} } [concat \ {0 one INT 1 -1 0} \ {1 two text 0 {} 0} \ @@ -685,18 +770,30 @@ do_test pragma-6.7 { {3 four REAL 0 X'abcdef' 0} \ {4 five {} 0 CURRENT_TIME 0} \ ] +do_test pragma-6.8 { + execsql { + CREATE TABLE t68(a,b,c,PRIMARY KEY(a,b,a,c)); + PRAGMA table_info(t68); + } +} [concat \ + {0 a {} 0 {} 1} \ + {1 b {} 0 {} 2} \ + {2 c {} 0 {} 4} \ +] } ;# ifcapable schema_pragmas # Miscellaneous tests # ifcapable schema_pragmas { +# EVIDENCE-OF: R-63500-32024 PRAGMA database.index_list(table-name); +# This pragma returns one row for each index associated with the given +# table. do_test pragma-7.1.1 { # Make sure a pragma knows to read the schema if it needs to db close sqlite3 db test.db - execsql { - pragma index_list(t3); - } -} {0 t3i1 0 1 sqlite_autoindex_t3_1 1} + capture_pragma db out "PRAGMA index_list(t3)" + db eval {SELECT name, "origin" FROM out ORDER BY name DESC} +} {t3i1 c sqlite_autoindex_t3_1 u} do_test pragma-7.1.2 { execsql { pragma index_list(t3_bogus); @@ -1281,18 +1378,23 @@ ifcapable pager_pragmas { db close forcedelete test.db sqlite3 db test.db - + + # EVIDENCE-OF: R-13905-26312 PRAGMA database.page_count; Return the + # total number of pages in the database file. + # do_test pragma-14.1 { execsql { pragma auto_vacuum = 0 } - execsql { pragma page_count } - } {0} + execsql { pragma page_count; pragma main.page_count } + } {0 0} do_test pragma-14.2 { execsql { CREATE TABLE abc(a, b, c); PRAGMA page_count; + PRAGMA main.page_count; + PRAGMA temp.page_count; } - } {2} + } {2 2 0} do_test pragma-14.2uc { execsql {pragma PAGE_COUNT} } {2} @@ -1701,23 +1803,90 @@ do_test 23.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d); CREATE INDEX i1 ON t1(b,c); CREATE INDEX i2 ON t1(c,d); + CREATE INDEX i2x ON t1(d COLLATE nocase, c DESC); CREATE TABLE t2(x INTEGER REFERENCES t1); } db2 eval {SELECT name FROM sqlite_master} -} {t1 i1 i2 t2} -do_test 23.2 { +} {t1 i1 i2 i2x t2} +do_test 23.2a { db eval { DROP INDEX i2; CREATE INDEX i2 ON t1(c,d,b); } - db2 eval {PRAGMA index_info(i2)} -} {0 2 c 1 3 d 2 1 b} + capture_pragma db2 out {PRAGMA index_info(i2)} + db2 eval {SELECT cid, name, '|' FROM out ORDER BY seqno} +} {2 c | 3 d | 1 b |} + +# EVIDENCE-OF: R-44874-46325 PRAGMA database.index_xinfo(index-name); +# This pragma returns information about every column in an index. +# +# EVIDENCE-OF: R-45970-35618 Unlike this index_info pragma, this pragma +# returns information about every column in the index, not just the key +# columns. +# +do_test 23.2b { + capture_pragma db2 out {PRAGMA index_xinfo(i2)} + db2 eval {SELECT cid, name, "desc", coll, "key", '|' FROM out ORDER BY seqno} +} {2 c 0 BINARY 1 | 3 d 0 BINARY 1 | 1 b 0 BINARY 1 | -1 {} 0 BINARY 0 |} + +# (The first column of output from PRAGMA index_xinfo is...) +# EVIDENCE-OF: R-00197-14279 The rank of the column within the index. (0 +# means left-most. Key columns come before auxiliary columns.) +# +# (The second column of output from PRAGMA index_xinfo is...) +# EVIDENCE-OF: R-40889-06838 The rank of the column within the table +# being indexed, or -1 if the index-column is the rowid of the table +# being indexed. +# +# (The third column of output from PRAGMA index_xinfo is...) +# EVIDENCE-OF: R-22751-28901 The name of the column being indexed, or +# NULL if the index-column is the rowid of the table being indexed. +# +# (The fourth column of output from PRAGMA index_xinfo is...) +# EVIDENCE-OF: R-11847-09179 1 if the index-column is sorted in reverse +# (DESC) order by the index and 0 otherwise. +# +# (The fifth column of output from PRAGMA index_xinfo is...) +# EVIDENCE-OF: R-15313-19540 The name for the collating sequence used to +# compare values in the index-column. +# +# (The sixth column of output from PRAGMA index_xinfo is...) +# EVIDENCE-OF: R-14310-64553 1 if the index-column is a key column and 0 +# if the index-column is an auxiliary column. +# +do_test 23.2c { + db2 eval {PRAGMA index_xinfo(i2)} +} {0 2 c 0 BINARY 1 1 3 d 0 BINARY 1 2 1 b 0 BINARY 1 3 -1 {} 0 BINARY 0} +do_test 23.2d { + db2 eval {PRAGMA index_xinfo(i2x)} +} {0 3 d 0 nocase 1 1 2 c 1 BINARY 1 2 -1 {} 0 BINARY 0} + +# EVIDENCE-OF: R-63500-32024 PRAGMA database.index_list(table-name); +# This pragma returns one row for each index associated with the given +# table. +# +# (The first column of output from PRAGMA index_list is...) +# EVIDENCE-OF: R-02753-24748 A sequence number assigned to each index +# for internal tracking purposes. +# +# (The second column of output from PRAGMA index_list is...) +# EVIDENCE-OF: R-35496-03635 The name of the index. +# +# (The third column of output from PRAGMA index_list is...) +# EVIDENCE-OF: R-57301-64506 "1" if the index is UNIQUE and "0" if not. +# +# (The fourth column of output from PRAGMA index_list is...) +# EVIDENCE-OF: R-36609-39554 "c" if the index was created by a CREATE +# INDEX statement, "u" if the index was created by a UNIQUE constraint, +# or "pk" if the index was created by a PRIMARY KEY constraint. +# do_test 23.3 { db eval { CREATE INDEX i3 ON t1(d,b,c); } - db2 eval {PRAGMA index_list(t1)} -} {0 i3 0 1 i2 0 2 i1 0} + capture_pragma db2 out {PRAGMA index_list(t1)} + db2 eval {SELECT seq, name, "unique", origin, '|' FROM out ORDER BY seq} +} {0 i3 0 c | 1 i2 0 c | 2 i2x 0 c | 3 i1 0 c |} do_test 23.4 { db eval { ALTER TABLE t1 ADD COLUMN e; diff --git a/test/pragma2.test b/test/pragma2.test index 0dbc977..3ade8c1 100644 --- a/test/pragma2.test +++ b/test/pragma2.test @@ -39,6 +39,10 @@ delete_file test3.db test3.db-journal sqlite3 db test.db; set DB [sqlite3_connection_pointer db] db eval {PRAGMA auto_vacuum=0} + +# EVIDENCE-OF: R-17887-14874 PRAGMA database.freelist_count; Return the +# number of unused pages in the database file. +# do_test pragma2-1.1 { execsql { PRAGMA freelist_count; diff --git a/test/printf.test b/test/printf.test index 7322272..6103d8a 100644 --- a/test/printf.test +++ b/test/printf.test @@ -472,6 +472,18 @@ do_test printf-1.16.7 { sqlite3_mprintf_int {abc: (%#6d) (%#6x) (%#6o) :xyz}\ 0xff676981 0xff676981 0xff676981 } {abc: (-9999999) (0xff676981) (037731664601) :xyz} +do_test printf-1.17.1 { + sqlite3_mprintf_int {abd: %2147483647d %2147483647x %2147483647o} 1 1 1 +} {} +do_test printf-1.17.2 { + sqlite3_mprintf_int {abd: %*d %x} 2147483647 1 1 +} {} +do_test printf-1.17.3 { + sqlite3_mprintf_int {abd: %*d %x} -2147483648 1 1 +} {abd: 1 1} +do_test printf-1.17.4 { + sqlite3_mprintf_int {abd: %.2147483648d %x %x} 1 1 1 +} {/.*/} do_test printf-2.1.1.1 { sqlite3_mprintf_double {abc: (%*.*f) :xyz} 1 1 0.001 } {abc: (0.0) :xyz} @@ -526,6 +538,9 @@ do_test printf-2.1.2.8 { do_test printf-2.1.2.9 { sqlite3_mprintf_double {abc: %d %d (%1.1g) :xyz} 1 1 1.0e-20 } {abc: 1 1 (1e-20) :xyz} +do_test printf-2.1.2.10 { + sqlite3_mprintf_double {abc: %*.*f} 2000000000 1000000000 1.0e-20 +} {abc: } do_test printf-2.1.3.1 { sqlite3_mprintf_double {abc: (%*.*f) :xyz} 1 1 1.0 } {abc: (1.0) :xyz} @@ -3466,6 +3481,15 @@ do_test printf-3.5 { do_test printf-3.6 { sqlite3_mprintf_str {%d %d A String: (%-30s)} 1 2 {This is the string} } [format {%d %d A String: (%-30s)} 1 2 {This is the string}] +do_test printf-3.7 { + sqlite3_mprintf_str {%d A String: (%*s)} 1 2147483647 {This is the string} +} [] +do_test printf-3.8 { + sqlite3_mprintf_str {%d A String: (%*s)} 1 -2147483648 {This is the string} +} {1 A String: (This is the string)} +do_test printf-3.9 { + sqlite3_mprintf_str {%d A String: (%.*s)} 1 -2147483648 {This is the string} +} {1 A String: (This is the string)} do_test snprintf-3.11 { sqlite3_snprintf_str 2 {x%d %d %s} 10 10 {This is the string} } {x} @@ -3685,6 +3709,9 @@ do_test printf-13.5 { do_test printf-13.6 { sqlite3_mprintf_hexdouble %.20f fff8000000000000 } {NaN} +do_test printf-13.7 { + sqlite3_mprintf_hexdouble %2147483648.10000f 4693b8b5b5056e17 +} {/100000000000000000000000000000000.00/} do_test printf-14.1 { sqlite3_mprintf_str {abc-%y-123} 0 0 {not used} diff --git a/test/printf2.test b/test/printf2.test index 21deeb7..fb031bd 100644 --- a/test/printf2.test +++ b/test/printf2.test @@ -58,6 +58,9 @@ do_execsql_test printf2-1.10 { do_execsql_test printf2-1.11 { SELECT printf('%lld%n',314159.2653,'hi'); } {314159} +do_execsql_test printf2-1.12 { + SELECT printf('%n',0); +} {{}} # EVIDENCE-OF: R-17002-27534 The %z format is interchangeable with %s. # diff --git a/test/rdonly.test b/test/rdonly.test index 938cc78..404c613 100644 --- a/test/rdonly.test +++ b/test/rdonly.test @@ -32,6 +32,11 @@ do_test rdonly-1.1 { SELECT * FROM t1; } } {1} + +# EVIDENCE-OF: R-29639-16887 The sqlite3_db_readonly(D,N) interface +# returns 1 if the database N of connection D is read-only, 0 if it is +# read/write, or -1 if N is not the name of a database on connection D. +# do_test rdonly-1.1.1 { sqlite3_db_readonly db main } {0} diff --git a/test/releasetest.tcl b/test/releasetest.tcl index 746fc9b..a429d83 100644 --- a/test/releasetest.tcl +++ b/test/releasetest.tcl @@ -14,16 +14,19 @@ optional) are: --config CONFIGNAME (Run only CONFIGNAME) --quick (Run "veryquick.test" only) --veryquick (Run "make smoketest" only) + --msvc (Use MSVC as the compiler) --buildonly (Just build testfixture - do not run) --dryrun (Print what would have happened) --info (Show diagnostic info) + --with-tcl=DIR (Use TCL build at DIR) The default value for --srcdir is the parent of the directory holding this script. The script determines the default value for --platform using the -$tcl_platform(os) and $tcl_platform(machine) variables. Supported -platforms are "Linux-x86", "Linux-x86_64" and "Darwin-i386". +$tcl_platform(os) and $tcl_platform(machine) variables. Supported +platforms are "Linux-x86", "Linux-x86_64", "Darwin-i386", +"Darwin-x86_64", "Windows NT-intel", and "Windows NT-amd64". Every test begins with a fresh run of the configure script at the top of the SQLite source tree. @@ -108,6 +111,13 @@ array set ::Configs [strip_comments { -DSQLITE_ENABLE_STAT4 -DSQLITE_MAX_ATTACHED=125 } + "Fast-One" { + -O6 + -DSQLITE_ENABLE_FTS4=1 + -DSQLITE_ENABLE_RTREE=1 + -DSQLITE_ENABLE_STAT4 + -DSQLITE_MAX_ATTACHED=125 + } "Device-One" { -O2 -DSQLITE_DEBUG=1 @@ -197,6 +207,8 @@ array set ::Configs [strip_comments { Fail2 {-O0} Fail3 {-O0} Fail4 {-O0} + FuzzFail1 {-O0} + FuzzFail2 {-O0} }] array set ::Platforms [strip_comments { @@ -212,6 +224,7 @@ array set ::Platforms [strip_comments { "No-lookaside" test "Devkit" test "Sanitize" {QUICKTEST_OMIT=func4.test,nan.test test} + "Fast-One" fuzzoomtest "Valgrind" valgrindtest "Default" "threadtest fulltest" "Device-One" fulltest @@ -238,6 +251,10 @@ array set ::Platforms [strip_comments { "Default" "mptest fulltestonly" "Have-Not" test } + "Windows NT-amd64" { + "Default" "mptest fulltestonly" + "Have-Not" test + } # The Failure-Detection platform runs various tests that deliberately # fail. This is used as a test of this script to verify that this script @@ -249,6 +266,8 @@ array set ::Platforms [strip_comments { Fail2 "TEST_FAILURE=2 valgrindtest" Fail3 "TEST_FAILURE=3 valgrindtest" Fail4 "TEST_FAILURE=4 test" + FuzzFail1 "TEST_FAILURE=5 test" + FuzzFail2 "TEST_FAILURE=5 valgrindtest" } }] @@ -296,6 +315,13 @@ proc count_tests_and_errors {logfile rcVar errmsgVar} { set errmsg $msg } } + if {[regexp {fatal error +(.*)} $line all msg]} { + incr ::NERRCASE + if {$rc==0} { + set rc 1 + set errmsg $msg + } + } if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} { incr ::NERRCASE if {$rc==0} { @@ -314,7 +340,13 @@ proc count_tests_and_errors {logfile rcVar errmsgVar} { } } close $fd - if {!$seen} { + if {$::BUILDONLY} { + if {$rc==0} { + set errmsg "Build complete" + } else { + set errmsg "Build failed" + } + } elseif {!$seen} { set rc 1 set errmsg "Test did not complete" if {[file readable core]} { @@ -329,10 +361,10 @@ proc run_test_suite {name testtarget config} { # CFLAGS. The makefile will pass OPTS to both gcc and lemon, but # CFLAGS is only passed to gcc. # - set cflags "-g" + set cflags [expr {$::MSVC ? "-Zi" : "-g"}] set opts "" set title ${name}($testtarget) - set configOpts "" + set configOpts $::WITHTCL regsub -all {#[^\n]*\n} $config \n config foreach arg $config { @@ -349,7 +381,14 @@ proc run_test_suite {name testtarget config} { set cflags [join $cflags " "] set opts [join $opts " "] - append opts " -DSQLITE_NO_SYNC=1 -DHAVE_USLEEP" + append opts " -DSQLITE_NO_SYNC=1" + + # Some configurations already set HAVE_USLEEP; in that case, skip it. + # + if {![regexp { -DHAVE_USLEEP$} $opts] + && ![regexp { -DHAVE_USLEEP[ =]+} $opts]} { + append opts " -DHAVE_USLEEP=1" + } # Set the sub-directory to use. # @@ -390,10 +429,10 @@ proc run_test_suite {name testtarget config} { if {$rc} { puts " FAIL $tm" incr ::NERR - if {$errmsg!=""} {puts " $errmsg"} } else { puts " Ok $tm" } + if {$errmsg!=""} {puts " $errmsg"} } } @@ -401,6 +440,7 @@ proc run_test_suite {name testtarget config} { # the current platform, which may be Windows (via MinGW, etc). # proc configureCommand {opts} { + if {$::MSVC} return [list]; # This is not needed for MSVC. set result [list trace_cmd exec] if {$::tcl_platform(platform)=="windows"} { lappend result sh @@ -414,7 +454,14 @@ proc configureCommand {opts} { # specified targets, compiler flags, and options. # proc makeCommand { targets cflags opts } { - set result [list trace_cmd exec make clean] + set result [list trace_cmd exec] + if {$::MSVC} { + set nmakeDir [file nativename $::SRCDIR] + set nmakeFile [file join $nmakeDir Makefile.msc] + lappend result nmake /f $nmakeFile TOP=$nmakeDir clean + } else { + lappend result make clean + } foreach target $targets { lappend result $target } @@ -443,10 +490,12 @@ proc trace_cmd {args} { proc process_options {argv} { set ::SRCDIR [file normalize [file dirname [file dirname $::argv0]]] set ::QUICK 0 + set ::MSVC 0 set ::BUILDONLY 0 set ::DRYRUN 0 set ::EXEC exec set ::TRACE 0 + set ::WITHTCL {} set config {} set platform $::tcl_platform(os)-$::tcl_platform(machine) @@ -476,6 +525,10 @@ proc process_options {argv} { set config [lindex $argv $i] } + -msvc { + set ::MSVC 1 + } + -buildonly { set ::BUILDONLY 1 } @@ -494,6 +547,7 @@ proc process_options {argv} { puts " --platform [list $platform]" puts " --config [list $config]" if {$::QUICK} {puts " --quick"} + if {$::MSVC} {puts " --msvc"} if {$::BUILDONLY} {puts " --buildonly"} if {$::DRYRUN} {puts " --dryrun"} if {$::TRACE} {puts " --trace"} @@ -507,7 +561,19 @@ proc process_options {argv} { } exit } - -g - + + -g { + if {$::MSVC} { + lappend ::EXTRACONFIG -Zi + } else { + lappend ::EXTRACONFIG [lindex $argv $i] + } + } + + -with-tcl=* { + set ::WITHTCL -$x + } + -D* - -O* - -enable-* - @@ -547,6 +613,7 @@ proc process_options {argv} { puts -nonewline "Flags:" if {$::DRYRUN} {puts -nonewline " --dryrun"} if {$::BUILDONLY} {puts -nonewline " --buildonly"} + if {$::MSVC} {puts -nonewline " --msvc"} switch -- $::QUICK { 1 {puts -nonewline " --quick"} 2 {puts -nonewline " --veryquick"} @@ -570,12 +637,20 @@ proc main {argv} { set ::SQLITE_VERSION {} set STARTTIME [clock seconds] foreach {zConfig target} $::CONFIGLIST { + if {$::MSVC && ($zConfig eq "Sanitize" || "checksymbols" in $target + || "valgrindtest" in $target)} { + puts "Skipping $zConfig / $target for MSVC..." + continue + } if {$target ne "checksymbols"} { switch -- $::QUICK { 1 {set target test} 2 {set target smoketest} } - if {$::BUILDONLY} {set target testfixture} + if {$::BUILDONLY} { + set target testfixture + if {$::MSVC} {append target .exe} + } } set config_options [concat $::Configs($zConfig) $::EXTRACONFIG] @@ -586,10 +661,11 @@ proc main {argv} { # it and run veryquick.test. If it did not include the SQLITE_DEBUG option # add it and run veryquick.test. if {$target!="checksymbols" && $target!="valgrindtest" - && !$::BUILDONLY && $::QUICK<2} { + && $target!="fuzzoomtest" && !$::BUILDONLY && $::QUICK<2} { set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*] set xtarget $target regsub -all {fulltest[a-z]*} $xtarget test xtarget + regsub -all {fuzzoomtest} $xtarget fuzztest xtarget if {$debug_idx < 0} { incr NTEST append config_options " -DSQLITE_DEBUG=1" diff --git a/test/resolver01.test b/test/resolver01.test index 7d95a21..59bb3c0 100644 --- a/test/resolver01.test +++ b/test/resolver01.test @@ -11,10 +11,12 @@ # # This file tests features of the name resolver (the component that # figures out what identifiers in the SQL statement refer to) that -# were fixed by ticket [2500cdb9be] +# were fixed by ticket [2500cdb9be]. # # See also tickets [1c69be2daf] and [f617ea3125] from 2013-08-14. # +# Also a fuzzer-discovered problem on 2015-04-23. +# set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -201,6 +203,12 @@ do_execsql_test resolver01-6.3 { GROUP BY lower(name); } {1 {} 1 {}} +do_execsql_test resolver01-7.1 { + SELECT 2 AS x WHERE (SELECT x AS y WHERE 3>y); +} {2} +do_execsql_test resolver01-7.2 { + SELECT 2 AS x WHERE (SELECT x AS y WHERE 1>y); +} {} diff --git a/test/select1.test b/test/select1.test index 875c87c..4d6c07f 100644 --- a/test/select1.test +++ b/test/select1.test @@ -307,6 +307,9 @@ do_test select1-4.4 { set v [catch {execsql {SELECT f1 FROM test1 ORDER BY min(f1)}} msg] lappend v $msg } {1 {misuse of aggregate: min()}} +do_catchsql_test select1-4.5 { + INSERT INTO test1(f1) SELECT f1 FROM test1 ORDER BY min(f1); +} {1 {misuse of aggregate: min()}} # The restriction not allowing constants in the ORDER BY clause # has been removed. See ticket #1768 @@ -1072,5 +1075,10 @@ if {[db one {PRAGMA locking_mode}]=="normal"} { do_test select1-16.1 { catchsql {SELECT 1 FROM (SELECT *)} } {1 {no tables specified}} + +# 2015-04-17: assertion fix. +do_catchsql_test select1-16.2 { + SELECT 1 FROM sqlite_master LIMIT 1,#1; +} {1 {near "#1": syntax error}} finish_test diff --git a/test/select4.test b/test/select4.test index 8fc200d..c0f88a1 100644 --- a/test/select4.test +++ b/test/select4.test @@ -105,6 +105,10 @@ ifcapable subquery { } } {0 1 2 2 3 3 3 3} } + +# EVIDENCE-OF: R-02644-22131 In a compound SELECT statement, only the +# last or right-most simple SELECT may have an ORDER BY clause. +# do_test select4-1.3 { set v [catch {execsql { SELECT DISTINCT log FROM t1 ORDER BY log @@ -114,6 +118,10 @@ do_test select4-1.3 { }} msg] lappend v $msg } {1 {ORDER BY clause should come after UNION ALL not before}} +do_catchsql_test select4-1.4 { + SELECT (VALUES(0) INTERSECT SELECT(0) UNION SELECT(0) ORDER BY 1 UNION + SELECT 0 UNION SELECT 0 ORDER BY 1); +} {1 {ORDER BY clause should come after UNION not before}} # Union operator # @@ -144,6 +152,15 @@ do_test select4-2.3 { }} msg] lappend v $msg } {1 {ORDER BY clause should come after UNION not before}} +do_test select4-2.4 { + set v [catch {execsql { + SELECT 0 ORDER BY (SELECT 0) UNION SELECT 0; + }} msg] + lappend v $msg +} {1 {ORDER BY clause should come after UNION not before}} +do_execsql_test select4-2.5 { + SELECT 123 AS x ORDER BY (SELECT x ORDER BY 1); +} {123} # Except operator # @@ -260,6 +277,16 @@ do_test select4-4.3 { }} msg] lappend v $msg } {1 {ORDER BY clause should come after INTERSECT not before}} +do_catchsql_test select4-4.4 { + SELECT 3 IN ( + SELECT 0 ORDER BY 1 + INTERSECT + SELECT 1 + INTERSECT + SELECT 2 + ORDER BY 1 + ); +} {1 {ORDER BY clause should come after INTERSECT not before}} # Various error messages while processing UNION or INTERSECT # @@ -795,6 +822,11 @@ do_test select4-11.15 { SELECT x FROM t2 } } {1 {SELECTs to the left and right of UNION do not have the same number of result columns}} +do_test select4-11.16 { + catchsql { + INSERT INTO t2(rowid) VALUES(2) UNION SELECT 3,4 UNION SELECT 5,6 ORDER BY 1; + } +} {1 {SELECTs to the left and right of UNION do not have the same number of result columns}} do_test select4-12.1 { sqlite3 db2 :memory: @@ -859,5 +891,23 @@ do_execsql_test select4-14.8 { do_execsql_test select4-14.9 { SELECT * FROM t14 UNION ALL VALUES(3,2,1),(2,3,1),(1,2,3),(2,1,3); } {1 2 3 4 5 6 3 2 1 2 3 1 1 2 3 2 1 3} +do_execsql_test select4-14.10 { + SELECT (VALUES(1),(2),(3),(4)) +} {1} +do_execsql_test select4-14.11 { + SELECT (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) +} {1} +do_execsql_test select4-14.12 { + VALUES(1) UNION VALUES(2); +} {1 2} +do_execsql_test select4-14.13 { + VALUES(1),(2),(3) EXCEPT VALUES(2); +} {1 3} +do_execsql_test select4-14.14 { + VALUES(1),(2),(3) EXCEPT VALUES(1),(3); +} {2} +do_execsql_test select4-14.15 { + SELECT * FROM (SELECT 123), (SELECT 456) ON likely(0 OR 1) OR 0; +} {123 456} finish_test diff --git a/test/select6.test b/test/select6.test index 64a8519..590512a 100644 --- a/test/select6.test +++ b/test/select6.test @@ -557,5 +557,61 @@ do_catchsql_test 10.8 { ) } $err +# 2015-02-09 Ticket [2f7170d73bf9abf80339187aa3677dce3dbcd5ca] +# "misuse of aggregate" error if aggregate column from FROM +# subquery is used in correlated subquery +# +do_execsql_test 11.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(w INT, x INT); + INSERT INTO t1(w,x) + VALUES(1,10),(2,20),(3,30), + (2,21),(3,31), + (3,32); + CREATE INDEX t1wx ON t1(w,x); + + DROP TABLE IF EXISTS t2; + CREATE TABLE t2(w INT, y VARCHAR(8)); + INSERT INTO t2(w,y) VALUES(1,'one'),(2,'two'),(3,'three'),(4,'four'); + CREATE INDEX t2wy ON t2(w,y); + + SELECT cnt, xyz, (SELECT y FROM t2 WHERE w=cnt), '|' + FROM (SELECT count(*) AS cnt, w AS xyz FROM t1 GROUP BY 2) + ORDER BY cnt, xyz; +} {1 1 one | 2 2 two | 3 3 three |} +do_execsql_test 11.2 { + SELECT cnt, xyz, lower((SELECT y FROM t2 WHERE w=cnt)), '|' + FROM (SELECT count(*) AS cnt, w AS xyz FROM t1 GROUP BY 2) + ORDER BY cnt, xyz; +} {1 1 one | 2 2 two | 3 3 three |} +do_execsql_test 11.3 { + SELECT cnt, xyz, '|' + FROM (SELECT count(*) AS cnt, w AS xyz FROM t1 GROUP BY 2) + WHERE (SELECT y FROM t2 WHERE w=cnt)!='two' + ORDER BY cnt, xyz; +} {1 1 | 3 3 |} +do_execsql_test 11.4 { + SELECT cnt, xyz, '|' + FROM (SELECT count(*) AS cnt, w AS xyz FROM t1 GROUP BY 2) + ORDER BY lower((SELECT y FROM t2 WHERE w=cnt)); +} {1 1 | 3 3 | 2 2 |} +do_execsql_test 11.5 { + SELECT cnt, xyz, + CASE WHEN (SELECT y FROM t2 WHERE w=cnt)=='two' + THEN 'aaa' ELSE 'bbb' + END, '|' + FROM (SELECT count(*) AS cnt, w AS xyz FROM t1 GROUP BY 2) + ORDER BY +cnt; +} {1 1 bbb | 2 2 aaa | 3 3 bbb |} + +do_execsql_test 11.100 { + DROP TABLE t1; + DROP TABLE t2; + CREATE TABLE t1(x); + CREATE TABLE t2(y, z); + SELECT ( SELECT y FROM t2 WHERE z = cnt ) + FROM ( SELECT count(*) AS cnt FROM t1 ); +} {{}} + finish_test diff --git a/test/selectA.test b/test/selectA.test index 6e593e8..0338338 100644 --- a/test/selectA.test +++ b/test/selectA.test @@ -1375,4 +1375,64 @@ do_execsql_test 4.2.2 { } {/2 . 3 . 4 . 5 . 6 . 7 ./} +proc strip_rnd {explain} { + regexp -all {sqlite_sq_[0123456789ABCDEF]*} $explain sqlite_sq +} + +proc do_same_test {tn q1 args} { + set r2 [strip_rnd [db eval "EXPLAIN $q1"]] + set i 1 + foreach q $args { + set tst [subst -nocommands {strip_rnd [db eval "EXPLAIN $q"]}] + uplevel do_test $tn.$i [list $tst] [list $r2] + incr i + } +} + +do_execsql_test 5.0 { + CREATE TABLE t8(a, b); + CREATE TABLE t9(c, d); +} {} + +do_same_test 5.1 { + SELECT a, b FROM t8 INTERSECT SELECT c, d FROM t9 ORDER BY a; +} { + SELECT a, b FROM t8 INTERSECT SELECT c, d FROM t9 ORDER BY t8.a; +} { + SELECT a, b FROM t8 INTERSECT SELECT c, d FROM t9 ORDER BY 1; +} { + SELECT a, b FROM t8 INTERSECT SELECT c, d FROM t9 ORDER BY c; +} { + SELECT a, b FROM t8 INTERSECT SELECT c, d FROM t9 ORDER BY t9.c; +} + +do_same_test 5.2 { + SELECT a, b FROM t8 UNION SELECT c, d FROM t9 ORDER BY a COLLATE NOCASE +} { + SELECT a, b FROM t8 UNION SELECT c, d FROM t9 ORDER BY t8.a COLLATE NOCASE +} { + SELECT a, b FROM t8 UNION SELECT c, d FROM t9 ORDER BY 1 COLLATE NOCASE +} { + SELECT a, b FROM t8 UNION SELECT c, d FROM t9 ORDER BY c COLLATE NOCASE +} { + SELECT a, b FROM t8 UNION SELECT c, d FROM t9 ORDER BY t9.c COLLATE NOCASE +} + +do_same_test 5.3 { + SELECT a, b FROM t8 EXCEPT SELECT c, d FROM t9 ORDER BY b, c COLLATE NOCASE +} { + SELECT a, b FROM t8 EXCEPT SELECT c, d FROM t9 ORDER BY 2, 1 COLLATE NOCASE +} { + SELECT a, b FROM t8 EXCEPT SELECT c, d FROM t9 ORDER BY d, a COLLATE NOCASE +} { + SELECT a, b FROM t8 EXCEPT SELECT * FROM t9 ORDER BY t9.d, c COLLATE NOCASE +} { + SELECT * FROM t8 EXCEPT SELECT c, d FROM t9 ORDER BY d, t8.a COLLATE NOCASE +} + +do_catchsql_test 5.4 { + SELECT * FROM t8 UNION SELECT * FROM t9 ORDER BY a+b COLLATE NOCASE +} {1 {1st ORDER BY term does not match any column in the result set}} + + finish_test diff --git a/test/selectE.test b/test/selectE.test index d7592bb..1cabeff 100644 --- a/test/selectE.test +++ b/test/selectE.test @@ -92,4 +92,9 @@ do_test selectE-2.2 { } } {} +do_catchsql_test selectE-3.1 { + SELECT 1 EXCEPT SELECT 2 ORDER BY 1 COLLATE nocase EXCEPT SELECT 3; +} {1 {ORDER BY clause should come after EXCEPT not before}} + + finish_test diff --git a/test/shell1.test b/test/shell1.test index f24b00d..2fda62e 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -406,19 +406,22 @@ do_test shell1-3.11.3 { catchcmd "test.db" ".import FOO BAR BAD" } {1 {Usage: .import FILE TABLE}} -# .indices ?TABLE? Show names of all indices -# If TABLE specified, only show indices for tables +# .indexes ?TABLE? Show names of all indexes +# If TABLE specified, only show indexes for tables # matching LIKE pattern TABLE. do_test shell1-3.12.1 { - catchcmd "test.db" ".indices" + catchcmd "test.db" ".indexes" } {0 {}} do_test shell1-3.12.2 { + catchcmd "test.db" ".indexes FOO" +} {0 {}} +do_test shell1-3.12.2-legacy { catchcmd "test.db" ".indices FOO" } {0 {}} do_test shell1-3.12.3 { # too many arguments - catchcmd "test.db" ".indices FOO BAD" -} {1 {Usage: .indices ?LIKE-PATTERN?}} + catchcmd "test.db" ".indexes FOO BAD" +} {1 {Usage: .indexes ?LIKE-PATTERN?}} # .mode MODE ?TABLE? Set output mode where MODE is one of: # ascii Columns/rows delimited by 0x1F and 0x1E @@ -735,6 +738,9 @@ do_test shell1-4.1 { PRAGMA encoding=UTF16; CREATE TABLE t1(x); INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f'); + CREATE TABLE t3(x,y); + INSERT INTO t3 VALUES(1,null), (2,''), (3,1), + (4,2.25), (5,'hello'), (6,x'807f'); } catchcmd test.db {.dump} } {0 {PRAGMA foreign_keys=OFF; @@ -746,11 +752,18 @@ INSERT INTO "t1" VALUES(1); INSERT INTO "t1" VALUES(2.25); INSERT INTO "t1" VALUES('hello'); INSERT INTO "t1" VALUES(X'807F'); +CREATE TABLE t3(x,y); +INSERT INTO "t3" VALUES(1,NULL); +INSERT INTO "t3" VALUES(2,''); +INSERT INTO "t3" VALUES(3,1); +INSERT INTO "t3" VALUES(4,2.25); +INSERT INTO "t3" VALUES(5,'hello'); +INSERT INTO "t3" VALUES(6,X'807F'); COMMIT;}} # Test the output of ".mode insert" # -do_test shell1-4.2 { +do_test shell1-4.2.1 { catchcmd test.db ".mode insert t1\nselect * from t1;" } {0 {INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES(''); @@ -759,6 +772,39 @@ INSERT INTO t1 VALUES(2.25); INSERT INTO t1 VALUES('hello'); INSERT INTO t1 VALUES(X'807f');}} +# Test the output of ".mode insert" with headers +# +do_test shell1-4.2.2 { + catchcmd test.db ".mode insert t1\n.headers on\nselect * from t1;" +} {0 {INSERT INTO t1(x) VALUES(NULL); +INSERT INTO t1(x) VALUES(''); +INSERT INTO t1(x) VALUES(1); +INSERT INTO t1(x) VALUES(2.25); +INSERT INTO t1(x) VALUES('hello'); +INSERT INTO t1(x) VALUES(X'807f');}} + +# Test the output of ".mode insert" +# +do_test shell1-4.2.3 { + catchcmd test.db ".mode insert t3\nselect * from t3;" +} {0 {INSERT INTO t3 VALUES(1,NULL); +INSERT INTO t3 VALUES(2,''); +INSERT INTO t3 VALUES(3,1); +INSERT INTO t3 VALUES(4,2.25); +INSERT INTO t3 VALUES(5,'hello'); +INSERT INTO t3 VALUES(6,X'807f');}} + +# Test the output of ".mode insert" with headers +# +do_test shell1-4.2.4 { + catchcmd test.db ".mode insert t3\n.headers on\nselect * from t3;" +} {0 {INSERT INTO t3(x,y) VALUES(1,NULL); +INSERT INTO t3(x,y) VALUES(2,''); +INSERT INTO t3(x,y) VALUES(3,1); +INSERT INTO t3(x,y) VALUES(4,2.25); +INSERT INTO t3(x,y) VALUES(5,'hello'); +INSERT INTO t3(x,y) VALUES(6,X'807f');}} + # Test the output of ".mode tcl" # do_test shell1-4.3 { @@ -815,4 +861,61 @@ do_test shell1-4.6 { ";" "$"} 7} +# Test using arbitrary byte data with the shell via standard input/output. +# +do_test shell1-5.0 { + # + # NOTE: Skip NUL byte because it appears to be incompatible with command + # shell argument parsing. + # + for {set i 1} {$i < 256} {incr i} { + # + # NOTE: Due to how the Tcl [exec] command works (i.e. where it treats + # command channels opened for it as textual ones), the carriage + # return character (and on Windows, the end-of-file character) + # cannot be used here. + # + if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} { + continue + } + set hex [format %02X $i] + set char [subst \\x$hex]; set oldChar $char + set escapes [list] + if {$tcl_platform(platform)=="windows"} { + # + # NOTE: On Windows, we need to escape all the whitespace characters, + # the alarm (\a) character, and those with special meaning to + # the SQLite shell itself. + # + set escapes [list \ + \a \\a \b \\b \t \\t \n \\n \v \\v \f \\f \r \\r \ + " " "\" \"" \" \\\" ' \"'\" \\ \\\\] + } else { + # + # NOTE: On Unix, we need to escape most of the whitespace characters + # and those with special meaning to the SQLite shell itself. + # The alarm (\a), backspace (\b), and carriage-return (\r) + # characters do not appear to require escaping on Unix. For + # the alarm and backspace characters, this is probably due to + # differences in the command shell. For the carriage-return, + # it is probably due to differences in how Tcl handles command + # channel end-of-line translations. + # + set escapes [list \ + \t \\t \n \\n \v \\v \f \\f \ + " " "\" \"" \" \\\" ' \"'\" \\ \\\\] + } + set char [string map $escapes $char] + set x [catchcmdex test.db ".print $char\n"] + set code [lindex $x 0] + set res [lindex $x 1] + if {$code ne "0"} { + error "failed with error: $res" + } + if {$res ne "$oldChar\n"} { + error "failed with byte $hex mismatch" + } + } +} {} + finish_test diff --git a/test/shell4.test b/test/shell4.test index c29faf0..fcb0b2b 100644 --- a/test/shell4.test +++ b/test/shell4.test @@ -12,12 +12,12 @@ # The focus of this file is testing the CLI shell tool. # These tests are specific to the .stats command. # -# $Id: shell4.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $ -# +# 2015-03-19: Added tests for .trace # Test plan: # # shell4-1.*: Basic tests specific to the "stats" command. +# shell4-2.*: Basic tests for ".trace" # set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -113,4 +113,24 @@ SELECT 1; [regexp {Autoindex Inserts} $res] } {1 1 1} +do_test shell4-2.1 { + catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace" +} {1 {Usage: .trace FILE|off}} +do_test shell4-2.2 { + catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace off\n.trace off\n" +} {0 {}} +do_test shell4-2.3 { + catchcmd ":memory:" ".trace stdout\n.trace\n.trace off\n.dump\n" +} {/^1 {PRAGMA.*Usage:.*}$/} +ifcapable trace { +do_test shell4-2.4 { + catchcmd ":memory:" ".trace stdout\nCREATE TABLE t1(x);SELECT * FROM t1;" +} {0 {CREATE TABLE t1(x); +SELECT * FROM t1;}} +do_test shell4-2.5 { + catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace stdout\nSELECT * FROM t1;" +} {0 {SELECT * FROM t1;}} +} + + finish_test diff --git a/test/shell5.test b/test/shell5.test index e22db04..b921acc 100644 --- a/test/shell5.test +++ b/test/shell5.test @@ -405,4 +405,34 @@ SELECT * FROM t5; set x } "0 \{\"test 1\"\x1F,test 2\x1Etest 3\x1Ftest 4\x1E\}" +do_test shell5-4.1 { + forcedelete shell5.csv + set fd [open shell5.csv w] + puts $fd "1,2,3" + puts $fd "4,5" + puts $fd "6,7,8" + close $fd + catchcmd test.db [string trim { +.mode csv +CREATE TABLE t6(a, b, c); +.import shell5.csv t6 + }] + db eval { SELECT * FROM t6 ORDER BY a } +} {1 2 3 4 5 {} 6 7 8} + +do_test shell5-4.2 { + forcedelete shell5.csv + set fd [open shell5.csv w] + puts $fd "1,2,3" + puts $fd "4,5" + puts $fd "6,7,8,9" + close $fd + catchcmd test.db [string trim { +.mode csv +CREATE TABLE t7(a, b, c); +.import shell5.csv t7 + }] + db eval { SELECT * FROM t7 ORDER BY a } +} {1 2 3 4 5 {} 6 7 8} + finish_test diff --git a/test/shrink.test b/test/shrink.test index e03ebee..6cc0786 100644 --- a/test/shrink.test +++ b/test/shrink.test @@ -24,6 +24,9 @@ do_test shrink-1.1 { INSERT INTO t1 VALUES(randomblob(1000000),1); } set ::baseline sqlite3_memory_used + # EVIDENCE-OF: R-58814-63508 The sqlite3_db_release_memory(D) interface + # attempts to free as much heap memory as possible from database + # connection D. sqlite3_db_release_memory db expr {$::baseline > [sqlite3_memory_used]+500000} } {1} diff --git a/test/softheap1.test b/test/softheap1.test index 522e455..07f981e 100644 --- a/test/softheap1.test +++ b/test/softheap1.test @@ -24,6 +24,14 @@ ifcapable !integrityck { return } +# EVIDENCE-OF: R-26343-45930 This pragma invokes the +# sqlite3_soft_heap_limit64() interface with the argument N, if N is +# specified and is a non-negative integer. +# +# EVIDENCE-OF: R-64451-07163 The soft_heap_limit pragma always returns +# the same integer that would be returned by the +# sqlite3_soft_heap_limit64(-1) C-language function. +# do_test softheap1-1.0 { execsql {PRAGMA soft_heap_limit} } [sqlite3_soft_heap_limit -1] diff --git a/test/sort4.test b/test/sort4.test index 7b91361..13d9a59 100644 --- a/test/sort4.test +++ b/test/sort4.test @@ -25,7 +25,20 @@ sqlite3 db test.db # Configure the sorter to use 3 background threads. -db eval {PRAGMA threads=3} +# +# EVIDENCE-OF: R-19249-32353 SQLITE_LIMIT_WORKER_THREADS The maximum +# number of auxiliary worker threads that a single prepared statement +# may start. +# +do_test sort4-init001 { + db eval {PRAGMA threads=5} + sqlite3_limit db SQLITE_LIMIT_WORKER_THREADS -1 +} {5} +do_test sort4-init002 { + sqlite3_limit db SQLITE_LIMIT_WORKER_THREADS 3 + db eval {PRAGMA threads} +} {3} + # Minimum number of seconds to run for. If the value is 0, each test # is run exactly once. Otherwise, tests are repeated until the timeout diff --git a/test/speedtest1.c b/test/speedtest1.c index 8e5b74c..93f7d14 100644 --- a/test/speedtest1.c +++ b/test/speedtest1.c @@ -12,7 +12,7 @@ static const char zHelp[] = " --explain Like --sqlonly but with added EXPLAIN keywords\n" " --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n" " --incrvacuum Enable incremenatal vacuum mode\n" - " --journalmode M Set the journal_mode to MODE\n" + " --journal M Set the journal_mode to M\n" " --key KEY Set the encryption key to KEY\n" " --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n" " --nosync Set PRAGMA synchronous=OFF\n" diff --git a/test/sqllimits1.test b/test/sqllimits1.test index 57fc931..39e3aed 100644 --- a/test/sqllimits1.test +++ b/test/sqllimits1.test @@ -250,6 +250,9 @@ do_test sqllimits1-4.10.1 { # Test cases sqllimits1-5.* test that the SQLITE_MAX_LENGTH limit # is enforced. # +# EVIDENCE-OF: R-61987-00541 SQLITE_LIMIT_LENGTH The maximum size of any +# string or BLOB or table row, in bytes. +# db close sqlite3 db test.db set LARGESIZE 99999 @@ -406,6 +409,9 @@ unset strvalue # Test cases sqllimits1-6.* test that the SQLITE_MAX_SQL_LENGTH limit # is enforced. # +# EVIDENCE-OF: R-09808-17554 SQLITE_LIMIT_SQL_LENGTH The maximum length +# of an SQL statement, in bytes. +# do_test sqllimits1-6.1 { sqlite3_limit db SQLITE_LIMIT_SQL_LENGTH 50000 set sql "SELECT 1 WHERE 1==1" @@ -567,6 +573,11 @@ do_test sqllimits1-7.7.4 { #-------------------------------------------------------------------- # Test cases sqllimits1-8.* test the SQLITE_MAX_COLUMN limit. # +# EVIDENCE-OF: R-43996-29471 SQLITE_LIMIT_COLUMN The maximum number of +# columns in a table definition or in the result set of a SELECT or the +# maximum number of columns in an index or in an ORDER BY or GROUP BY +# clause. +# set SQLITE_LIMIT_COLUMN 200 sqlite3_limit db SQLITE_LIMIT_COLUMN $SQLITE_LIMIT_COLUMN do_test sqllimits1-8.1 { @@ -670,6 +681,9 @@ do_test sqllimits1-8.11 { # limit is enforced. The limit refers to the number of terms in # the expression. # +# EVIDENCE-OF: R-12723-08526 SQLITE_LIMIT_EXPR_DEPTH The maximum depth +# of the parse tree on any expression. +# if {$SQLITE_MAX_EXPR_DEPTH==0} { puts -nonewline stderr "WARNING: Compile with -DSQLITE_MAX_EXPR_DEPTH to run " puts stderr "tests sqllimits1-9.X" @@ -729,6 +743,9 @@ if 0 { # Test the SQLITE_LIMIT_FUNCTION_ARG limit works. Test case names # match the pattern "sqllimits1-11.*". # +# EVIDENCE-OF: R-59001-45278 SQLITE_LIMIT_FUNCTION_ARG The maximum +# number of arguments on a function. +# for {set max 5} {$max<=$SQLITE_MAX_FUNCTION_ARG} {incr max} { do_test sqllimits1-11.$max.1 { set vals [list] @@ -762,6 +779,9 @@ for {set max 5} {$max<=$SQLITE_MAX_FUNCTION_ARG} {incr max} { #-------------------------------------------------------------------- # Test cases sqllimits1-12.*: Test the SQLITE_MAX_ATTACHED limit. # +# EVIDENCE-OF: R-41778-26203 SQLITE_LIMIT_ATTACHED The maximum number of +# attached databases. +# ifcapable attach { do_test sqllimits1-12.1 { set max $::SQLITE_MAX_ATTACHED @@ -785,6 +805,9 @@ ifcapable attach { # Test cases sqllimits1-13.*: Check that the SQLITE_MAX_VARIABLE_NUMBER # limit works. # +# EVIDENCE-OF: R-42363-29104 SQLITE_LIMIT_VARIABLE_NUMBER The maximum +# index number of any parameter in an SQL statement. +# do_test sqllimits1-13.1 { set max $::SQLITE_MAX_VARIABLE_NUMBER catchsql "SELECT ?[expr {$max+1}] FROM t1" @@ -806,6 +829,9 @@ do_test sqllimits1-13.2 { # implementation by overriding the like() scalar function bypasses # this limitation. # +# EVIDENCE-OF: R-12940-37052 SQLITE_LIMIT_LIKE_PATTERN_LENGTH The +# maximum length of the pattern argument to the LIKE or GLOB operators. +# # These tests check that the limit is not incorrectly applied to # the left-hand-side of the LIKE operator (the string being tested # against the pattern). diff --git a/test/stat.test b/test/stat.test index f0447e4..57c1b9e 100644 --- a/test/stat.test +++ b/test/stat.test @@ -166,8 +166,10 @@ sqlite3 db test.db register_dbstat_vtab db do_execsql_test stat-5.1 { PRAGMA auto_vacuum = OFF; - CREATE VIRTUAL TABLE temp.stat USING dbstat; - CREATE TABLE t1(x); + CREATE TABLE tx(y); + ATTACH ':memory:' AS aux1; + CREATE VIRTUAL TABLE temp.stat USING dbstat(aux1); + CREATE TABLE aux1.t1(x); INSERT INTO t1 VALUES(zeroblob(1513)); INSERT INTO t1 VALUES(zeroblob(1514)); SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload @@ -178,4 +180,8 @@ do_execsql_test stat-5.1 { t1 /001+000000 4 overflow 0 1020 0 0 \ ] +do_catchsql_test stat-6.1 { + CREATE VIRTUAL TABLE temp.s2 USING dbstat(mainx); +} {1 {no such database: mainx}} + finish_test diff --git a/test/statfault.test b/test/statfault.test new file mode 100644 index 0000000..ce79e32 --- /dev/null +++ b/test/statfault.test @@ -0,0 +1,45 @@ +# 2015 April 28 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl +set testprefix statfault + +ifcapable !vtab||!compound { + finish_test + return +} + +register_dbstat_vtab db +do_execsql_test statfault-1 { + CREATE TABLE t1(a, b UNIQUE); + INSERT INTO t1 VALUES(1, randomblob(500)); + INSERT INTO t1 VALUES(randomblob(500), 1); + INSERT INTO t1 VALUES(2, randomblob(250)); + INSERT INTO t1 VALUES(randomblob(250), 2); + CREATE VIRTUAL TABLE sss USING dbstat; +} {} +faultsim_save_and_close + +do_faultsim_test 1 -faults * -prep { + faultsim_restore_and_reopen + register_dbstat_vtab db + execsql { SELECT 1 FROM sqlite_master LIMIT 1 } +} -body { + execsql { SELECT count(*) FROM sss } +} -test { + faultsim_test_result {0 8} +} + + +finish_test diff --git a/test/subquery.test b/test/subquery.test index 93c3f28..06facbb 100644 --- a/test/subquery.test +++ b/test/subquery.test @@ -584,4 +584,14 @@ do_test subquery-7.11 { } {30303} } ;############# Disabled +# 2015-04-21. +# Verify that a memory leak in the table column type and collation analysis +# is plugged. +# +do_execsql_test subquery-8.1 { + CREATE TABLE t8(a TEXT, b INT); + SELECT (SELECT 0 FROM (SELECT * FROM t1)) AS x WHERE x; + SELECT (SELECT 0 FROM (SELECT * FROM (SELECT 0))) AS x WHERE x; +} {} + finish_test diff --git a/test/table.test b/test/table.test index 69f105a..faa9712 100644 --- a/test/table.test +++ b/test/table.test @@ -272,6 +272,25 @@ do_test table-5.2.1 { } } {} +do_test table-5.2.2 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + CREATE TABLE t0(a,b); + CREATE INDEX t ON t0(a); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE TABLE a.b(a UNIQUE'; + BEGIN; + CREATE TABLE t1(x); + ROLLBACK; + DROP TABLE IF EXISTS t99; + } +} {} +db close +forcedelete test.db +sqlite3 db test.db + # Make sure an EXPLAIN does not really create a new table # do_test table-5.3 { diff --git a/test/tclsqlite.test b/test/tclsqlite.test index 3d9cd46..8d7fea0 100644 --- a/test/tclsqlite.test +++ b/test/tclsqlite.test @@ -118,7 +118,7 @@ do_test tcl-1.14 { do_test tcl-1.15 { set v [catch {db function} msg] lappend v $msg -} {1 {wrong # args: should be "db function NAME [-argcount N] SCRIPT"}} +} {1 {wrong # args: should be "db function NAME ?SWITCHES? SCRIPT"}} do_test tcl-1.16 { set v [catch {db last_insert_rowid xyz} msg] lappend v $msg diff --git a/test/tester.tcl b/test/tester.tcl index dad2266..37ca69f 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -666,6 +666,15 @@ proc do_test {name cmd expected} { flush stdout } +proc dumpbytes {s} { + set r "" + for {set i 0} {$i < [string length $s]} {incr i} { + if {$i > 0} {append r " "} + append r [format %02X [scan [string index $s $i] %c]] + } + return $r +} + proc catchcmd {db {cmd ""}} { global CLI set out [open cmds.txt w] @@ -676,6 +685,30 @@ proc catchcmd {db {cmd ""}} { list $rc $msg } +proc catchcmdex {db {cmd ""}} { + global CLI + set out [open cmds.txt w] + fconfigure $out -encoding binary -translation binary + puts -nonewline $out $cmd + close $out + set line "exec -keepnewline -- $CLI $db < cmds.txt" + set chans [list stdin stdout stderr] + foreach chan $chans { + catch { + set modes($chan) [fconfigure $chan] + fconfigure $chan -encoding binary -translation binary -buffering none + } + } + set rc [catch { eval $line } msg] + foreach chan $chans { + catch { + eval fconfigure [list $chan] $modes($chan) + } + } + # puts [dumpbytes $msg] + list $rc $msg +} + proc filepath_normalize {p} { # test cases should be written to assume "unix"-like file paths if {$::tcl_platform(platform)!="unix"} { diff --git a/test/trace2.test b/test/trace2.test index 562c70c..a3f0aeb 100644 --- a/test/trace2.test +++ b/test/trace2.test @@ -143,7 +143,7 @@ ifcapable fts3 { INSERT INTO x1(x1) VALUES('optimize'); } { "INSERT INTO x1(x1) VALUES('optimize');" - "-- SELECT DISTINCT level / (1024 * ?) FROM 'main'.'x1_segdir'" + "-- SELECT ? UNION SELECT level / (1024 * ?) FROM 'main'.'x1_segdir'" "-- SELECT idx, start_block, leaves_end_block, end_block, root FROM 'main'.'x1_segdir' WHERE level BETWEEN ? AND ?ORDER BY level DESC, idx ASC" "-- SELECT max(level) FROM 'main'.'x1_segdir' WHERE level BETWEEN ? AND ?" "-- SELECT coalesce((SELECT max(blockid) FROM 'main'.'x1_segments') + 1, 1)" diff --git a/test/trigger1.test b/test/trigger1.test index 1ebe12c..a190efd 100644 --- a/test/trigger1.test +++ b/test/trigger1.test @@ -712,4 +712,20 @@ do_test trigger1-16.7 { } } {1 {the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers}} +#------------------------------------------------------------------------- +# Test that bug [34cd55d68e0e6e7c] has been fixed. +# +do_execsql_test trigger1-17.0 { + CREATE TABLE t17a(ii INT); + CREATE TABLE t17b(tt TEXT PRIMARY KEY, ss); + CREATE TRIGGER t17a_ai AFTER INSERT ON t17a BEGIN + INSERT INTO t17b(tt) VALUES(new.ii); + END; + CREATE TRIGGER t17b_ai AFTER INSERT ON t17b BEGIN + UPDATE t17b SET ss = 4; + END; + INSERT INTO t17a(ii) VALUES('1'); + PRAGMA integrity_check; +} {ok} + finish_test diff --git a/test/trigger7.test b/test/trigger7.test index 8fde200..2219624 100644 --- a/test/trigger7.test +++ b/test/trigger7.test @@ -114,6 +114,6 @@ do_test trigger7-99.1 { db close catch { sqlite3 db test.db } catchsql { DROP TRIGGER t2r5 } -} {1 {malformed database schema (t2r12) - near "nonsense": syntax error}} +} {1 {malformed database schema (t2r12)}} finish_test diff --git a/test/triggerC.test b/test/triggerC.test index 14cc0f0..3e47521 100644 --- a/test/triggerC.test +++ b/test/triggerC.test @@ -12,6 +12,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix triggerC ifcapable {!trigger} { finish_test return @@ -993,4 +994,52 @@ reset_db optimization_control db factor-constants 0 do_execsql_test triggerC-14.2 $SQL {1 2 3} +#------------------------------------------------------------------------- +# Check that table names used by trigger programs are dequoted exactly +# once. +# +do_execsql_test 15.1.1 { + PRAGMA recursive_triggers = 1; + CREATE TABLE node( + id int not null primary key, + pid int not null default 0 references node, + key varchar not null, + path varchar default '', + unique(pid, key) + ); + CREATE TRIGGER node_delete_referencing AFTER DELETE ON "node" + BEGIN + DELETE FROM "node" WHERE pid = old."id"; + END; +} +do_execsql_test 15.1.2 { + INSERT INTO node(id, pid, key) VALUES(9, 0, 'test'); + INSERT INTO node(id, pid, key) VALUES(90, 9, 'test1'); + INSERT INTO node(id, pid, key) VALUES(900, 90, 'test2'); + DELETE FROM node WHERE id=9; + SELECT * FROM node; +} + +do_execsql_test 15.2.1 { + CREATE TABLE x1 (x); + + CREATE TABLE x2 (a, b); + CREATE TABLE '"x2"'(a, b); + + INSERT INTO x2 VALUES(1, 2); + INSERT INTO x2 VALUES(3, 4); + INSERT INTO '"x2"' SELECT * FROM x2; + + CREATE TRIGGER x1ai AFTER INSERT ON x1 BEGIN + INSERT INTO """x2""" VALUES('x', 'y'); + DELETE FROM """x2""" WHERE a=1; + UPDATE """x2""" SET b = 11 WHERE a = 3; + END; + + INSERT INTO x1 VALUES('go!'); +} + +do_execsql_test 15.2.2 { SELECT * FROM x2; } {1 2 3 4} +do_execsql_test 15.2.3 { SELECT * FROM """x2"""; } {3 11 x y} + finish_test diff --git a/test/vacuum2.test b/test/vacuum2.test index b3bfab3..0350c8e 100644 --- a/test/vacuum2.test +++ b/test/vacuum2.test @@ -15,6 +15,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix vacuum2 # Do not use a codec for tests in this file, as the database file is # manipulated directly using tcl scripts (using the [hexio_write] command). @@ -227,5 +228,24 @@ do_test vacuum2-5.4 { lappend res2 $res } {1 2 3 4 5 6 7 8 9 10 {1 {cannot VACUUM - SQL statements in progress}}} +#------------------------------------------------------------------------- +# Check that if the definition of a collation sequence is changed and +# VACUUM run, records are store in the (new) correct order following the +# VACUUM. Even if the modified collation is attached to a PK of a WITHOUT +# ROWID table. + +proc cmp {lhs rhs} { string compare $lhs $rhs } +db collate cmp cmp +do_execsql_test 6.0 { + CREATE TABLE t6(x PRIMARY KEY COLLATE cmp, y) WITHOUT ROWID; + CREATE INDEX t6y ON t6(y); + INSERT INTO t6 VALUES('i', 'one'); + INSERT INTO t6 VALUES('ii', 'one'); + INSERT INTO t6 VALUES('iii', 'one'); +} +integrity_check 6.1 +proc cmp {lhs rhs} { string compare $rhs $lhs } +do_execsql_test 6.2 VACUUM +integrity_check 6.3 finish_test diff --git a/test/vtab1.test b/test/vtab1.test index 2929b1e..c0cf3e4 100644 --- a/test/vtab1.test +++ b/test/vtab1.test @@ -1437,4 +1437,95 @@ ifcapable fts3 { } {SQLITE_OK} } + +#------------------------------------------------------------------------- +# The following tests verify that a DROP TABLE command on a virtual +# table does not cause other operations to crash. +# +# 23.1: Dropping a vtab while a SELECT is running on it. +# +# 23.2: Dropping a vtab while a SELECT that will, but has not yet, +# open a cursor on the vtab, is running. In this case the +# DROP TABLE succeeds and the SELECT hits an error. +# +# 23.3: Dropping a vtab from within a user-defined-function callback +# in the middle of an "INSERT INTO vtab SELECT ..." statement. +# +reset_db +load_static_extension db wholenumber +load_static_extension db eval +register_echo_module db + +do_test 23.1 { + execsql { CREATE VIRTUAL TABLE t1 USING wholenumber } + set res "" + db eval { SELECT value FROM t1 WHERE value<10 } { + if {$value == 5} { + set res [catchsql { DROP TABLE t1 }] + } + } + set res +} {1 {database table is locked}} + +do_test 23.2 { + execsql { + CREATE TABLE t2(value); + INSERT INTO t2 VALUES(1), (2), (3); + } + + set res2 [list [catch { + db eval { + SELECT value FROM t2 UNION ALL + SELECT value FROM t1 WHERE value<10 + } { + if {$value == 2} { set res1 [catchsql { DROP TABLE t1 }] } + } + } msg] $msg] + list $res1 $res2 +} {{0 {}} {1 {database table is locked}}} + +do_test 23.3.1 { + execsql { CREATE VIRTUAL TABLE t1e USING echo(t2) } + execsql { INSERT INTO t1e SELECT 4 } + catchsql { INSERT INTO t1e SELECT eval('DROP TABLE t1e') } +} {1 {database table is locked}} +do_execsql_test 23.3.2 { SELECT * FROM t1e } {1 2 3 4} + +#------------------------------------------------------------------------- +# At one point SQL like this: +# +# SAVEPOINT xyz; -- Opens SQL transaction +# INSERT INTO vtab -- Write to virtual table +# ROLLBACK TO xyz; +# RELEASE xyz; +# +# was not invoking the xRollbackTo() callback for the ROLLBACK TO +# operation. Which meant that virtual tables like FTS3 would incorrectly +# commit the results of the INSERT as part of the "RELEASE xyz" command. +# +# The following tests check that this has been fixed. +# +ifcapable fts3 { + do_execsql_test 24.0 { + CREATE VIRTUAL TABLE t4 USING fts3(); + SAVEPOINT a; + INSERT INTO t4 VALUES('a b c'); + ROLLBACK TO a; + RELEASE a; + SELECT * FROM t4; + } {} + + do_execsql_test 24.1 { SELECT * FROM t4 WHERE t4 MATCH 'b' } {} + do_execsql_test 24.2 { INSERT INTO t4(t4) VALUES('integrity-check') } {} + + do_execsql_test 24.3 { + SAVEPOINT a; + CREATE VIRTUAL TABLE t5 USING fts3(); + SAVEPOINT b; + ROLLBACK TO a; + SAVEPOINT c; + RELEASE a; + } +} + finish_test diff --git a/test/vtab2.test b/test/vtab2.test index 05a4834..3884ec5 100644 --- a/test/vtab2.test +++ b/test/vtab2.test @@ -10,10 +10,10 @@ #*********************************************************************** # This file implements regression tests for SQLite library. # -# $Id: vtab2.test,v 1.9 2008/10/13 10:37:50 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix vtab2 ifcapable !vtab||!schema_pragmas { finish_test @@ -133,4 +133,24 @@ do_test vtab2-4.5 { execsql { SELECT * FROM fkey } } {t1 a} +#------------------------------------------------------------------------- +# +ifcapable fts3 { + reset_db + do_execsql_test 5.1 { + PRAGMA encoding='UTF16'; + } + + do_test 5.2 { + sqlite3_exec_hex db { CREATE VIRTUAL TABLE %C8 USING fts3 } + } {0 {}} + + do_test 5.3 { + sqlite3_exec_hex db { CREATE VIRTUAL TABLE %C9 USING s } + } {/1 {malformed database schema.* already exists}/} +} + + + finish_test + diff --git a/test/vtabA.test b/test/vtabA.test index 928cc2b..eddaa70 100644 --- a/test/vtabA.test +++ b/test/vtabA.test @@ -74,28 +74,39 @@ do_test vtabA-1.6 { SELECT * FROM t1e; } } {{value a} {value c}} +do_execsql_test vtabA-1.7 { + DELETE FROM t1e; + INSERT INTO t1e SELECT 'abc','def'; +} {} +do_execsql_test vtabA-1.8 { + INSERT INTO t1e VALUES('ghi','jkl'),('mno','pqr'),('stu','vwx'); +} {} +do_execsql_test vtabA-1.9 { + SELECT a,b,c, '|' FROM t1e ORDER BY 1; +} {abc {} def | ghi {} jkl | mno {} pqr | stu {} vwx |} + # Test that the expansion of a '*' expression in the result set of # a SELECT does not include the hidden column. # -do_test vtabA-1.7 { +do_test vtabA-1.20 { execsql { INSERT INTO t1e SELECT * FROM t1e; } } {} -do_test vtabA-1.8 { +do_test vtabA-1.21 { execsql { - SELECT * FROM t1e; + SELECT * FROM t1e ORDER BY 1; } -} {{value a} {value c} {value a} {value c}} +} {abc def abc def ghi jkl ghi jkl mno pqr mno pqr stu vwx stu vwx} # Test that the declaration type of the hidden column does not include # the token "HIDDEN". # -do_test vtabA-1.9 { +do_test vtabA-1.22 { get_decltype t1e b } {VARCHAR} -do_test vtabA-1.10 { +do_test vtabA-1.23 { get_collist t1e } {a c} diff --git a/test/wal5.test b/test/wal5.test index 2d3522b..360d9c9 100644 --- a/test/wal5.test +++ b/test/wal5.test @@ -457,18 +457,18 @@ foreach {testprefix do_wal_checkpoint} { } {1 2 3 4 5 6 7 8 9 10} proc xBusyHandler {n} { return 1 } - do_test 5.$tn.14 { do_wal_checkpoint db -mode truncate } {1 4 4} - do_test 5.$tn.15 { file size test.db-wal } [wal_file_size 4 1024] + do_test 5.$tn.15 { do_wal_checkpoint db -mode truncate } {1 4 4} + do_test 5.$tn.16 { file size test.db-wal } [wal_file_size 4 1024] - do_test 5.$tn.16 { do_wal_checkpoint db -mode restart } {1 4 4} + do_test 5.$tn.17 { do_wal_checkpoint db -mode restart } {1 4 4} proc xBusyHandler {n} { sql2 { COMMIT } ; return 0 } db busy xBusyHandler - do_test 5.$tn.17 { do_wal_checkpoint db -mode restart } {0 4 4} - do_test 5.$tn.18 { file size test.db-wal } [wal_file_size 4 1024] + do_test 5.$tn.18 { do_wal_checkpoint db -mode restart } {0 4 4} + do_test 5.$tn.19 { file size test.db-wal } [wal_file_size 4 1024] - do_test 5.$tn.19 { do_wal_checkpoint db -mode truncate } {0 0 0} - do_test 5.$tn.20 { file size test.db-wal } 0 + do_test 5.$tn.20 { do_wal_checkpoint db -mode truncate } {0 0 0} + do_test 5.$tn.21 { file size test.db-wal } 0 } } diff --git a/test/walblock.test b/test/walblock.test new file mode 100644 index 0000000..23167a8 --- /dev/null +++ b/test/walblock.test @@ -0,0 +1,114 @@ +# 2015 Mar 17 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/lock_common.tcl +source $testdir/wal_common.tcl + +finish_test; return; # Feature currently not implemented. +ifcapable !wal {finish_test ; return } +if {$::tcl_platform(platform)!="unix"} { finish_test ; return } +set testprefix walblock + +catch { db close } +testvfs tvfs -fullshm 1 +foreach f [glob test.db*] { forcedelete $f } + +sqlite3 db test.db -vfs tvfs +do_execsql_test 1.1.0 { + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + INSERT INTO t1 VALUES(5, 6); + PRAGMA journal_mode = wal; + INSERT INTO t1 VALUES(7, 8); +} {wal} + +do_test 1.1.1 { + lsort [glob test.db*] +} {test.db test.db-shm test.db-wal} + +do_test 1.1.2 { + set C [launch_testfixture] + testfixture $C { + sqlite3 db test.db + db eval { SELECT * FROM t1 } + } +} {1 2 3 4 5 6 7 8} + +do_test 1.1.3 { + set ::out [list] + testfixture $C { + db eval { SELECT * FROM t1 } + } [list set ::out] + set ::out +} {} + +do_test 1.1.4 { + vwait ::out + set ::out +} {1 2 3 4 5 6 7 8} + +# +# Test that if a read client cannot read the wal-index header because a +# write client is in the middle of updating it, the reader blocks until +# the writer finishes. +# +# 1. Open a write transaction using client [db] in this process. +# +# 2. Attempt to commit the write transaction. Intercept the xShmBarrier() +# call made by the writer between updating the two copies of the +# wal-index header. +# +# 3. Within the xShmBarrier() callback, make an asynchronous request to +# the other process to read from the database. It should block, as it +# cannot get read the wal-index header. +# +# 4. Still in xShmBarrier(), wait for 5 seconds. Check that the other +# process has not answered the request. +# +# 5: Finish committing the transaction. Then wait for 0.5 seconds more. +# Ensure that the second process has by this stage read the database +# and that the snapshot it read included the transaction committed in +# step (4). +# +do_execsql_test 1.2.1 { + BEGIN; + INSERT INTO t1 VALUES(9, 10); +} {} + +tvfs script barrier_callback +tvfs filter xShmBarrier +proc barrier_callback {method args} { + set ::out "" + testfixture $::C { db eval { SELECT * FROM t1 } } {set ::out} + + do_test "1.2.2.(blocking 10 seconds)" { + set ::continue 0 + after 10000 {set ::continue 1} + vwait ::continue + set ::out + } {} +} + +execsql COMMIT + +do_test "1.2.3.(blocking 0.5 seconds)" { + set ::continue 0 + after 500 {set ::continue 1} + vwait ::continue + set ::out +} {1 2 3 4 5 6 7 8 9 10} + + +finish_test diff --git a/test/where8.test b/test/where8.test index 139251a..a155a95 100644 --- a/test/where8.test +++ b/test/where8.test @@ -66,11 +66,11 @@ do_test where8-1.3 { do_test where8-1.4 { execsql_status2 { SELECT c FROM t1 WHERE a > 8 OR b GLOB 't*' } -} {IX X III II 0 0 9} +} {IX X III II 0 0 10} do_test where8-1.5 { execsql_status2 { SELECT c FROM t1 WHERE a > 8 OR b GLOB 'f*' } -} {IX X V IV 0 0 9} +} {IX X V IV 0 0 10} do_test where8-1.6 { execsql_status { SELECT c FROM t1 WHERE a = 1 OR b = 'three' ORDER BY rowid } diff --git a/test/whereD.test b/test/whereD.test index db99304..17fdac7 100644 --- a/test/whereD.test +++ b/test/whereD.test @@ -129,11 +129,11 @@ do_execsql_test 3.0 { do_searchcount_test 3.1 { SELECT a, b FROM t3 WHERE (a=1 AND b='one') OR (a=2 AND b='two') -} {1 one 2 two search 2} +} {1 one 2 two search 4} do_searchcount_test 3.2 { SELECT a, c FROM t3 WHERE (a=1 AND b='one') OR (a=2 AND b='two') -} {1 i 2 ii search 4} +} {1 i 2 ii search 6} do_searchcount_test 3.4.1 { SELECT y FROM t4 WHERE x='a' @@ -142,24 +142,24 @@ do_searchcount_test 3.4.2 { SELECT a, b FROM t3 WHERE (a=1 AND b=(SELECT y FROM t4 WHERE x='a')) OR (a=2 AND b='two') -} {1 one 2 two search 4} +} {1 one 2 two search 6} do_searchcount_test 3.4.3 { SELECT a, b FROM t3 WHERE (a=2 AND b='two') OR (a=1 AND b=(SELECT y FROM t4 WHERE x='a')) -} {2 two 1 one search 4} +} {2 two 1 one search 6} do_searchcount_test 3.4.4 { SELECT a, b FROM t3 WHERE (a=2 AND b=(SELECT y FROM t4 WHERE x='b')) OR (a=1 AND b=(SELECT y FROM t4 WHERE x='a')) -} {2 two 1 one search 6} +} {2 two 1 one search 8} do_searchcount_test 3.5.1 { SELECT a, b FROM t3 WHERE (a=1 AND b='one') OR rowid=4 -} {1 one 2 two search 2} +} {1 one 2 two search 3} do_searchcount_test 3.5.2 { SELECT a, c FROM t3 WHERE (a=1 AND b='one') OR rowid=4 -} {1 i 2 ii search 2} +} {1 i 2 ii search 3} # Ticket [d02e1406a58ea02d] (2012-10-04) # LEFT JOIN with an OR in the ON clause causes segfault diff --git a/test/whereK.test b/test/whereK.test new file mode 100644 index 0000000..13c8650 --- /dev/null +++ b/test/whereK.test @@ -0,0 +1,72 @@ +# 2015-03-16 +# +# 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 file is testing OR expressions where terms can be +# factored from either side of the OR and combined into a single new +# AND term that is beneficial to the search. Examples: +# +# (x>A OR x=A) --> ... AND (x>=A) +# (x>A OR (x=A AND y>=B) --> ... AND (x>=A) +# + + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix whereK + +do_execsql_test 1.1 { + CREATE TABLE t1(a,b,c); + WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<99) + INSERT INTO t1(a,b,c) SELECT x, x/10, x%10 FROM c; + CREATE INDEX t1bc ON t1(b,c); + SELECT a FROM t1 WHERE b>9 OR b=9 ORDER BY +a; +} {90 91 92 93 94 95 96 97 98 99} +do_execsql_test 1.1eqp { + EXPLAIN QUERY PLAN + SELECT a FROM t1 WHERE b>9 OR b=9 ORDER BY +a; +} {/SEARCH TABLE t1 USING INDEX t1bc/} + +do_execsql_test 1.2 { + SELECT a FROM t1 WHERE b>8 OR (b=8 AND c>7) ORDER BY +a; +} {88 89 90 91 92 93 94 95 96 97 98 99} +do_execsql_test 1.2eqp { + EXPLAIN QUERY PLAN + SELECT a FROM t1 WHERE b>8 OR (b=8 AND c>7) ORDER BY +a; +} {/SEARCH TABLE t1 USING INDEX t1bc/} + +do_execsql_test 1.3 { + SELECT a FROM t1 WHERE (b=8 AND c>7) OR b>8 ORDER BY +a; +} {88 89 90 91 92 93 94 95 96 97 98 99} +do_execsql_test 1.3eqp { + EXPLAIN QUERY PLAN + SELECT a FROM t1 WHERE (b=8 AND c>7) OR b>8 ORDER BY +a; +} {/SEARCH TABLE t1 USING INDEX t1bc/} + +do_execsql_test 1.4 { + SELECT a FROM t1 WHERE (b=8 AND c>7) OR 87) OR 87) OR (b>8 AND c NOT IN (4,5,6)) + ORDER BY +a; +} {88 89 90 91 92 93 97 98 99} +do_execsql_test 1.5eqp { + EXPLAIN QUERY PLAN + SELECT a FROM t1 WHERE (b=8 AND c>7) OR (b>8 AND c NOT IN (4,5,6)) + ORDER BY +a; +} {/SEARCH TABLE t1 USING INDEX t1bc/} + +finish_test diff --git a/test/win32lock.test b/test/win32lock.test index cff1ed3..d1f3d1a 100644 --- a/test/win32lock.test +++ b/test/win32lock.test @@ -64,6 +64,7 @@ while {1} { if {[info exists ::log] && $::log!=""} { do_test win32lock-1.2-$delay1-log1 { regsub {\d+} $::log # x + regsub { at line \d+} $x "" x set x } {{delayed #ms for lock/sharing conflict}} } @@ -112,6 +113,7 @@ while {1} { if {[info exists ::log] && $::log!=""} { do_test win32lock-2.2-$delay1-log1 { regsub {\d+} $::log # x + regsub { at line \d+} $x "" x set x } {{delayed #ms for lock/sharing conflict}} } diff --git a/test/with1.test b/test/with1.test index 42d2277..80892d2 100644 --- a/test/with1.test +++ b/test/with1.test @@ -827,5 +827,26 @@ WITH RECURSIVE SELECT x FROM t1 EXCEPT SELECT y FROM t2 ORDER BY 1; } {2 4 8 10 14 16 20} +# 2015-03-21 +# Column wildcards on the LHS of a recursive table expression +# +do_catchsql_test 13.1 { + WITH RECURSIVE c(i) AS (SELECT * UNION ALL SELECT i+1 FROM c WHERE i<10) + SELECT i FROM c; +} {1 {no tables specified}} +do_catchsql_test 13.2 { + WITH RECURSIVE c(i) AS (SELECT 5,* UNION ALL SELECT i+1 FROM c WHERE i<10) + SELECT i FROM c; +} {1 {no tables specified}} +do_catchsql_test 13.3 { + WITH RECURSIVE c(i,j) AS (SELECT 5,* UNION ALL SELECT i+1,11 FROM c WHERE i<10) + SELECT i FROM c; +} {1 {table c has 1 values for 2 columns}} + +# 2015-04-12 +# +do_execsql_test 14.1 { + WITH x AS (SELECT * FROM t) SELECT 0 EXCEPT SELECT 0 ORDER BY 1 COLLATE binary; +} {} finish_test diff --git a/test/without_rowid6.test b/test/without_rowid6.test index e827cca..8ca78ba 100644 --- a/test/without_rowid6.test +++ b/test/without_rowid6.test @@ -37,5 +37,81 @@ do_execsql_test without_rowid6-140 { SELECT c FROM t1 ORDER BY b LIMIT 5; } {x1y x2y x3y x4y x5y} +# Column t1.b starts out as a unique index, but that index is +# subsequently converted into a PRIMARY KEY. +# +do_execsql_test without_rowid6-200 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1( + a UNIQUE, + b UNIQUE, + c UNIQUE, + PRIMARY KEY(b) + ) WITHOUT ROWID; + INSERT INTO t1(a,b,c) VALUES(1,8,3),(4,5,6),(7,2,9); + SELECT a FROM t1 WHERE b>3 ORDER BY b; +} {4 1} +do_execsql_test without_rowid6-210 { + EXPLAIN QUERY PLAN + SELECT a FROM t1 WHERE b>3 ORDER BY b; +} {/SEARCH TABLE t1 USING PRIMARY KEY .b>../} +do_execsql_test without_rowid6-220 { + PRAGMA index_list(t1); +} {/sqlite_autoindex_t1_2 1 pk/} + +do_execsql_test without_rowid6-300 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1( + a UNIQUE, + b PRIMARY KEY, + c UNIQUE, + UNIQUE(b) + ) WITHOUT ROWID; + INSERT INTO t1(a,b,c) VALUES(1,8,3),(4,5,6),(7,2,9); + SELECT a FROM t1 WHERE b>3 ORDER BY b; +} {4 1} +do_execsql_test without_rowid6-310 { + EXPLAIN QUERY PLAN + SELECT a FROM t1 WHERE b>3 ORDER BY b; +} {/SEARCH TABLE t1 USING PRIMARY KEY .b>../} +do_execsql_test without_rowid6-320 { + PRAGMA index_list(t1); +} {/sqlite_autoindex_t1_2 1 pk/} + +do_execsql_test without_rowid6-400 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1( + a UNIQUE, + b UNIQUE PRIMARY KEY, + c UNIQUE + ) WITHOUT ROWID; + INSERT INTO t1(a,b,c) VALUES(1,8,3),(4,5,6),(7,2,9); + SELECT a FROM t1 WHERE b>3 ORDER BY b; +} {4 1} +do_execsql_test without_rowid6-410 { + EXPLAIN QUERY PLAN + SELECT a FROM t1 WHERE b>3 ORDER BY b; +} {/SEARCH TABLE t1 USING PRIMARY KEY .b>../} +do_execsql_test without_rowid6-420 { + PRAGMA index_list(t1); +} {/sqlite_autoindex_t1_2 1 pk/} + +do_execsql_test without_rowid6-500 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a,b,c, + UNIQUE(b,c), + PRIMARY KEY(b,c) + ) WITHOUT ROWID; + INSERT INTO t1(a,b,c) VALUES(1,8,3),(4,5,6),(7,2,9); + SELECT a FROM t1 WHERE b>3 ORDER BY b; +} {4 1} +do_execsql_test without_rowid6-510 { + EXPLAIN QUERY PLAN + SELECT a FROM t1 WHERE b>3 ORDER BY b; +} {/SEARCH TABLE t1 USING PRIMARY KEY .b>../} +do_execsql_test without_rowid6-520 { + PRAGMA index_list(t1); +} {/sqlite_autoindex_t1_1 1 pk/} + finish_test diff --git a/test/zeroblob.test b/test/zeroblob.test index f4a1950..e70fd0b 100644 --- a/test/zeroblob.test +++ b/test/zeroblob.test @@ -255,5 +255,14 @@ do_test zeroblob-9.8 { db eval {SELECT zeroblob(2) IN (zeroblob(2))} } {1} +# Oversized zeroblob records +# +do_test zeroblob-10.1 { + db eval { + CREATE TABLE t10(a,b,c); + } + catchsql {INSERT INTO t10 VALUES(zeroblob(1e9),zeroblob(1e9),zeroblob(1e9))} +} {1 {string or blob too big}} + finish_test diff --git a/tool/build-all-msvc.bat b/tool/build-all-msvc.bat index 1fb61d4..9f5176d 100755 --- a/tool/build-all-msvc.bat +++ b/tool/build-all-msvc.bat @@ -28,6 +28,11 @@ REM In the example above, "C:\dev\sqlite\core" represents the root of the REM source tree for SQLite and "C:\Temp" represents the final destination REM directory for the generated output files. REM +REM Please note that the SQLite build process performed by the Makefile +REM associated with this batch script requires both Gawk ^(gawk.exe^) and Tcl +REM 8.5 ^(tclsh85.exe^) to be present in a directory contained in the PATH +REM environment variable unless a pre-existing amalgamation file is used. +REM REM There are several environment variables that may be set to modify the REM behavior of this batch script and its associated Makefile. The list of REM platforms to build may be overriden by using the PLATFORMS environment @@ -37,17 +42,58 @@ REM being used. The list of configurations to build may be overridden by REM setting the CONFIGURATIONS environment variable, which should contain a REM list of configurations to build ^(e.g. Debug Retail^). Neither of these REM variable values may contain any double quotes, surrounding or embedded. -REM Finally, the NCRTLIBPATH and NSDKLIBPATH environment variables may be set -REM to specify the location of the CRT and SDK, respectively, needed to compile -REM executables native to the architecture of the build machine during any -REM cross-compilation that may be necessary, depending on the platforms to be -REM built. These values in these two variables should be surrounded by double -REM quotes if they contain spaces. REM -REM Please note that the SQLite build process performed by the Makefile -REM associated with this batch script requires both Gawk ^(gawk.exe^) and Tcl -REM 8.5 ^(tclsh85.exe^) to be present in a directory contained in the PATH -REM environment variable unless a pre-existing amalgamation file is used. +REM Finally, the NCRTLIBPATH, NUCRTLIBPATH, and NSDKLIBPATH environment +REM variables may be set to specify the location of the CRT, Universal CRT, and +REM Windows SDK, respectively, that may be needed to compile executables native +REM to the architecture of the build machine during any cross-compilation that +REM may be necessary, depending on the platforms to be built. These values in +REM these three variables should be surrounded by double quotes if they contain +REM spaces. +REM +REM There are a few other environment variables that impact the build process +REM when set ^(to anything^), they are: +REM +REM NOCLEAN +REM +REM When set, the "clean" target will not be used during each build iteration. +REM However, the target binaries, if any, will still be deleted manually prior +REM to being rebuilt. Setting this environment variable is only rarely needed +REM and could cause issues in some circumstances; therefore, setting it is not +REM recommended. +REM +REM NOSYMBOLS +REM +REM When set, copying of symbol files ^(*.pdb^) created during the build will +REM be skipped and they will not appear in the final destination directory. +REM Setting this environment variable is never strictly needed and could cause +REM issues in some circumstances; therefore, setting it is not recommended. +REM +REM BUILD_ALL_SHELL +REM +REM When set, the command line shell will be built for each selected platform +REM and configuration as well. In addition, the command line shell binaries +REM will be copied, with their symbols, to the final destination directory. +REM +REM USE_WINV63_NSDKLIBPATH +REM +REM When set, modifies how the NSDKLIBPATH environment variable is built, based +REM on the WindowsSdkDir environment variable. It forces this batch script to +REM assume the Windows 8.1 SDK location should be used. +REM +REM USE_WINV100_NSDKLIBPATH +REM +REM When set, modifies how the NSDKLIBPATH environment variable is built, based +REM on the WindowsSdkDir environment variable. It causes this batch script to +REM assume the Windows 10.0 SDK location should be used. +REM +REM NMAKE_ARGS +REM +REM When set, the value is expanded and passed to the NMAKE command line, after +REM its other arguments. This is used to specify additional NMAKE options, for +REM example: +REM +REM SET NMAKE_ARGS=FOR_WINRT=1 REM SETLOCAL @@ -58,6 +104,9 @@ IF NOT DEFINED _AECHO (SET _AECHO=REM) IF NOT DEFINED _CECHO (SET _CECHO=REM) IF NOT DEFINED _VECHO (SET _VECHO=REM) +SET REDIRECT=^> +IF DEFINED __ECHO SET REDIRECT=^^^> + %_AECHO% Running %0 %* REM SET DFLAGS=/L @@ -214,8 +263,20 @@ SET TOOLPATH=%gawk.exe_PATH%;%tclsh85.exe_PATH% %_VECHO% ToolPath = '%TOOLPATH%' REM -REM NOTE: Check for MSVC 2012/2013 because the Windows SDK directory handling -REM is slightly different for those versions. +REM NOTE: Setting the Windows SDK library path is only required for MSVC +REM 2012, 2013, and 2015. +REM +CALL :fn_UnsetVariable SET_NSDKLIBPATH + +REM +REM NOTE: Setting the Universal CRT library path is only required for MSVC +REM 2015. +REM +CALL :fn_UnsetVariable SET_NUCRTLIBPATH + +REM +REM NOTE: Check for MSVC 2012, 2013, and 2015 specially because the Windows +REM SDK directory handling is slightly different for those versions. REM IF "%VisualStudioVersion%" == "11.0" ( REM @@ -233,8 +294,22 @@ IF "%VisualStudioVersion%" == "11.0" ( IF NOT DEFINED NSDKLIBPATH ( SET SET_NSDKLIBPATH=1 ) -) ELSE ( - CALL :fn_UnsetVariable SET_NSDKLIBPATH +) ELSE IF "%VisualStudioVersion%" == "14.0" ( + REM + REM NOTE: If the Windows SDK library path has already been set, do not set + REM it to something else later on. + REM + IF NOT DEFINED NSDKLIBPATH ( + SET SET_NSDKLIBPATH=1 + ) + + REM + REM NOTE: If the Universal CRT library path has already been set, do not set + REM it to something else later on. + REM + IF NOT DEFINED NUCRTLIBPATH ( + SET SET_NUCRTLIBPATH=1 + ) ) REM @@ -291,6 +366,7 @@ FOR %%P IN (%PLATFORMS%) DO ( CALL :fn_UnsetVariable LIB CALL :fn_UnsetVariable LIBPATH CALL :fn_UnsetVariable Platform + CALL :fn_UnsetVariable UniversalCRTSdkDir REM CALL :fn_UnsetVariable VCINSTALLDIR CALL :fn_UnsetVariable VSINSTALLDIR CALL :fn_UnsetVariable WindowsPhoneKitDir @@ -318,7 +394,18 @@ FOR %%P IN (%PLATFORMS%) DO ( %_AECHO% Building the %%B configuration for platform %%P with name %%D... IF /I "%%B" == "Debug" ( - SET DEBUG=2 + REM + REM NOTE: Using this level for the DEBUG environment variable should + REM disable all compiler optimizations and prevent use of the + REM NDEBUG define. Additionally, both SQLITE_ENABLE_API_ARMOR + REM and SQLITE_DEBUG defines should be enabled. + REM + SET DEBUG=3 + + REM + REM NOTE: Setting this to non-zero should enable the SQLITE_MEMDEBUG + REM define. + REM SET MEMDEBUG=1 ) ELSE ( CALL :fn_UnsetVariable DEBUG @@ -371,8 +458,8 @@ FOR %%P IN (%PLATFORMS%) DO ( ) REM - REM NOTE: When using MSVC 2012 and/or 2013, the native SDK path cannot - REM simply use the "lib" sub-directory beneath the location + REM NOTE: When using MSVC 2012, 2013, or 2015, the native SDK path + REM cannot simply be the "lib" sub-directory beneath the location REM specified in the WindowsSdkDir environment variable because REM that location does not actually contain the necessary library REM files for x86. This must be done for each iteration because @@ -391,19 +478,39 @@ FOR %%P IN (%PLATFORMS%) DO ( CALL :fn_CopyVariable WindowsSdkDir NSDKLIBPATH REM - REM NOTE: The Windows 8.1 SDK has a slightly different directory - REM naming convention. + REM NOTE: The Windows 8.x and Windows 10.0 SDKs have a slightly + REM different directory naming conventions. REM - IF DEFINED USE_WINV63_NSDKLIBPATH ( + IF DEFINED USE_WINV100_NSDKLIBPATH ( + CALL :fn_AppendVariable NSDKLIBPATH \..\10\lib\10.0.10030.0\um\x86 + CALL :fn_CopyVariable UniversalCRTSdkDir PSDKLIBPATH + CALL :fn_AppendVariable PSDKLIBPATH Lib\10.0.10030.0\um\%%D + ) ELSE IF DEFINED USE_WINV63_NSDKLIBPATH ( CALL :fn_AppendVariable NSDKLIBPATH \lib\winv6.3\um\x86 ) ELSE IF "%VisualStudioVersion%" == "12.0" ( CALL :fn_AppendVariable NSDKLIBPATH \..\8.0\lib\win8\um\x86 + ) ELSE IF "%VisualStudioVersion%" == "14.0" ( + CALL :fn_AppendVariable NSDKLIBPATH \..\8.0\lib\win8\um\x86 ) ELSE ( CALL :fn_AppendVariable NSDKLIBPATH \lib\win8\um\x86 ) ) ) + REM + REM NOTE: When using MSVC 2015, setting the Universal CRT library path + REM for x86 may be required as well. This must also be done for + REM each iteration because it relies upon the UniversalCRTSdkDir + REM environment variable being set by the batch file used to + REM setup the MSVC environment. + REM + IF DEFINED SET_NUCRTLIBPATH ( + IF DEFINED UniversalCRTSdkDir ( + CALL :fn_CopyVariable UniversalCRTSdkDir NUCRTLIBPATH + CALL :fn_AppendVariable NUCRTLIBPATH \lib\winv10.0\ucrt\x86 + ) + ) + REM REM NOTE: Unless prevented from doing so, invoke NMAKE with the MSVC REM makefile to clean any stale build output from previous @@ -420,11 +527,11 @@ FOR %%P IN (%PLATFORMS%) DO ( ) ELSE ( REM REM NOTE: Even when the cleaning step has been disabled, we still - REM need to remove the build output for the files we are + REM need to remove the build output for all the files we are REM specifically wanting to build for each platform. REM - %_AECHO% Cleaning final output files only... - %__ECHO% DEL /Q *.lo sqlite3.dll sqlite3.lib sqlite3.pdb + %_AECHO% Cleaning final core library output files only... + %__ECHO% DEL /Q *.lo sqlite3.dll sqlite3.lib sqlite3.pdb 2%REDIRECT% NUL ) REM @@ -476,6 +583,64 @@ FOR %%P IN (%PLATFORMS%) DO ( GOTO errors ) ) + + REM + REM NOTE: If requested, also build the shell executable. + REM + IF DEFINED BUILD_ALL_SHELL ( + REM + REM NOTE: If necessary, make sure any previous build output for the + REM shell executable is deleted. + REM + IF DEFINED NOCLEAN ( + REM + REM NOTE: Even when the cleaning step has been disabled, we still + REM need to remove the build output for all the files we are + REM specifically wanting to build for each platform. + REM + %_AECHO% Cleaning final shell executable output files only... + %__ECHO% DEL /Q sqlite3.exe sqlite3sh.pdb 2%REDIRECT% NUL + ) + + REM + REM NOTE: Call NMAKE with the MSVC makefile to build the "sqlite3.exe" + REM binary. The x86 compiler will be used to compile the native + REM command line tools needed during the build process itself. + REM Also, disable looking for and/or linking to the native Tcl + REM runtime library. + REM + %__ECHO% %NMAKE_CMD% sqlite3.exe XCOMPILE=1 USE_NATIVE_LIBPATHS=1 NO_TCL=1 %NMAKE_ARGS% + + IF ERRORLEVEL 1 ( + ECHO Failed to build %%B "sqlite3.exe" for platform %%P. + GOTO errors + ) + + REM + REM NOTE: Copy the "sqlite3.exe" file to the appropriate directory + REM for the build and platform beneath the binary directory. + REM + %__ECHO% XCOPY sqlite3.exe "%BINARYDIRECTORY%\%%B\%%D\" %FFLAGS% %DFLAGS% + + IF ERRORLEVEL 1 ( + ECHO Failed to copy "sqlite3.exe" to "%BINARYDIRECTORY%\%%B\%%D\". + GOTO errors + ) + + REM + REM NOTE: Copy the "sqlite3sh.pdb" file to the appropriate directory + REM for the build and platform beneath the binary directory + REM unless we are prevented from doing so. + REM + IF NOT DEFINED NOSYMBOLS ( + %__ECHO% XCOPY sqlite3sh.pdb "%BINARYDIRECTORY%\%%B\%%D\" %FFLAGS% %DFLAGS% + + IF ERRORLEVEL 1 ( + ECHO Failed to copy "sqlite3sh.pdb" to "%BINARYDIRECTORY%\%%B\%%D\". + GOTO errors + ) + ) + ) ) ) ) @@ -503,6 +668,19 @@ REM NOTE: If we get to this point, we have succeeded. REM GOTO no_errors +:fn_ShowVariable + SETLOCAL + SET __ECHO_CMD=ECHO %%%2%% + FOR /F "delims=" %%V IN ('%__ECHO_CMD%') DO ( + IF NOT "%%V" == "" ( + IF NOT "%%V" == "%%%2%%" ( + %_VECHO% %1 = '%%V' + ) + ) + ) + ENDLOCAL + GOTO :EOF + :fn_ResetErrorLevel VERIFY > NUL GOTO :EOF diff --git a/tool/fuzzershell.c b/tool/fuzzershell.c new file mode 100644 index 0000000..4eea55b --- /dev/null +++ b/tool/fuzzershell.c @@ -0,0 +1,846 @@ +/* +** 2015-04-17 +** +** 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 is a utility program designed to aid running the SQLite library +** against an external fuzzer, such as American Fuzzy Lop (AFL) +** (http://lcamtuf.coredump.cx/afl/). Basically, this program reads +** SQL text from standard input and passes it through to SQLite for evaluation, +** just like the "sqlite3" command-line shell. Differences from the +** command-line shell: +** +** (1) The complex "dot-command" extensions are omitted. This +** prevents the fuzzer from discovering that it can run things +** like ".shell rm -rf ~" +** +** (2) The database is opened with the SQLITE_OPEN_MEMORY flag so that +** no disk I/O from the database is permitted. The ATTACH command +** with a filename still uses an in-memory database. +** +** (3) The main in-memory database can be initialized from a template +** disk database so that the fuzzer starts with a database containing +** content. +** +** (4) The eval() SQL function is added, allowing the fuzzer to do +** interesting recursive operations. +** +** (5) An error is raised if there is a memory leak. +** +** The input text can be divided into separate test cases using comments +** of the form: +** +** |****<...>****| +** +** where the "..." is arbitrary text. (Except the "|" should really be "/". +** "|" is used here to avoid compiler errors about nested comments.) +** A separate in-memory SQLite database is created to run each test case. +** This feature allows the "queue" of AFL to be captured into a single big +** file using a command like this: +** +** (for i in id:*; do echo '|****<'$i'>****|'; cat $i; done) >~/all-queue.txt +** +** (Once again, change the "|" to "/") Then all elements of the AFL queue +** can be run in a single go (for regression testing, for example) by typing: +** +** fuzzershell -f ~/all-queue.txt +** +** After running each chunk of SQL, the database connection is closed. The +** program aborts if the close fails or if there is any unfreed memory after +** the close. +** +** New test cases can be appended to all-queue.txt at any time. If redundant +** test cases are added, they can be eliminated by running: +** +** fuzzershell -f ~/all-queue.txt --unique-cases ~/unique-cases.txt +*/ +#include +#include +#include +#include +#include +#include "sqlite3.h" + +/* +** All global variables are gathered into the "g" singleton. +*/ +struct GlobalVars { + const char *zArgv0; /* Name of program */ + sqlite3_mem_methods sOrigMem; /* Original memory methods */ + sqlite3_mem_methods sOomMem; /* Memory methods with OOM simulator */ + int iOomCntdown; /* Memory fails on 1 to 0 transition */ + int nOomFault; /* Increments for each OOM fault */ + int bOomOnce; /* Fail just once if true */ + int bOomEnable; /* True to enable OOM simulation */ + int nOomBrkpt; /* Number of calls to oomFault() */ + char zTestName[100]; /* Name of current test */ +} g; + +/* +** Maximum number of iterations for an OOM test +*/ +#ifndef OOM_MAX +# define OOM_MAX 625 +#endif + +/* +** This routine is called when a simulated OOM occurs. It exists as a +** convenient place to set a debugger breakpoint. +*/ +static void oomFault(void){ + g.nOomBrkpt++; /* Prevent oomFault() from being optimized out */ +} + + +/* Versions of malloc() and realloc() that simulate OOM conditions */ +static void *oomMalloc(int nByte){ + if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){ + g.iOomCntdown--; + if( g.iOomCntdown==0 ){ + if( g.nOomFault==0 ) oomFault(); + g.nOomFault++; + if( !g.bOomOnce ) g.iOomCntdown = 1; + return 0; + } + } + return g.sOrigMem.xMalloc(nByte); +} +static void *oomRealloc(void *pOld, int nByte){ + if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){ + g.iOomCntdown--; + if( g.iOomCntdown==0 ){ + if( g.nOomFault==0 ) oomFault(); + g.nOomFault++; + if( !g.bOomOnce ) g.iOomCntdown = 1; + return 0; + } + } + return g.sOrigMem.xRealloc(pOld, nByte); +} + +/* +** Print an error message and abort in such a way to indicate to the +** fuzzer that this counts as a crash. +*/ +static void abendError(const char *zFormat, ...){ + va_list ap; + if( g.zTestName[0] ){ + fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName); + }else{ + fprintf(stderr, "%s: ", g.zArgv0); + } + va_start(ap, zFormat); + vfprintf(stderr, zFormat, ap); + va_end(ap); + fprintf(stderr, "\n"); + abort(); +} +/* +** Print an error message and quit, but not in a way that would look +** like a crash. +*/ +static void fatalError(const char *zFormat, ...){ + va_list ap; + if( g.zTestName[0] ){ + fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName); + }else{ + fprintf(stderr, "%s: ", g.zArgv0); + } + va_start(ap, zFormat); + vfprintf(stderr, zFormat, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(1); +} + +/* +** Evaluate some SQL. Abort if unable. +*/ +static void sqlexec(sqlite3 *db, const char *zFormat, ...){ + va_list ap; + char *zSql; + char *zErrMsg = 0; + int rc; + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg); + if( rc ) abendError("failed sql [%s]: %s", zSql, zErrMsg); + sqlite3_free(zSql); +} + +/* +** This callback is invoked by sqlite3_log(). +*/ +static void shellLog(void *pNotUsed, int iErrCode, const char *zMsg){ + printf("LOG: (%d) %s\n", iErrCode, zMsg); + fflush(stdout); +} +static void shellLogNoop(void *pNotUsed, int iErrCode, const char *zMsg){ + return; +} + +/* +** This callback is invoked by sqlite3_exec() to return query results. +*/ +static int execCallback(void *NotUsed, int argc, char **argv, char **colv){ + int i; + static unsigned cnt = 0; + printf("ROW #%u:\n", ++cnt); + for(i=0; inUsed+p->szSep+1 > p->nAlloc ){ + char *zNew; + p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; + /* Using sqlite3_realloc64() would be better, but it is a recent + ** addition and will cause a segfault if loaded by an older version + ** of SQLite. */ + zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0; + if( zNew==0 ){ + sqlite3_free(p->z); + memset(p, 0, sizeof(*p)); + return 1; + } + p->z = zNew; + } + if( p->nUsed>0 ){ + memcpy(&p->z[p->nUsed], p->zSep, p->szSep); + p->nUsed += p->szSep; + } + memcpy(&p->z[p->nUsed], z, sz); + p->nUsed += sz; + } + return 0; +} + +/* +** Implementation of the eval(X) and eval(X,Y) SQL functions. +** +** Evaluate the SQL text in X. Return the results, using string +** Y as the separator. If Y is omitted, use a single space character. +*/ +static void sqlEvalFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zSql; + sqlite3 *db; + char *zErr = 0; + int rc; + struct EvalResult x; + + memset(&x, 0, sizeof(x)); + x.zSep = " "; + zSql = (const char*)sqlite3_value_text(argv[0]); + if( zSql==0 ) return; + if( argc>1 ){ + x.zSep = (const char*)sqlite3_value_text(argv[1]); + if( x.zSep==0 ) return; + } + x.szSep = (int)strlen(x.zSep); + db = sqlite3_context_db_handle(context); + rc = sqlite3_exec(db, zSql, callback, &x, &zErr); + if( rc!=SQLITE_OK ){ + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + }else if( x.zSep==0 ){ + sqlite3_result_error_nomem(context); + sqlite3_free(x.z); + }else{ + sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free); + } +} +/* End of the eval() implementation +******************************************************************************/ + +/* +** Print sketchy documentation for this utility program +*/ +static void showHelp(void){ + printf("Usage: %s [options] ?FILE...?\n", g.zArgv0); + printf( +"Read SQL text from FILE... (or from standard input if FILE... is omitted)\n" +"and then evaluate each block of SQL contained therein.\n" +"Options:\n" +" --autovacuum Enable AUTOVACUUM mode\n" +" --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n" +" --help Show this help text\n" +" --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n" +" --oom Run each test multiple times in a simulated OOM loop\n" +" --pagesize N Set the page size to N\n" +" --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n" +" -q Reduced output\n" +" --quiet Reduced output\n" +" --scratch N SZ Configure scratch memory for N slots of SZ bytes each\n" +" --unique-cases FILE Write all unique test cases to FILE\n" +" --utf16be Set text encoding to UTF-16BE\n" +" --utf16le Set text encoding to UTF-16LE\n" +" -v Increased output\n" +" --verbose Increased output\n" + ); +} + +/* +** Return the value of a hexadecimal digit. Return -1 if the input +** is not a hex digit. +*/ +static int hexDigitValue(char c){ + if( c>='0' && c<='9' ) return c - '0'; + if( c>='a' && c<='f' ) return c - 'a' + 10; + if( c>='A' && c<='F' ) return c - 'A' + 10; + return -1; +} + +/* +** Interpret zArg as an integer value, possibly with suffixes. +*/ +static int integerValue(const char *zArg){ + sqlite3_int64 v = 0; + static const struct { char *zSuffix; int iMult; } aMult[] = { + { "KiB", 1024 }, + { "MiB", 1024*1024 }, + { "GiB", 1024*1024*1024 }, + { "KB", 1000 }, + { "MB", 1000000 }, + { "GB", 1000000000 }, + { "K", 1000 }, + { "M", 1000000 }, + { "G", 1000000000 }, + }; + int i; + int isNeg = 0; + if( zArg[0]=='-' ){ + isNeg = 1; + zArg++; + }else if( zArg[0]=='+' ){ + zArg++; + } + if( zArg[0]=='0' && zArg[1]=='x' ){ + int x; + zArg += 2; + while( (x = hexDigitValue(zArg[0]))>=0 ){ + v = (v<<4) + x; + zArg++; + } + }else{ + while( isdigit(zArg[0]) ){ + v = v*10 + zArg[0] - '0'; + zArg++; + } + } + for(i=0; i0x7fffffff ) abendError("parameter too large - max 2147483648"); + return (int)(isNeg? -v : v); +} + +/* Return the current wall-clock time */ +static sqlite3_int64 timeOfDay(void){ + static sqlite3_vfs *clockVfs = 0; + sqlite3_int64 t; + if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); + if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){ + clockVfs->xCurrentTimeInt64(clockVfs, &t); + }else{ + double r; + clockVfs->xCurrentTime(clockVfs, &r); + t = (sqlite3_int64)(r*86400000.0); + } + return t; +} + +int main(int argc, char **argv){ + char *zIn = 0; /* Input text */ + int nAlloc = 0; /* Number of bytes allocated for zIn[] */ + int nIn = 0; /* Number of bytes of zIn[] used */ + size_t got; /* Bytes read from input */ + int rc = SQLITE_OK; /* Result codes from API functions */ + int i; /* Loop counter */ + int iNext; /* Next block of SQL */ + sqlite3 *db; /* Open database */ + char *zErrMsg = 0; /* Error message returned from sqlite3_exec() */ + const char *zEncoding = 0; /* --utf16be or --utf16le */ + int nHeap = 0, mnHeap = 0; /* Heap size from --heap */ + int nLook = 0, szLook = 0; /* --lookaside configuration */ + int nPCache = 0, szPCache = 0;/* --pcache configuration */ + int nScratch = 0, szScratch=0;/* --scratch configuration */ + int pageSize = 0; /* Desired page size. 0 means default */ + void *pHeap = 0; /* Allocated heap space */ + void *pLook = 0; /* Allocated lookaside space */ + void *pPCache = 0; /* Allocated storage for pcache */ + void *pScratch = 0; /* Allocated storage for scratch */ + int doAutovac = 0; /* True for --autovacuum */ + char *zSql; /* SQL to run */ + char *zToFree = 0; /* Call sqlite3_free() on this afte running zSql */ + int verboseFlag = 0; /* --verbose or -v flag */ + int quietFlag = 0; /* --quiet or -q flag */ + int nTest = 0; /* Number of test cases run */ + int multiTest = 0; /* True if there will be multiple test cases */ + int lastPct = -1; /* Previous percentage done output */ + sqlite3 *dataDb = 0; /* Database holding compacted input data */ + sqlite3_stmt *pStmt = 0; /* Statement to insert testcase into dataDb */ + const char *zDataOut = 0; /* Write compacted data to this output file */ + int nHeader = 0; /* Bytes of header comment text on input file */ + int oomFlag = 0; /* --oom */ + int oomCnt = 0; /* Counter for the OOM loop */ + char zErrBuf[200]; /* Space for the error message */ + const char *zFailCode; /* Value of the TEST_FAILURE environment var */ + const char *zPrompt; /* Initial prompt when large-file fuzzing */ + int nInFile = 0; /* Number of input files to read */ + char **azInFile = 0; /* Array of input file names */ + int jj; /* Loop counter for azInFile[] */ + sqlite3_int64 iBegin; /* Start time for the whole program */ + sqlite3_int64 iStart, iEnd; /* Start and end-times for a test case */ + + iBegin = timeOfDay(); + zFailCode = getenv("TEST_FAILURE"); + g.zArgv0 = argv[0]; + zPrompt = ""; + for(i=1; i=argc-2 ) abendError("missing arguments on %s\n", argv[i]); + nHeap = integerValue(argv[i+1]); + mnHeap = integerValue(argv[i+2]); + i += 2; + }else + if( strcmp(z,"help")==0 ){ + showHelp(); + return 0; + }else + if( strcmp(z,"lookaside")==0 ){ + if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); + nLook = integerValue(argv[i+1]); + szLook = integerValue(argv[i+2]); + i += 2; + }else + if( strcmp(z,"oom")==0 ){ + oomFlag = 1; + }else + if( strcmp(z,"pagesize")==0 ){ + if( i>=argc-1 ) abendError("missing argument on %s", argv[i]); + pageSize = integerValue(argv[++i]); + }else + if( strcmp(z,"pcache")==0 ){ + if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); + nPCache = integerValue(argv[i+1]); + szPCache = integerValue(argv[i+2]); + i += 2; + }else + if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){ + quietFlag = 1; + verboseFlag = 0; + }else + if( strcmp(z,"scratch")==0 ){ + if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); + nScratch = integerValue(argv[i+1]); + szScratch = integerValue(argv[i+2]); + i += 2; + }else + if( strcmp(z, "unique-cases")==0 ){ + if( i>=argc-1 ) abendError("missing arguments on %s", argv[i]); + if( zDataOut ) abendError("only one --minimize allowed"); + zDataOut = argv[++i]; + }else + if( strcmp(z,"utf16le")==0 ){ + zEncoding = "utf16le"; + }else + if( strcmp(z,"utf16be")==0 ){ + zEncoding = "utf16be"; + }else + if( strcmp(z,"verbose")==0 || strcmp(z,"v")==0 ){ + quietFlag = 0; + verboseFlag = 1; + }else + { + abendError("unknown option: %s", argv[i]); + } + }else{ + addNewInFile: + nInFile++; + azInFile = realloc(azInFile, sizeof(azInFile[0])*nInFile); + if( azInFile==0 ) abendError("out of memory"); + azInFile[nInFile-1] = argv[i]; + } + } + + /* Do global SQLite initialization */ + sqlite3_config(SQLITE_CONFIG_LOG, verboseFlag ? shellLog : shellLogNoop, 0); + if( nHeap>0 ){ + pHeap = malloc( nHeap ); + if( pHeap==0 ) fatalError("cannot allocate %d-byte heap\n", nHeap); + rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap); + if( rc ) abendError("heap configuration failed: %d\n", rc); + } + if( oomFlag ){ + sqlite3_config(SQLITE_CONFIG_GETMALLOC, &g.sOrigMem); + g.sOomMem = g.sOrigMem; + g.sOomMem.xMalloc = oomMalloc; + g.sOomMem.xRealloc = oomRealloc; + sqlite3_config(SQLITE_CONFIG_MALLOC, &g.sOomMem); + } + if( nLook>0 ){ + sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0); + if( szLook>0 ){ + pLook = malloc( nLook*szLook ); + if( pLook==0 ) fatalError("out of memory"); + } + } + if( nScratch>0 && szScratch>0 ){ + pScratch = malloc( nScratch*(sqlite3_int64)szScratch ); + if( pScratch==0 ) fatalError("cannot allocate %lld-byte scratch", + nScratch*(sqlite3_int64)szScratch); + rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, pScratch, szScratch, nScratch); + if( rc ) abendError("scratch configuration failed: %d\n", rc); + } + if( nPCache>0 && szPCache>0 ){ + pPCache = malloc( nPCache*(sqlite3_int64)szPCache ); + if( pPCache==0 ) fatalError("cannot allocate %lld-byte pcache", + nPCache*(sqlite3_int64)szPCache); + rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache); + if( rc ) abendError("pcache configuration failed: %d", rc); + } + + /* If the --unique-cases option was supplied, open the database that will + ** be used to gather unique test cases. + */ + if( zDataOut ){ + rc = sqlite3_open(":memory:", &dataDb); + if( rc ) abendError("cannot open :memory: database"); + rc = sqlite3_exec(dataDb, + "CREATE TABLE testcase(sql BLOB PRIMARY KEY, tm) WITHOUT ROWID;",0,0,0); + if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); + rc = sqlite3_prepare_v2(dataDb, + "INSERT OR IGNORE INTO testcase(sql,tm)VALUES(?1,?2)", + -1, &pStmt, 0); + if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); + } + + /* Initialize the input buffer used to hold SQL text */ + if( nInFile==0 ) nInFile = 1; + nAlloc = 1000; + zIn = malloc(nAlloc); + if( zIn==0 ) fatalError("out of memory"); + + /* Loop over all input files */ + for(jj=0; jj****/"); + if( z ){ + z += 6; + sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "%.*s", + (int)(z-&zIn[i]) - 12, &zIn[i+6]); + if( verboseFlag ){ + printf("%.*s\n", (int)(z-&zIn[i]), &zIn[i]); + fflush(stdout); + } + i += (int)(z-&zIn[i]); + multiTest = 1; + } + } + for(iNext=i; iNext1 ){ + printf("%s\n", zPrompt); + } + fflush(stdout); + + /* Run the next test case. Run it multiple times in --oom mode + */ + if( oomFlag ){ + oomCnt = g.iOomCntdown = 1; + g.nOomFault = 0; + g.bOomOnce = 1; + if( verboseFlag ){ + printf("Once.%d\n", oomCnt); + fflush(stdout); + } + }else{ + oomCnt = 0; + } + do{ + rc = sqlite3_open_v2( + "main.db", &db, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY, + 0); + if( rc!=SQLITE_OK ){ + abendError("Unable to open the in-memory database"); + } + if( pLook ){ + rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE,pLook,szLook,nLook); + if( rc!=SQLITE_OK ) abendError("lookaside configuration filed: %d", rc); + } + #ifndef SQLITE_OMIT_TRACE + sqlite3_trace(db, verboseFlag ? traceCallback : traceNoop, 0); + #endif + sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0); + sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0); + sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 1000000); + if( zEncoding ) sqlexec(db, "PRAGMA encoding=%s", zEncoding); + if( pageSize ) sqlexec(db, "PRAGMA pagesize=%d", pageSize); + if( doAutovac ) sqlexec(db, "PRAGMA auto_vacuum=FULL"); + iStart = timeOfDay(); + g.bOomEnable = 1; + if( verboseFlag ){ + zErrMsg = 0; + rc = sqlite3_exec(db, zSql, execCallback, 0, &zErrMsg); + if( zErrMsg ){ + sqlite3_snprintf(sizeof(zErrBuf),zErrBuf,"%z", zErrMsg); + zErrMsg = 0; + } + }else { + rc = sqlite3_exec(db, zSql, execNoop, 0, 0); + } + g.bOomEnable = 0; + iEnd = timeOfDay(); + rc = sqlite3_close(db); + if( rc ){ + abendError("sqlite3_close() failed with rc=%d", rc); + } + if( !zDataOut && sqlite3_memory_used()>0 ){ + abendError("memory in use after close: %lld bytes",sqlite3_memory_used()); + } + if( oomFlag ){ + /* Limit the number of iterations of the OOM loop to OOM_MAX. If the + ** first pass (single failure) exceeds 2/3rds of OOM_MAX this skip the + ** second pass (continuous failure after first) completely. */ + if( g.nOomFault==0 || oomCnt>OOM_MAX ){ + if( g.bOomOnce && oomCnt<=(OOM_MAX*2/3) ){ + oomCnt = g.iOomCntdown = 1; + g.bOomOnce = 0; + }else{ + oomCnt = 0; + } + }else{ + g.iOomCntdown = ++oomCnt; + g.nOomFault = 0; + } + if( oomCnt ){ + if( verboseFlag ){ + printf("%s.%d\n", g.bOomOnce ? "Once" : "Multi", oomCnt); + fflush(stdout); + } + nTest++; + } + } + }while( oomCnt>0 ); + + /* Store unique test cases in the in the dataDb database if the + ** --unique-cases flag is present + */ + if( zDataOut ){ + sqlite3_bind_blob(pStmt, 1, &zIn[i], iNext-i, SQLITE_STATIC); + sqlite3_bind_int64(pStmt, 2, iEnd - iStart); + rc = sqlite3_step(pStmt); + if( rc!=SQLITE_DONE ) abendError("%s", sqlite3_errmsg(dataDb)); + sqlite3_reset(pStmt); + } + + /* Free the SQL from the current test case + */ + if( zToFree ){ + sqlite3_free(zToFree); + zToFree = 0; + } + zIn[iNext] = cSaved; + + /* Show test-case results in --verbose mode + */ + if( verboseFlag ){ + printf("RESULT-CODE: %d\n", rc); + if( zErrMsg ){ + printf("ERROR-MSG: [%s]\n", zErrBuf); + } + fflush(stdout); + } + + /* Simulate an error if the TEST_FAILURE environment variable is "5". + ** This is used to verify that automated test script really do spot + ** errors that occur in this test program. + */ + if( zFailCode ){ + if( zFailCode[0]=='5' && zFailCode[1]==0 ){ + abendError("simulated failure"); + }else if( zFailCode[0]!=0 ){ + /* If TEST_FAILURE is something other than 5, just exit the test + ** early */ + printf("\nExit early due to TEST_FAILURE being set"); + break; + } + } + } + if( !verboseFlag && multiTest && !quietFlag && !oomFlag ) printf("\n"); + } + + /* Report total number of tests run + */ + if( nTest>1 && !quietFlag ){ + sqlite3_int64 iElapse = timeOfDay() - iBegin; + printf("%s: 0 errors out of %d tests in %d.%03d seconds\nSQLite %s %s\n", + g.zArgv0, nTest, (int)(iElapse/1000), (int)(iElapse%1000), + sqlite3_libversion(), sqlite3_sourceid()); + } + + /* Write the unique test cases if the --unique-cases flag was used + */ + if( zDataOut ){ + int n = 0; + FILE *out = fopen(zDataOut, "wb"); + if( out==0 ) abendError("cannot open %s for writing", zDataOut); + if( nHeader>0 ) fwrite(zIn, nHeader, 1, out); + sqlite3_finalize(pStmt); + rc = sqlite3_prepare_v2(dataDb, "SELECT sql, tm FROM testcase ORDER BY tm, sql", + -1, &pStmt, 0); + if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + fprintf(out,"/****<%d:%dms>****/", ++n, sqlite3_column_int(pStmt,1)); + fwrite(sqlite3_column_blob(pStmt,0),sqlite3_column_bytes(pStmt,0),1,out); + } + fclose(out); + sqlite3_finalize(pStmt); + sqlite3_close(dataDb); + } + + /* Clean up and exit. + */ + free(azInFile); + free(zIn); + free(pHeap); + free(pLook); + free(pScratch); + free(pPCache); + return 0; +} diff --git a/tool/lemon.c b/tool/lemon.c index 4ada425..89d992c 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -1114,7 +1114,6 @@ void FindActions(struct lemon *lemp) /* Resolve conflicts */ for(i=0; instate; i++){ struct action *ap, *nap; - struct state *stp; stp = lemp->sorted[i]; /* assert( stp->ap ); */ stp->ap = Action_sort(stp->ap); @@ -1731,7 +1730,7 @@ static char *msort( char *ep; char *set[LISTSIZE]; int i; - offset = (unsigned long)next - (unsigned long)list; + offset = (unsigned long)((char*)next - (char*)list); for(i=0; iinclude,&lineno); if( mhflag ){ - char *name = file_makename(lemp, ".h"); - fprintf(out,"#include \"%s\"\n", name); lineno++; - free(name); + char *incName = file_makename(lemp, ".h"); + fprintf(out,"#include \"%s\"\n", incName); lineno++; + free(incName); } tplt_xfer(lemp->name,in,out,&lineno); @@ -3791,7 +3790,6 @@ void ReportTable( } name = lemp->name ? lemp->name : "Parse"; if( lemp->arg && lemp->arg[0] ){ - int i; i = lemonStrlen(lemp->arg); while( i>=1 && isspace(lemp->arg[i-1]) ) i--; while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--; @@ -4479,18 +4477,18 @@ int Strsafe_insert(const char *data) } if( x1a->count>=x1a->size ){ /* Need to make the hash table bigger */ - int i,size; + int i,arrSize; struct s_x1 array; - array.size = size = x1a->size*2; + array.size = arrSize = x1a->size*2; array.count = x1a->count; - array.tbl = (x1node*)calloc(size, sizeof(x1node) + sizeof(x1node*)); + array.tbl = (x1node*)calloc(arrSize, sizeof(x1node) + sizeof(x1node*)); if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ - array.ht = (x1node**)&(array.tbl[size]); - for(i=0; icount; i++){ x1node *oldnp, *newnp; oldnp = &(x1a->tbl[i]); - h = strhash(oldnp->data) & (size-1); + h = strhash(oldnp->data) & (arrSize-1); newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; @@ -4646,18 +4644,18 @@ int Symbol_insert(struct symbol *data, const char *key) } if( x2a->count>=x2a->size ){ /* Need to make the hash table bigger */ - int i,size; + int i,arrSize; struct s_x2 array; - array.size = size = x2a->size*2; + array.size = arrSize = x2a->size*2; array.count = x2a->count; - array.tbl = (x2node*)calloc(size, sizeof(x2node) + sizeof(x2node*)); + array.tbl = (x2node*)calloc(arrSize, sizeof(x2node) + sizeof(x2node*)); if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ - array.ht = (x2node**)&(array.tbl[size]); - for(i=0; icount; i++){ x2node *oldnp, *newnp; oldnp = &(x2a->tbl[i]); - h = strhash(oldnp->key) & (size-1); + h = strhash(oldnp->key) & (arrSize-1); newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; @@ -4722,12 +4720,12 @@ int Symbol_count() struct symbol **Symbol_arrayof() { struct symbol **array; - int i,size; + int i,arrSize; if( x2a==0 ) return 0; - size = x2a->count; - array = (struct symbol **)calloc(size, sizeof(struct symbol *)); + arrSize = x2a->count; + array = (struct symbol **)calloc(arrSize, sizeof(struct symbol *)); if( array ){ - for(i=0; itbl[i].data; + for(i=0; itbl[i].data; } return array; } @@ -4843,18 +4841,18 @@ int State_insert(struct state *data, struct config *key) } if( x3a->count>=x3a->size ){ /* Need to make the hash table bigger */ - int i,size; + int i,arrSize; struct s_x3 array; - array.size = size = x3a->size*2; + array.size = arrSize = x3a->size*2; array.count = x3a->count; - array.tbl = (x3node*)calloc(size, sizeof(x3node) + sizeof(x3node*)); + array.tbl = (x3node*)calloc(arrSize, sizeof(x3node) + sizeof(x3node*)); if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ - array.ht = (x3node**)&(array.tbl[size]); - for(i=0; icount; i++){ x3node *oldnp, *newnp; oldnp = &(x3a->tbl[i]); - h = statehash(oldnp->key) & (size-1); + h = statehash(oldnp->key) & (arrSize-1); newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; @@ -4901,12 +4899,12 @@ struct state *State_find(struct config *key) struct state **State_arrayof() { struct state **array; - int i,size; + int i,arrSize; if( x3a==0 ) return 0; - size = x3a->count; - array = (struct state **)calloc(size, sizeof(struct state *)); + arrSize = x3a->count; + array = (struct state **)calloc(arrSize, sizeof(struct state *)); if( array ){ - for(i=0; itbl[i].data; + for(i=0; itbl[i].data; } return array; } @@ -4983,18 +4981,18 @@ int Configtable_insert(struct config *data) } if( x4a->count>=x4a->size ){ /* Need to make the hash table bigger */ - int i,size; + int i,arrSize; struct s_x4 array; - array.size = size = x4a->size*2; + array.size = arrSize = x4a->size*2; array.count = x4a->count; - array.tbl = (x4node*)calloc(size, sizeof(x4node) + sizeof(x4node*)); + array.tbl = (x4node*)calloc(arrSize, sizeof(x4node) + sizeof(x4node*)); if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ - array.ht = (x4node**)&(array.tbl[size]); - for(i=0; icount; i++){ x4node *oldnp, *newnp; oldnp = &(x4a->tbl[i]); - h = confighash(oldnp->data) & (size-1); + h = confighash(oldnp->data) & (arrSize-1); newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index 21503d1..964946e 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -4,10 +4,10 @@ # # To add new pragmas, first add the name and other relevant attributes # of the pragma to the "pragma_def" object below. Then run this script -# to generate the C-code for the lookup table and copy/paste the output -# of this script into the appropriate spot in the pragma.c source file. +# to generate the ../src/pragma.h header file that contains macros and +# the lookup table needed for pragma name lookup in the pragma.c module. # Then add the extra "case PragTyp_XXXXX:" and subsequent code for the -# new pragma. +# new pragma in ../src/pragma.c. # set pragma_def { @@ -205,6 +205,14 @@ set pragma_def { IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: index_info + TYPE: INDEX_INFO + ARG: 0 + FLAG: NeedSchema + IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + + NAME: index_xinfo + TYPE: INDEX_INFO + ARG: 1 FLAG: NeedSchema IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) @@ -308,7 +316,20 @@ set pragma_def { NAME: threads } -fconfigure stdout -translation lf + +# Open the output file +# +set destfile "[file dir [file dir [file normal $argv0]]]/src/pragma.h" +puts "Overwriting $destfile with new pragma table..." +set fd [open $destfile wb] +puts $fd {/* DO NOT EDIT! +** This file is automatically generated by the script at +** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit +** that script and rerun it. +*/} + +# Parse the PRAGMA table above. +# set name {} set type {} set if {} @@ -362,7 +383,7 @@ foreach name $allnames { set if [lindex $allbyname($name) 2] if {[regexp SQLITE_DEBUG $if] || [regexp SQLITE_HAS_CODEC $if]} continue set seentype($type) 1 - puts [format {#define %-35s %4d} PragTyp_$type $pnum] + puts $fd [format {#define %-35s %4d} PragTyp_$type $pnum] incr pnum } foreach name $allnames { @@ -371,14 +392,14 @@ foreach name $allnames { set if [lindex $allbyname($name) 2] if {[regexp SQLITE_DEBUG $if]} continue set seentype($type) 1 - puts [format {#define %-35s %4d} PragTyp_$type $pnum] + puts $fd [format {#define %-35s %4d} PragTyp_$type $pnum] incr pnum } foreach name $allnames { set type [lindex $allbyname($name) 0] if {[info exists seentype($type)]} continue set seentype($type) 1 - puts [format {#define %-35s %4d} PragTyp_$type $pnum] + puts $fd [format {#define %-35s %4d} PragTyp_$type $pnum] incr pnum } @@ -386,18 +407,18 @@ foreach name $allnames { # set fv 1 foreach f [lsort [array names allflags]] { - puts [format {#define PragFlag_%-20s 0x%02x} $f $fv] + puts $fd [format {#define PragFlag_%-20s 0x%02x} $f $fv] set fv [expr {$fv*2}] } # Generate the lookup table # -puts "static const struct sPragmaNames \173" -puts " const char *const zName; /* Name of pragma */" -puts " u8 ePragTyp; /* PragTyp_XXX value */" -puts " u8 mPragFlag; /* Zero or more PragFlag_XXX values */" -puts " u32 iArg; /* Extra argument */" -puts "\175 aPragmaNames\[\] = \173" +puts $fd "static const struct sPragmaNames \173" +puts $fd " const char *const zName; /* Name of pragma */" +puts $fd " u8 ePragTyp; /* PragTyp_XXX value */" +puts $fd " u8 mPragFlag; /* Zero or more PragFlag_XXX values */" +puts $fd " u32 iArg; /* Extra argument */" +puts $fd "\175 aPragmaNames\[\] = \173" set current_if {} set spacer [format { %26s } {}] @@ -406,13 +427,13 @@ foreach name $allnames { if {$if!=$current_if} { if {$current_if!=""} { foreach this_if $current_if { - puts "#endif" + puts $fd "#endif" } } set current_if $if if {$current_if!=""} { foreach this_if $current_if { - puts "#if $this_if" + puts $fd "#if $this_if" } } } @@ -422,17 +443,17 @@ foreach name $allnames { } else { set flagx PragFlag_[join $flag {|PragFlag_}] } - puts " \173 /* zName: */ \"$name\"," - puts " /* ePragTyp: */ PragTyp_$type," - puts " /* ePragFlag: */ $flagx," - puts " /* iArg: */ $arg \175," + puts $fd " \173 /* zName: */ \"$name\"," + puts $fd " /* ePragTyp: */ PragTyp_$type," + puts $fd " /* ePragFlag: */ $flagx," + puts $fd " /* iArg: */ $arg \175," } if {$current_if!=""} { foreach this_if $current_if { - puts "#endif" + puts $fd "#endif" } } -puts "\175;" +puts $fd "\175;" # count the number of pragmas, for information purposes # @@ -444,4 +465,4 @@ foreach name $allnames { if {[regexp {^defined} $if] || [regexp {[^!]defined} $if]} continue incr dfltcnt } -puts "/* Number of pragmas: $dfltcnt on by default, $allcnt total. */" +puts $fd "/* Number of pragmas: $dfltcnt on by default, $allcnt total. */" diff --git a/tool/mksqlite3c-noext.tcl b/tool/mksqlite3c-noext.tcl index 2752226..0e1d0fc 100644 --- a/tool/mksqlite3c-noext.tcl +++ b/tool/mksqlite3c-noext.tcl @@ -17,13 +17,13 @@ # After the "tsrc" directory has been created and populated, run # this script: # -# tclsh mksqlite3c.tcl +# tclsh mksqlite3c-noext.tcl # # The amalgamated SQLite code will be written into sqlite3.c # # Begin by reading the "sqlite3.h" header file. Extract the version number -# from in this file. The versioon number is needed to generate the header +# from in this file. The version number is needed to generate the header # comment of the amalgamation. # if {[lsearch $argv --nostatic]>=0} { @@ -80,9 +80,6 @@ if {$addstatic} { puts $out \ {#ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static -#endif -#ifndef SQLITE_API -# define SQLITE_API #endif} } @@ -106,6 +103,7 @@ foreach hdr { pager.h parse.h pcache.h + pragma.h sqlite3ext.h sqlite3.h sqliteicu.h @@ -113,12 +111,31 @@ foreach hdr { sqliteLimit.h vdbe.h vdbeInt.h + vxworks.h wal.h + whereInt.h } { set available_hdr($hdr) 1 } set available_hdr(sqliteInt.h) 0 +# These headers should be copied into the amalgamation without modifying any +# of their function declarations or definitions. +set varonly_hdr(sqlite3.h) 1 + +# These are the functions that accept a variable number of arguments. They +# always need to use the "cdecl" calling convention even when another calling +# convention (e.g. "stcall") is being used for the rest of the library. +set cdecllist { + sqlite3_config + sqlite3_db_config + sqlite3_log + sqlite3_mprintf + sqlite3_snprintf + sqlite3_test_control + sqlite3_vtab_config +} + # 78 stars used for comment formatting. set s78 \ {*****************************************************************************} @@ -135,21 +152,21 @@ proc section_comment {text} { # Read the source file named $filename and write it into the # sqlite3.c output file. If any #include statements are seen, -# process them approprately. +# process them appropriately. # proc copy_file {filename} { - global seen_hdr available_hdr out addstatic linemacros + global seen_hdr available_hdr varonly_hdr cdecllist out addstatic linemacros set ln 0 set tail [file tail $filename] section_comment "Begin file $tail" if {$linemacros} {puts $out "#line 1 \"$filename\""} set in [open $filename r] set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)} - set declpattern {[a-zA-Z][a-zA-Z_0-9 ]+ \**(sqlite3[_a-zA-Z0-9]+)\(} + set declpattern {([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3[_a-zA-Z0-9]+)(\(.*)} if {[file extension $filename]==".h"} { set declpattern " *$declpattern" } - set declpattern ^$declpattern + set declpattern ^$declpattern\$ while {![eof $in]} { set line [gets $in] incr ln @@ -165,42 +182,67 @@ proc copy_file {filename} { if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""} } } elseif {![info exists seen_hdr($hdr)]} { - set seen_hdr($hdr) 1 + if {![regexp {/\*\s+amalgamator:\s+dontcache\s+\*/} $line]} { + set seen_hdr($hdr) 1 + } + puts $out $line + } elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} { + # This include file must be kept because there was a "keep" + # directive inside of a line comment. puts $out $line } else { - puts $out "/* $line */" + # Comment out the entire line, replacing any nested comment + # begin/end markers with the harmless substring "**". + puts $out "/* [string map [list /* ** */ **] $line] */" } } elseif {[regexp {^#ifdef __cplusplus} $line]} { puts $out "#if 0" } elseif {!$linemacros && [regexp {^#line} $line]} { # Skip #line directives. } elseif {$addstatic && ![regexp {^(static|typedef)} $line]} { - regsub {^SQLITE_API } $line {} line - if {[regexp $declpattern $line all funcname]} { + # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before + # functions if this header file does not need it. + if {![info exists varonly_hdr($tail)] + && [regexp $declpattern $line all rettype funcname rest]} { + regsub {^SQLITE_API } $line {} line # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions. # so that linkage can be modified at compile-time. if {[regexp {^sqlite3_} $funcname]} { - puts $out "SQLITE_API $line" + set line SQLITE_API + append line " " [string trim $rettype] + if {[string index $rettype end] ne "*"} { + append line " " + } + if {[lsearch -exact $cdecllist $funcname] >= 0} { + append line SQLITE_CDECL + } else { + append line SQLITE_STDCALL + } + append line " " $funcname $rest + puts $out $line } else { puts $out "SQLITE_PRIVATE $line" } } elseif {[regexp $varpattern $line all varname]} { - # Add the SQLITE_PRIVATE before variable declarations or - # definitions for internal use - if {![regexp {^sqlite3_} $varname]} { - regsub {^extern } $line {} line - puts $out "SQLITE_PRIVATE $line" - } else { - if {[regexp {const char sqlite3_version\[\];} $line]} { - set line {const char sqlite3_version[] = SQLITE_VERSION;} + # Add the SQLITE_PRIVATE before variable declarations or + # definitions for internal use + regsub {^SQLITE_API } $line {} line + if {![regexp {^sqlite3_} $varname]} { + regsub {^extern } $line {} line + puts $out "SQLITE_PRIVATE $line" + } else { + if {[regexp {const char sqlite3_version\[\];} $line]} { + set line {const char sqlite3_version[] = SQLITE_VERSION;} + } + regsub {^SQLITE_EXTERN } $line {} line + puts $out "SQLITE_API $line" } - regsub {^SQLITE_EXTERN } $line {} line - puts $out "SQLITE_API $line" - } } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} { + regsub {^SQLITE_API } $line {} line regsub {^SQLITE_EXTERN } $line {} line - puts $out "SQLITE_PRIVATE $line" + puts $out $line } elseif {[regexp {^void \(\*sqlite3Os} $line]} { + regsub {^SQLITE_API } $line {} line puts $out "SQLITE_PRIVATE $line" } else { puts $out $line diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index 1d597a5..0c2f3e7 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -17,7 +17,7 @@ # After the "tsrc" directory has been created and populated, run # this script: # -# tclsh mksqlite3c.tcl +# tclsh mksqlite3c.tcl --srcdir $SRC # # The amalgamated SQLite code will be written into sqlite3.c # @@ -26,15 +26,17 @@ # from in this file. The version number is needed to generate the header # comment of the amalgamation. # -if {[lsearch $argv --nostatic]>=0} { - set addstatic 0 -} else { - set addstatic 1 -} -if {[lsearch $argv --linemacros]>=0} { - set linemacros 1 -} else { - set linemacros 0 +set addstatic 1 +set linemacros 0 +for {set i 0} {$i<[llength $argv]} {incr i} { + set x [lindex $argv $i] + if {[regexp {^-+nostatic$} $x]} { + set addstatic 0 + } elseif {[regexp {^-+linemacros} $x]} { + set linemacros 1 + } else { + error "unknown command-line option: $x" + } } set in [open tsrc/sqlite3.h] set cnt 0 @@ -80,9 +82,6 @@ if {$addstatic} { puts $out \ {#ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static -#endif -#ifndef SQLITE_API -# define SQLITE_API #endif} } @@ -110,6 +109,7 @@ foreach hdr { pager.h parse.h pcache.h + pragma.h rtree.h sqlite3ext.h sqlite3.h @@ -118,6 +118,7 @@ foreach hdr { sqliteLimit.h vdbe.h vdbeInt.h + vxworks.h wal.h whereInt.h } { @@ -125,6 +126,23 @@ foreach hdr { } set available_hdr(sqliteInt.h) 0 +# These headers should be copied into the amalgamation without modifying any +# of their function declarations or definitions. +set varonly_hdr(sqlite3.h) 1 + +# These are the functions that accept a variable number of arguments. They +# always need to use the "cdecl" calling convention even when another calling +# convention (e.g. "stcall") is being used for the rest of the library. +set cdecllist { + sqlite3_config + sqlite3_db_config + sqlite3_log + sqlite3_mprintf + sqlite3_snprintf + sqlite3_test_control + sqlite3_vtab_config +} + # 78 stars used for comment formatting. set s78 \ {*****************************************************************************} @@ -144,18 +162,18 @@ proc section_comment {text} { # process them appropriately. # proc copy_file {filename} { - global seen_hdr available_hdr out addstatic linemacros + global seen_hdr available_hdr varonly_hdr cdecllist out addstatic linemacros set ln 0 set tail [file tail $filename] section_comment "Begin file $tail" if {$linemacros} {puts $out "#line 1 \"$filename\""} set in [open $filename r] set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)} - set declpattern {[a-zA-Z][a-zA-Z_0-9 ]+ \**(sqlite3[_a-zA-Z0-9]+)\(} + set declpattern {([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3[_a-zA-Z0-9]+)(\(.*)} if {[file extension $filename]==".h"} { set declpattern " *$declpattern" } - set declpattern ^$declpattern + set declpattern ^$declpattern\$ while {![eof $in]} { set line [gets $in] incr ln @@ -189,32 +207,49 @@ proc copy_file {filename} { } elseif {!$linemacros && [regexp {^#line} $line]} { # Skip #line directives. } elseif {$addstatic && ![regexp {^(static|typedef)} $line]} { - regsub {^SQLITE_API } $line {} line - if {[regexp $declpattern $line all funcname]} { + # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before + # functions if this header file does not need it. + if {![info exists varonly_hdr($tail)] + && [regexp $declpattern $line all rettype funcname rest]} { + regsub {^SQLITE_API } $line {} line # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions. # so that linkage can be modified at compile-time. if {[regexp {^sqlite3_} $funcname]} { - puts $out "SQLITE_API $line" + set line SQLITE_API + append line " " [string trim $rettype] + if {[string index $rettype end] ne "*"} { + append line " " + } + if {[lsearch -exact $cdecllist $funcname] >= 0} { + append line SQLITE_CDECL + } else { + append line SQLITE_STDCALL + } + append line " " $funcname $rest + puts $out $line } else { puts $out "SQLITE_PRIVATE $line" } } elseif {[regexp $varpattern $line all varname]} { - # Add the SQLITE_PRIVATE before variable declarations or - # definitions for internal use - if {![regexp {^sqlite3_} $varname]} { - regsub {^extern } $line {} line - puts $out "SQLITE_PRIVATE $line" - } else { - if {[regexp {const char sqlite3_version\[\];} $line]} { - set line {const char sqlite3_version[] = SQLITE_VERSION;} + # Add the SQLITE_PRIVATE before variable declarations or + # definitions for internal use + regsub {^SQLITE_API } $line {} line + if {![regexp {^sqlite3_} $varname]} { + regsub {^extern } $line {} line + puts $out "SQLITE_PRIVATE $line" + } else { + if {[regexp {const char sqlite3_version\[\];} $line]} { + set line {const char sqlite3_version[] = SQLITE_VERSION;} + } + regsub {^SQLITE_EXTERN } $line {} line + puts $out "SQLITE_API $line" } - regsub {^SQLITE_EXTERN } $line {} line - puts $out "SQLITE_API $line" - } } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} { + regsub {^SQLITE_API } $line {} line regsub {^SQLITE_EXTERN } $line {} line puts $out $line } elseif {[regexp {^void \(\*sqlite3Os} $line]} { + regsub {^SQLITE_API } $line {} line puts $out "SQLITE_PRIVATE $line" } else { puts $out $line @@ -333,6 +368,7 @@ foreach file { rtree.c icu.c fts3_icu.c + dbstat.c } { copy_file tsrc/$file } diff --git a/tool/mksqlite3h.tcl b/tool/mksqlite3h.tcl index a89b9f9..cabce1f 100644 --- a/tool/mksqlite3h.tcl +++ b/tool/mksqlite3h.tcl @@ -63,7 +63,7 @@ close $in # Set up patterns for recognizing API declarations. # set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+sqlite3_[_a-zA-Z0-9]+(\[|;| =)} -set declpattern {^ *[a-zA-Z][a-zA-Z_0-9 ]+ \**sqlite3_[_a-zA-Z0-9]+\(} +set declpattern {^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3_[_a-zA-Z0-9]+)(\(.*)$} # Force the output to use unix line endings, even on Windows. fconfigure stdout -translation lf @@ -73,6 +73,19 @@ set filelist [subst { $TOP/ext/rtree/sqlite3rtree.h }] +# These are the functions that accept a variable number of arguments. They +# always need to use the "cdecl" calling convention even when another calling +# convention (e.g. "stcall") is being used for the rest of the library. +set cdecllist { + sqlite3_config + sqlite3_db_config + sqlite3_log + sqlite3_mprintf + sqlite3_snprintf + sqlite3_test_control + sqlite3_vtab_config +} + # Process the source files. # foreach file $filelist { @@ -89,21 +102,23 @@ foreach file $filelist { regsub -- --VERS-- $line $zVersion line regsub -- --VERSION-NUMBER-- $line $nVersion line regsub -- --SOURCE-ID-- $line "$zDate $zUuid" line - - if {[regexp {define SQLITE_EXTERN extern} $line]} { - puts $line - puts [gets $in] - puts "" - puts "#ifndef SQLITE_API" - puts "# define SQLITE_API" - puts "#endif" - set line "" - } - - if {([regexp $varpattern $line] && ![regexp {^ *typedef} $line]) - || ([regexp $declpattern $line]) - } { + + if {[regexp $varpattern $line] && ![regexp {^ *typedef} $line]} { set line "SQLITE_API $line" + } else { + if {[regexp $declpattern $line all rettype funcname rest]} { + set line SQLITE_API + append line " " [string trim $rettype] + if {[string index $rettype end] ne "*"} { + append line " " + } + if {[lsearch -exact $cdecllist $funcname] >= 0} { + append line SQLITE_CDECL + } else { + append line SQLITE_STDCALL + } + append line " " $funcname $rest + } } puts $line } diff --git a/tool/mkvsix.tcl b/tool/mkvsix.tcl index 208ce2b..15ae2b0 100644 --- a/tool/mkvsix.tcl +++ b/tool/mkvsix.tcl @@ -174,6 +174,9 @@ proc writeFile { fileName data } { return "" } +# +# TODO: Modify this procedure when a new version of Visual Studio is released. +# proc getMinVsVersionXmlChunk { vsVersion } { switch -exact $vsVersion { 2012 { @@ -184,17 +187,26 @@ proc getMinVsVersionXmlChunk { vsVersion } { return [appendArgs \ "\r\n " {MinVSVersion="12.0"}] } + 2015 { + return [appendArgs \ + "\r\n " {MinVSVersion="14.0"}] + } default { return "" } } } +# +# TODO: Modify this procedure when a new version of Visual Studio is released. +# proc getMaxPlatformVersionXmlChunk { packageFlavor vsVersion } { # - # NOTE: Only Visual Studio 2013 supports this SDK manifest attribute. + # NOTE: Only Visual Studio 2013 and later support this attribute within the + # SDK manifest. # - if {![string equal $vsVersion 2013]} then { + if {![string equal $vsVersion 2013] && \ + ![string equal $vsVersion 2015]} then { return "" } @@ -221,6 +233,9 @@ proc getMaxPlatformVersionXmlChunk { packageFlavor vsVersion } { } } +# +# TODO: Modify this procedure when a new version of Visual Studio is released. +# proc getExtraFileListXmlChunk { packageFlavor vsVersion } { # # NOTE: Windows Phone 8.0 does not require any extra attributes in its VSIX @@ -245,6 +260,14 @@ proc getExtraFileListXmlChunk { packageFlavor vsVersion } { "\r\n " AppliesTo=\" $appliesTo \" \ "\r\n " {DependsOn="Microsoft.VCLibs, version=12.0"}] } + 2015 { + # + # TODO: Is the ".AppLocal" suffix always needed here? + # + return [appendArgs \ + "\r\n " AppliesTo=\" $appliesTo \" \ + "\r\n " {DependsOn="Microsoft.VCLibs.AppLocal, version=14.0"}] + } default { return "" } @@ -354,10 +377,11 @@ if {[string length $vsVersion] == 0} then { fail "invalid Visual Studio version" } -if {![string equal $vsVersion 2012] && ![string equal $vsVersion 2013]} then { +if {![string equal $vsVersion 2012] && ![string equal $vsVersion 2013] && \ + ![string equal $vsVersion 2015]} then { fail [appendArgs \ "unsupported Visual Studio version, must be one of: " \ - [list 2012 2013]] + [list 2012 2013 2015]] } set shortNames(WinRT,2012) SQLite.WinRT @@ -368,6 +392,7 @@ set shortNames(WP80,2013) SQLite.WP80.2013 set shortNames(WP81,2013) SQLite.WP81 set shortNames(Win32,2012) SQLite.Win32 set shortNames(Win32,2013) SQLite.Win32.2013 +set shortNames(UAP,2015) SQLite.UAP.2015 set displayNames(WinRT,2012) "SQLite for Windows Runtime" set displayNames(WinRT,2013) "SQLite for Windows Runtime" @@ -377,6 +402,7 @@ set displayNames(WP80,2013) "SQLite for Windows Phone" set displayNames(WP81,2013) "SQLite for Windows Phone 8.1" set displayNames(Win32,2012) "SQLite for Windows" set displayNames(Win32,2013) "SQLite for Windows" +set displayNames(UAP,2015) "SQLite for Universal App Platform" if {[string equal $packageFlavor WinRT]} then { set shortName $shortNames($packageFlavor,$vsVersion) @@ -432,6 +458,22 @@ if {[string equal $packageFlavor WinRT]} then { set extraSdkPath "\\..\\$targetPlatformIdentifier" set extraFileListAttributes \ [getExtraFileListXmlChunk $packageFlavor $vsVersion] +} elseif {[string equal $packageFlavor UAP]} then { + if {$vsVersion ne "2015"} then { + fail [appendArgs \ + "unsupported combination, package flavor " $packageFlavor \ + " is only supported with Visual Studio 2015"] + } + set shortName $shortNames($packageFlavor,$vsVersion) + set displayName $displayNames($packageFlavor,$vsVersion) + set targetPlatformIdentifier UAP + set targetPlatformVersion v0.8.0.0 + set minVsVersion [getMinVsVersionXmlChunk $vsVersion] + set maxPlatformVersion \ + [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] + set extraSdkPath "\\..\\$targetPlatformIdentifier" + set extraFileListAttributes \ + [getExtraFileListXmlChunk $packageFlavor $vsVersion] } elseif {[string equal $packageFlavor Win32]} then { set shortName $shortNames($packageFlavor,$vsVersion) set displayName $displayNames($packageFlavor,$vsVersion) @@ -446,7 +488,7 @@ if {[string equal $packageFlavor WinRT]} then { } else { fail [appendArgs \ "unsupported package flavor, must be one of: " \ - [list WinRT WinRT81 WP80 WP81 Win32]] + [list WinRT WinRT81 WP80 WP81 UAP Win32]] } ############################################################################### diff --git a/tool/showdb.c b/tool/showdb.c index 82b8c9f..c90f410 100644 --- a/tool/showdb.c +++ b/tool/showdb.c @@ -64,11 +64,13 @@ static void out_of_memory(void){ */ static unsigned char *getContent(int ofst, int nByte){ unsigned char *aData; + int got; aData = malloc(nByte+32); if( aData==0 ) out_of_memory(); memset(aData, 0, nByte+32); lseek(db, ofst, SEEK_SET); - if( read(db, aData, nByte)0 && got +#include +#include +#include +#include + +/* This utility only looks for locks in the first 2 billion bytes */ +#define MX_LCK 2147483647 + +/* +** Print all locks on the inode of "fd" that occur in between +** lwr and upr, inclusive. +*/ +static int showLocksInRange(int fd, off_t lwr, off_t upr){ + int cnt = 0; + struct flock x; + + x.l_type = F_WRLCK; + x.l_whence = SEEK_SET; + x.l_start = lwr; + x.l_len = upr-lwr; + fcntl(fd, F_GETLK, &x); + if( x.l_type==F_UNLCK ) return 0; + printf("start: %-12d len: %-5d pid: %-5d type: %s\n", + (int)x.l_start, (int)x.l_len, + x.l_pid, x.l_type==F_WRLCK ? "WRLCK" : "RDLCK"); + cnt++; + if( x.l_start>lwr ){ + cnt += showLocksInRange(fd, lwr, x.l_start-1); + } + if( x.l_start+x.l_len0 } foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] { set is_index [expr {$name!=$tblname}] + set idx_btree [expr {$is_index || [is_without_rowid $name]}] db eval { SELECT sum(ncell) AS nentry, - sum(isleaf(pagetype, $is_index) * ncell) AS leaf_entries, + sum(isleaf(pagetype, $idx_btree) * ncell) AS leaf_entries, sum(payload) AS payload, - sum(isoverflow(pagetype, $is_index) * payload) AS ovfl_payload, + sum(isoverflow(pagetype, $idx_btree) * payload) AS ovfl_payload, sum(path LIKE '%+000000') AS ovfl_cnt, max(mx_payload) AS mx_payload, - sum(isinternal(pagetype, $is_index)) AS int_pages, - sum(isleaf(pagetype, $is_index)) AS leaf_pages, - sum(isoverflow(pagetype, $is_index)) AS ovfl_pages, - sum(isinternal(pagetype, $is_index) * unused) AS int_unused, - sum(isleaf(pagetype, $is_index) * unused) AS leaf_unused, - sum(isoverflow(pagetype, $is_index) * unused) AS ovfl_unused, + sum(isinternal(pagetype, $idx_btree)) AS int_pages, + sum(isleaf(pagetype, $idx_btree)) AS leaf_pages, + sum(isoverflow(pagetype, $idx_btree)) AS ovfl_pages, + sum(isinternal(pagetype, $idx_btree) * unused) AS int_unused, + sum(isleaf(pagetype, $idx_btree) * unused) AS leaf_unused, + sum(isoverflow(pagetype, $idx_btree) * unused) AS ovfl_unused, sum(pgsize) AS compressed_size FROM temp.dbstat WHERE name = $name } break diff --git a/tool/sqldiff.c b/tool/sqldiff.c new file mode 100644 index 0000000..0b3f02c --- /dev/null +++ b/tool/sqldiff.c @@ -0,0 +1,1242 @@ +/* +** 2015-04-06 +** +** 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 is a utility program that computes the differences in content +** between two SQLite databases. +** +** To compile, simply link against SQLite. +** +** See the showHelp() routine below for a brief description of how to +** run the utility. +*/ +#include +#include +#include +#include +#include +#include "sqlite3.h" + +/* +** All global variables are gathered into the "g" singleton. +*/ +struct GlobalVars { + const char *zArgv0; /* Name of program */ + int bSchemaOnly; /* Only show schema differences */ + int bSchemaPK; /* Use the schema-defined PK, not the true PK */ + unsigned fDebug; /* Debug flags */ + sqlite3 *db; /* The database connection */ +} g; + +/* +** Allowed values for g.fDebug +*/ +#define DEBUG_COLUMN_NAMES 0x000001 +#define DEBUG_DIFF_SQL 0x000002 + +/* +** Dynamic string object +*/ +typedef struct Str Str; +struct Str { + char *z; /* Text of the string */ + int nAlloc; /* Bytes allocated in z[] */ + int nUsed; /* Bytes actually used in z[] */ +}; + +/* +** Initialize a Str object +*/ +static void strInit(Str *p){ + p->z = 0; + p->nAlloc = 0; + p->nUsed = 0; +} + +/* +** Print an error resulting from faulting command-line arguments and +** abort the program. +*/ +static void cmdlineError(const char *zFormat, ...){ + va_list ap; + fprintf(stderr, "%s: ", g.zArgv0); + va_start(ap, zFormat); + vfprintf(stderr, zFormat, ap); + va_end(ap); + fprintf(stderr, "\n\"%s --help\" for more help\n", g.zArgv0); + exit(1); +} + +/* +** Print an error message for an error that occurs at runtime, then +** abort the program. +*/ +static void runtimeError(const char *zFormat, ...){ + va_list ap; + fprintf(stderr, "%s: ", g.zArgv0); + va_start(ap, zFormat); + vfprintf(stderr, zFormat, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(1); +} + +/* +** Free all memory held by a Str object +*/ +static void strFree(Str *p){ + sqlite3_free(p->z); + strInit(p); +} + +/* +** Add formatted text to the end of a Str object +*/ +static void strPrintf(Str *p, const char *zFormat, ...){ + int nNew; + for(;;){ + if( p->z ){ + va_list ap; + va_start(ap, zFormat); + sqlite3_vsnprintf(p->nAlloc-p->nUsed, p->z+p->nUsed, zFormat, ap); + va_end(ap); + nNew = (int)strlen(p->z + p->nUsed); + }else{ + nNew = p->nAlloc; + } + if( p->nUsed+nNew < p->nAlloc-1 ){ + p->nUsed += nNew; + break; + } + p->nAlloc = p->nAlloc*2 + 1000; + p->z = sqlite3_realloc(p->z, p->nAlloc); + if( p->z==0 ) runtimeError("out of memory"); + } +} + + + +/* Safely quote an SQL identifier. Use the minimum amount of transformation +** necessary to allow the string to be used with %s. +** +** Space to hold the returned string is obtained from sqlite3_malloc(). The +** caller is responsible for ensuring this space is freed when no longer +** needed. +*/ +static char *safeId(const char *zId){ + /* All SQLite keywords, in alphabetical order */ + static const char *azKeywords[] = { + "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS", + "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY", + "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT", + "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE", + "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE", + "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH", + "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN", + "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF", + "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER", + "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", + "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL", + "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA", + "PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP", + "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT", + "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP", + "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE", + "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE", + "WITH", "WITHOUT", + }; + int lwr, upr, mid, c, i, x; + for(i=x=0; (c = zId[i])!=0; i++){ + if( !isalpha(c) && c!='_' ){ + if( i>0 && isdigit(c) ){ + x++; + }else{ + return sqlite3_mprintf("\"%w\"", zId); + } + } + } + if( x ) return sqlite3_mprintf("%s", zId); + lwr = 0; + upr = sizeof(azKeywords)/sizeof(azKeywords[0]) - 1; + while( lwr<=upr ){ + mid = (lwr+upr)/2; + c = sqlite3_stricmp(azKeywords[mid], zId); + if( c==0 ) return sqlite3_mprintf("\"%w\"", zId); + if( c<0 ){ + lwr = mid+1; + }else{ + upr = mid-1; + } + } + return sqlite3_mprintf("%s", zId); +} + +/* +** Prepare a new SQL statement. Print an error and abort if anything +** goes wrong. +*/ +static sqlite3_stmt *db_vprepare(const char *zFormat, va_list ap){ + char *zSql; + int rc; + sqlite3_stmt *pStmt; + + zSql = sqlite3_vmprintf(zFormat, ap); + if( zSql==0 ) runtimeError("out of memory"); + rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0); + if( rc ){ + runtimeError("SQL statement error: %s\n\"%s\"", sqlite3_errmsg(g.db), + zSql); + } + sqlite3_free(zSql); + return pStmt; +} +static sqlite3_stmt *db_prepare(const char *zFormat, ...){ + va_list ap; + sqlite3_stmt *pStmt; + va_start(ap, zFormat); + pStmt = db_vprepare(zFormat, ap); + va_end(ap); + return pStmt; +} + +/* +** Free a list of strings +*/ +static void namelistFree(char **az){ + if( az ){ + int i; + for(i=0; az[i]; i++) sqlite3_free(az[i]); + sqlite3_free(az); + } +} + +/* +** Return a list of column names for the table zDb.zTab. Space to +** hold the list is obtained from sqlite3_malloc() and should released +** using namelistFree() when no longer needed. +** +** Primary key columns are listed first, followed by data columns. +** The number of columns in the primary key is returned in *pnPkey. +** +** Normally, the "primary key" in the previous sentence is the true +** primary key - the rowid or INTEGER PRIMARY KEY for ordinary tables +** or the declared PRIMARY KEY for WITHOUT ROWID tables. However, if +** the g.bSchemaPK flag is set, then the schema-defined PRIMARY KEY is +** used in all cases. In that case, entries that have NULL values in +** any of their primary key fields will be excluded from the analysis. +** +** If the primary key for a table is the rowid but rowid is inaccessible, +** then this routine returns a NULL pointer. +** +** Examples: +** CREATE TABLE t1(a INT UNIQUE, b INTEGER, c TEXT, PRIMARY KEY(c)); +** *pnPKey = 1; +** az = { "rowid", "a", "b", "c", 0 } // Normal case +** az = { "c", "a", "b", 0 } // g.bSchemaPK==1 +** +** CREATE TABLE t2(a INT UNIQUE, b INTEGER, c TEXT, PRIMARY KEY(b)); +** *pnPKey = 1; +** az = { "b", "a", "c", 0 } +** +** CREATE TABLE t3(x,y,z,PRIMARY KEY(y,z)); +** *pnPKey = 1 // Normal case +** az = { "rowid", "x", "y", "z", 0 } // Normal case +** *pnPKey = 2 // g.bSchemaPK==1 +** az = { "y", "x", "z", 0 } // g.bSchemaPK==1 +** +** CREATE TABLE t4(x,y,z,PRIMARY KEY(y,z)) WITHOUT ROWID; +** *pnPKey = 2 +** az = { "y", "z", "x", 0 } +** +** CREATE TABLE t5(rowid,_rowid_,oid); +** az = 0 // The rowid is not accessible +*/ +static char **columnNames(const char *zDb, const char *zTab, int *pnPKey){ + char **az = 0; /* List of column names to be returned */ + int naz = 0; /* Number of entries in az[] */ + sqlite3_stmt *pStmt; /* SQL statement being run */ + char *zPkIdxName = 0; /* Name of the PRIMARY KEY index */ + int truePk = 0; /* PRAGMA table_info indentifies the PK to use */ + int nPK = 0; /* Number of PRIMARY KEY columns */ + int i, j; /* Loop counters */ + + if( g.bSchemaPK==0 ){ + /* Normal case: Figure out what the true primary key is for the table. + ** * For WITHOUT ROWID tables, the true primary key is the same as + ** the schema PRIMARY KEY, which is guaranteed to be present. + ** * For rowid tables with an INTEGER PRIMARY KEY, the true primary + ** key is the INTEGER PRIMARY KEY. + ** * For all other rowid tables, the rowid is the true primary key. + */ + pStmt = db_prepare("PRAGMA %s.index_list=%Q", zDb, zTab); + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + if( sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,3),"pk")==0 ){ + zPkIdxName = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); + break; + } + } + sqlite3_finalize(pStmt); + if( zPkIdxName ){ + int nKey = 0; + int nCol = 0; + truePk = 0; + pStmt = db_prepare("PRAGMA %s.index_xinfo=%Q", zDb, zPkIdxName); + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + nCol++; + if( sqlite3_column_int(pStmt,5) ){ nKey++; continue; } + if( sqlite3_column_int(pStmt,1)>=0 ) truePk = 1; + } + if( nCol==nKey ) truePk = 1; + if( truePk ){ + nPK = nKey; + }else{ + nPK = 1; + } + sqlite3_finalize(pStmt); + sqlite3_free(zPkIdxName); + }else{ + truePk = 1; + nPK = 1; + } + pStmt = db_prepare("PRAGMA %s.table_info=%Q", zDb, zTab); + }else{ + /* The g.bSchemaPK==1 case: Use whatever primary key is declared + ** in the schema. The "rowid" will still be used as the primary key + ** if the table definition does not contain a PRIMARY KEY. + */ + nPK = 0; + pStmt = db_prepare("PRAGMA %s.table_info=%Q", zDb, zTab); + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + if( sqlite3_column_int(pStmt,5)>0 ) nPK++; + } + sqlite3_reset(pStmt); + if( nPK==0 ) nPK = 1; + truePk = 1; + } + *pnPKey = nPK; + naz = nPK; + az = sqlite3_malloc( sizeof(char*)*(nPK+1) ); + if( az==0 ) runtimeError("out of memory"); + memset(az, 0, sizeof(char*)*(nPK+1)); + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + int iPKey; + if( truePk && (iPKey = sqlite3_column_int(pStmt,5))>0 ){ + az[iPKey-1] = safeId((char*)sqlite3_column_text(pStmt,1)); + }else{ + az = sqlite3_realloc(az, sizeof(char*)*(naz+2) ); + if( az==0 ) runtimeError("out of memory"); + az[naz++] = safeId((char*)sqlite3_column_text(pStmt,1)); + } + } + sqlite3_finalize(pStmt); + if( az ) az[naz] = 0; + if( az[0]==0 ){ + const char *azRowid[] = { "rowid", "_rowid_", "oid" }; + for(i=0; i=naz ){ + az[0] = sqlite3_mprintf("%s", azRowid[i]); + break; + } + } + if( az[0]==0 ){ + for(i=1; inPk2 ){ + zSep = "SELECT "; + for(i=0; i>= 8; + for(i=7; i>=0; i--){ + p[i] = (unsigned char)((v & 0x7f) | 0x80); + v >>= 7; + } + fwrite(p, 8, 1, out); + }else{ + n = 9; + do{ + p[n--] = (unsigned char)((v & 0x7f) | 0x80); + v >>= 7; + }while( v!=0 ); + p[9] &= 0x7f; + fwrite(p+n+1, 9-n, 1, out); + } +} + +/* +** Write an SQLite value onto out. +*/ +static void putValue(FILE *out, sqlite3_value *pVal){ + int iDType = sqlite3_value_type(pVal); + sqlite3_int64 iX; + double rX; + sqlite3_uint64 uX; + int j; + + putc(iDType, out); + switch( iDType ){ + case SQLITE_INTEGER: + iX = sqlite3_value_int64(pVal); + memcpy(&uX, &iX, 8); + for(j=56; j>=0; j-=8) putc((uX>>j)&0xff, out); + break; + case SQLITE_FLOAT: + rX = sqlite3_value_double(pVal); + memcpy(&uX, &rX, 8); + for(j=56; j>=0; j-=8) putc((uX>>j)&0xff, out); + break; + case SQLITE_TEXT: + iX = sqlite3_value_bytes(pVal); + putsVarint(out, (sqlite3_uint64)iX); + fwrite(sqlite3_value_text(pVal),1,(size_t)iX,out); + break; + case SQLITE_BLOB: + iX = sqlite3_value_bytes(pVal); + putsVarint(out, (sqlite3_uint64)iX); + fwrite(sqlite3_value_blob(pVal),1,(size_t)iX,out); + break; + case SQLITE_NULL: + break; + } +} + +/* +** Generate a CHANGESET for all differences from main.zTab to aux.zTab. +*/ +static void changeset_one_table(const char *zTab, FILE *out){ + sqlite3_stmt *pStmt; /* SQL statment */ + char *zId = safeId(zTab); /* Escaped name of the table */ + char **azCol = 0; /* List of escaped column names */ + int nCol = 0; /* Number of columns */ + int *aiFlg = 0; /* 0 if column is not part of PK */ + int *aiPk = 0; /* Column numbers for each PK column */ + int nPk = 0; /* Number of PRIMARY KEY columns */ + Str sql; /* SQL for the diff query */ + int i, k; /* Loop counters */ + const char *zSep; /* List separator */ + + pStmt = db_prepare( + "SELECT A.sql=B.sql FROM main.sqlite_master A, aux.sqlite_master B" + " WHERE A.name=%Q AND B.name=%Q", zTab, zTab + ); + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + if( sqlite3_column_int(pStmt,0)==0 ){ + runtimeError("schema changes for table %s", safeId(zTab)); + } + }else{ + runtimeError("table %s missing from one or both databases", safeId(zTab)); + } + sqlite3_finalize(pStmt); + pStmt = db_prepare("PRAGMA main.table_info=%Q", zTab); + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + nCol++; + azCol = sqlite3_realloc(azCol, sizeof(char*)*nCol); + if( azCol==0 ) runtimeError("out of memory"); + aiFlg = sqlite3_realloc(aiFlg, sizeof(int)*nCol); + if( aiFlg==0 ) runtimeError("out of memory"); + azCol[nCol-1] = safeId((const char*)sqlite3_column_text(pStmt,1)); + aiFlg[nCol-1] = i = sqlite3_column_int(pStmt,5); + if( i>0 ){ + if( i>nPk ){ + nPk = i; + aiPk = sqlite3_realloc(aiPk, sizeof(int)*nPk); + if( aiPk==0 ) runtimeError("out of memory"); + } + aiPk[i-1] = nCol-1; + } + } + sqlite3_finalize(pStmt); + if( nPk==0 ) goto end_changeset_one_table; + strInit(&sql); + if( nCol>nPk ){ + strPrintf(&sql, "SELECT %d", SQLITE_UPDATE); + for(i=0; i0 ) sqlite3_free(azCol[--nCol]); + sqlite3_free(azCol); + sqlite3_free(aiPk); + sqlite3_free(zId); +} + +/* +** Print sketchy documentation for this utility program +*/ +static void showHelp(void){ + printf("Usage: %s [options] DB1 DB2\n", g.zArgv0); + printf( +"Output SQL text that would transform DB1 into DB2.\n" +"Options:\n" +" --changeset FILE Write a CHANGESET into FILE\n" +" -L|--lib LIBRARY Load an SQLite extension library\n" +" --primarykey Use schema-defined PRIMARY KEYs\n" +" --schema Show only differences in the schema\n" +" --summary Show only a summary of the differences\n" +" --table TAB Show only differences in table TAB\n" + ); +} + +int main(int argc, char **argv){ + const char *zDb1 = 0; + const char *zDb2 = 0; + int i; + int rc; + char *zErrMsg = 0; + char *zSql; + sqlite3_stmt *pStmt; + char *zTab = 0; + FILE *out = stdout; + void (*xDiff)(const char*,FILE*) = diff_one_table; + int nExt = 0; + char **azExt = 0; + + g.zArgv0 = argv[0]; + for(i=1; i Date: Mon, 13 Jul 2015 09:53:10 -0500 Subject: [PATCH 38/59] Bump cipher version to 3.3.1 --- src/crypto.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypto.h b/src/crypto.h index a614ede..b048b49 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -45,9 +45,9 @@ #ifndef CIPHER_VERSION #ifdef SQLCIPHER_FIPS -#define CIPHER_VERSION "3.3.0 FIPS" +#define CIPHER_VERSION "3.3.1 FIPS" #else -#define CIPHER_VERSION "3.3.0" +#define CIPHER_VERSION "3.3.1" #endif #endif From 951d2ed667a8ec4a06766f65a183b4949b3b8d11 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 13 Jul 2015 10:23:35 -0500 Subject: [PATCH 39/59] Add release notes for 3.3.1 --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c67f1fc..a53cc76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. ## [Unreleased][unreleased] +## [3.3.1] - 2015-07-13 +### Changed +- Merge upstream SQLite 3.8.10.2 +- Fixed segfault when provided an invalid cipher name +- Check for codec context when performing `PRAGMA cipher_store_pass` +- Remove extraneous null check in `PRAGMA cipher_migrate` + ## [3.3.0] - 2015-03-25 ### Added - Added FIPS API calls within the OpenSSL crypto provider @@ -49,7 +56,8 @@ All notable changes to this project will be documented in this file. ### Security - Change KDF iteration length from 4,000 to 64,000 -[unreleased]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.0...prerelease +[unreleased]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.1...prerelease +[3.3.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.0...v3.3.1 [3.3.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.2.0...v3.3.0 [3.2.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.1.0...v3.2.0 [3.1.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.1...v3.1.0 From 6737dca1bc7ff766a61838a670b4cf8da9dd8652 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 13 Jul 2015 10:35:55 -0500 Subject: [PATCH 40/59] Fix link for 3.3.1 release --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a53cc76..2f35868 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,7 +57,7 @@ All notable changes to this project will be documented in this file. - Change KDF iteration length from 4,000 to 64,000 [unreleased]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.1...prerelease -[3.3.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.0...v3.3.1 +[3.3.1]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.0...v3.3.1 [3.3.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.2.0...v3.3.0 [3.2.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.1.0...v3.2.0 [3.1.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.1...v3.1.0 From b69e1d36beb85d1f32014ec324518f87c664750d Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 13 Jul 2015 11:54:42 -0500 Subject: [PATCH 41/59] Rebuild configure to work properly with libtool --- configure | 4098 ++++++++++++++++++----------------------------------- 1 file changed, 1400 insertions(+), 2698 deletions(-) diff --git a/configure b/configure index 4ae63c9..82a361c 100755 --- a/configure +++ b/configure @@ -196,14 +196,6 @@ test -x / || exit 1" as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 - - test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( - ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - PATH=/empty FPATH=/empty; export PATH FPATH - test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ - || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes @@ -561,8 +553,155 @@ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +$* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + test -n "$DJDIR" || exec 7<&0 &1 @@ -665,23 +804,20 @@ VERSION program_prefix TCLLIBDIR TCLSH_CMD +AWK INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM CPP -LT_SYS_LIBRARY_PATH OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL -MANIFEST_TOOL -AWK +lt_ECHO RANLIB STRIP -ac_ct_AR AR -DLLTOOL OBJDUMP LN_S NM @@ -753,9 +889,7 @@ enable_shared enable_static with_pic enable_fast_install -with_aix_soname with_gnu_ld -with_sysroot enable_libtool_lock enable_largefile enable_threadsafe @@ -781,7 +915,6 @@ CFLAGS LDFLAGS LIBS CPPFLAGS -LT_SYS_LIBRARY_PATH CPP TCLLIBDIR' @@ -1421,14 +1554,9 @@ Optional Features: Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + --with-pic try to use only PIC/non-PIC objects [default=use both] - --with-aix-soname=aix|svr4|both - shared library versioning (aka "SONAME") variant to - provide on AIX, [default=aix]. --with-gnu-ld assume the C compiler uses GNU ld [default=no] - --with-sysroot[=DIR] Search for dependent libraries within DIR (or the - compiler's sysroot if not specified). --with-crypto-lib Specify which crypto library to use --with-tcl=DIR directory containing tcl configuration (tclConfig.sh) @@ -1443,8 +1571,6 @@ Some influential environment variables: LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory - LT_SYS_LIBRARY_PATH - User-defined run-time library search path. CPP C preprocessor TCLLIBDIR Where to install tcl plugin @@ -2293,6 +2419,31 @@ fi ######### # Programs needed # +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.2.6' +macro_revision='1.3012' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then @@ -2322,31 +2473,6 @@ ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. -case `pwd` in - *\ * | *\ *) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 -$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; -esac - - - -macro_version='2.4.6' -macro_revision='2.4.6' - - - - - - - - - - - - - -ltmain=$ac_aux_dir/ltmain.sh - # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 @@ -2418,75 +2544,6 @@ IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac -# Backslashify metacharacters that are still active within -# double-quoted strings. -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 -$as_echo_n "checking how to print strings... " >&6; } -# Test print first, because it will be a builtin if present. -if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ - test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='print -r --' -elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='printf %s\n' -else - # Use this function as a fallback that always works. - func_fallback_echo () - { - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' - } - ECHO='func_fallback_echo' -fi - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "" -} - -case $ECHO in - printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 -$as_echo "printf" >&6; } ;; - print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 -$as_echo "print -r" >&6; } ;; - *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 -$as_echo "cat" >&6; } ;; -esac - - - - - - - - - - - - - - ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3577,19 +3634,19 @@ test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : - withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld -if test yes = "$GCC"; then +if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) - # gcc leaves a trailing carriage return, which upsets mingw + # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; @@ -3603,7 +3660,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; } while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done - test -z "$LD" && LD=$ac_prog + test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. @@ -3614,7 +3671,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; } with_gnu_ld=unknown ;; esac -elif test yes = "$with_gnu_ld"; then +elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else @@ -3625,32 +3682,32 @@ if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do - IFS=$lt_save_ifs + IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD=$ac_dir/$ac_prog + lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } @@ -3693,38 +3750,33 @@ if ${lt_cv_path_NM+:} false; then : else if test -n "$NM"; then # Let the user override the test. - lt_cv_path_NM=$NM + lt_cv_path_NM="$NM" else - lt_nm_to_check=${ac_tool_prefix}nm + lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS=$lt_save_ifs + IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. - tmp_nm=$ac_dir/$lt_tmp_nm - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. - # Adding the 'sed 1q' prevents false positives on HP-UX, which says: + # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file - # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty - case $build_os in - mingw*) lt_bad_file=conftest.nm/nofile ;; - *) lt_bad_file=/dev/null ;; - esac - case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in - *$lt_bad_file* | *'Invalid file or object type'*) + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" - break 2 + break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" - break 2 + break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but @@ -3735,22 +3787,19 @@ else esac fi done - IFS=$lt_save_ifs + IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } -if test no != "$lt_cv_path_NM"; then - NM=$lt_cv_path_NM +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - if test -n "$ac_tool_prefix"; then - for ac_prog in dumpbin "link -dump" + if test -n "$ac_tool_prefix"; then + for ac_prog in "dumpbin -symbols" "link -dump -symbols" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 @@ -3794,7 +3843,7 @@ fi fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN - for ac_prog in dumpbin "link -dump" + for ac_prog in "dumpbin -symbols" "link -dump -symbols" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 @@ -3849,18 +3898,9 @@ esac fi fi - case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols -headers" - ;; - *) - DUMPBIN=: - ;; - esac - fi - if test : != "$DUMPBIN"; then - NM=$DUMPBIN + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm @@ -3877,13 +3917,13 @@ if ${lt_cv_nm_interface+:} false; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval echo "\"\$as_me:3920: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:3923: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: output\"" >&5) + (eval echo "\"\$as_me:3926: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -3911,7 +3951,7 @@ if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 - teststring=ABCD + teststring="ABCD" case $build_os in msdosdjgpp*) @@ -3940,18 +3980,13 @@ else lt_cv_sys_max_cmd_len=8192; ;; - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; - bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` @@ -3970,11 +4005,6 @@ else lt_cv_sys_max_cmd_len=196608 ;; - os2*) - # The test takes a long time on OS/2. - lt_cv_sys_max_cmd_len=8192 - ;; - osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not @@ -4001,23 +4031,22 @@ else ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then + if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8; do + for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. - while { test X`env echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test 17 != "$i" # 1/2 MB should be enough + while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring @@ -4035,7 +4064,7 @@ else fi -if test -n "$lt_cv_sys_max_cmd_len"; then +if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else @@ -4053,6 +4082,30 @@ max_cmd_len=$lt_cv_sys_max_cmd_len : ${MV="mv -f"} : ${RM="rm -f"} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else @@ -4084,80 +4137,6 @@ esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 -$as_echo_n "checking how to convert $build file names to $host format... " >&6; } -if ${lt_cv_to_host_file_cmd+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $host in - *-*-mingw* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 - ;; - esac - ;; - *-*-cygwin* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin - ;; - esac - ;; - * ) # unhandled hosts (and "normal" native builds) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; -esac - -fi - -to_host_file_cmd=$lt_cv_to_host_file_cmd -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 -$as_echo "$lt_cv_to_host_file_cmd" >&6; } - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 -$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } -if ${lt_cv_to_tool_file_cmd+:} false; then : - $as_echo_n "(cached) " >&6 -else - #assume ordinary cross tools, or native build. -lt_cv_to_tool_file_cmd=func_convert_file_noop -case $host in - *-*-mingw* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 - ;; - esac - ;; -esac - -fi - -to_tool_file_cmd=$lt_cv_to_tool_file_cmd -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 -$as_echo "$lt_cv_to_tool_file_cmd" >&6; } - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : @@ -4174,14 +4153,9 @@ case $reload_flag in esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in - cygwin* | mingw* | pw32* | cegcc*) - if test yes != "$GCC"; then - reload_cmds=false - fi - ;; darwin*) - if test yes = "$GCC"; then - reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi @@ -4309,13 +4283,13 @@ lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. -# 'unknown' -- same as none, but documents that we really don't know. +# `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path -# that responds to the $file_magic_cmd with a given extended regex. -# If you have 'file' or equivalent on your system and you're not sure -# whether 'pass_all' will *always* work, you probably want this one. +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) @@ -4346,13 +4320,12 @@ mingw* | pw32*) lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else - # Keep this pattern in sync with the one in func_win32_libid. - lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; -cegcc*) +cegcc) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' @@ -4378,7 +4351,7 @@ freebsd* | dragonfly*) fi ;; -haiku*) +gnu*) lt_cv_deplibs_check_method=pass_all ;; @@ -4390,11 +4363,11 @@ hpux10.20* | hpux11*) lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac @@ -4415,8 +4388,8 @@ irix5* | irix6* | nonstopux*) lt_cv_deplibs_check_method=pass_all ;; -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) +# This must be Linux ELF. +linux* | k*bsd*-gnu) lt_cv_deplibs_check_method=pass_all ;; @@ -4438,8 +4411,8 @@ newos6*) lt_cv_deplibs_check_method=pass_all ;; -openbsd* | bitrig*) - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' @@ -4492,29 +4465,11 @@ sysv4 | sysv4.3*) tpf*) lt_cv_deplibs_check_method=pass_all ;; -os2*) - lt_cv_deplibs_check_method=pass_all - ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } - -file_magic_glob= -want_nocaseglob=no -if test "$build" = "$host"; then - case $host_os in - mingw* | pw32*) - if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then - want_nocaseglob=yes - else - file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` - fi - ;; - esac -fi - file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown @@ -4528,165 +4483,11 @@ test -z "$deplibs_check_method" && deplibs_check_method=unknown - - - - - - - - - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DLLTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DLLTOOL=$ac_cv_prog_DLLTOOL -if test -n "$DLLTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 -$as_echo "$DLLTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DLLTOOL"; then - ac_ct_DLLTOOL=$DLLTOOL - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_DLLTOOL"; then - ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DLLTOOL="dlltool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL -if test -n "$ac_ct_DLLTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 -$as_echo "$ac_ct_DLLTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_DLLTOOL" = x; then - DLLTOOL="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DLLTOOL=$ac_ct_DLLTOOL - fi -else - DLLTOOL="$ac_cv_prog_DLLTOOL" -fi - -test -z "$DLLTOOL" && DLLTOOL=dlltool - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 -$as_echo_n "checking how to associate runtime and link libraries... " >&6; } -if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_sharedlib_from_linklib_cmd='unknown' - -case $host_os in -cygwin* | mingw* | pw32* | cegcc*) - # two different shell functions defined in ltmain.sh; - # decide which one to use based on capabilities of $DLLTOOL - case `$DLLTOOL --help 2>&1` in - *--identify-strict*) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib - ;; - *) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback - ;; - esac - ;; -*) - # fallback: assume linklib IS sharedlib - lt_cv_sharedlib_from_linklib_cmd=$ECHO - ;; -esac - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 -$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } -sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd -test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO - - - - - - - - -if test -n "$ac_tool_prefix"; then - for ac_prog in ar - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : @@ -4702,7 +4503,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -4722,15 +4523,11 @@ $as_echo "no" >&6; } fi - test -n "$AR" && break - done fi -if test -z "$AR"; then +if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR - for ac_prog in ar -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : @@ -4746,7 +4543,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="$ac_prog" + ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -4765,10 +4562,6 @@ else $as_echo "no" >&6; } fi - - test -n "$ac_ct_AR" && break -done - if test "x$ac_ct_AR" = x; then AR="false" else @@ -4780,72 +4573,16 @@ ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi -fi - -: ${AR=ar} -: ${AR_FLAGS=cru} - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 -$as_echo_n "checking for archiver @FILE support... " >&6; } -if ${lt_cv_ar_at_file+:} false; then : - $as_echo_n "(cached) " >&6 else - lt_cv_ar_at_file=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - echo conftest.$ac_objext > conftest.lst - lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -eq "$ac_status"; then - # Ensure the archiver fails upon bogus file names. - rm -f conftest.$ac_objext libconftest.a - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test 0 -ne "$ac_status"; then - lt_cv_ar_at_file=@ - fi - fi - rm -f conftest.* libconftest.a - + AR="$ac_cv_prog_AR" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 -$as_echo "$lt_cv_ar_at_file" >&6; } +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru + + + -if test no = "$lt_cv_ar_at_file"; then - archiver_list_spec= -else - archiver_list_spec=$lt_cv_ar_at_file -fi @@ -5058,84 +4795,30 @@ old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in - bitrig* | openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac - old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" -fi - -case $host_os in - darwin*) - lock_old_archive_extraction=yes ;; - *) - lock_old_archive_extraction=no ;; -esac - - - - - - - - - - - - - - - - - - - - - -for ac_prog in gawk mawk nawk awk -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AWK+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AWK="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -$as_echo "$AWK" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi - test -n "$AWK" && break -done + + + + + + + + + + + + + @@ -5190,7 +4873,7 @@ cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) - if test ia64 = "$host_cpu"; then + if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; @@ -5223,44 +4906,14 @@ case `$NM -V 2>&1` in symcode='[ABCDGIRSTW]' ;; esac -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Gets list of data symbols to import. - lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" - # Adjust the below global symbol transforms to fixup imported variables. - lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" - lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" - lt_c_name_lib_hook="\ - -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ - -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" -else - # Disable hooks by default. - lt_cv_sys_global_symbol_to_import= - lt_cdecl_hook= - lt_c_name_hook= - lt_c_name_lib_hook= -fi - # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="sed -n"\ -$lt_cdecl_hook\ -" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ -$lt_c_name_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" - -# Transform an extracted symbol line into symbol name with lib prefix and -# symbol address. -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ -$lt_c_name_lib_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= @@ -5278,29 +4931,24 @@ for ac_symprfx in "" "_"; do # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function, - # D for any global variable and I for any imported variable. + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ -" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ -" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ -" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ -" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ -" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ -" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ -" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ -" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi - lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no @@ -5326,8 +4974,8 @@ _LT_EOF test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 - (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then @@ -5342,18 +4990,6 @@ _LT_EOF if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE -/* DATA imports from DLLs on WIN32 can't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT_DLSYM_CONST -#elif defined __osf__ -/* This system does not cope well with relocations in const data. */ -# define LT_DLSYM_CONST -#else -# define LT_DLSYM_CONST const -#endif - #ifdef __cplusplus extern "C" { #endif @@ -5365,7 +5001,7 @@ _LT_EOF cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ -LT_DLSYM_CONST struct { +const struct { const char *name; void *address; } @@ -5373,7 +5009,7 @@ lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF - $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; @@ -5391,19 +5027,19 @@ static const void *lt_preloaded_setup() { _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext - lt_globsym_save_LIBS=$LIBS - lt_globsym_save_CFLAGS=$CFLAGS - LIBS=conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest$ac_exeext; then + test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi - LIBS=$lt_globsym_save_LIBS - CFLAGS=$lt_globsym_save_CFLAGS + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&5 fi @@ -5420,7 +5056,7 @@ _LT_EOF rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. - if test yes = "$pipe_works"; then + if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= @@ -5440,12 +5076,6 @@ else $as_echo "ok" >&6; } fi -# Response file support. -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - nm_file_list_spec='@' -elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then - nm_file_list_spec='@' -fi @@ -5467,152 +5097,19 @@ fi - - - - - - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 -$as_echo_n "checking for sysroot... " >&6; } - -# Check whether --with-sysroot was given. -if test "${with_sysroot+set}" = set; then : - withval=$with_sysroot; -else - with_sysroot=no -fi - - -lt_sysroot= -case $with_sysroot in #( - yes) - if test yes = "$GCC"; then - lt_sysroot=`$CC --print-sysroot 2>/dev/null` - fi - ;; #( - /*) - lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` - ;; #( - no|'') - ;; #( - *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 -$as_echo "$with_sysroot" >&6; } - as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 - ;; -esac - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 -$as_echo "${lt_sysroot:-no}" >&6; } - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 -$as_echo_n "checking for a working dd... " >&6; } -if ${ac_cv_path_lt_DD+:} false; then : - $as_echo_n "(cached) " >&6 -else - printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -: ${lt_DD:=$DD} -if test -z "$lt_DD"; then - ac_path_lt_DD_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in dd; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_lt_DD" || continue -if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: -fi - $ac_path_lt_DD_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_lt_DD"; then - : - fi -else - ac_cv_path_lt_DD=$lt_DD -fi - -rm -f conftest.i conftest2.i conftest.out -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 -$as_echo "$ac_cv_path_lt_DD" >&6; } - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 -$as_echo_n "checking how to truncate binary pipes... " >&6; } -if ${lt_cv_truncate_bin+:} false; then : - $as_echo_n "(cached) " >&6 -else - printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -lt_cv_truncate_bin= -if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" -fi -rm -f conftest.i conftest2.i conftest.out -test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 -$as_echo "$lt_cv_truncate_bin" >&6; } - - - - - - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in $*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi -test no = "$enable_libtool_lock" || enable_libtool_lock=yes +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) - # Find out what ABI is being produced by ac_compile, and set mode - # options accordingly. + # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 @@ -5621,25 +5118,24 @@ ia64-*-hpux*) test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) - HPUX_IA64_MODE=32 + HPUX_IA64_MODE="32" ;; *ELF-64*) - HPUX_IA64_MODE=64 + HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext + # Find out which ABI we are using. + echo '#line 5132 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - if test yes = "$lt_cv_prog_gnu_ld"; then + if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" @@ -5668,50 +5164,9 @@ ia64-*-hpux*) rm -rf conftest* ;; -mips64*-*linux*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - emul=elf - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - emul="${emul}32" - ;; - *64-bit*) - emul="${emul}64" - ;; - esac - case `/usr/bin/file conftest.$ac_objext` in - *MSB*) - emul="${emul}btsmip" - ;; - *LSB*) - emul="${emul}ltsmip" - ;; - esac - case `/usr/bin/file conftest.$ac_objext` in - *N32*) - emul="${emul}n32" - ;; - esac - LD="${LD-ld} -m $emul" - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. Note that the listed cases only cover the - # situations where additional linker options are needed (such as when - # doing 32-bit compilation for a host where ld defaults to 64-bit, or - # vice versa); the common cases where no linker options are needed do - # not appear in the list. + # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 @@ -5725,19 +5180,9 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) - case `/usr/bin/file conftest.o` in - *x86-64*) - LD="${LD-ld} -m elf32_x86_64" - ;; - *) - LD="${LD-ld} -m elf_i386" - ;; - esac + LD="${LD-ld} -m elf_i386" ;; - powerpc64le-*linux*) - LD="${LD-ld} -m elf32lppclinux" - ;; - powerpc64-*linux*) + ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) @@ -5756,10 +5201,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; - powerpcle-*linux*) - LD="${LD-ld} -m elf64lppc" - ;; - powerpc-*linux*) + ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) @@ -5777,7 +5219,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS=$CFLAGS + SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } @@ -5817,14 +5259,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } - if test yes != "$lt_cv_cc_needs_belf"; then + if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS=$SAVE_CFLAGS + CFLAGS="$SAVE_CFLAGS" fi ;; -*-*solaris*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. +sparc*-*solaris*) + # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 @@ -5834,20 +5275,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; } case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in - yes*) - case $host in - i?86-*-solaris*|x86_64-*-solaris*) - LD="${LD-ld} -m elf_x86_64" - ;; - sparc*-*-solaris*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - # GNU ld 2.21 introduced _sol2 emulations. Use them if available. - if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then - LD=${LD-ld}_sol2 - fi - ;; + yes*) LD="${LD-ld} -m elf64_sparc" ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" @@ -5861,124 +5289,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; } ;; esac -need_locks=$enable_libtool_lock - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. -set dummy ${ac_tool_prefix}mt; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$MANIFEST_TOOL"; then - ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL -if test -n "$MANIFEST_TOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 -$as_echo "$MANIFEST_TOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_MANIFEST_TOOL"; then - ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL - # Extract the first word of "mt", so it can be a program name with args. -set dummy mt; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_MANIFEST_TOOL"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL -if test -n "$ac_ct_MANIFEST_TOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 -$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_MANIFEST_TOOL" = x; then - MANIFEST_TOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL - fi -else - MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" -fi - -test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 -$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } -if ${lt_cv_path_mainfest_tool+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_path_mainfest_tool=no - echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 - $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out - cat conftest.err >&5 - if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_mainfest_tool=yes - fi - rm -f conftest* -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 -$as_echo "$lt_cv_path_mainfest_tool" >&6; } -if test yes != "$lt_cv_path_mainfest_tool"; then - MANIFEST_TOOL=: -fi - - - - +need_locks="$enable_libtool_lock" case $host_os in @@ -6475,7 +5786,7 @@ if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no - if test -z "$LT_MULTI_MODULE"; then + if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the @@ -6487,13 +5798,7 @@ else $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? - # If there is a non-empty error log, and "single_module" - # appears in it, assume the flag caused a linker warning - if test -s conftest.err && $GREP single_module conftest.err; then - cat conftest.err >&5 - # Otherwise, if the output was created with a 0 exit code from - # the compiler, it worked. - elif test -f libconftest.dylib && test 0 = "$_lt_result"; then + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 @@ -6504,7 +5809,6 @@ else fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : @@ -6532,74 +5836,39 @@ else fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS + LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 -$as_echo_n "checking for -force_load linker flag... " >&6; } -if ${lt_cv_ld_force_load+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ld_force_load=no - cat > conftest.c << _LT_EOF -int forced_loaded() { return 2;} -_LT_EOF - echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 - $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 - echo "$AR cru libconftest.a conftest.o" >&5 - $AR cru libconftest.a conftest.o 2>&5 - echo "$RANLIB libconftest.a" >&5 - $RANLIB libconftest.a 2>&5 - cat > conftest.c << _LT_EOF -int main() { return 0;} -_LT_EOF - echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err - _lt_result=$? - if test -s conftest.err && $GREP force_load conftest.err; then - cat conftest.err >&5 - elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then - lt_cv_ld_force_load=yes - else - cat conftest.err >&5 - fi - rm -f conftest.err libconftest.a conftest conftest.c - rm -rf conftest.dSYM - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 -$as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) - _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) - _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; - 10.[012][,.]*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) - _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac - if test yes = "$lt_cv_apple_cc_single_mod"; then + if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi - if test yes = "$lt_cv_ld_exported_symbols_list"; then - _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else - _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi - if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then + if test "$DSYMUTIL" != ":"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= @@ -6607,41 +5876,6 @@ $as_echo "$lt_cv_ld_force_load" >&6; } ;; esac -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x$2 in - x) - ;; - *:) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" - ;; - x:*) - eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" - ;; - *) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" - ;; - esac -} - ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -6924,8 +6158,6 @@ done - - # Set options @@ -6945,14 +6177,14 @@ if test "${enable_shared+set}" = set; then : *) enable_shared=no # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do - IFS=$lt_save_ifs + IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done - IFS=$lt_save_ifs + IFS="$lt_save_ifs" ;; esac else @@ -6976,14 +6208,14 @@ if test "${enable_static+set}" = set; then : *) enable_static=no # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do - IFS=$lt_save_ifs + IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done - IFS=$lt_save_ifs + IFS="$lt_save_ifs" ;; esac else @@ -7001,27 +6233,14 @@ fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : - withval=$with_pic; lt_p=${PACKAGE-default} - case $withval in - yes|no) pic_mode=$withval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $withval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac + withval=$with_pic; pic_mode="$withval" else pic_mode=default fi +test -z "$pic_mode" && pic_mode=default + @@ -7037,14 +6256,14 @@ if test "${enable_fast_install+set}" = set; then : *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do - IFS=$lt_save_ifs + IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done - IFS=$lt_save_ifs + IFS="$lt_save_ifs" ;; esac else @@ -7058,63 +6277,11 @@ fi - shared_archive_member_spec= -case $host,$enable_shared in -power*-*-aix[5-9]*,yes) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 -$as_echo_n "checking which variant of shared library versioning to provide... " >&6; } - -# Check whether --with-aix-soname was given. -if test "${with_aix_soname+set}" = set; then : - withval=$with_aix_soname; case $withval in - aix|svr4|both) - ;; - *) - as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 - ;; - esac - lt_cv_with_aix_soname=$with_aix_soname -else - if ${lt_cv_with_aix_soname+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_with_aix_soname=aix -fi - - with_aix_soname=$lt_cv_with_aix_soname -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 -$as_echo "$with_aix_soname" >&6; } - if test aix != "$with_aix_soname"; then - # For the AIX way of multilib, we name the shared archive member - # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', - # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. - # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, - # the AIX toolchain works better with OBJECT_MODE set (default 32). - if test 64 = "${OBJECT_MODE-32}"; then - shared_archive_member_spec=shr_64 - else - shared_archive_member_spec=shr - fi - fi - ;; -*) - with_aix_soname=aix - ;; -esac - - - - - - - # This can be used to rebuild libtool when needed -LIBTOOL_DEPS=$ltmain +LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' @@ -7137,11 +6304,6 @@ LIBTOOL='$(SHELL) $(top_builddir)/libtool' - - - - - @@ -7163,7 +6325,7 @@ test -z "$LN_S" && LN_S="ln -s" -if test -n "${ZSH_VERSION+set}"; then +if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi @@ -7197,30 +6359,60 @@ _ACEOF + + + + + + + + + + + + + case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. - if test set != "${COLLECT_NAMES+set}"; then + if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + # Global variables: ofile=libtool can_build_shared=yes -# All known linkers require a '.a' archive for static linking (except MSVC, +# All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a -with_gnu_ld=$lt_cv_prog_gnu_ld +with_gnu_ld="$lt_cv_prog_gnu_ld" -old_CC=$CC -old_CFLAGS=$CFLAGS +old_CC="$CC" +old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc @@ -7229,8 +6421,15 @@ test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o -func_cc_basename $compiler -cc_basename=$func_cc_basename_result +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it @@ -7245,22 +6444,22 @@ if ${lt_cv_path_MAGIC_CMD+:} false; then : else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs + IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/${ac_tool_prefix}file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : @@ -7283,13 +6482,13 @@ _LT_EOF break fi done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi -MAGIC_CMD=$lt_cv_path_MAGIC_CMD +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } @@ -7311,22 +6510,22 @@ if ${lt_cv_path_MAGIC_CMD+:} false; then : else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs + IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/file"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"file" + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : @@ -7349,13 +6548,13 @@ _LT_EOF break fi done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi -MAGIC_CMD=$lt_cv_path_MAGIC_CMD +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } @@ -7376,7 +6575,7 @@ esac # Use C for the default configuration in the libtool script -lt_save_CC=$CC +lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -7434,13 +6633,8 @@ if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= -if test yes = "$GCC"; then - case $cc_basename in - nvcc*) - lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; - *) - lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; - esac +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag=' -fno-builtin' { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } @@ -7450,7 +6644,7 @@ else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment + lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins @@ -7460,15 +6654,15 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6657: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 + echo "$as_me:6661: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes @@ -7480,7 +6674,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } -if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : @@ -7497,19 +6691,20 @@ fi lt_prog_compiler_pic= lt_prog_compiler_static= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } - if test yes = "$GCC"; then + if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. - if test ia64 = "$host_cpu"; then + if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi - lt_prog_compiler_pic='-fPIC' ;; amigaos*) @@ -7520,8 +6715,8 @@ lt_prog_compiler_static= ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac @@ -7537,11 +6732,6 @@ lt_prog_compiler_static= # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac ;; darwin* | rhapsody*) @@ -7550,12 +6740,6 @@ lt_prog_compiler_static= lt_prog_compiler_pic='-fno-common' ;; - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag @@ -7598,21 +6782,12 @@ lt_prog_compiler_static= lt_prog_compiler_pic='-fPIC' ;; esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' - if test ia64 = "$host_cpu"; then + if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else @@ -7620,29 +6795,10 @@ lt_prog_compiler_static= fi ;; - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' - case $host_os in - os2*) - lt_prog_compiler_static='$wl-static' - ;; - esac ;; hpux9* | hpux10* | hpux11*) @@ -7658,7 +6814,7 @@ lt_prog_compiler_static= ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='$wl-a ${wl}archive' + lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) @@ -7667,9 +6823,9 @@ lt_prog_compiler_static= lt_prog_compiler_static='-non_shared' ;; - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + linux* | k*bsd*-gnu) case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. + # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' @@ -7688,19 +6844,7 @@ lt_prog_compiler_static= lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' @@ -7712,40 +6856,25 @@ lt_prog_compiler_static= # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' ;; esac ;; @@ -7777,7 +6906,7 @@ lt_prog_compiler_static= lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + f77* | f90* | f95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; @@ -7797,7 +6926,7 @@ lt_prog_compiler_static= ;; sysv4*MP*) - if test -d /usr/nec; then + if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi @@ -7826,7 +6955,7 @@ lt_prog_compiler_static= fi case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: + # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; @@ -7834,17 +6963,13 @@ case $host_os in lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 +$as_echo "$lt_prog_compiler_pic" >&6; } + + + + -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -$as_echo_n "checking for $compiler option to produce PIC... " >&6; } -if ${lt_cv_prog_compiler_pic+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_pic=$lt_prog_compiler_pic -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -$as_echo "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. @@ -7858,7 +6983,7 @@ else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins @@ -7868,15 +6993,15 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6996: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 + echo "$as_me:7000: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes @@ -7888,7 +7013,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } -if test yes = "$lt_cv_prog_compiler_pic_works"; then +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; @@ -7905,11 +7030,6 @@ fi - - - - - # # Check to make sure the static flag actually works. # @@ -7920,7 +7040,7 @@ if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no - save_LDFLAGS=$LDFLAGS + save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then @@ -7929,7 +7049,7 @@ else if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes @@ -7939,13 +7059,13 @@ else fi fi $RM -r conftest* - LDFLAGS=$save_LDFLAGS + LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } -if test yes = "$lt_cv_prog_compiler_static_works"; then +if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= @@ -7978,16 +7098,16 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7101: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 + echo "$as_me:7105: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes @@ -8033,16 +7153,16 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7156: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 + echo "$as_me:7160: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes @@ -8065,8 +7185,8 @@ $as_echo "$lt_cv_prog_compiler_c_o" >&6; } -hard_links=nottested -if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } @@ -8078,9 +7198,9 @@ $as_echo_n "checking if we can lock with hard links... " >&6; } ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } - if test no = "$hard_links"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 -$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else @@ -8108,6 +7228,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported @@ -8123,9 +7244,9 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ' (' and ')$', so one must not match beginning or - # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', - # as well as any symbol that contains 'd'. + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if @@ -8140,7 +7261,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. - if test yes != "$GCC"; then + if test "$GCC" != yes; then with_gnu_ld=no fi ;; @@ -8148,57 +7269,30 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; - openbsd* | bitrig*) + openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes - - # On some targets, GNU ld is compatible enough with the native linker - # that we're better off using the native interface for both. - lt_use_gnu_ld_interface=no - if test yes = "$with_gnu_ld"; then - case $host_os in - aix*) - # The AIX port of GNU ld has always aspired to compatibility - # with the native linker. However, as the warning in the GNU ld - # block says, versions before 2.19.5* couldn't really create working - # shared libraries, regardless of the interface used. - case `$LD -v 2>&1` in - *\ \(GNU\ Binutils\)\ 2.19.5*) ;; - *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; - *\ \(GNU\ Binutils\)\ [3-9]*) ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - fi - - if test yes = "$lt_use_gnu_ld_interface"; then + if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='$wl' + wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - export_dynamic_flag_spec='$wl--export-dynamic' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no - case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in - *GNU\ gold*) supports_anon_versioning=yes ;; + case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... @@ -8210,16 +7304,15 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken - if test ia64 != "$host_cpu"; then + if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 -*** Warning: the GNU linker, at least up to release 2.19, is reported +*** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to install binutils -*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. -*** You will then need to restart the configuration process. +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. _LT_EOF fi @@ -8229,7 +7322,7 @@ _LT_EOF case $host_cpu in powerpc) # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) @@ -8245,7 +7338,7 @@ _LT_EOF allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi @@ -8255,97 +7348,61 @@ _LT_EOF # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' - export_dynamic_flag_spec='$wl--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file, use it as - # is; otherwise, prepend EXPORTS... - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; - haiku*) - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - link_all_deplibs=yes - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes - ;; - interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; - gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + gnu* | linux* | tpf* | k*bsd*-gnu) tmp_diet=no - if test linux-dietlibc = "$host_os"; then + if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ - && test no = "$tmp_diet" + && test "$tmp_diet" = no then - tmp_addflag=' $pic_flag' + tmp_addflag= tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; - pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group f77 and f90 compilers - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; @@ -8356,47 +7413,39 @@ _LT_EOF lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; - nagfor*) # NAGFOR 5.3 - tmp_sharedflag='-Wl,-shared' ;; - xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + xl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; - nvcc*) # Cuda Compiler Driver 2.2 - whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - compiler_needs_object=yes - ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac - archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - if test yes = "$supports_anon_versioning"; then + if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in - tcc*) - export_dynamic_flag_spec='-rdynamic' - ;; - xlf* | bgf* | bgxlf* | mpixlf*) + xlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' - if test yes = "$supports_anon_versioning"; then + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld='-rpath $libdir' + archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac @@ -8410,8 +7459,8 @@ _LT_EOF archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; @@ -8429,8 +7478,8 @@ _LT_EOF _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi @@ -8442,7 +7491,7 @@ _LT_EOF ld_shlibs=no cat <<_LT_EOF 1>&2 -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify @@ -8457,9 +7506,9 @@ _LT_EOF # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi @@ -8476,15 +7525,15 @@ _LT_EOF *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac - if test no = "$ld_shlibs"; then + if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= @@ -8500,7 +7549,7 @@ _LT_EOF # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes - if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported @@ -8508,57 +7557,32 @@ _LT_EOF ;; aix[4-9]*) - if test ia64 = "$host_cpu"; then + if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' - no_entry_flag= + no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to GNU nm, but means don't demangle to AIX nm. - # Without the "-l" option, or with the "-B" option, AIX nm treats - # weak defined symbols like other global defined symbols, whereas - # GNU nm marks them as "W". - # While the 'weak' keyword is ignored in the Export File, we need - # it in the Import File for the 'aix-soname' feature, so we have - # to replace the "-B" option with "-P" for AIX nm. + # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else - export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # have runtime linking enabled, and use it for executables. - # For shared libraries, we enable/disable runtime linking - # depending on the kind of the shared library created - - # when "with_aix_soname,aix_use_runtimelinking" is: - # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables - # "aix,yes" lib.so shared, rtl:yes, for executables - # lib.a static archive - # "both,no" lib.so.V(shr.o) shared, rtl:yes - # lib.a(lib.so.V) shared, rtl:no, for executables - # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a(lib.so.V) shared, rtl:no - # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a static archive + # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do - if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done - if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then - # With aix-soname=svr4, we create the lib.so.V shared archives only, - # so we don't have lib.a shared libs to link our executables. - # We have to force runtime linking in this case. - aix_use_runtimelinking=yes - LDFLAGS="$LDFLAGS -Wl,-brtl" - fi ;; esac @@ -8577,21 +7601,13 @@ _LT_EOF hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes - file_list_spec='$wl-f,' - case $with_aix_soname,$aix_use_runtimelinking in - aix,*) ;; # traditional, no import file - svr4,* | *,yes) # use import file - # The Import File defines what to hardcode. - hardcode_direct=no - hardcode_direct_absolute=no - ;; - esac + file_list_spec='${wl}-f,' - if test yes = "$GCC"; then + if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ - collect2name=`$CC -print-prog-name=collect2` + collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then @@ -8610,48 +7626,35 @@ _LT_EOF ;; esac shared_flag='-shared' - if test yes = "$aix_use_runtimelinking"; then - shared_flag="$shared_flag "'$wl-G' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' fi - # Need to ensure runtime linking is disabled for the traditional - # shared library, or the linker may eventually find shared libraries - # /with/ Import File - we do not want to mix them. - shared_flag_aix='-shared' - shared_flag_svr4='-shared $wl-G' else # not using gcc - if test ia64 = "$host_cpu"; then + if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else - if test yes = "$aix_use_runtimelinking"; then - shared_flag='$wl-G' + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' else - shared_flag='$wl-bM:SRE' + shared_flag='${wl}-bM:SRE' fi - shared_flag_aix='$wl-bM:SRE' - shared_flag_svr4='$wl-G' fi fi - export_dynamic_flag_spec='$wl-bexpall' + export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes - if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if ${lt_cv_aix_libpath_+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -8664,47 +7667,34 @@ main () _ACEOF if ac_fn_c_try_link "$LINENO"; then : - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else - if test ia64 = "$host_cpu"; then - hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. - if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - if ${lt_cv_aix_libpath_+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -8717,57 +7707,33 @@ main () _ACEOF if ac_fn_c_try_link "$LINENO"; then : - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=/usr/lib:/lib - fi +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. - no_undefined_flag=' $wl-bernotok' - allow_undefined_flag=' $wl-berok' - if test yes = "$with_gnu_ld"; then - # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec='$convenience' - fi + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' archive_cmds_need_lc=yes - archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' - # -brtl affects multiple linker settings, -berok does not and is overridden later - compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' - if test svr4 != "$with_aix_soname"; then - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' - fi - if test aix != "$with_aix_soname"; then - archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' - else - # used by -dlpreopen to get the symbols - archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' - fi - archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; @@ -8776,7 +7742,7 @@ fi case $host_cpu in powerpc) # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) @@ -8796,65 +7762,20 @@ fi # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. - case $cc_basename in - cl*) - # Native MSVC - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - always_export_symbols=yes - file_list_spec='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' - archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then - cp "$export_symbols" "$output_objdir/$soname.def"; - echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; - else - $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, )='true' - enable_shared_with_static_runtimes=yes - exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - # Don't use ranlib - old_postinstall_cmds='chmod 644 $oldlib' - postlink_cmds='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile=$lt_outputfile.exe - lt_tool_outputfile=$lt_tool_outputfile.exe - ;; - esac~ - if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # Assume MSVC wrapper - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_from_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' - enable_shared_with_static_runtimes=yes - ;; - esac + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes ;; darwin* | rhapsody*) @@ -8864,24 +7785,19 @@ fi hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported - if test yes = "$lt_cv_ld_force_load"; then - whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - - else - whole_archive_flag_spec='' - fi + whole_archive_flag_spec='' link_all_deplibs=yes - allow_undefined_flag=$_lt_dar_allow_undefined + allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in - ifort*|nagfor*) _lt_dar_can_shared=yes ;; + ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac - if test yes = "$_lt_dar_can_shared"; then - output_verbose_link_cmd=func_echo_all - archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" - module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" - archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" - module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no @@ -8895,6 +7811,10 @@ fi hardcode_shlibpath_var=no ;; + freebsd1*) + ld_shlibs=no + ;; + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little @@ -8907,7 +7827,7 @@ fi ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2.*) + freebsd2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes @@ -8916,40 +7836,41 @@ fi # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) - if test yes = "$GCC"; then - archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else - archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi - hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes - export_dynamic_flag_spec='$wl-E' + export_dynamic_flag_spec='${wl}-E' ;; hpux10*) - if test yes,no = "$GCC,$with_gnu_ld"; then - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' + export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes @@ -8957,72 +7878,33 @@ fi ;; hpux11*) - if test yes,no = "$GCC,$with_gnu_ld"; then + if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) - archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) - archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) - archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) - archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) - - # Older versions of the 11.00 compiler do not understand -b yet - # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 -$as_echo_n "checking if $CC understands -b... " >&6; } -if ${lt_cv_prog_compiler__b+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler__b=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -b" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler__b=yes - fi - else - lt_cv_prog_compiler__b=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 -$as_echo "$lt_cv_prog_compiler__b" >&6; } - -if test yes = "$lt_cv_prog_compiler__b"; then - archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' -else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' -fi - + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi - if test no = "$with_gnu_ld"; then - hardcode_libdir_flag_spec='$wl+b $wl$libdir' + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in @@ -9033,7 +7915,7 @@ fi *) hardcode_direct=yes hardcode_direct_absolute=yes - export_dynamic_flag_spec='$wl-E' + export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. @@ -9044,58 +7926,35 @@ fi ;; irix5* | irix6* | nonstopux*) - if test yes = "$GCC"; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. - # This should be the same for all languages, so no per-tag cache variable. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 -$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } -if ${lt_cv_irix_exported_symbol+:} false; then : - $as_echo_n "(cached) " >&6 -else - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -int foo (void) { return 0; } +int foo(void) {} _ACEOF if ac_fn_c_try_link "$LINENO"; then : - lt_cv_irix_exported_symbol=yes -else - lt_cv_irix_exported_symbol=no + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 -$as_echo "$lt_cv_irix_exported_symbol" >&6; } - if test yes = "$lt_cv_irix_exported_symbol"; then - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' - fi + LDFLAGS="$save_LDFLAGS" else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; - linux*) - case $cc_basename in - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - ld_shlibs=yes - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out @@ -9110,7 +7969,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; @@ -9118,19 +7977,27 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } *nto* | *qnx*) ;; - openbsd* | bitrig*) + openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' - export_dynamic_flag_spec='$wl-E' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' else - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='$wl-rpath,$libdir' + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac fi else ld_shlibs=no @@ -9141,53 +8008,33 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported - shrext_cmds=.dll - archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - enable_shared_with_static_runtimes=yes + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag - if test yes = "$GCC"; then - allow_undefined_flag=' $wl-expect_unresolved $wl\*' - archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' @@ -9198,24 +8045,24 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } solaris*) no_undefined_flag=' -z defs' - if test yes = "$GCC"; then - wlarc='$wl' - archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' - archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) - wlarc='$wl' - archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi @@ -9225,11 +8072,11 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, - # but understands '-z linker_flag'. GCC discards it without '$wl', + # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) - if test yes = "$GCC"; then - whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi @@ -9239,10 +8086,10 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } ;; sunos4*) - if test sequent = "$host_vendor"; then + if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. - archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi @@ -9291,43 +8138,43 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag='$wl-z,text' + no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) - # Note: We CANNOT use -z defs as we might desire, because we do not + # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. - no_undefined_flag='$wl-z,text' - allow_undefined_flag='$wl-z,nodefs' + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='$wl-R,$libdir' + hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes - export_dynamic_flag_spec='$wl-Bexport' + export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' - if test yes = "$GCC"; then - archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else - archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; @@ -9342,10 +8189,10 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } ;; esac - if test sni = "$host_vendor"; then + if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - export_dynamic_flag_spec='$wl-Blargedynsym' + export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi @@ -9353,7 +8200,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } -test no = "$ld_shlibs" && can_build_shared=no +test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld @@ -9379,7 +8226,7 @@ x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes - if test yes,yes = "$GCC,$enable_shared"; then + if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. @@ -9390,50 +8237,44 @@ x|xyes) # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } -if ${lt_cv_archive_cmds_need_lc+:} false; then : - $as_echo_n "(cached) " >&6 -else - $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl - pic_flag=$lt_prog_compiler_pic - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag - allow_undefined_flag= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } - then - lt_cv_archive_cmds_need_lc=no - else - lt_cv_archive_cmds_need_lc=yes - fi - allow_undefined_flag=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 -$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } - archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + then + archive_cmds_need_lc=no + else + archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 +$as_echo "$archive_cmds_need_lc" >&6; } ;; esac fi @@ -9585,6 +8426,11 @@ esac + + + + + @@ -9594,58 +8440,44 @@ esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } -if test yes = "$GCC"; then +if test "$GCC" = yes; then case $host_os in - darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; - *) lt_awk_arg='/^libraries:/' ;; + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; esac - case $host_os in - mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; - *) lt_sed_strip_eq='s|=/|/|g' ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` - case $lt_search_path_spec in - *\;*) + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` - ;; - *) - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` - ;; - esac + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary... + # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= - lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - # ...but if some path component already ends with the multilib dir we assume - # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). - case "$lt_multi_os_dir; $lt_search_path_spec " in - "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) - lt_multi_os_dir= - ;; - esac + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" - elif test -n "$lt_multi_os_dir"; then + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done - lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' -BEGIN {RS = " "; FS = "/|\n";} { - lt_foo = ""; - lt_count = 0; + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { - lt_foo = "/" $lt_i lt_foo; + lt_foo="/" $lt_i lt_foo; } else { lt_count--; } @@ -9655,20 +8487,14 @@ BEGIN {RS = " "; FS = "/|\n";} { if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` - # AWK program above erroneously prepends '/' to C:/dos/paths - # for these hosts. - case $host_os in - mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ - $SED 's|/\([A-Za-z]:\)|\1|g'` ;; - esac - sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= -shrext_cmds=.so +shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= @@ -9685,108 +8511,56 @@ hardcode_into_libs=no # flags to be left without arguments need_version=unknown - - case $host_os in aix3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname.a' + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='$libname$release$shared_ext$major' + soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) - version_type=linux # correct to gnu/linux during the next big refactor + version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes - if test ia64 = "$host_cpu"; then + if test "$host_cpu" = ia64; then # AIX 5 supports IA64 - library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with - # the line '#! .'. This would cause the generated library to - # depend on '.', always an invalid library. This was fixed in + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' - echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac - # Using Import Files as archive members, it is possible to support - # filename-based versioning of shared library archives on AIX. While - # this would work for both with and without runtime linking, it will - # prevent static linking of such archives. So we do filename-based - # shared library versioning with .so extension only, which is used - # when both runtime linking and shared linking is enabled. - # Unfortunately, runtime linking may impact performance, so we do - # not want this to be the default eventually. Also, we use the - # versioned .so libs for executables only if there is the -brtl - # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. - # To allow for filename-based versioning support, we need to create - # libNAME.so.V as an archive file, containing: - # *) an Import File, referring to the versioned filename of the - # archive as well as the shared archive member, telling the - # bitwidth (32 or 64) of that shared object, and providing the - # list of exported symbols of that shared object, eventually - # decorated with the 'weak' keyword - # *) the shared object with the F_LOADONLY flag set, to really avoid - # it being seen by the linker. - # At run time we better use the real file rather than another symlink, - # but for link time we create the symlink libNAME.so -> libNAME.so.V - - case $with_aix_soname,$aix_use_runtimelinking in - # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. - aix,yes) # traditional libtool - dynamic_linker='AIX unversionable lib.so' + if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - aix,no) # traditional AIX only - dynamic_linker='AIX lib.a(lib.so.V)' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - ;; - svr4,*) # full svr4 only - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,yes) # both, prefer svr4 - dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # unpreferred sharedlib libNAME.a needs extra handling - postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' - postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,no) # both, prefer aix - dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling - postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' - postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' - ;; - esac + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi shlibpath_var=LIBPATH fi ;; @@ -9796,27 +8570,27 @@ amigaos*) powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) - library_names_spec='$libname$shared_ext' + library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) - version_type=linux # correct to gnu/linux during the next big refactor + version_type=linux need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" @@ -9828,17 +8602,16 @@ bsdi[45]*) cygwin* | mingw* | pw32* | cegcc*) version_type=windows - shrext_cmds=.dll + shrext_cmds=".dll" need_version=no need_lib_prefix=no - case $GCC,$cc_basename in - yes,*) - # gcc + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ @@ -9854,84 +8627,37 @@ cygwin* | mingw* | pw32* | cegcc*) case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac - dynamic_linker='Win32 ld.exe' - ;; - - *,cl*) - # Native MSVC - libname_spec='$name' - soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' - library_names_spec='$libname.dll.lib' - - case $build_os in - mingw*) - sys_lib_search_path_spec= - lt_save_ifs=$IFS - IFS=';' - for lt_path in $LIB - do - IFS=$lt_save_ifs - # Let DOS variable expansion print the short 8.3 style file name. - lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` - sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" - done - IFS=$lt_save_ifs - # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` - ;; - cygwin*) - # Convert to unix form, then to dos form, then back to unix form - # but this time dos style (no spaces!) so that the unix form looks - # like /cygdrive/c/PROGRA~1:/cygdr... - sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` - sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` - sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - ;; - *) - sys_lib_search_path_spec=$LIB - if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # FIXME: find the short name or the path components, as spaces are - # common. (e.g. "Program Files" -> "PROGRA~1") - ;; - esac - - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - dynamic_linker='Win32 link.exe' ;; *) - # Assume MSVC wrapper - library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' - dynamic_linker='Win32 ld.exe' + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac + dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; @@ -9941,8 +8667,8 @@ darwin* | rhapsody*) version_type=darwin need_lib_prefix=no need_version=no - library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' - soname_spec='$libname$release$major$shared_ext' + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' @@ -9952,14 +8678,18 @@ darwin* | rhapsody*) ;; dgux*) - version_type=linux # correct to gnu/linux during the next big refactor + version_type=linux need_lib_prefix=no need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; +freebsd1*) + dynamic_linker=no + ;; + freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. @@ -9967,26 +8697,38 @@ freebsd* | dragonfly*) objformat=`/usr/bin/objformat` else case $host_os in - freebsd[23].*) objformat=aout ;; + freebsd[123]*) objformat=aout ;; *) objformat=elf ;; esac fi - version_type=freebsd-$objformat + # Handle Gentoo/FreeBSD as it was Linux + case $host_vendor in + gentoo) + version_type=linux ;; + *) + version_type=freebsd-$objformat ;; + esac + case $version_type in freebsd-elf*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; + linux) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + need_lib_prefix=no + need_version=no + ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in - freebsd2.*) + freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) @@ -10005,16 +8747,13 @@ freebsd* | dragonfly*) esac ;; -haiku*) - version_type=linux # correct to gnu/linux during the next big refactor +gnu*) + version_type=linux need_lib_prefix=no need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=no - sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; @@ -10031,15 +8770,14 @@ hpux9* | hpux10* | hpux11*) dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - if test 32 = "$HPUX_IA64_MODE"; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' @@ -10047,8 +8785,8 @@ hpux9* | hpux10* | hpux11*) dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; @@ -10057,22 +8795,20 @@ hpux9* | hpux10* | hpux11*) dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' ;; esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 ;; interix[3-9]*) - version_type=linux # correct to gnu/linux during the next big refactor + version_type=linux need_lib_prefix=no need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no @@ -10083,16 +8819,16 @@ irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) - if test yes = "$lt_cv_prog_gnu_ld"; then - version_type=linux # correct to gnu/linux during the next big refactor + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= @@ -10111,8 +8847,8 @@ irix5* | irix6* | nonstopux*) esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" - sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; @@ -10121,47 +8857,22 @@ linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; -linux*android*) - version_type=none # Android doesn't support versioned libraries. +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux need_lib_prefix=no need_version=no - library_names_spec='$libname$release$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - dynamic_linker='Android linker' - # Don't embed -rpath directories since the linker doesn't support them. - hardcode_libdir_flag_spec='-L$libdir' - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no - # Some binutils ld are patched to set DT_RUNPATH - if ${lt_cv_shlibpath_overrides_runpath+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -10174,31 +8885,22 @@ main () _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : - lt_cv_shlibpath_overrides_runpath=yes + shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - -fi - - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes - # Ideally, we could use ldconfig to report *all* directores which are - # searched for libraries, however this is still not possible. Aside from not - # being certain /sbin/ldconfig is available, command - # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, - # even though it is searched at run-time. Try to do the best guess by - # appending ld.so.conf contents (and includes) to the search path. + # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi @@ -10216,12 +8918,12 @@ netbsd*) need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH @@ -10230,8 +8932,8 @@ netbsd*) ;; newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; @@ -10240,68 +8942,58 @@ newsos6) version_type=qnx need_lib_prefix=no need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; -openbsd* | bitrig*) +openbsd*) version_type=sunos - sys_lib_dlsearch_path_spec=/usr/lib + sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - need_version=no - else - need_version=yes - fi - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi ;; os2*) libname_spec='$name' - version_type=windows - shrext_cmds=.dll - need_version=no + shrext_cmds=".dll" need_lib_prefix=no - # OS/2 can only load a DLL with a base name of 8 characters or less. - soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; - v=$($ECHO $release$versuffix | tr -d .-); - n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); - $ECHO $n$v`$shared_ext' - library_names_spec='${libname}_dll.$libext' + library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' - shlibpath_var=BEGINLIBPATH - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' + shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) @@ -10309,11 +9001,11 @@ rdos*) ;; solaris*) - version_type=linux # correct to gnu/linux during the next big refactor + version_type=linux need_lib_prefix=no need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes @@ -10323,20 +9015,20 @@ solaris*) sunos4*) version_type=sunos - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes - if test yes = "$with_gnu_ld"; then + if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) @@ -10357,24 +9049,24 @@ sysv4 | sysv4.3*) ;; sysv4*MP*) - if test -d /usr/nec; then - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' - soname_spec='$libname$shared_ext.$major' + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=sco + version_type=freebsd-elf need_lib_prefix=no need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes - if test yes = "$with_gnu_ld"; then + if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' @@ -10389,19 +9081,19 @@ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux # correct to gnu/linux during the next big refactor + version_type=linux need_lib_prefix=no need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; @@ -10411,40 +9103,20 @@ uts4*) esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } -test no = "$dynamic_linker" && can_build_shared=no +test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test yes = "$GCC"; then +if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi -if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then - sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi - -if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then - sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi -# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... -configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec - -# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code -func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" - -# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool -configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH - - - - - - - - - - - @@ -10536,15 +9208,15 @@ $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || - test yes = "$hardcode_automatic"; then + test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. - if test no != "$hardcode_direct" && + if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one - ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && - test no != "$hardcode_minus_L"; then + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else @@ -10559,12 +9231,12 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } -if test relink = "$hardcode_action" || - test yes = "$inherit_rpath"; then +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no -elif test yes = "$shlibpath_overrides_runpath" || - test no = "$enable_shared"; then +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi @@ -10574,7 +9246,7 @@ fi - if test yes != "$enable_dlopen"; then + if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown @@ -10584,23 +9256,23 @@ else case $host_os in beos*) - lt_cv_dlopen=load_add_on + lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) - lt_cv_dlopen=LoadLibrary + lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) - lt_cv_dlopen=dlopen + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) - # if libdl is installed we need to link against it + # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : @@ -10638,10 +9310,10 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else - lt_cv_dlopen=dyld + lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes @@ -10649,18 +9321,10 @@ fi ;; - tpf*) - # Don't try to run any link tests for TPF. We know it's impossible - # because TPF is a cross-compiler, and we know how we open DSOs. - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - lt_cv_dlopen_self=no - ;; - *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : - lt_cv_dlopen=shl_load + lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } @@ -10699,11 +9363,11 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : - lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : - lt_cv_dlopen=dlopen + lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } @@ -10742,7 +9406,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } @@ -10781,7 +9445,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : - lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } @@ -10820,7 +9484,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : - lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi @@ -10841,21 +9505,21 @@ fi ;; esac - if test no = "$lt_cv_dlopen"; then - enable_dlopen=no - else + if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes + else + enable_dlopen=no fi case $lt_cv_dlopen in dlopen) - save_CPPFLAGS=$CPPFLAGS - test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - save_LDFLAGS=$LDFLAGS + save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - save_LIBS=$LIBS + save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 @@ -10863,13 +9527,13 @@ $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else - if test yes = "$cross_compiling"; then : + if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" +#line 9536 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10910,13 +9574,7 @@ else # endif #endif -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); -#endif - -int fnord () { return 42; } +void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); @@ -10925,11 +9583,7 @@ int main () if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else @@ -10942,7 +9596,7 @@ _LT_EOF (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in @@ -10962,20 +9616,20 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } - if test yes = "$lt_cv_dlopen_self"; then + if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else - if test yes = "$cross_compiling"; then : + if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" +#line 9632 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11016,13 +9670,7 @@ else # endif #endif -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); -#endif - -int fnord () { return 42; } +void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); @@ -11031,11 +9679,7 @@ int main () if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else @@ -11048,7 +9692,7 @@ _LT_EOF (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in @@ -11069,9 +9713,9 @@ fi $as_echo "$lt_cv_dlopen_self_static" >&6; } fi - CPPFLAGS=$save_CPPFLAGS - LDFLAGS=$save_LDFLAGS - LIBS=$save_LIBS + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" ;; esac @@ -11115,7 +9759,7 @@ else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) - if test -n "$STRIP"; then + if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 @@ -11143,7 +9787,7 @@ fi - # Report what library types will actually be built + # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 @@ -11151,13 +9795,13 @@ $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } - test no = "$can_build_shared" && enable_shared=no + test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) - test yes = "$enable_shared" && enable_static=no + test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' @@ -11165,12 +9809,8 @@ $as_echo_n "checking whether to build shared libraries... " >&6; } ;; aix[4-9]*) - if test ia64 != "$host_cpu"; then - case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in - yes,aix,yes) ;; # shared object as lib.so file only - yes,svr4,*) ;; # shared object as lib.so archive member only - yes,*) enable_static=no ;; # shared object in lib.a archive as well - esac + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no fi ;; esac @@ -11180,7 +9820,7 @@ $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. - test yes = "$enable_shared" || enable_static=yes + test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } @@ -11194,9 +9834,7 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -CC=$lt_save_CC - - +CC="$lt_save_CC" @@ -13508,159 +12146,131 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' -macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' -macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' -enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' -enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' -pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' -enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' -shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' -SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' -ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' -PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' -host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' -host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' -host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' -build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' -build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' -build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' -SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' -Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' -GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' -EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' -FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' -LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' -NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' -LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' -max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' -ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' -exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' -lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' -lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' -lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' -lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' -lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' -reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' -reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' -OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' -deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' -file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' -file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' -want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' -DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' -sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' -AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' -AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' -archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' -STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' -RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' -old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' -old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' -lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' -CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' -CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' -compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' -GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' -lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' -nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' -lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' -lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' -objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' -MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' -need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' -MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' -DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' -NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' -LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' -OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' -OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' -libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' -shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' -extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' -export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' -whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' -compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' -old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' -archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' -module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' -module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' -with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' -allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' -no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' -hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' -hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' -hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' -hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' -hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' -inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' -link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' -always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' -export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' -exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' -include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' -prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' -postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' -file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' -variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' -need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' -need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' -version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' -runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' -libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' -library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' -soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' -install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' -postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' -postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' -finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' -hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' -sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' -configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' -configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' -hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' -enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' -old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' -striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`' +macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`' +enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`' +pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`' +host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`' +host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`' +host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`' +build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`' +build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`' +build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`' +SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`' +Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`' +GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`' +EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`' +FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`' +LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`' +NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`' +LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`' +ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`' +exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`' +lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`' +reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`' +AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`' +STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`' +RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`' +compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`' +GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`' +SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`' +ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`' +need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`' +LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`' +libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`' +fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`' +version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`' +runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`' +libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`' +soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`' +old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`' +striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - # Quote evaled strings. -for var in SHELL \ -ECHO \ -PATH_SEPARATOR \ -SED \ +for var in SED \ GREP \ EGREP \ FGREP \ @@ -13673,13 +12283,8 @@ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ -file_magic_glob \ -want_nocaseglob \ -DLLTOOL \ -sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ -archiver_list_spec \ STRIP \ RANLIB \ CC \ @@ -13687,19 +12292,16 @@ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ -lt_cv_sys_global_symbol_to_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ -lt_cv_nm_interface \ -nm_file_list_spec \ -lt_cv_truncate_bin \ +SHELL \ +ECHO \ lt_prog_compiler_no_builtin_flag \ -lt_prog_compiler_pic \ lt_prog_compiler_wl \ +lt_prog_compiler_pic \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ -MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ @@ -13713,7 +12315,9 @@ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ +hardcode_libdir_flag_spec_ld \ hardcode_libdir_separator \ +fix_srcfile_path \ exclude_expsyms \ include_expsyms \ file_list_spec \ @@ -13721,13 +12325,12 @@ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ -install_override_mode \ finish_eval \ old_striplib \ striplib; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" @@ -13749,16 +12352,14 @@ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ -postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ -configure_time_dlsearch_path \ -configure_time_lt_sys_library_path; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in +sys_lib_dlsearch_path_spec; do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" @@ -13766,17 +12367,26 @@ configure_time_lt_sys_library_path; do esac done -ac_aux_dir='$ac_aux_dir' +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\$0 --fallback-echo"') lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\` + ;; +esac -# See if we are running on zsh, and set the options that allow our +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. -if test -n "\${ZSH_VERSION+set}"; then +if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' @@ -14352,53 +12962,54 @@ $as_echo "$as_me: executing $ac_file commands" >&6;} case $ac_file$ac_mode in "libtool":C) - # See if we are running on zsh, and set the options that allow our + # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}"; then + if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi - cfgfile=${ofile}T + cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL -# Generated automatically by $as_me ($PACKAGE) $VERSION + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. - -# Provide generalized library-building support services. -# Written by Gordon Matzigkeit, 1996 - -# Copyright (C) 2014 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of of the License, or -# (at your option) any later version. # -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program or library that is built -# using GNU Libtool, you may include this file under the same -# distribution terms that you use for the rest of that program. +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 # -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. -available_tags='' - -# Configured defaults for sys_lib_dlsearch_path munging. -: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} +available_tags="" # ### BEGIN LIBTOOL CONFIG @@ -14418,18 +13029,6 @@ pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install -# Shared archive member basename,for filename based shared library versioning on AIX. -shared_archive_member_spec=$shared_archive_member_spec - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# An echo program that protects backslashes. -ECHO=$lt_ECHO - -# The PATH separator for the build system. -PATH_SEPARATOR=$lt_PATH_SEPARATOR - # The host system. host_alias=$host_alias host=$host @@ -14479,11 +13078,9 @@ SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP -# convert \$build file names to \$host format. -to_host_file_cmd=$lt_cv_to_host_file_cmd - -# convert \$build files to toolchain format. -to_tool_file_cmd=$lt_cv_to_tool_file_cmd +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds # An object symbol dumper. OBJDUMP=$lt_OBJDUMP @@ -14491,30 +13088,13 @@ OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method -# Command to use when deplibs_check_method = "file_magic". +# Command to use when deplibs_check_method == "file_magic". file_magic_cmd=$lt_file_magic_cmd -# How to find potential files when deplibs_check_method = "file_magic". -file_magic_glob=$lt_file_magic_glob - -# Find potential files using nocaseglob when deplibs_check_method = "file_magic". -want_nocaseglob=$lt_want_nocaseglob - -# DLL creation program. -DLLTOOL=$lt_DLLTOOL - -# Command to associate shared and link libraries. -sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd - # The archiver. AR=$lt_AR - -# Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS -# How to feed a file listing to the archiver. -archiver_list_spec=$lt_archiver_list_spec - # A symbol stripping program. STRIP=$lt_STRIP @@ -14523,9 +13103,6 @@ RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds -# Whether to use a lock for old archive extraction. -lock_old_archive_extraction=$lock_old_archive_extraction - # A C compiler. LTCC=$lt_CC @@ -14538,39 +13115,27 @@ global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl -# Transform the output of nm into a list of symbols to manually relocate. -global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import - # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix -# The name lister interface. -nm_interface=$lt_lt_cv_nm_interface - -# Specify filename containing input files for \$NM. -nm_file_list_spec=$lt_nm_file_list_spec - -# The root where to search for dependent libraries,and where our libraries should be installed. -lt_sysroot=$lt_sysroot - -# Command to truncate a binary pipe. -lt_truncate_bin=$lt_lt_cv_truncate_bin - # The name of the directory that contains temporary libtool files. objdir=$objdir +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that does not interpret backslashes. +ECHO=$lt_ECHO + # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks -# Manifest tool. -MANIFEST_TOOL=$lt_MANIFEST_TOOL - # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL @@ -14627,9 +13192,6 @@ library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec -# Permission mode override for installation of shared libraries. -install_override_mode=$lt_install_override_mode - # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds @@ -14649,11 +13211,8 @@ hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec -# Detected run-time system search path for libraries. -sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path - -# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. -configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen @@ -14672,10 +13231,6 @@ striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds @@ -14688,12 +13243,12 @@ with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic - # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static @@ -14743,16 +13298,20 @@ no_undefined_flag=$lt_no_undefined_flag # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct -# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e impossible to change by setting \$shlibpath_var if the +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute @@ -14776,6 +13335,9 @@ inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols @@ -14791,9 +13353,6 @@ include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds -# Commands necessary for finishing linking programs. -postlink_cmds=$lt_postlink_cmds - # Specify filename containing input files. file_list_spec=$lt_file_list_spec @@ -14802,65 +13361,6 @@ hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG -_LT_EOF - - cat <<'_LT_EOF' >> "$cfgfile" - -# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE - -# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x$2 in - x) - ;; - *:) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" - ;; - x:*) - eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" - ;; - *) - eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" - ;; - esac -} - - -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in $*""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} - - -# ### END FUNCTIONS SHARED WITH CONFIGURE - _LT_EOF case $host_os in @@ -14869,7 +13369,7 @@ _LT_EOF # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. -if test set != "${COLLECT_NAMES+set}"; then +if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi @@ -14878,17 +13378,219 @@ _LT_EOF esac -ltmain=$ac_aux_dir/ltmain.sh +ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? - sed '$q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) - mv -f "$cfgfile" "$ofile" || + case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $* )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[^=]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$@"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1+=\$2" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1=\$$1\$2" +} + +_LT_EOF + ;; + esac + + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" From d1e1e72fb05ceb787f69fdabf10e30a4a125bb2e Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 13 Jul 2015 11:58:18 -0500 Subject: [PATCH 42/59] Adjust cipher_version test for 3.3.1 release --- test/crypto.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/crypto.test b/test/crypto.test index 84f8d57..0caf7aa 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -1541,7 +1541,7 @@ do_test verify-pragma-cipher-version { execsql { PRAGMA cipher_version; } -} {3.3.0} +} {3.3.1} db close file delete -force test.db From 8554c8577fc9632355c14dd8b9c8d68f0c813533 Mon Sep 17 00:00:00 2001 From: Christian Noon Date: Tue, 17 Nov 2015 20:50:22 -0800 Subject: [PATCH 43/59] Created a new SQLCipher framework target for iOS 8.0+. --- macosx/Info.plist | 26 ++ macosx/SQLCipher.h | 5 + sqlcipher.xcodeproj/project.pbxproj | 244 +++++++++++++++++- .../xcschemes/SQLCipher iOS.xcscheme | 80 ++++++ 4 files changed, 347 insertions(+), 8 deletions(-) create mode 100644 macosx/Info.plist create mode 100644 macosx/SQLCipher.h create mode 100644 sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher iOS.xcscheme diff --git a/macosx/Info.plist b/macosx/Info.plist new file mode 100644 index 0000000..dd6cc70 --- /dev/null +++ b/macosx/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 3.3.1 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/macosx/SQLCipher.h b/macosx/SQLCipher.h new file mode 100644 index 0000000..d43dd88 --- /dev/null +++ b/macosx/SQLCipher.h @@ -0,0 +1,5 @@ + +@import Foundation; + +FOUNDATION_EXPORT double SQLCipherVersionNumber; +FOUNDATION_EXPORT const unsigned char SQLCipherVersionString[]; diff --git a/sqlcipher.xcodeproj/project.pbxproj b/sqlcipher.xcodeproj/project.pbxproj index a3459bc..cd79669 100644 --- a/sqlcipher.xcodeproj/project.pbxproj +++ b/sqlcipher.xcodeproj/project.pbxproj @@ -21,7 +21,8 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ - 28B46E6317CD07A700672510 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28B46E6217CD07A600672510 /* Security.framework */; }; + 4C0041A61BFC3A5000ED2AD5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C0041A51BFC3A5000ED2AD5 /* Security.framework */; }; + 4C0041AB1BFC3A7E00ED2AD5 /* SQLCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9069D0A30FCE1A4D0042E34C /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 9069D0A20FCE1A4D0042E34C /* sqlite3.c */; }; /* End PBXBuildFile section */ @@ -33,20 +34,37 @@ remoteGlobalIDString = 9069D08B0FCE185A0042E34C; remoteInfo = amalgamation; }; + 4C0041A11BFC392D00ED2AD5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9069D08B0FCE185A0042E34C; + remoteInfo = amalgamation; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 28B46E6217CD07A600672510 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 4C0041981BFC382400ED2AD5 /* SQLCipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLCipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4C0041A51BFC3A5000ED2AD5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 4C0041A81BFC3A7E00ED2AD5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = macosx/Info.plist; sourceTree = ""; }; + 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SQLCipher.h; path = macosx/SQLCipher.h; sourceTree = ""; }; 9069D0A20FCE1A4D0042E34C /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sqlite3.c; sourceTree = ""; }; D2AAC046055464E500DB518D /* libsqlcipher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsqlcipher.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 4C0041941BFC382400ED2AD5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D289987405E68DCB004EDB86 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 28B46E6317CD07A700672510 /* Security.framework in Frameworks */, + 4C0041A61BFC3A5000ED2AD5 /* Security.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -56,9 +74,9 @@ 08FB7794FE84155DC02AAC07 /* sqlcipher */ = { isa = PBXGroup; children = ( - 28B46E6217CD07A600672510 /* Security.framework */, 08FB7795FE84155DC02AAC07 /* Source */, - C6A0FF2B0290797F04C91782 /* Documentation */, + 4C0041A41BFC3A3800ED2AD5 /* Supporting Files */, + 4C0041A71BFC3A5400ED2AD5 /* Frameworks */, 1AB674ADFE9D54B511CA2CBB /* Products */, ); name = sqlcipher; @@ -76,20 +94,39 @@ isa = PBXGroup; children = ( D2AAC046055464E500DB518D /* libsqlcipher.a */, + 4C0041981BFC382400ED2AD5 /* SQLCipher.framework */, ); name = Products; sourceTree = ""; }; - C6A0FF2B0290797F04C91782 /* Documentation */ = { + 4C0041A41BFC3A3800ED2AD5 /* Supporting Files */ = { isa = PBXGroup; children = ( + 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */, + 4C0041A81BFC3A7E00ED2AD5 /* Info.plist */, ); - name = Documentation; + name = "Supporting Files"; + sourceTree = ""; + }; + 4C0041A71BFC3A5400ED2AD5 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4C0041A51BFC3A5000ED2AD5 /* Security.framework */, + ); + name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + 4C0041951BFC382400ED2AD5 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C0041AB1BFC3A7E00ED2AD5 /* SQLCipher.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D2AAC043055464E500DB518D /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -100,6 +137,25 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 4C0041971BFC382400ED2AD5 /* SQLCipher iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4C00419D1BFC382500ED2AD5 /* Build configuration list for PBXNativeTarget "SQLCipher iOS" */; + buildPhases = ( + 4C0041931BFC382400ED2AD5 /* Sources */, + 4C0041941BFC382400ED2AD5 /* Frameworks */, + 4C0041951BFC382400ED2AD5 /* Headers */, + 4C0041961BFC382400ED2AD5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 4C0041A21BFC392D00ED2AD5 /* PBXTargetDependency */, + ); + name = "SQLCipher iOS"; + productName = SQLCipher; + productReference = 4C0041981BFC382400ED2AD5 /* SQLCipher.framework */; + productType = "com.apple.product-type.framework"; + }; D2AAC045055464E500DB518D /* sqlcipher */ = { isa = PBXNativeTarget; buildConfigurationList = 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "sqlcipher" */; @@ -124,7 +180,12 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0450; + LastUpgradeCheck = 0710; + TargetAttributes = { + 4C0041971BFC382400ED2AD5 = { + CreatedOnToolsVersion = 7.1; + }; + }; }; buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "sqlcipher" */; compatibilityVersion = "Xcode 3.2"; @@ -140,12 +201,23 @@ projectDirPath = ""; projectRoot = ""; targets = ( + 4C0041971BFC382400ED2AD5 /* SQLCipher iOS */, D2AAC045055464E500DB518D /* sqlcipher */, 9069D08B0FCE185A0042E34C /* amalgamation */, ); }; /* End PBXProject section */ +/* Begin PBXResourcesBuildPhase section */ + 4C0041961BFC382400ED2AD5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + /* Begin PBXShellScriptBuildPhase section */ 9069D08A0FCE185A0042E34C /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -164,6 +236,13 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 4C0041931BFC382400ED2AD5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D2AAC044055464E500DB518D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -180,6 +259,11 @@ target = 9069D08B0FCE185A0042E34C /* amalgamation */; targetProxy = 289BE0E7180C4930003E52DA /* PBXContainerItemProxy */; }; + 4C0041A21BFC392D00ED2AD5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 9069D08B0FCE185A0042E34C /* amalgamation */; + targetProxy = 4C0041A11BFC392D00ED2AD5 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -258,6 +342,7 @@ x86_64, i386, ); + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = c99; GCC_OPTIMIZATION_LEVEL = 0; GCC_WARN_ABOUT_RETURN_TYPE = YES; @@ -299,6 +384,141 @@ }; name = Release; }; + 4C00419E1BFC382500ED2AD5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + BITCODE_GENERATION_MODE = marker; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = macosx/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_CFLAGS = ( + "-DSQLITE_HAS_CODEC", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE", + "-DSQLCIPHER_CRYPTO_CC", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; + PRODUCT_NAME = SQLCipher; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALID_ARCHS = "arm64 armv7 armv7s"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + 4C00419F1BFC382500ED2AD5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + BITCODE_GENERATION_MODE = bitcode; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = macosx/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = ( + "-DSQLITE_HAS_CODEC", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE", + "-DSQLCIPHER_CRYPTO_CC", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; + PRODUCT_NAME = SQLCipher; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + TARGETED_DEVICE_FAMILY = "1,2"; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALIDATE_PRODUCT = YES; + VALID_ARCHS = "arm64 armv7 armv7s"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; 9069D08C0FCE185A0042E34C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -346,6 +566,14 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 4C00419D1BFC382500ED2AD5 /* Build configuration list for PBXNativeTarget "SQLCipher iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4C00419E1BFC382500ED2AD5 /* Debug */, + 4C00419F1BFC382500ED2AD5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; 9069D0900FCE18970042E34C /* Build configuration list for PBXAggregateTarget "amalgamation" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher iOS.xcscheme b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher iOS.xcscheme new file mode 100644 index 0000000..a988b2b --- /dev/null +++ b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher iOS.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a2d461cd6d6693402d48d20d47a8e9d206ce7eb0 Mon Sep 17 00:00:00 2001 From: Christian Noon Date: Tue, 17 Nov 2015 20:57:18 -0800 Subject: [PATCH 44/59] Added a new OSX framework target for OS X 10.9+. --- sqlcipher.xcodeproj/project.pbxproj | 229 +++++++++++++++++- .../xcschemes/SQLCipher OSX.xcscheme | 80 ++++++ 2 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher OSX.xcscheme diff --git a/sqlcipher.xcodeproj/project.pbxproj b/sqlcipher.xcodeproj/project.pbxproj index cd79669..6d8dbdc 100644 --- a/sqlcipher.xcodeproj/project.pbxproj +++ b/sqlcipher.xcodeproj/project.pbxproj @@ -23,6 +23,9 @@ /* Begin PBXBuildFile section */ 4C0041A61BFC3A5000ED2AD5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C0041A51BFC3A5000ED2AD5 /* Security.framework */; }; 4C0041AB1BFC3A7E00ED2AD5 /* SQLCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C0041B41BFC3B2200ED2AD5 /* SQLCipher OSX.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041B31BFC3B2200ED2AD5 /* SQLCipher OSX.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C0041BC1BFC3C7500ED2AD5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C0041BB1BFC3C7500ED2AD5 /* Security.framework */; }; + 4C0041BD1BFC3C8300ED2AD5 /* SQLCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9069D0A30FCE1A4D0042E34C /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 9069D0A20FCE1A4D0042E34C /* sqlite3.c */; }; /* End PBXBuildFile section */ @@ -41,6 +44,13 @@ remoteGlobalIDString = 9069D08B0FCE185A0042E34C; remoteInfo = amalgamation; }; + 4C0041B91BFC3C6E00ED2AD5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9069D08B0FCE185A0042E34C; + remoteInfo = amalgamation; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -48,6 +58,10 @@ 4C0041A51BFC3A5000ED2AD5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 4C0041A81BFC3A7E00ED2AD5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = macosx/Info.plist; sourceTree = ""; }; 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SQLCipher.h; path = macosx/SQLCipher.h; sourceTree = ""; }; + 4C0041B11BFC3B2200ED2AD5 /* SQLCipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLCipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4C0041B31BFC3B2200ED2AD5 /* SQLCipher OSX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SQLCipher OSX.h"; sourceTree = ""; }; + 4C0041B51BFC3B2200ED2AD5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 4C0041BB1BFC3C7500ED2AD5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; 9069D0A20FCE1A4D0042E34C /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sqlite3.c; sourceTree = ""; }; D2AAC046055464E500DB518D /* libsqlcipher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsqlcipher.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -60,6 +74,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4C0041AD1BFC3B2200ED2AD5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C0041BC1BFC3C7500ED2AD5 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D289987405E68DCB004EDB86 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -76,6 +98,7 @@ children = ( 08FB7795FE84155DC02AAC07 /* Source */, 4C0041A41BFC3A3800ED2AD5 /* Supporting Files */, + 4C0041B21BFC3B2200ED2AD5 /* SQLCipher OSX */, 4C0041A71BFC3A5400ED2AD5 /* Frameworks */, 1AB674ADFE9D54B511CA2CBB /* Products */, ); @@ -95,6 +118,7 @@ children = ( D2AAC046055464E500DB518D /* libsqlcipher.a */, 4C0041981BFC382400ED2AD5 /* SQLCipher.framework */, + 4C0041B11BFC3B2200ED2AD5 /* SQLCipher.framework */, ); name = Products; sourceTree = ""; @@ -111,11 +135,21 @@ 4C0041A71BFC3A5400ED2AD5 /* Frameworks */ = { isa = PBXGroup; children = ( + 4C0041BB1BFC3C7500ED2AD5 /* Security.framework */, 4C0041A51BFC3A5000ED2AD5 /* Security.framework */, ); name = Frameworks; sourceTree = ""; }; + 4C0041B21BFC3B2200ED2AD5 /* SQLCipher OSX */ = { + isa = PBXGroup; + children = ( + 4C0041B31BFC3B2200ED2AD5 /* SQLCipher OSX.h */, + 4C0041B51BFC3B2200ED2AD5 /* Info.plist */, + ); + path = "SQLCipher OSX"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -127,6 +161,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4C0041AE1BFC3B2200ED2AD5 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C0041BD1BFC3C8300ED2AD5 /* SQLCipher.h in Headers */, + 4C0041B41BFC3B2200ED2AD5 /* SQLCipher OSX.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D2AAC043055464E500DB518D /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -156,6 +199,25 @@ productReference = 4C0041981BFC382400ED2AD5 /* SQLCipher.framework */; productType = "com.apple.product-type.framework"; }; + 4C0041B01BFC3B2200ED2AD5 /* SQLCipher OSX */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4C0041B61BFC3B2200ED2AD5 /* Build configuration list for PBXNativeTarget "SQLCipher OSX" */; + buildPhases = ( + 4C0041AC1BFC3B2200ED2AD5 /* Sources */, + 4C0041AD1BFC3B2200ED2AD5 /* Frameworks */, + 4C0041AE1BFC3B2200ED2AD5 /* Headers */, + 4C0041AF1BFC3B2200ED2AD5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 4C0041BA1BFC3C6E00ED2AD5 /* PBXTargetDependency */, + ); + name = "SQLCipher OSX"; + productName = "SQLCipher OSX"; + productReference = 4C0041B11BFC3B2200ED2AD5 /* SQLCipher.framework */; + productType = "com.apple.product-type.framework"; + }; D2AAC045055464E500DB518D /* sqlcipher */ = { isa = PBXNativeTarget; buildConfigurationList = 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "sqlcipher" */; @@ -185,6 +247,9 @@ 4C0041971BFC382400ED2AD5 = { CreatedOnToolsVersion = 7.1; }; + 4C0041B01BFC3B2200ED2AD5 = { + CreatedOnToolsVersion = 7.1; + }; }; }; buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "sqlcipher" */; @@ -202,6 +267,7 @@ projectRoot = ""; targets = ( 4C0041971BFC382400ED2AD5 /* SQLCipher iOS */, + 4C0041B01BFC3B2200ED2AD5 /* SQLCipher OSX */, D2AAC045055464E500DB518D /* sqlcipher */, 9069D08B0FCE185A0042E34C /* amalgamation */, ); @@ -216,6 +282,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4C0041AF1BFC3B2200ED2AD5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -243,6 +316,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4C0041AC1BFC3B2200ED2AD5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D2AAC044055464E500DB518D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -264,6 +344,11 @@ target = 9069D08B0FCE185A0042E34C /* amalgamation */; targetProxy = 4C0041A11BFC392D00ED2AD5 /* PBXContainerItemProxy */; }; + 4C0041BA1BFC3C6E00ED2AD5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 9069D08B0FCE185A0042E34C /* amalgamation */; + targetProxy = 4C0041B91BFC3C6E00ED2AD5 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -388,7 +473,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; BITCODE_GENERATION_MODE = marker; @@ -519,6 +603,141 @@ }; name = Release; }; + 4C0041B71BFC3B2200ED2AD5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + BITCODE_GENERATION_MODE = marker; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_VERSION = A; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = macosx/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_CFLAGS = ( + "-DSQLITE_HAS_CODEC", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE", + "-DSQLCIPHER_CRYPTO_CC", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; + PRODUCT_NAME = SQLCipher; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALID_ARCHS = "i386 x86_64"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + 4C0041B81BFC3B2200ED2AD5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + BITCODE_GENERATION_MODE = bitcode; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_VERSION = A; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = macosx/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = ( + "-DSQLITE_HAS_CODEC", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE", + "-DSQLCIPHER_CRYPTO_CC", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; + PRODUCT_NAME = SQLCipher; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = macosx; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALID_ARCHS = "i386 x86_64"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; 9069D08C0FCE185A0042E34C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -574,6 +793,14 @@ ); defaultConfigurationIsVisible = 0; }; + 4C0041B61BFC3B2200ED2AD5 /* Build configuration list for PBXNativeTarget "SQLCipher OSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4C0041B71BFC3B2200ED2AD5 /* Debug */, + 4C0041B81BFC3B2200ED2AD5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; 9069D0900FCE18970042E34C /* Build configuration list for PBXAggregateTarget "amalgamation" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher OSX.xcscheme b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher OSX.xcscheme new file mode 100644 index 0000000..9b69b15 --- /dev/null +++ b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher OSX.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 71691b6a1ccd2a7ae2d0fa8f03ad822ae6aaac9e Mon Sep 17 00:00:00 2001 From: Christian Noon Date: Tue, 17 Nov 2015 21:03:22 -0800 Subject: [PATCH 45/59] Created a new tvOS framework target supporting tvOS 9.0+. --- macosx/Info-tvOS.plist | 30 +++ sqlcipher.xcodeproj/project.pbxproj | 221 ++++++++++++++++-- .../xcschemes/SQLCipher OSX.xcscheme | 6 +- .../xcschemes/SQLCipher tvOS.xcscheme | 80 +++++++ 4 files changed, 320 insertions(+), 17 deletions(-) create mode 100644 macosx/Info-tvOS.plist create mode 100644 sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher tvOS.xcscheme diff --git a/macosx/Info-tvOS.plist b/macosx/Info-tvOS.plist new file mode 100644 index 0000000..5234c89 --- /dev/null +++ b/macosx/Info-tvOS.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 3.3.1 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + UIRequiredDeviceCapabilities + + arm64 + + + diff --git a/sqlcipher.xcodeproj/project.pbxproj b/sqlcipher.xcodeproj/project.pbxproj index 6d8dbdc..6e92c21 100644 --- a/sqlcipher.xcodeproj/project.pbxproj +++ b/sqlcipher.xcodeproj/project.pbxproj @@ -23,9 +23,10 @@ /* Begin PBXBuildFile section */ 4C0041A61BFC3A5000ED2AD5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C0041A51BFC3A5000ED2AD5 /* Security.framework */; }; 4C0041AB1BFC3A7E00ED2AD5 /* SQLCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4C0041B41BFC3B2200ED2AD5 /* SQLCipher OSX.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041B31BFC3B2200ED2AD5 /* SQLCipher OSX.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4C0041BC1BFC3C7500ED2AD5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C0041BB1BFC3C7500ED2AD5 /* Security.framework */; }; 4C0041BD1BFC3C8300ED2AD5 /* SQLCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C0041CE1BFC3D3900ED2AD5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C0041CD1BFC3D3900ED2AD5 /* Security.framework */; }; + 4C0041CF1BFC3D4000ED2AD5 /* SQLCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9069D0A30FCE1A4D0042E34C /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 9069D0A20FCE1A4D0042E34C /* sqlite3.c */; }; /* End PBXBuildFile section */ @@ -51,6 +52,13 @@ remoteGlobalIDString = 9069D08B0FCE185A0042E34C; remoteInfo = amalgamation; }; + 4C0041CB1BFC3D3000ED2AD5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9069D08B0FCE185A0042E34C; + remoteInfo = amalgamation; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -59,9 +67,10 @@ 4C0041A81BFC3A7E00ED2AD5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = macosx/Info.plist; sourceTree = ""; }; 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SQLCipher.h; path = macosx/SQLCipher.h; sourceTree = ""; }; 4C0041B11BFC3B2200ED2AD5 /* SQLCipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLCipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 4C0041B31BFC3B2200ED2AD5 /* SQLCipher OSX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SQLCipher OSX.h"; sourceTree = ""; }; - 4C0041B51BFC3B2200ED2AD5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4C0041BB1BFC3C7500ED2AD5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + 4C0041C31BFC3CC000ED2AD5 /* SQLCipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLCipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4C0041CD1BFC3D3900ED2AD5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + 4C0041D01BFC3D9A00ED2AD5 /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-tvOS.plist"; path = "macosx/Info-tvOS.plist"; sourceTree = ""; }; 9069D0A20FCE1A4D0042E34C /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sqlite3.c; sourceTree = ""; }; D2AAC046055464E500DB518D /* libsqlcipher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsqlcipher.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -82,6 +91,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4C0041BF1BFC3CC000ED2AD5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C0041CE1BFC3D3900ED2AD5 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D289987405E68DCB004EDB86 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -98,7 +115,6 @@ children = ( 08FB7795FE84155DC02AAC07 /* Source */, 4C0041A41BFC3A3800ED2AD5 /* Supporting Files */, - 4C0041B21BFC3B2200ED2AD5 /* SQLCipher OSX */, 4C0041A71BFC3A5400ED2AD5 /* Frameworks */, 1AB674ADFE9D54B511CA2CBB /* Products */, ); @@ -119,6 +135,7 @@ D2AAC046055464E500DB518D /* libsqlcipher.a */, 4C0041981BFC382400ED2AD5 /* SQLCipher.framework */, 4C0041B11BFC3B2200ED2AD5 /* SQLCipher.framework */, + 4C0041C31BFC3CC000ED2AD5 /* SQLCipher.framework */, ); name = Products; sourceTree = ""; @@ -128,6 +145,7 @@ children = ( 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */, 4C0041A81BFC3A7E00ED2AD5 /* Info.plist */, + 4C0041D01BFC3D9A00ED2AD5 /* Info-tvOS.plist */, ); name = "Supporting Files"; sourceTree = ""; @@ -135,21 +153,13 @@ 4C0041A71BFC3A5400ED2AD5 /* Frameworks */ = { isa = PBXGroup; children = ( + 4C0041CD1BFC3D3900ED2AD5 /* Security.framework */, 4C0041BB1BFC3C7500ED2AD5 /* Security.framework */, 4C0041A51BFC3A5000ED2AD5 /* Security.framework */, ); name = Frameworks; sourceTree = ""; }; - 4C0041B21BFC3B2200ED2AD5 /* SQLCipher OSX */ = { - isa = PBXGroup; - children = ( - 4C0041B31BFC3B2200ED2AD5 /* SQLCipher OSX.h */, - 4C0041B51BFC3B2200ED2AD5 /* Info.plist */, - ); - path = "SQLCipher OSX"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -166,7 +176,14 @@ buildActionMask = 2147483647; files = ( 4C0041BD1BFC3C8300ED2AD5 /* SQLCipher.h in Headers */, - 4C0041B41BFC3B2200ED2AD5 /* SQLCipher OSX.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4C0041C01BFC3CC000ED2AD5 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C0041CF1BFC3D4000ED2AD5 /* SQLCipher.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -218,6 +235,25 @@ productReference = 4C0041B11BFC3B2200ED2AD5 /* SQLCipher.framework */; productType = "com.apple.product-type.framework"; }; + 4C0041C21BFC3CC000ED2AD5 /* SQLCipher tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4C0041C81BFC3CC000ED2AD5 /* Build configuration list for PBXNativeTarget "SQLCipher tvOS" */; + buildPhases = ( + 4C0041BE1BFC3CC000ED2AD5 /* Sources */, + 4C0041BF1BFC3CC000ED2AD5 /* Frameworks */, + 4C0041C01BFC3CC000ED2AD5 /* Headers */, + 4C0041C11BFC3CC000ED2AD5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 4C0041CC1BFC3D3000ED2AD5 /* PBXTargetDependency */, + ); + name = "SQLCipher tvOS"; + productName = "SQLCipher tvOS"; + productReference = 4C0041C31BFC3CC000ED2AD5 /* SQLCipher.framework */; + productType = "com.apple.product-type.framework"; + }; D2AAC045055464E500DB518D /* sqlcipher */ = { isa = PBXNativeTarget; buildConfigurationList = 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "sqlcipher" */; @@ -250,6 +286,9 @@ 4C0041B01BFC3B2200ED2AD5 = { CreatedOnToolsVersion = 7.1; }; + 4C0041C21BFC3CC000ED2AD5 = { + CreatedOnToolsVersion = 7.1; + }; }; }; buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "sqlcipher" */; @@ -268,6 +307,7 @@ targets = ( 4C0041971BFC382400ED2AD5 /* SQLCipher iOS */, 4C0041B01BFC3B2200ED2AD5 /* SQLCipher OSX */, + 4C0041C21BFC3CC000ED2AD5 /* SQLCipher tvOS */, D2AAC045055464E500DB518D /* sqlcipher */, 9069D08B0FCE185A0042E34C /* amalgamation */, ); @@ -289,6 +329,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4C0041C11BFC3CC000ED2AD5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -323,6 +370,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4C0041BE1BFC3CC000ED2AD5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D2AAC044055464E500DB518D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -349,6 +403,11 @@ target = 9069D08B0FCE185A0042E34C /* amalgamation */; targetProxy = 4C0041B91BFC3C6E00ED2AD5 /* PBXContainerItemProxy */; }; + 4C0041CC1BFC3D3000ED2AD5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 9069D08B0FCE185A0042E34C /* amalgamation */; + targetProxy = 4C0041CB1BFC3D3000ED2AD5 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -738,6 +797,132 @@ }; name = Release; }; + 4C0041C91BFC3CC000ED2AD5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + BITCODE_GENERATION_MODE = marker; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = "macosx/Info-tvOS.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_CFLAGS = ( + "-DSQLITE_HAS_CODEC", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE", + "-DSQLCIPHER_CRYPTO_CC", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; + PRODUCT_NAME = SQLCipher; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "appletvsimulator appletvos"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALID_ARCHS = arm64; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 4C0041CA1BFC3CC000ED2AD5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + BITCODE_GENERATION_MODE = bitcode; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = "macosx/Info-tvOS.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = ( + "-DSQLITE_HAS_CODEC", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE", + "-DSQLCIPHER_CRYPTO_CC", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; + PRODUCT_NAME = SQLCipher; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "appletvsimulator appletvos"; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALIDATE_PRODUCT = YES; + VALID_ARCHS = arm64; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; 9069D08C0FCE185A0042E34C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -801,6 +986,14 @@ ); defaultConfigurationIsVisible = 0; }; + 4C0041C81BFC3CC000ED2AD5 /* Build configuration list for PBXNativeTarget "SQLCipher tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4C0041C91BFC3CC000ED2AD5 /* Debug */, + 4C0041CA1BFC3CC000ED2AD5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; 9069D0900FCE18970042E34C /* Build configuration list for PBXAggregateTarget "amalgamation" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher OSX.xcscheme b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher OSX.xcscheme index 9b69b15..a1b6956 100644 --- a/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher OSX.xcscheme +++ b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher OSX.xcscheme @@ -15,7 +15,7 @@ @@ -46,7 +46,7 @@ @@ -64,7 +64,7 @@ diff --git a/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher tvOS.xcscheme b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher tvOS.xcscheme new file mode 100644 index 0000000..64430e2 --- /dev/null +++ b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher tvOS.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1372da7f603c99ac2509c2d9a3e41ff66e100b0c Mon Sep 17 00:00:00 2001 From: Christian Noon Date: Tue, 17 Nov 2015 21:09:56 -0800 Subject: [PATCH 46/59] Created a new watchOS framework target supporting watchOS 2.0+. --- sqlcipher.xcodeproj/project.pbxproj | 219 ++++++++++++++++++ .../xcschemes/SQLCipher tvOS.xcscheme | 6 +- .../xcschemes/SQLCipher watchOS.xcscheme | 80 +++++++ 3 files changed, 302 insertions(+), 3 deletions(-) create mode 100644 sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher watchOS.xcscheme diff --git a/sqlcipher.xcodeproj/project.pbxproj b/sqlcipher.xcodeproj/project.pbxproj index 6e92c21..5cbe282 100644 --- a/sqlcipher.xcodeproj/project.pbxproj +++ b/sqlcipher.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 4C0041BD1BFC3C8300ED2AD5 /* SQLCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4C0041CE1BFC3D3900ED2AD5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C0041CD1BFC3D3900ED2AD5 /* Security.framework */; }; 4C0041CF1BFC3D4000ED2AD5 /* SQLCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C0041E11BFC3F0800ED2AD5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C0041E01BFC3F0800ED2AD5 /* Security.framework */; }; + 4C0041E21BFC3F5A00ED2AD5 /* SQLCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9069D0A30FCE1A4D0042E34C /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 9069D0A20FCE1A4D0042E34C /* sqlite3.c */; }; /* End PBXBuildFile section */ @@ -59,6 +61,13 @@ remoteGlobalIDString = 9069D08B0FCE185A0042E34C; remoteInfo = amalgamation; }; + 4C0041DE1BFC3F0100ED2AD5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9069D08B0FCE185A0042E34C; + remoteInfo = amalgamation; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -71,6 +80,8 @@ 4C0041C31BFC3CC000ED2AD5 /* SQLCipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLCipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4C0041CD1BFC3D3900ED2AD5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; 4C0041D01BFC3D9A00ED2AD5 /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-tvOS.plist"; path = "macosx/Info-tvOS.plist"; sourceTree = ""; }; + 4C0041D61BFC3E2500ED2AD5 /* SQLCipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLCipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4C0041E01BFC3F0800ED2AD5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS2.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; 9069D0A20FCE1A4D0042E34C /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sqlite3.c; sourceTree = ""; }; D2AAC046055464E500DB518D /* libsqlcipher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsqlcipher.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -99,6 +110,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4C0041D21BFC3E2500ED2AD5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C0041E11BFC3F0800ED2AD5 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D289987405E68DCB004EDB86 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -136,6 +155,7 @@ 4C0041981BFC382400ED2AD5 /* SQLCipher.framework */, 4C0041B11BFC3B2200ED2AD5 /* SQLCipher.framework */, 4C0041C31BFC3CC000ED2AD5 /* SQLCipher.framework */, + 4C0041D61BFC3E2500ED2AD5 /* SQLCipher.framework */, ); name = Products; sourceTree = ""; @@ -153,6 +173,7 @@ 4C0041A71BFC3A5400ED2AD5 /* Frameworks */ = { isa = PBXGroup; children = ( + 4C0041E01BFC3F0800ED2AD5 /* Security.framework */, 4C0041CD1BFC3D3900ED2AD5 /* Security.framework */, 4C0041BB1BFC3C7500ED2AD5 /* Security.framework */, 4C0041A51BFC3A5000ED2AD5 /* Security.framework */, @@ -187,6 +208,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4C0041D31BFC3E2500ED2AD5 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C0041E21BFC3F5A00ED2AD5 /* SQLCipher.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D2AAC043055464E500DB518D /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -254,6 +283,25 @@ productReference = 4C0041C31BFC3CC000ED2AD5 /* SQLCipher.framework */; productType = "com.apple.product-type.framework"; }; + 4C0041D51BFC3E2500ED2AD5 /* SQLCipher watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4C0041DB1BFC3E2600ED2AD5 /* Build configuration list for PBXNativeTarget "SQLCipher watchOS" */; + buildPhases = ( + 4C0041D11BFC3E2500ED2AD5 /* Sources */, + 4C0041D21BFC3E2500ED2AD5 /* Frameworks */, + 4C0041D31BFC3E2500ED2AD5 /* Headers */, + 4C0041D41BFC3E2500ED2AD5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 4C0041DF1BFC3F0100ED2AD5 /* PBXTargetDependency */, + ); + name = "SQLCipher watchOS"; + productName = SQLCipher; + productReference = 4C0041D61BFC3E2500ED2AD5 /* SQLCipher.framework */; + productType = "com.apple.product-type.framework"; + }; D2AAC045055464E500DB518D /* sqlcipher */ = { isa = PBXNativeTarget; buildConfigurationList = 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "sqlcipher" */; @@ -289,6 +337,9 @@ 4C0041C21BFC3CC000ED2AD5 = { CreatedOnToolsVersion = 7.1; }; + 4C0041D51BFC3E2500ED2AD5 = { + CreatedOnToolsVersion = 7.1; + }; }; }; buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "sqlcipher" */; @@ -308,6 +359,7 @@ 4C0041971BFC382400ED2AD5 /* SQLCipher iOS */, 4C0041B01BFC3B2200ED2AD5 /* SQLCipher OSX */, 4C0041C21BFC3CC000ED2AD5 /* SQLCipher tvOS */, + 4C0041D51BFC3E2500ED2AD5 /* SQLCipher watchOS */, D2AAC045055464E500DB518D /* sqlcipher */, 9069D08B0FCE185A0042E34C /* amalgamation */, ); @@ -336,6 +388,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4C0041D41BFC3E2500ED2AD5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -377,6 +436,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4C0041D11BFC3E2500ED2AD5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D2AAC044055464E500DB518D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -408,6 +474,11 @@ target = 9069D08B0FCE185A0042E34C /* amalgamation */; targetProxy = 4C0041CB1BFC3D3000ED2AD5 /* PBXContainerItemProxy */; }; + 4C0041DF1BFC3F0100ED2AD5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 9069D08B0FCE185A0042E34C /* amalgamation */; + targetProxy = 4C0041DE1BFC3F0100ED2AD5 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -840,7 +911,9 @@ GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = "macosx/Info-tvOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = YES; OTHER_CFLAGS = ( "-DSQLITE_HAS_CODEC", @@ -859,6 +932,7 @@ VALID_ARCHS = arm64; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Debug; }; @@ -901,7 +975,9 @@ GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = "macosx/Info-tvOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; OTHER_CFLAGS = ( "-DSQLITE_HAS_CODEC", @@ -920,6 +996,141 @@ VALID_ARCHS = arm64; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; + 4C0041DC1BFC3E2600ED2AD5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + BITCODE_GENERATION_MODE = marker; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = macosx/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_CFLAGS = ( + "-DSQLITE_HAS_CODEC", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE", + "-DSQLCIPHER_CRYPTO_CC", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; + PRODUCT_NAME = SQLCipher; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "watchsimulator watchos"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = 4; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALID_ARCHS = armv7k; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + 4C0041DD1BFC3E2600ED2AD5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + "ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD)"; + BITCODE_GENERATION_MODE = bitcode; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = macosx/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = ( + "-DSQLITE_HAS_CODEC", + "-DSQLITE_TEMP_STORE=2", + "-DSQLITE_THREADSAFE", + "-DSQLCIPHER_CRYPTO_CC", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; + PRODUCT_NAME = SQLCipher; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "watchsimulator watchos"; + TARGETED_DEVICE_FAMILY = 4; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALIDATE_PRODUCT = YES; + VALID_ARCHS = armv7k; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Release; }; @@ -994,6 +1205,14 @@ ); defaultConfigurationIsVisible = 0; }; + 4C0041DB1BFC3E2600ED2AD5 /* Build configuration list for PBXNativeTarget "SQLCipher watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4C0041DC1BFC3E2600ED2AD5 /* Debug */, + 4C0041DD1BFC3E2600ED2AD5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; 9069D0900FCE18970042E34C /* Build configuration list for PBXAggregateTarget "amalgamation" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher tvOS.xcscheme b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher tvOS.xcscheme index 64430e2..9104d67 100644 --- a/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher tvOS.xcscheme +++ b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher tvOS.xcscheme @@ -15,7 +15,7 @@ @@ -46,7 +46,7 @@ @@ -64,7 +64,7 @@ diff --git a/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher watchOS.xcscheme b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher watchOS.xcscheme new file mode 100644 index 0000000..c0058e9 --- /dev/null +++ b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher watchOS.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 09b03f1646130a1582954dcf6c797b22afc492d1 Mon Sep 17 00:00:00 2001 From: Christian Noon Date: Tue, 17 Nov 2015 21:28:53 -0800 Subject: [PATCH 47/59] Updated buildable name in watchOS scheme to latest version. --- .../xcshareddata/xcschemes/SQLCipher watchOS.xcscheme | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher watchOS.xcscheme b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher watchOS.xcscheme index c0058e9..db6e6d9 100644 --- a/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher watchOS.xcscheme +++ b/sqlcipher.xcodeproj/xcshareddata/xcschemes/SQLCipher watchOS.xcscheme @@ -15,7 +15,7 @@ @@ -46,7 +46,7 @@ @@ -64,7 +64,7 @@ From f4595d3e5ffe386bb0033a0e80b8135f993b4d12 Mon Sep 17 00:00:00 2001 From: Christian Noon Date: Tue, 17 Nov 2015 22:10:00 -0800 Subject: [PATCH 48/59] Fixed build related issues with included files and umbrella header. Resolved the following: - Added sqlite3.h to the project to be copied in framework bundle - Added sqlite3.c to all the framework targets to be compiled - Added sqlite3.h to umbrella header - Added clang warning suppression to compile without warnings --- macosx/SQLCipher.h | 2 + sqlcipher.xcodeproj/project.pbxproj | 84 +++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/macosx/SQLCipher.h b/macosx/SQLCipher.h index d43dd88..1023799 100644 --- a/macosx/SQLCipher.h +++ b/macosx/SQLCipher.h @@ -3,3 +3,5 @@ FOUNDATION_EXPORT double SQLCipherVersionNumber; FOUNDATION_EXPORT const unsigned char SQLCipherVersionString[]; + +#import "sqlite3.h" diff --git a/sqlcipher.xcodeproj/project.pbxproj b/sqlcipher.xcodeproj/project.pbxproj index 5cbe282..b15edcc 100644 --- a/sqlcipher.xcodeproj/project.pbxproj +++ b/sqlcipher.xcodeproj/project.pbxproj @@ -29,6 +29,14 @@ 4C0041CF1BFC3D4000ED2AD5 /* SQLCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4C0041E11BFC3F0800ED2AD5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C0041E01BFC3F0800ED2AD5 /* Security.framework */; }; 4C0041E21BFC3F5A00ED2AD5 /* SQLCipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041A91BFC3A7E00ED2AD5 /* SQLCipher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C0041FA1BFC46A600ED2AD5 /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041F91BFC46A600ED2AD5 /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C0041FB1BFC46A600ED2AD5 /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041F91BFC46A600ED2AD5 /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C0041FC1BFC46A600ED2AD5 /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041F91BFC46A600ED2AD5 /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C0041FD1BFC46A600ED2AD5 /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0041F91BFC46A600ED2AD5 /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C0041FE1BFC474700ED2AD5 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 9069D0A20FCE1A4D0042E34C /* sqlite3.c */; }; + 4C0041FF1BFC474700ED2AD5 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 9069D0A20FCE1A4D0042E34C /* sqlite3.c */; }; + 4C0042001BFC474700ED2AD5 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 9069D0A20FCE1A4D0042E34C /* sqlite3.c */; }; + 4C0042011BFC474800ED2AD5 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 9069D0A20FCE1A4D0042E34C /* sqlite3.c */; }; 9069D0A30FCE1A4D0042E34C /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 9069D0A20FCE1A4D0042E34C /* sqlite3.c */; }; /* End PBXBuildFile section */ @@ -82,6 +90,7 @@ 4C0041D01BFC3D9A00ED2AD5 /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-tvOS.plist"; path = "macosx/Info-tvOS.plist"; sourceTree = ""; }; 4C0041D61BFC3E2500ED2AD5 /* SQLCipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLCipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4C0041E01BFC3F0800ED2AD5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS2.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + 4C0041F91BFC46A600ED2AD5 /* sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqlite3.h; sourceTree = ""; }; 9069D0A20FCE1A4D0042E34C /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sqlite3.c; sourceTree = ""; }; D2AAC046055464E500DB518D /* libsqlcipher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsqlcipher.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -144,6 +153,7 @@ isa = PBXGroup; children = ( 9069D0A20FCE1A4D0042E34C /* sqlite3.c */, + 4C0041F91BFC46A600ED2AD5 /* sqlite3.h */, ); name = Source; sourceTree = ""; @@ -188,6 +198,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 4C0041FA1BFC46A600ED2AD5 /* sqlite3.h in Headers */, 4C0041AB1BFC3A7E00ED2AD5 /* SQLCipher.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -196,6 +207,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 4C0041FB1BFC46A600ED2AD5 /* sqlite3.h in Headers */, 4C0041BD1BFC3C8300ED2AD5 /* SQLCipher.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -204,6 +216,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 4C0041FC1BFC46A600ED2AD5 /* sqlite3.h in Headers */, 4C0041CF1BFC3D4000ED2AD5 /* SQLCipher.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -212,6 +225,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 4C0041FD1BFC46A600ED2AD5 /* sqlite3.h in Headers */, 4C0041E21BFC3F5A00ED2AD5 /* SQLCipher.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -419,6 +433,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4C0041FE1BFC474700ED2AD5 /* sqlite3.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -426,6 +441,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4C0041FF1BFC474700ED2AD5 /* sqlite3.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -433,6 +449,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4C0042001BFC474700ED2AD5 /* sqlite3.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -440,6 +457,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4C0042011BFC474800ED2AD5 /* sqlite3.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -638,10 +656,17 @@ "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; + GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VALUE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = macosx/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; @@ -653,6 +678,12 @@ "-DSQLITE_TEMP_STORE=2", "-DSQLITE_THREADSAFE", "-DSQLCIPHER_CRYPTO_CC", + "-Wno-ambiguous-macro", + "-Wno-#warnings", + "-Wno-conversion", + "-Wno-unused-const-variable", + "-Wno-unused-function", + "-Wno-unreachable-code", ); PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; PRODUCT_NAME = SQLCipher; @@ -703,10 +734,17 @@ GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; + GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VALUE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = macosx/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; @@ -718,6 +756,12 @@ "-DSQLITE_TEMP_STORE=2", "-DSQLITE_THREADSAFE", "-DSQLCIPHER_CRYPTO_CC", + "-Wno-ambiguous-macro", + "-Wno-#warnings", + "-Wno-conversion", + "-Wno-unused-const-variable", + "-Wno-unused-function", + "-Wno-unreachable-code", ); PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; PRODUCT_NAME = SQLCipher; @@ -788,6 +832,12 @@ "-DSQLITE_TEMP_STORE=2", "-DSQLITE_THREADSAFE", "-DSQLCIPHER_CRYPTO_CC", + "-Wno-ambiguous-macro", + "-Wno-#warnings", + "-Wno-conversion", + "-Wno-unused-const-variable", + "-Wno-unused-function", + "-Wno-unreachable-code", ); PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; PRODUCT_NAME = SQLCipher; @@ -854,6 +904,12 @@ "-DSQLITE_TEMP_STORE=2", "-DSQLITE_THREADSAFE", "-DSQLCIPHER_CRYPTO_CC", + "-Wno-ambiguous-macro", + "-Wno-#warnings", + "-Wno-conversion", + "-Wno-unused-const-variable", + "-Wno-unused-function", + "-Wno-unreachable-code", ); PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; PRODUCT_NAME = SQLCipher; @@ -920,6 +976,12 @@ "-DSQLITE_TEMP_STORE=2", "-DSQLITE_THREADSAFE", "-DSQLCIPHER_CRYPTO_CC", + "-Wno-ambiguous-macro", + "-Wno-#warnings", + "-Wno-conversion", + "-Wno-unused-const-variable", + "-Wno-unused-function", + "-Wno-unreachable-code", ); PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; PRODUCT_NAME = SQLCipher; @@ -984,6 +1046,12 @@ "-DSQLITE_TEMP_STORE=2", "-DSQLITE_THREADSAFE", "-DSQLCIPHER_CRYPTO_CC", + "-Wno-ambiguous-macro", + "-Wno-#warnings", + "-Wno-conversion", + "-Wno-unused-const-variable", + "-Wno-unused-function", + "-Wno-unreachable-code", ); PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; PRODUCT_NAME = SQLCipher; @@ -1053,6 +1121,12 @@ "-DSQLITE_TEMP_STORE=2", "-DSQLITE_THREADSAFE", "-DSQLCIPHER_CRYPTO_CC", + "-Wno-ambiguous-macro", + "-Wno-#warnings", + "-Wno-conversion", + "-Wno-unused-const-variable", + "-Wno-unused-function", + "-Wno-unreachable-code", ); PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; PRODUCT_NAME = SQLCipher; @@ -1118,6 +1192,12 @@ "-DSQLITE_TEMP_STORE=2", "-DSQLITE_THREADSAFE", "-DSQLCIPHER_CRYPTO_CC", + "-Wno-ambiguous-macro", + "-Wno-#warnings", + "-Wno-conversion", + "-Wno-unused-const-variable", + "-Wno-unused-function", + "-Wno-unreachable-code", ); PRODUCT_BUNDLE_IDENTIFIER = net.zetetic.SQLCipher; PRODUCT_NAME = SQLCipher; @@ -1188,6 +1268,7 @@ 4C00419F1BFC382500ED2AD5 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 4C0041B61BFC3B2200ED2AD5 /* Build configuration list for PBXNativeTarget "SQLCipher OSX" */ = { isa = XCConfigurationList; @@ -1196,6 +1277,7 @@ 4C0041B81BFC3B2200ED2AD5 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 4C0041C81BFC3CC000ED2AD5 /* Build configuration list for PBXNativeTarget "SQLCipher tvOS" */ = { isa = XCConfigurationList; @@ -1204,6 +1286,7 @@ 4C0041CA1BFC3CC000ED2AD5 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 4C0041DB1BFC3E2600ED2AD5 /* Build configuration list for PBXNativeTarget "SQLCipher watchOS" */ = { isa = XCConfigurationList; @@ -1212,6 +1295,7 @@ 4C0041DD1BFC3E2600ED2AD5 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 9069D0900FCE18970042E34C /* Build configuration list for PBXAggregateTarget "amalgamation" */ = { isa = XCConfigurationList; From f5563904625614a52da075bc7133e9d2e7095612 Mon Sep 17 00:00:00 2001 From: Steve Thomas Date: Wed, 27 Jan 2016 10:53:24 -0600 Subject: [PATCH 49/59] Added cipher_isHex() --- src/crypto.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/crypto.h b/src/crypto.h index b048b49..1148c30 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -160,6 +160,19 @@ static void cipher_bin2hex(const unsigned char* in, int sz, char *out) { } } +static int cipher_isHex(const unsigned char *hex, int sz){ + int i; + for(i = 0; i < sz; i++) { + unsigned char c = hex[i]; + if ((c < '0' || c > '9') && + (c < 'A' || c > 'F') && + (c < 'a' || c > 'f')) { + return 0; + } + } + return 1; +} + /* extensions defined in crypto_impl.c */ typedef struct codec_ctx codec_ctx; From a5d41bf0ade6f69b2fbfb9e79451101e4c236bac Mon Sep 17 00:00:00 2001 From: Steve Thomas Date: Wed, 27 Jan 2016 10:59:39 -0600 Subject: [PATCH 50/59] Validate Hex --- src/crypto_impl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 12fefb8..1e559ee 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -885,12 +885,12 @@ static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) { if(ctx->read_ctx->provider->random(ctx->read_ctx->provider_ctx, ctx->kdf_salt, FILE_HEADER_SZ) != SQLITE_OK) return SQLITE_ERROR; ctx->need_kdf_salt = 0; } - if (c_ctx->pass_sz == ((c_ctx->key_sz * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0) { + if (c_ctx->pass_sz == ((c_ctx->key_sz * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0 && cipher_isHex(c_ctx->pass + 2, c_ctx->key_sz * 2)) { int n = c_ctx->pass_sz - 3; /* adjust for leading x' and tailing ' */ const unsigned char *z = c_ctx->pass + 2; /* adjust lead offset of x' */ CODEC_TRACE(("cipher_ctx_key_derive: using raw key from hex\n")); cipher_hex2bin(z, n, c_ctx->key); - } else if (c_ctx->pass_sz == (((c_ctx->key_sz + ctx->kdf_salt_sz) * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0) { + } else if (c_ctx->pass_sz == (((c_ctx->key_sz + ctx->kdf_salt_sz) * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0 && cipher_isHex(c_ctx->pass + 2, (c_ctx->key_sz + ctx->kdf_salt_sz) * 2)) { const unsigned char *z = c_ctx->pass + 2; /* adjust lead offset of x' */ CODEC_TRACE(("cipher_ctx_key_derive: using raw key from hex\n")); cipher_hex2bin(z, (c_ctx->key_sz * 2), c_ctx->key); From 376eb11e20ea276d46d430b17e809f50d2939468 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 22 Feb 2016 10:40:43 -0600 Subject: [PATCH 51/59] Snapshot of upstream SQLite 3.11.0 --- Makefile.arm-wince-mingw32ce-gcc | 138 - Makefile.in | 232 +- Makefile.linux-gcc | 5 - Makefile.msc | 797 +- Makefile.vxworks | 673 - README.md | 19 +- VERSION | 2 +- addopcodes.awk | 34 - autoconf/Makefile.am | 10 +- autoconf/Makefile.msc | 921 ++ autoconf/README | 32 - autoconf/README.txt | 113 + autoconf/config.guess | 1530 -- autoconf/config.sub | 1773 --- autoconf/configure.ac | 67 +- autoconf/depcomp | 708 - autoconf/install-sh | 527 - autoconf/ltmain.sh | 9655 ------------- autoconf/missing | 331 - autoconf/tea/Makefile.in | 2 +- autoconf/tea/win/nmakehlp.c | 6 +- configure | 420 +- configure.ac | 73 +- ext/async/sqlite3async.c | 16 +- ext/fts1/fts1.c | 6 +- ext/fts1/simple_tokenizer.c | 2 +- ext/fts3/fts3.c | 99 +- ext/fts3/fts3Int.h | 19 +- ext/fts3/fts3_expr.c | 226 +- ext/fts3/fts3_icu.c | 13 +- ext/fts3/fts3_snippet.c | 314 +- ext/fts3/fts3_tokenizer.c | 15 +- ext/fts3/fts3_write.c | 36 +- ext/fts3/tool/fts3view.c | 2 +- ext/fts3/unicode/mkunicode.tcl | 223 +- ext/fts3/unicode/parseunicode.tcl | 146 + ext/fts5/extract_api_docs.tcl | 252 + ext/fts5/fts5.h | 578 + ext/fts5/fts5Int.h | 776 + ext/fts5/fts5_aux.c | 562 + ext/fts5/fts5_buffer.c | 392 + ext/fts5/fts5_config.c | 945 ++ ext/fts5/fts5_expr.c | 2560 ++++ ext/fts5/fts5_hash.c | 527 + ext/fts5/fts5_index.c | 6281 ++++++++ ext/fts5/fts5_main.c | 2710 ++++ ext/fts5/fts5_storage.c | 1125 ++ ext/fts5/fts5_tcl.c | 1150 ++ ext/fts5/fts5_test_mi.c | 424 + ext/fts5/fts5_test_tok.c | 482 + ext/fts5/fts5_tokenize.c | 1242 ++ ext/fts5/fts5_unicode2.c | 360 + ext/fts5/fts5_varint.c | 345 + ext/fts5/fts5_vocab.c | 641 + ext/fts5/fts5parse.y | 184 + ext/fts5/mkportersteps.tcl | 222 + ext/fts5/test/fts5_common.tcl | 642 + ext/fts5/test/fts5aa.test | 562 + ext/fts5/test/fts5ab.test | 297 + ext/fts5/test/fts5ac.test | 279 + ext/fts5/test/fts5ad.test | 245 + ext/fts5/test/fts5ae.test | 312 + ext/fts5/test/fts5af.test | 148 + ext/fts5/test/fts5ag.test | 145 + ext/fts5/test/fts5ah.test | 170 + ext/fts5/test/fts5ai.test | 58 + ext/fts5/test/fts5aj.test | 69 + ext/fts5/test/fts5ak.test | 150 + ext/fts5/test/fts5al.test | 300 + ext/fts5/test/fts5alter.test | 103 + ext/fts5/test/fts5auto.test | 345 + ext/fts5/test/fts5aux.test | 250 + ext/fts5/test/fts5auxdata.test | 115 + ext/fts5/test/fts5bigpl.test | 64 + ext/fts5/test/fts5bigtok.test | 67 + ext/fts5/test/fts5columnsize.test | 151 + ext/fts5/test/fts5config.test | 251 + ext/fts5/test/fts5conflict.test | 70 + ext/fts5/test/fts5content.test | 258 + ext/fts5/test/fts5corrupt.test | 99 + ext/fts5/test/fts5corrupt2.test | 272 + ext/fts5/test/fts5corrupt3.test | 408 + ext/fts5/test/fts5detail.test | 244 + ext/fts5/test/fts5dlidx.test | 200 + ext/fts5/test/fts5doclist.test | 47 + ext/fts5/test/fts5ea.test | 99 + ext/fts5/test/fts5eb.test | 69 + ext/fts5/test/fts5fault1.test | 354 + ext/fts5/test/fts5fault2.test | 140 + ext/fts5/test/fts5fault3.test | 113 + ext/fts5/test/fts5fault4.test | 398 + ext/fts5/test/fts5fault5.test | 133 + ext/fts5/test/fts5fault6.test | 295 + ext/fts5/test/fts5fault7.test | 119 + ext/fts5/test/fts5fault8.test | 60 + ext/fts5/test/fts5fault9.test | 156 + ext/fts5/test/fts5faultA.test | 64 + ext/fts5/test/fts5full.test | 43 + ext/fts5/test/fts5hash.test | 133 + ext/fts5/test/fts5integrity.test | 213 + ext/fts5/test/fts5matchinfo.test | 471 + ext/fts5/test/fts5merge.test | 194 + ext/fts5/test/fts5merge2.test | 59 + ext/fts5/test/fts5near.test | 71 + ext/fts5/test/fts5onepass.test | 181 + ext/fts5/test/fts5optimize.test | 66 + ext/fts5/test/fts5phrase.test | 119 + ext/fts5/test/fts5plan.test | 67 + ext/fts5/test/fts5porter.test | 11806 ++++++++++++++++ ext/fts5/test/fts5porter2.test | 70 + ext/fts5/test/fts5prefix.test | 345 + ext/fts5/test/fts5query.test | 83 + ext/fts5/test/fts5rank.test | 100 + ext/fts5/test/fts5rebuild.test | 67 + ext/fts5/test/fts5restart.test | 152 + ext/fts5/test/fts5rowid.test | 219 + ext/fts5/test/fts5simple.test | 413 + ext/fts5/test/fts5simple2.test | 338 + ext/fts5/test/fts5simple3.test | 85 + ext/fts5/test/fts5synonym.test | 424 + ext/fts5/test/fts5synonym2.test | 164 + ext/fts5/test/fts5tok1.test | 115 + ext/fts5/test/fts5tok2.test | 47 + ext/fts5/test/fts5tokenizer.test | 266 + ext/fts5/test/fts5unicode.test | 62 + ext/fts5/test/fts5unicode2.test | 589 + ext/fts5/test/fts5unicode3.test | 129 + ext/fts5/test/fts5unindexed.test | 79 + ext/fts5/test/fts5update.test | 121 + ext/fts5/test/fts5version.test | 64 + ext/fts5/test/fts5vocab.test | 449 + ext/fts5/tool/fts5speed.tcl | 64 + ext/fts5/tool/fts5txt2db.tcl | 228 + ext/fts5/tool/loadfts5.tcl | 172 + ext/fts5/tool/mkfts5c.tcl | 113 + ext/fts5/tool/showfts5.tcl | 97 + ext/icu/icu.c | 2 +- ext/misc/amatch.c | 4 +- ext/misc/closure.c | 4 +- ext/misc/ieee754.c | 6 +- ext/misc/json1.c | 2192 +++ ext/misc/series.c | 405 + ext/misc/spellfix.c | 205 +- ext/rbu/rbu.c | 124 + ext/rbu/rbu1.test | 680 + ext/rbu/rbu10.test | 188 + ext/rbu/rbu11.test | 198 + ext/rbu/rbu12.test | 235 + ext/rbu/rbu13.test | 65 + ext/rbu/rbu14.test | 95 + ext/rbu/rbu3.test | 207 + ext/rbu/rbu5.test | 331 + ext/rbu/rbu6.test | 103 + ext/rbu/rbu7.test | 110 + ext/rbu/rbu8.test | 75 + ext/rbu/rbu9.test | 128 + ext/rbu/rbuA.test | 84 + ext/rbu/rbuB.test | 62 + ext/rbu/rbu_common.tcl | 38 + ext/rbu/rbucrash.test | 149 + ext/rbu/rbudiff.test | 150 + ext/rbu/rbufault.test | 237 + ext/rbu/rbufault2.test | 58 + ext/rbu/rbufts.test | 134 + ext/rbu/rbusave.test | 105 + ext/rbu/sqlite3rbu.c | 4060 ++++++ ext/rbu/sqlite3rbu.h | 461 + ext/rbu/test_rbu.c | 279 + ext/rtree/rtree.c | 48 +- ext/rtree/rtree1.test | 55 + ext/rtree/rtreeC.test | 83 + ext/rtree/rtreeE.test | 15 +- ext/rtree/sqlite3rtree.h | 2 + main.mk | 251 +- manifest | 851 +- manifest.uuid | 2 +- mkopcodec.awk | 50 - mkopcodeh.awk | 230 - mptest/mptest.c | 79 +- src/alter.c | 48 +- src/analyze.c | 53 +- src/attach.c | 21 +- src/backup.c | 28 +- src/bitvec.c | 12 +- src/btmutex.c | 42 +- src/btree.c | 2063 +-- src/btree.h | 82 +- src/btreeInt.h | 41 +- src/build.c | 631 +- src/callback.c | 14 +- src/complete.c | 2 +- src/ctime.c | 12 + src/date.c | 111 +- src/dbstat.c | 121 +- src/delete.c | 167 +- src/expr.c | 542 +- src/fkey.c | 39 +- src/func.c | 107 +- src/global.c | 7 +- src/insert.c | 357 +- src/legacy.c | 2 +- src/lempar.c | 864 -- src/loadext.c | 14 +- src/main.c | 242 +- src/malloc.c | 318 +- src/mem1.c | 5 +- src/mem3.c | 2 +- src/mem5.c | 54 +- src/mutex.c | 23 +- src/mutex_noop.c | 2 +- src/mutex_unix.c | 23 +- src/mutex_w32.c | 24 + src/os.c | 54 +- src/os_common.h | 28 +- src/os_unix.c | 588 +- src/os_win.c | 61 +- src/pager.c | 570 +- src/pager.h | 32 +- src/parse.y | 209 +- src/pcache.c | 139 +- src/pcache.h | 23 +- src/pcache1.c | 506 +- src/pragma.c | 592 +- src/pragma.h | 87 +- src/prepare.c | 91 +- src/printf.c | 177 +- src/resolve.c | 189 +- src/rowset.c | 2 +- src/select.c | 933 +- src/shell.c | 1009 +- src/sqlite.h.in | 407 +- src/sqlite3.rc | 2 + src/sqlite3ext.h | 31 +- src/sqliteInt.h | 431 +- src/status.c | 40 +- src/tclsqlite.c | 72 +- src/test1.c | 266 +- src/test2.c | 2 +- src/test3.c | 53 +- src/test8.c | 61 +- src/test_config.c | 54 + src/test_fs.c | 589 +- src/test_func.c | 35 +- src/test_loadext.c | 2 +- src/test_malloc.c | 26 +- src/test_multiplex.c | 17 +- src/test_mutex.c | 97 +- src/test_rtree.c | 48 +- src/test_sqllog.c | 81 +- src/test_tclvar.c | 194 +- src/test_windirent.c | 157 + src/test_windirent.h | 105 + src/threads.c | 13 +- src/tokenize.c | 236 +- src/treeview.c | 486 + src/trigger.c | 36 +- src/update.c | 228 +- src/utf.c | 6 +- src/util.c | 53 +- src/vdbe.c | 1116 +- src/vdbe.h | 23 +- src/vdbeInt.h | 121 +- src/vdbeapi.c | 153 +- src/vdbeaux.c | 945 +- src/vdbeblob.c | 116 +- src/vdbemem.c | 100 +- src/vdbesort.c | 49 +- src/vdbetrace.c | 14 +- src/vtab.c | 108 +- src/vxworks.h | 3 + src/wal.c | 438 +- src/wal.h | 9 + src/walker.c | 11 +- src/where.c | 3324 +---- src/whereInt.h | 101 +- src/wherecode.c | 1722 +++ src/whereexpr.c | 1359 ++ test/affinity2.test | 61 + test/alter3.test | 12 +- test/analyze3.test | 20 +- test/analyze9.test | 3 - test/analyzeB.test | 1 - test/analyzeD.test | 1 - test/analyzeF.test | 5 +- test/analyzer1.test | 52 + test/atof1.test | 2 +- test/autoindex5.test | 129 + test/bc_common.tcl | 4 +- test/cacheflush.test | 323 + test/capi3c.test | 23 + test/capi3d.test | 4 +- test/cffault.test | 158 + test/check.test | 20 + test/collate4.test | 8 +- test/conflict2.test | 8 +- test/corrupt2.test | 49 +- test/corrupt7.test | 49 +- test/corruptC.test | 5 + test/corruptE.test | 46 +- test/corruptH.test | 1 - test/corruptI.test | 154 + test/cost.test | 3 - test/cursorhint.test | 162 + test/date.test | 9 + test/delete.test | 1 - test/delete4.test | 145 + test/distinct.test | 17 + test/e_blobbytes.test | 2 - test/e_blobclose.test | 1 - test/e_blobopen.test | 1 - test/e_blobwrite.test | 1 - test/e_createtable.test | 15 +- test/e_delete.test | 13 +- test/e_expr.test | 8 +- test/e_insert.test | 16 +- test/e_reindex.test | 7 +- test/e_resolve.test | 12 +- test/e_update.test | 16 +- test/e_uri.test | 2 + test/e_walauto.test | 1 - test/e_walckpt.test | 1 - test/enc3.test | 5 +- test/extraquick.test | 16 + test/filectrl.test | 1 - test/fkey1.test | 34 + test/fkey5.test | 4 +- test/fkey8.test | 1 - test/fordelete.test | 209 + test/fts3atoken.test | 110 +- test/fts3conf.test | 43 +- test/fts3d.test | 2 +- test/fts3defer2.test | 6 + test/fts3expr3.test | 32 + test/fts3expr4.test | 1 - test/fts3fault.test | 8 +- test/fts3join.test | 2 - test/fts3matchinfo.test | 39 +- test/fts3offsets.test | 123 + test/fts3query.test | 4 +- test/fts3snippet.test | 1 - test/fts4check.test | 1 - test/fts4content.test | 5 +- test/fts4growth.test | 1 - test/fts4growth2.test | 1 - test/fts4incr.test | 4 +- test/fts4langid.test | 46 +- test/fts4noti.test | 3 - test/fts4onepass.test | 146 + test/fts4unicode.test | 14 +- test/fuzz3.test | 3 + test/fuzzcheck.c | 1188 ++ test/fuzzdata1.db | Bin 0 -> 4398080 bytes test/fuzzdata1.txt | Bin 2966109 -> 0 bytes test/{fuzzdata2.txt => fuzzdata2.db} | Bin 15739506 -> 17021952 bytes test/fuzzdata3.db | Bin 0 -> 11848704 bytes test/fuzzdata4.db | Bin 0 -> 2021376 bytes test/fuzzer1.test | 46 - test/fuzzer2.test | 72 + test/hexlit.test | 3 + test/hidden.test | 153 + test/ieee754.test | 60 + test/in.test | 20 +- test/incrcorrupt.test | 1 - test/index.test | 6 +- test/index2.test | 3 +- test/index3.test | 49 +- test/index5.test | 6 +- test/index6.test | 49 + test/indexedby.test | 6 +- test/indexexpr1.test | 327 + test/join.test | 26 + test/join5.test | 23 + test/json101.test | 360 + test/json102.test | 301 + test/json103.test | 78 + test/like.test | 53 +- test/like3.test | 7 +- test/lookaside.test | 4 +- test/malloc5.test | 37 +- test/mallocK.test | 1 - test/mallocL.test | 1 - test/malloc_common.tcl | 16 +- test/memdb.test | 7 +- test/memsubsys1.test | 9 +- test/memsubsys2.test | 7 +- test/misc1.test | 26 + test/misc4.test | 21 + test/mkfuzzdata1.tcl | 113 - test/mmap1.test | 65 +- test/mmap4.test | 104 + test/mutex1.test | 39 +- test/numindex1.test | 79 + test/offset1.test | 161 + test/orderby1.test | 17 + test/orderby9.test | 62 + test/oserror.test | 4 +- test/ovfl.test | 2 - test/parser1.test | 79 + test/pcache.test | 2 +- test/pcache2.test | 9 +- test/permutations.test | 67 +- test/pragma.test | 47 +- test/pragma2.test | 83 +- test/progress.test | 1 - test/quota.test | 1 + test/rbu.test | 17 + test/releasetest.tcl | 496 +- test/rollback2.test | 1 - test/rollbackfault.test | 2 - test/rowallock.test | 67 + test/rowid.test | 3 + test/{savepoint3.test => savepointfault.test} | 13 +- test/select4.test | 26 + test/select7.test | 18 + test/select8.test | 1 - test/shared3.test | 1 - test/shared4.test | 1 - test/shrink.test | 2 + test/skipscan1.test | 30 + test/snapshot.test | 339 + test/snapshot_fault.test | 164 + test/sort.test | 46 - test/sort2.test | 28 +- test/sort3.test | 52 +- test/sort5.test | 1 - test/speedtest1.c | 76 +- test/spellfix.test | 116 + test/spellfix2.test | 118 + test/spellfix3.test | 43 + test/sqldiff1.test | 65 + test/sqllimits1.test | 17 +- test/sqllog.test | 113 + test/stat.test | 67 + test/subtype1.test | 31 + test/symlink.test | 191 + test/sync.test | 11 +- test/syscall.test | 4 +- test/sysfault.test | 1 + test/tabfunc01.test | 123 + test/table.test | 28 + test/tester.tcl | 281 +- test/threadtest2.c | 2 +- test/threadtest3.c | 70 +- test/tkt-9f2eb3abac.test | 1 - test/tkt-ba7cbfaedc.test | 2 - test/tkt3871.test | 10 +- test/trace.test | 8 + test/transitive1.test | 74 +- test/trigger7.test | 1 - test/triggerE.test | 2 - test/unique2.test | 8 + test/uri.test | 8 + test/view.test | 35 +- test/vtab1.test | 102 +- test/vtab2.test | 9 +- test/vtab4.test | 32 +- test/vtab6.test | 5 + test/vtabE.test | 2 + test/vtabH.test | 202 + test/vtabI.test | 126 + test/vtab_shared.test | 1 - test/wal.test | 104 +- test/wal3.test | 147 +- test/wal6.test | 43 +- test/walcksum.test | 54 - test/walcrash.test | 3 +- test/waloverwrite.test | 162 + test/walprotocol.test | 177 + test/walslow.test | 158 + test/where.test | 50 +- test/where2.test | 9 +- test/where4.test | 40 +- test/where7.test | 12 + test/where8.test | 22 +- test/whereC.test | 1 + test/whereD.test | 67 +- test/whereG.test | 37 + test/whereI.test | 1 - test/{where8m.test => wherefault.test} | 12 +- test/with1.test | 142 + test/with2.test | 4 +- test/with3.test | 64 + test/withM.test | 3 - test/without_rowid1.test | 51 + test/without_rowid3.test | 16 + test/without_rowid5.test | 6 +- test/without_rowid6.test | 4 + test/wordcount.c | 5 +- test/zeroblob.test | 54 +- tool/GetFile.cs | 450 + tool/GetTclKit.bat | 273 + tool/addopcodes.tcl | 63 + tool/build-all-msvc.bat | 84 +- tool/cg_anno.tcl | 24 + tool/diffdb.c | 44 - tool/fuzzershell.c | 35 +- tool/lemon.c | 381 +- tool/lempar.c | 410 +- tool/loadfts.c | 242 + tool/mkautoconfamal.sh | 69 +- tool/mkkeywordhash.c | 63 +- tool/mkmsvcmin.tcl | 98 + tool/mkopcodec.tcl | 50 + tool/mkopcodeh.tcl | 234 + tool/mkpragmatab.tcl | 8 +- tool/mksqlite3c-noext.tcl | 4 + tool/mksqlite3c.tcl | 18 +- tool/mksqlite3h.tcl | 3 +- tool/mkvsix.tcl | 15 +- tool/opcodeDoc.awk | 23 - tool/replace.tcl | 20 + tool/run-speed-test.sh | 68 + tool/showdb.c | 350 +- tool/showjournal.c | 6 +- tool/showstat4.c | 4 +- tool/showwal.c | 7 +- tool/space_used.tcl | 111 - tool/spaceanal.tcl | 59 +- tool/speedtest16.c | 4 +- tool/speedtest8inst1.c | 4 +- tool/sqldiff.c | 693 +- tool/srcck1.c | 158 + tool/tostr.awk | 8 - tool/tostr.tcl | 12 + tool/vdbe_profile.tcl | 8 + tool/warnings.sh | 28 +- 526 files changed, 91752 insertions(+), 28942 deletions(-) delete mode 100644 Makefile.arm-wince-mingw32ce-gcc delete mode 100644 Makefile.vxworks delete mode 100644 addopcodes.awk create mode 100644 autoconf/Makefile.msc delete mode 100644 autoconf/README create mode 100644 autoconf/README.txt delete mode 100755 autoconf/config.guess delete mode 100755 autoconf/config.sub delete mode 100755 autoconf/depcomp delete mode 100755 autoconf/install-sh delete mode 100644 autoconf/ltmain.sh delete mode 100755 autoconf/missing create mode 100644 ext/fts3/unicode/parseunicode.tcl create mode 100644 ext/fts5/extract_api_docs.tcl create mode 100644 ext/fts5/fts5.h create mode 100644 ext/fts5/fts5Int.h create mode 100644 ext/fts5/fts5_aux.c create mode 100644 ext/fts5/fts5_buffer.c create mode 100644 ext/fts5/fts5_config.c create mode 100644 ext/fts5/fts5_expr.c create mode 100644 ext/fts5/fts5_hash.c create mode 100644 ext/fts5/fts5_index.c create mode 100644 ext/fts5/fts5_main.c create mode 100644 ext/fts5/fts5_storage.c create mode 100644 ext/fts5/fts5_tcl.c create mode 100644 ext/fts5/fts5_test_mi.c create mode 100644 ext/fts5/fts5_test_tok.c create mode 100644 ext/fts5/fts5_tokenize.c create mode 100644 ext/fts5/fts5_unicode2.c create mode 100644 ext/fts5/fts5_varint.c create mode 100644 ext/fts5/fts5_vocab.c create mode 100644 ext/fts5/fts5parse.y create mode 100644 ext/fts5/mkportersteps.tcl create mode 100644 ext/fts5/test/fts5_common.tcl create mode 100644 ext/fts5/test/fts5aa.test create mode 100644 ext/fts5/test/fts5ab.test create mode 100644 ext/fts5/test/fts5ac.test create mode 100644 ext/fts5/test/fts5ad.test create mode 100644 ext/fts5/test/fts5ae.test create mode 100644 ext/fts5/test/fts5af.test create mode 100644 ext/fts5/test/fts5ag.test create mode 100644 ext/fts5/test/fts5ah.test create mode 100644 ext/fts5/test/fts5ai.test create mode 100644 ext/fts5/test/fts5aj.test create mode 100644 ext/fts5/test/fts5ak.test create mode 100644 ext/fts5/test/fts5al.test create mode 100644 ext/fts5/test/fts5alter.test create mode 100644 ext/fts5/test/fts5auto.test create mode 100644 ext/fts5/test/fts5aux.test create mode 100644 ext/fts5/test/fts5auxdata.test create mode 100644 ext/fts5/test/fts5bigpl.test create mode 100644 ext/fts5/test/fts5bigtok.test create mode 100644 ext/fts5/test/fts5columnsize.test create mode 100644 ext/fts5/test/fts5config.test create mode 100644 ext/fts5/test/fts5conflict.test create mode 100644 ext/fts5/test/fts5content.test create mode 100644 ext/fts5/test/fts5corrupt.test create mode 100644 ext/fts5/test/fts5corrupt2.test create mode 100644 ext/fts5/test/fts5corrupt3.test create mode 100644 ext/fts5/test/fts5detail.test create mode 100644 ext/fts5/test/fts5dlidx.test create mode 100644 ext/fts5/test/fts5doclist.test create mode 100644 ext/fts5/test/fts5ea.test create mode 100644 ext/fts5/test/fts5eb.test create mode 100644 ext/fts5/test/fts5fault1.test create mode 100644 ext/fts5/test/fts5fault2.test create mode 100644 ext/fts5/test/fts5fault3.test create mode 100644 ext/fts5/test/fts5fault4.test create mode 100644 ext/fts5/test/fts5fault5.test create mode 100644 ext/fts5/test/fts5fault6.test create mode 100644 ext/fts5/test/fts5fault7.test create mode 100644 ext/fts5/test/fts5fault8.test create mode 100644 ext/fts5/test/fts5fault9.test create mode 100644 ext/fts5/test/fts5faultA.test create mode 100644 ext/fts5/test/fts5full.test create mode 100644 ext/fts5/test/fts5hash.test create mode 100644 ext/fts5/test/fts5integrity.test create mode 100644 ext/fts5/test/fts5matchinfo.test create mode 100644 ext/fts5/test/fts5merge.test create mode 100644 ext/fts5/test/fts5merge2.test create mode 100644 ext/fts5/test/fts5near.test create mode 100644 ext/fts5/test/fts5onepass.test create mode 100644 ext/fts5/test/fts5optimize.test create mode 100644 ext/fts5/test/fts5phrase.test create mode 100644 ext/fts5/test/fts5plan.test create mode 100644 ext/fts5/test/fts5porter.test create mode 100644 ext/fts5/test/fts5porter2.test create mode 100644 ext/fts5/test/fts5prefix.test create mode 100644 ext/fts5/test/fts5query.test create mode 100644 ext/fts5/test/fts5rank.test create mode 100644 ext/fts5/test/fts5rebuild.test create mode 100644 ext/fts5/test/fts5restart.test create mode 100644 ext/fts5/test/fts5rowid.test create mode 100644 ext/fts5/test/fts5simple.test create mode 100644 ext/fts5/test/fts5simple2.test create mode 100644 ext/fts5/test/fts5simple3.test create mode 100644 ext/fts5/test/fts5synonym.test create mode 100644 ext/fts5/test/fts5synonym2.test create mode 100644 ext/fts5/test/fts5tok1.test create mode 100644 ext/fts5/test/fts5tok2.test create mode 100644 ext/fts5/test/fts5tokenizer.test create mode 100644 ext/fts5/test/fts5unicode.test create mode 100644 ext/fts5/test/fts5unicode2.test create mode 100644 ext/fts5/test/fts5unicode3.test create mode 100644 ext/fts5/test/fts5unindexed.test create mode 100644 ext/fts5/test/fts5update.test create mode 100644 ext/fts5/test/fts5version.test create mode 100644 ext/fts5/test/fts5vocab.test create mode 100644 ext/fts5/tool/fts5speed.tcl create mode 100644 ext/fts5/tool/fts5txt2db.tcl create mode 100644 ext/fts5/tool/loadfts5.tcl create mode 100644 ext/fts5/tool/mkfts5c.tcl create mode 100644 ext/fts5/tool/showfts5.tcl create mode 100644 ext/misc/json1.c create mode 100644 ext/misc/series.c create mode 100644 ext/rbu/rbu.c create mode 100644 ext/rbu/rbu1.test create mode 100644 ext/rbu/rbu10.test create mode 100644 ext/rbu/rbu11.test create mode 100644 ext/rbu/rbu12.test create mode 100644 ext/rbu/rbu13.test create mode 100644 ext/rbu/rbu14.test create mode 100644 ext/rbu/rbu3.test create mode 100644 ext/rbu/rbu5.test create mode 100644 ext/rbu/rbu6.test create mode 100644 ext/rbu/rbu7.test create mode 100644 ext/rbu/rbu8.test create mode 100644 ext/rbu/rbu9.test create mode 100644 ext/rbu/rbuA.test create mode 100644 ext/rbu/rbuB.test create mode 100644 ext/rbu/rbu_common.tcl create mode 100644 ext/rbu/rbucrash.test create mode 100644 ext/rbu/rbudiff.test create mode 100644 ext/rbu/rbufault.test create mode 100644 ext/rbu/rbufault2.test create mode 100644 ext/rbu/rbufts.test create mode 100644 ext/rbu/rbusave.test create mode 100644 ext/rbu/sqlite3rbu.c create mode 100644 ext/rbu/sqlite3rbu.h create mode 100644 ext/rbu/test_rbu.c delete mode 100644 mkopcodec.awk delete mode 100644 mkopcodeh.awk delete mode 100644 src/lempar.c create mode 100644 src/test_windirent.c create mode 100644 src/test_windirent.h create mode 100644 src/treeview.c create mode 100644 src/wherecode.c create mode 100644 src/whereexpr.c create mode 100644 test/affinity2.test create mode 100644 test/analyzer1.test create mode 100644 test/autoindex5.test create mode 100644 test/cacheflush.test create mode 100644 test/cffault.test create mode 100644 test/cursorhint.test create mode 100644 test/delete4.test create mode 100644 test/extraquick.test create mode 100644 test/fordelete.test create mode 100644 test/fts3offsets.test create mode 100644 test/fts4onepass.test create mode 100644 test/fuzzcheck.c create mode 100644 test/fuzzdata1.db delete mode 100644 test/fuzzdata1.txt rename test/{fuzzdata2.txt => fuzzdata2.db} (75%) create mode 100644 test/fuzzdata3.db create mode 100644 test/fuzzdata4.db create mode 100644 test/fuzzer2.test create mode 100644 test/hidden.test create mode 100644 test/ieee754.test create mode 100644 test/indexexpr1.test create mode 100644 test/json101.test create mode 100644 test/json102.test create mode 100644 test/json103.test delete mode 100644 test/mkfuzzdata1.tcl create mode 100644 test/mmap4.test create mode 100644 test/numindex1.test create mode 100644 test/offset1.test create mode 100644 test/orderby9.test create mode 100644 test/parser1.test create mode 100644 test/rbu.test create mode 100644 test/rowallock.test rename test/{savepoint3.test => savepointfault.test} (94%) create mode 100644 test/snapshot.test create mode 100644 test/snapshot_fault.test create mode 100644 test/spellfix2.test create mode 100644 test/spellfix3.test create mode 100644 test/sqldiff1.test create mode 100644 test/sqllog.test create mode 100644 test/subtype1.test create mode 100644 test/symlink.test create mode 100644 test/tabfunc01.test create mode 100644 test/vtabH.test create mode 100644 test/vtabI.test create mode 100644 test/waloverwrite.test create mode 100644 test/walprotocol.test rename test/{where8m.test => wherefault.test} (84%) create mode 100644 test/with3.test create mode 100644 tool/GetFile.cs create mode 100644 tool/GetTclKit.bat create mode 100644 tool/addopcodes.tcl create mode 100755 tool/cg_anno.tcl delete mode 100644 tool/diffdb.c create mode 100644 tool/loadfts.c create mode 100644 tool/mkmsvcmin.tcl create mode 100644 tool/mkopcodec.tcl create mode 100644 tool/mkopcodeh.tcl delete mode 100644 tool/opcodeDoc.awk create mode 100644 tool/replace.tcl create mode 100644 tool/run-speed-test.sh delete mode 100644 tool/space_used.tcl create mode 100644 tool/srcck1.c delete mode 100644 tool/tostr.awk create mode 100644 tool/tostr.tcl diff --git a/Makefile.arm-wince-mingw32ce-gcc b/Makefile.arm-wince-mingw32ce-gcc deleted file mode 100644 index 323b7ea..0000000 --- a/Makefile.arm-wince-mingw32ce-gcc +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/make -# -# Makefile for SQLITE -# -# This is a template makefile for SQLite. Most people prefer to -# use the autoconf generated "configure" script to generate the -# makefile automatically. But that does not work for everybody -# and in every situation. If you are having problems with the -# "configure" script, you might want to try this makefile as an -# alternative. Create a copy of this file, edit the parameters -# below and type "make". -# - -#### The directory where to find the mingw32ce tools -MINGW32CE = /opt/mingw32ce/bin - -#### The target prefix of the mingw32ce tools -TARGET = arm-wince-mingw32ce - -#### The toplevel directory of the source tree. This is the directory -# that contains this "Makefile.in" and the "configure.in" script. -# -TOP = ../sqlite - -#### C Compiler and options for use in building executables that -# will run on the platform that is doing the build. -# -BCC = gcc -g -O2 -#BCC = /opt/ancic/bin/c89 -0 - -#### If the target operating system supports the "usleep()" system -# call, then define the HAVE_USLEEP macro for all C modules. -# -USLEEP = -#USLEEP = -DHAVE_USLEEP=1 - -#### If you want the SQLite library to be safe for use within a -# multi-threaded program, then define the following macro -# appropriately: -# -THREADSAFE = -DTHREADSAFE=1 -#THREADSAFE = -DTHREADSAFE=0 - -#### Specify any extra linker options needed to make the library -# thread safe -# -#THREADLIB = -lpthread -THREADLIB = - -#### Specify any extra libraries needed to access required functions. -# -#TLIBS = -lrt # fdatasync on Solaris 8 -TLIBS = - -#### Leave SQLITE_DEBUG undefined for maximum speed. Use SQLITE_DEBUG=1 -# to check for memory leaks. Use SQLITE_DEBUG=2 to print a log of all -# malloc()s and free()s in order to track down memory leaks. -# -# SQLite uses some expensive assert() statements in the inner loop. -# You can make the library go almost twice as fast if you compile -# with -DNDEBUG=1 -# -#OPTS = -DSQLITE_DEBUG=2 -#OPTS = -DSQLITE_DEBUG=1 -#OPTS = -OPTS = -DNDEBUG=1 -DSQLITE_OS_WIN=1 -D_WIN32_WCE=1 -#OPTS += -DHAVE_FDATASYNC=1 - -#### The suffix to add to executable files. ".exe" for windows. -# Nothing for unix. -# -EXE = .exe -#EXE = - -#### C Compile and options for use in building executables that -# will run on the target platform. This is usually the same -# as BCC, unless you are cross-compiling. -# -#TCC = gcc -O6 -#TCC = gcc -g -O0 -Wall -#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage -#TCC = /opt/mingw/bin/i386-mingw32-gcc -O6 -TCC = $(MINGW32CE)/$(TARGET)-gcc -O2 -#TCC = /opt/ansic/bin/c89 -O +z -Wl,-a,archive - -#### Tools used to build a static library. -# -#AR = ar cr -#AR = /opt/mingw/bin/i386-mingw32-ar cr -AR = $(MINGW32CE)/$(TARGET)-ar cr -#RANLIB = ranlib -#RANLIB = /opt/mingw/bin/i386-mingw32-ranlib -RANLIB = $(MINGW32CE)/$(TARGET)-ranlib - -#MKSHLIB = gcc -shared -#SO = so -#SHPREFIX = lib -MKSHLIB = $(MINGW32CE)/$(TARGET)-gcc -shared -SO = dll -SHPREFIX = - -#### Extra compiler options needed for programs that use the TCL library. -# -#TCL_FLAGS = -#TCL_FLAGS = -DSTATIC_BUILD=1 -TCL_FLAGS = -I/home/drh/tcltk/8.5linux -#TCL_FLAGS = -I/home/drh/tcltk/8.5win -DSTATIC_BUILD=1 -#TCL_FLAGS = -I/home/drh/tcltk/8.3hpux - -#### Linker options needed to link against the TCL library. -# -#LIBTCL = -ltcl -lm -ldl -LIBTCL = /home/drh/tcltk/8.5linux/libtcl8.5g.a -lm -ldl -#LIBTCL = /home/drh/tcltk/8.5win/libtcl85s.a -lmsvcrt -#LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc - -#### Additional objects for SQLite library when TCL support is enabled. -TCLOBJ = -#TCLOBJ = tclsqlite.o - -#### Compiler options needed for programs that use the readline() library. -# -READLINE_FLAGS = -#READLINE_FLAGS = -DHAVE_READLINE=1 -I/usr/include/readline - -#### Linker options needed by programs using readline() must link against. -# -LIBREADLINE = -#LIBREADLINE = -static -lreadline -ltermcap - -#### Which "awk" program provides nawk compatibilty -# -# NAWK = nawk -NAWK = awk - -# You should not have to change anything below this line -############################################################################### -include $(TOP)/main.mk diff --git a/Makefile.in b/Makefile.in index 0591150..013cf44 100644 --- a/Makefile.in +++ b/Makefile.in @@ -54,6 +54,7 @@ LIBTCL = @TCL_LIB_SPEC@ # Compiler options needed for programs that use the readline() library. # READLINE_FLAGS = -DHAVE_READLINE=@TARGET_HAVE_READLINE@ @TARGET_READLINE_INC@ +READLINE_FLAGS += -DHAVE_EDITLINE=@TARGET_HAVE_EDITLINE@ # The library that programs using readline() must link against. # @@ -65,7 +66,7 @@ TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@ # Any target libraries which libsqlite must be linked against # -TLIBS = @LIBS@ +TLIBS = @LIBS@ $(LIBS) # Flags controlling use of the in memory btree implementation # @@ -155,9 +156,6 @@ LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(TCC) $(LTCOMPILE_EXTRAS) LTLINK = $(LIBTOOL) --mode=link $(TCC) $(LTCOMPILE_EXTRAS) @LDFLAGS@ $(LTLINK_EXTRAS) LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL) -# nawk compatible awk. -NAWK = @AWK@ - # You should not have to change anything below this line ############################################################################### @@ -173,18 +171,20 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \ fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \ fts3_tokenize_vtab.lo \ fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \ + fts5.lo \ func.lo global.lo hash.lo \ - icu.lo insert.lo journal.lo legacy.lo loadext.lo \ + icu.lo insert.lo journal.lo json1.lo legacy.lo loadext.lo \ main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \ memjournal.lo \ mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \ notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ - random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \ - table.lo threads.lo tokenize.lo trigger.lo \ + random.lo resolve.lo rowset.lo rtree.lo select.lo sqlite3rbu.lo status.lo \ + table.lo threads.lo tokenize.lo treeview.lo trigger.lo \ update.lo util.lo vacuum.lo \ vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ - vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo + vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \ + utf.lo vtab.lo # Object files for the amalgamation. # @@ -270,9 +270,10 @@ SRC = \ $(TOP)/src/sqliteInt.h \ $(TOP)/src/sqliteLimit.h \ $(TOP)/src/table.c \ - $(TOP)/src/threads.c \ $(TOP)/src/tclsqlite.c \ + $(TOP)/src/threads.c \ $(TOP)/src/tokenize.c \ + $(TOP)/src/treeview.c \ $(TOP)/src/trigger.c \ $(TOP)/src/utf.c \ $(TOP)/src/update.c \ @@ -293,6 +294,8 @@ SRC = \ $(TOP)/src/wal.h \ $(TOP)/src/walker.c \ $(TOP)/src/where.c \ + $(TOP)/src/wherecode.c \ + $(TOP)/src/whereexpr.c \ $(TOP)/src/whereInt.h # Source code for extensions @@ -339,6 +342,12 @@ SRC += \ SRC += \ $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/rtree.c +SRC += \ + $(TOP)/ext/rbu/sqlite3rbu.h \ + $(TOP)/ext/rbu/sqlite3rbu.c +SRC += \ + $(TOP)/ext/misc/json1.c + # Generated source code files @@ -393,9 +402,11 @@ TESTSRC = \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vfs.c \ + $(TOP)/src/test_windirent.c \ $(TOP)/src/test_wsd.c \ $(TOP)/ext/fts3/fts3_term.c \ - $(TOP)/ext/fts3/fts3_test.c + $(TOP)/ext/fts3/fts3_test.c \ + $(TOP)/ext/rbu/test_rbu.c # Statically linked extensions # @@ -405,10 +416,14 @@ TESTSRC += \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ + $(TOP)/ext/fts5/fts5_tcl.c \ + $(TOP)/ext/fts5/fts5_test_mi.c \ + $(TOP)/ext/fts5/fts5_test_tok.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ + $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/wholenumber.c @@ -450,6 +465,8 @@ TESTSRC2 = \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbetrace.c \ $(TOP)/src/where.c \ + $(TOP)/src/wherecode.c \ + $(TOP)/src/whereexpr.c \ parse.c \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ @@ -510,6 +527,33 @@ EXTHDR += \ EXTHDR += \ $(TOP)/ext/rtree/sqlite3rtree.h +# executables needed for testing +# +TESTPROGS = \ + testfixture$(TEXE) \ + sqlite3$(TEXE) \ + sqlite3_analyzer$(TEXE) \ + sqldiff$(TEXE) + +# Databases containing fuzzer test cases +# +FUZZDATA = \ + $(TOP)/test/fuzzdata1.db \ + $(TOP)/test/fuzzdata2.db \ + $(TOP)/test/fuzzdata3.db \ + $(TOP)/test/fuzzdata4.db + +# Standard options to testfixture +# +TESTOPTS = --verbose=file --output=test-out.txt + +# Extra compiler options for various shell tools +# +SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 +SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS +FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 +FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 + # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # @@ -532,16 +576,26 @@ libtclsqlite3.la: tclsqlite.lo libsqlite3.la -version-info "8:6:8" \ -avoid-version -sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h - $(LTLINK) $(READLINE_FLAGS) \ - -o $@ $(TOP)/src/shell.c libsqlite3.la \ +sqlite3$(TEXE): $(TOP)/src/shell.c sqlite3.c + $(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \ + $(TOP)/src/shell.c sqlite3.c \ $(LIBREADLINE) $(TLIBS) -rpath "$(libdir)" sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h - $(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) + $(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) + +srcck1$(BEXE): $(TOP)/tool/srcck1.c + $(BCC) -o srcck1$(BEXE) $(TOP)/tool/srcck1.c + +sourcetest: srcck1$(BEXE) sqlite3.c + ./srcck1 sqlite3.c fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h - $(LTLINK) -o $@ $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS) + $(LTLINK) -o $@ $(FUZZERSHELL_OPT) \ + $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS) + +fuzzcheck$(TEXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h + $(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/fuzzcheck.c sqlite3.c $(TLIBS) mptester$(TEXE): sqlite3.c $(TOP)/mptest/mptest.c $(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \ @@ -567,19 +621,23 @@ mptest: mptester$(TEXE) # files are automatically generated. This target takes care of # all that automatic generation. # -.target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl +.target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl fts5.c rm -rf tsrc mkdir tsrc cp -f $(SRC) tsrc rm tsrc/sqlite.h.in tsrc/parse.y $(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl $(OPTS) vdbe.new mv vdbe.new tsrc/vdbe.c + cp fts5.c fts5.h tsrc touch .target_source sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl cp tsrc/shell.c tsrc/sqlite3ext.h . +sqlite3ext.h: .target_source + cp tsrc/sqlite3ext.h . + tclsqlite3.c: sqlite3.c echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c cat sqlite3.c >>tclsqlite3.c @@ -596,9 +654,9 @@ sqlite3.lo: sqlite3.c # Rules to build the LEMON compiler generator # -lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/src/lempar.c +lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c $(BCC) -o $@ $(TOP)/tool/lemon.c - cp $(TOP)/src/lempar.c . + cp $(TOP)/tool/lempar.c . # Rules to build individual *.o files from generated *.c files. This # applies to: @@ -779,6 +837,9 @@ threads.lo: $(TOP)/src/threads.c $(HDR) tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/tokenize.c +treeview.lo: $(TOP)/src/treeview.c $(HDR) + $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/treeview.c + trigger.lo: $(TOP)/src/trigger.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/trigger.c @@ -827,6 +888,12 @@ walker.lo: $(TOP)/src/walker.c $(HDR) where.lo: $(TOP)/src/where.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/where.c +wherecode.lo: $(TOP)/src/wherecode.c $(HDR) + $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/wherecode.c + +whereexpr.lo: $(TOP)/src/whereexpr.c $(HDR) + $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/whereexpr.c + tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR) $(LTCOMPILE) -DUSE_TCL_STUBS=1 -c $(TOP)/src/tclsqlite.c @@ -842,22 +909,22 @@ tclsqlite3$(TEXE): tclsqlite-shell.lo libsqlite3.la # Rules to build opcodes.c and opcodes.h # -opcodes.c: opcodes.h $(TOP)/mkopcodec.awk - $(NAWK) -f $(TOP)/mkopcodec.awk opcodes.h >opcodes.c +opcodes.c: opcodes.h $(TOP)/tool/mkopcodec.tcl + $(TCLSH_CMD) $(TOP)/tool/mkopcodec.tcl opcodes.h >opcodes.c -opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk - cat parse.h $(TOP)/src/vdbe.c | $(NAWK) -f $(TOP)/mkopcodeh.awk >opcodes.h +opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl + cat parse.h $(TOP)/src/vdbe.c | $(TCLSH_CMD) $(TOP)/tool/mkopcodeh.tcl >opcodes.h # Rules to build parse.c and parse.h - the outputs of lemon. # parse.h: parse.c -parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/addopcodes.awk +parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/tool/addopcodes.tcl cp $(TOP)/src/parse.y . rm -f parse.h ./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) parse.y mv parse.h parse.h.temp - $(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h + $(TCLSH_CMD) $(TOP)/tool/addopcodes.tcl parse.h.temp >parse.h sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION $(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h @@ -933,6 +1000,45 @@ fts3_write.lo: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c +json1.lo: $(TOP)/ext/misc/json1.c + $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c + +# FTS5 things +# +FTS5_SRC = \ + $(TOP)/ext/fts5/fts5.h \ + $(TOP)/ext/fts5/fts5Int.h \ + $(TOP)/ext/fts5/fts5_aux.c \ + $(TOP)/ext/fts5/fts5_buffer.c \ + $(TOP)/ext/fts5/fts5_main.c \ + $(TOP)/ext/fts5/fts5_config.c \ + $(TOP)/ext/fts5/fts5_expr.c \ + $(TOP)/ext/fts5/fts5_hash.c \ + $(TOP)/ext/fts5/fts5_index.c \ + fts5parse.c fts5parse.h \ + $(TOP)/ext/fts5/fts5_storage.c \ + $(TOP)/ext/fts5/fts5_tokenize.c \ + $(TOP)/ext/fts5/fts5_unicode2.c \ + $(TOP)/ext/fts5/fts5_varint.c \ + $(TOP)/ext/fts5/fts5_vocab.c \ + +fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon + cp $(TOP)/ext/fts5/fts5parse.y . + rm -f fts5parse.h + ./lemon $(OPTS) fts5parse.y + +fts5parse.h: fts5parse.c + +fts5.c: $(FTS5_SRC) + $(TCLSH_CMD) $(TOP)/ext/fts5/tool/mkfts5c.tcl + cp $(TOP)/ext/fts5/fts5.h . + +fts5.lo: fts5.c $(HDR) $(EXTHDR) + $(LTCOMPILE) -DSQLITE_CORE -c fts5.c + +sqlite3rbu.lo: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR) + $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rbu/sqlite3rbu.c + # Rules to build the 'testfixture' application. # @@ -955,51 +1061,58 @@ testfixture$(TEXE): $(TESTFIXTURE_SRC) -o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS) # A very detailed test running most or all test cases -fulltest: testfixture$(TEXE) sqlite3$(TEXE) fuzztest - ./testfixture$(TEXE) $(TOP)/test/all.test +fulltest: $(TESTPROGS) fuzztest + ./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS) # Really really long testing -soaktest: testfixture$(TEXE) sqlite3$(TEXE) fuzzoomtest - ./testfixture$(TEXE) $(TOP)/test/all.test -soak=1 +soaktest: $(TESTPROGS) + ./testfixture$(TEXE) $(TOP)/test/all.test -soak=1 $(TESTOPTS) -# Do extra testing but not aeverything. -fulltestonly: testfixture$(TEXE) sqlite3$(TEXE) +# Do extra testing but not everything. +fulltestonly: $(TESTPROGS) fuzztest ./testfixture$(TEXE) $(TOP)/test/full.test # Fuzz testing -fuzztest: fuzzershell$(TEXE) - ./fuzzershell$(TEXE) $(TOP)/test/fuzzdata1.txt $(TOP)/test/fuzzdata2.txt +fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) + ./fuzzcheck$(TEXE) $(FUZZDATA) -fuzzoomtest: fuzzershell$(TEXE) - ./fuzzershell$(TEXE) -f $(TOP)/test/fuzzdata1.txt --oom +fastfuzztest: fuzzcheck$(TEXE) $(FUZZDATA) + ./fuzzcheck$(TEXE) --limit-mem 100M $(FUZZDATA) -# This is the common case. Run many tests but not those that take -# a really long time. +valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) + valgrind ./fuzzcheck$(TEXE) --cell-size-check --limit-mem 10M --timeout 600 $(FUZZDATA) + +# Minimal testing that runs in less than 3 minutes # -test: testfixture$(TEXE) sqlite3$(TEXE) fuzztest - ./testfixture$(TEXE) $(TOP)/test/veryquick.test +quicktest: ./testfixture$(TEXE) + ./testfixture$(TEXE) $(TOP)/test/extraquick.test $(TESTOPTS) + +# This is the common case. Run many tests that do not take too long, +# including fuzzcheck, sqlite3_analyzer, and sqldiff tests. +# +test: $(TESTPROGS) sourcetest fastfuzztest + ./testfixture$(TEXE) $(TOP)/test/veryquick.test $(TESTOPTS) # Run a test using valgrind. This can take a really long time # because valgrind is so much slower than a native machine. # -valgrindtest: testfixture$(TEXE) sqlite3$(TEXE) fuzzershell$(TEXE) - valgrind -v ./fuzzershell$(TEXE) -f $(TOP)/test/fuzzdata1.txt - OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind +valgrindtest: $(TESTPROGS) valgrindfuzz + OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind $(TESTOPTS) # A very fast test that checks basic sanity. The name comes from # the 60s-era electronics testing: "Turn it on and see if smoke # comes out." # -smoketest: testfixture$(TEXE) fuzzershell$(TEXE) - ./testfixture$(TEXE) $(TOP)/test/main.test +smoketest: $(TESTPROGS) fuzzcheck$(TEXE) + ./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS) sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl echo "#define TCLSH 2" > $@ - echo "#define SQLITE_ENABLE_DBSTAT_VTAB" >> $@ + echo "#define SQLITE_ENABLE_DBSTAT_VTAB 1" >> $@ cat sqlite3.c $(TOP)/src/tclsqlite.c >> $@ echo "static const char *tclsh_main_loop(void){" >> $@ echo "static const char *zMainloop = " >> $@ - $(NAWK) -f $(TOP)/tool/tostr.awk $(TOP)/tool/spaceanal.tcl >> $@ + $(TCLSH_CMD) $(TOP)/tool/tostr.tcl $(TOP)/tool/spaceanal.tcl >> $@ echo "; return zMainloop; }" >> $@ sqlite3_analyzer$(TEXE): sqlite3_analyzer.c @@ -1029,6 +1142,12 @@ wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.c speedtest1$(TEXE): $(TOP)/test/speedtest1.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/test/speedtest1.c sqlite3.lo $(TLIBS) +rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo + $(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS) + +loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la + $(LTLINK) $(TOP)/tool/loadfts.c libsqlite3.la -o $@ $(TLIBS) + # This target will fail if the SQLite amalgamation contains any exported # symbols that do not begin with "sqlite3_". It is run as part of the # releasetest.tcl script. @@ -1037,10 +1156,15 @@ checksymbols: sqlite3.lo nm -g --defined-only sqlite3.o | grep -v " sqlite3_" ; test $$? -ne 0 echo '0 errors out of 1 tests' -# Build the amalgamation-autoconf package. +# Build the amalgamation-autoconf package. The amalamgation-tarball target builds +# a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz. +# The snapshot-tarball target builds a tarball named by the SHA1 hash # amalgamation-tarball: sqlite3.c - TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh + TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal + +snapshot-tarball: sqlite3.c + TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot # The next two rules are used to support the "threadtest" target. Building # threadtest runs a few thread-safety tests that are implemented in C. This @@ -1054,7 +1178,7 @@ THREADTEST3_SRC = $(TOP)/test/threadtest3.c \ $(TOP)/test/tt3_lookaside1.c threadtest3$(TEXE): sqlite3.lo $(THREADTEST3_SRC) - $(LTLINK) $(TOP)/test/threadtest3.c sqlite3.lo -o $@ $(TLIBS) + $(LTLINK) $(TOP)/test/threadtest3.c $(TOP)/src/test_multiplex.c sqlite3.lo -o $@ $(TLIBS) threadtest: threadtest3$(TEXE) ./threadtest3$(TEXE) @@ -1068,9 +1192,9 @@ lib_install: libsqlite3.la $(INSTALL) -d $(DESTDIR)$(libdir) $(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir) -install: sqlite3$(BEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_install} +install: sqlite3$(TEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_install} $(INSTALL) -d $(DESTDIR)$(bindir) - $(LTINSTALL) sqlite3$(BEXE) $(DESTDIR)$(bindir) + $(LTINSTALL) sqlite3$(TEXE) $(DESTDIR)$(bindir) $(INSTALL) -d $(DESTDIR)$(includedir) $(INSTALL) -m 0644 sqlite3.h $(DESTDIR)$(includedir) $(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(includedir) @@ -1106,9 +1230,15 @@ clean: rm -f sqlite3_analyzer$(TEXE) sqlite3_analyzer.c rm -f sqlite-*-output.vsix rm -f mptester mptester.exe + rm -f rbu rbu.exe + rm -f srcck1 srcck1.exe + rm -f fuzzershell fuzzershell.exe + rm -f fuzzcheck fuzzcheck.exe + rm -f sqldiff sqldiff.exe + rm -f fts5.* fts5parse.* distclean: clean - rm -f config.log config.status libtool Makefile sqlite3.pc + rm -f config.h config.log config.status libtool Makefile sqlite3.pc # # Windows section diff --git a/Makefile.linux-gcc b/Makefile.linux-gcc index 1c9f24f..1491a4b 100644 --- a/Makefile.linux-gcc +++ b/Makefile.linux-gcc @@ -118,11 +118,6 @@ READLINE_FLAGS = LIBREADLINE = #LIBREADLINE = -static -lreadline -ltermcap -#### Which "awk" program provides nawk compatibilty -# -# NAWK = nawk -NAWK = awk - # You should not have to change anything below this line ############################################################################### include $(TOP)/main.mk diff --git a/Makefile.msc b/Makefile.msc index df39851..843f9a2 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -10,11 +10,13 @@ # TOP = . +# <> # Set this non-0 to create and use the SQLite amalgamation file. # !IFNDEF USE_AMALGAMATION USE_AMALGAMATION = 1 !ENDIF +# <> # Set this non-0 to enable full warnings (-W4, etc) when compiling. # @@ -36,6 +38,13 @@ USE_STDCALL = 0 DYNAMIC_SHELL = 0 !ENDIF +# Set this non-0 to enable extra code that attempts to detect misuse of the +# SQLite API. +# +!IFNDEF API_ARMOR +API_ARMOR = 0 +!ENDIF + # If necessary, create a list of harmless compiler warnings to disable when # compiling the various tools. For the SQLite source code itself, warnings, # if any, will be disabled from within it. @@ -43,7 +52,7 @@ DYNAMIC_SHELL = 0 !IFNDEF NO_WARN !IF $(USE_FULLWARN)!=0 NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206 -NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706 +NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4305 -wd4306 -wd4702 -wd4706 !ENDIF !ENDIF @@ -61,11 +70,13 @@ USE_WP81_OPTS = 0 SPLIT_AMALGAMATION = 0 !ENDIF +# <> # Set this non-0 to use the International Components for Unicode (ICU). # !IFNDEF USE_ICU USE_ICU = 0 !ENDIF +# <> # Set this non-0 to dynamically link to the MSVC runtime library. # @@ -115,20 +126,28 @@ USE_RC = 1 FOR_WINRT = 0 !ENDIF -# Set this non-0 to compile binaries suitable for the UAP environment. +# Set this non-0 to compile binaries suitable for the UWP environment. # This setting does not apply to any binaries that require Tcl to operate # properly (i.e. the text fixture, etc). # -!IFNDEF FOR_UAP -FOR_UAP = 0 +!IFNDEF FOR_UWP +FOR_UWP = 0 !ENDIF +# Set this non-0 to compile binaries suitable for the Windows 10 platform. +# +!IFNDEF FOR_WIN10 +FOR_WIN10 = 0 +!ENDIF + +# <> # Set this non-0 to skip attempting to look for and/or link with the Tcl # runtime library. # !IFNDEF NO_TCL NO_TCL = 0 !ENDIF +# <> # Set this to non-0 to create and use PDBs. # @@ -179,6 +198,49 @@ DEBUG = 0 OPTIMIZATIONS = 2 !ENDIF +# Set the source code file to be used by executables and libraries when +# they need the amalgamation. +# +!IFNDEF SQLITE3C +!IF $(SPLIT_AMALGAMATION)!=0 +SQLITE3C = sqlite3-all.c +!ELSE +SQLITE3C = sqlite3.c +!ENDIF +!ENDIF + +# Set the include code file to be used by executables and libraries when +# they need SQLite. +# +!IFNDEF SQLITE3H +SQLITE3H = sqlite3.h +!ENDIF + +# This is the name to use for the SQLite dynamic link library (DLL). +# +!IFNDEF SQLITE3DLL +SQLITE3DLL = sqlite3.dll +!ENDIF + +# This is the name to use for the SQLite import library (LIB). +# +!IFNDEF SQLITE3LIB +SQLITE3LIB = sqlite3.lib +!ENDIF + +# This is the name to use for the SQLite shell executable (EXE). +# +!IFNDEF SQLITE3EXE +SQLITE3EXE = sqlite3.exe +!ENDIF + +# This is the argument used to set the program database (PDB) file for the +# SQLite shell executable (EXE). +# +!IFNDEF SQLITE3EXEPDB +SQLITE3EXEPDB = /pdb:sqlite3sh.pdb +!ENDIF + # These are the "standard" SQLite compilation options used when compiling for # the Windows platform. # @@ -188,10 +250,32 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 !ENDIF +# These are the "extended" SQLite compilation options used when compiling for +# the Windows 10 platform. +# +!IFNDEF EXT_FEATURE_FLAGS +!IF $(FOR_WIN10)!=0 +EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1 +EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_SYSTEM_MALLOC=1 +EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_OMIT_LOCALTIME=1 +!ELSE +EXT_FEATURE_FLAGS = +!ENDIF +!ENDIF + ############################################################################### ############################### END OF OPTIONS ################################ ############################################################################### +# When compiling for the Windows 10 platform, the PLATFORM macro must be set +# to an appropriate value (e.g. x86, x64, arm, arm64, etc). +# +!IF $(FOR_WIN10)!=0 +!IFNDEF PLATFORM +!ERROR Using the FOR_WIN10 option requires a value for PLATFORM. +!ENDIF +!ENDIF + # This assumes that MSVC is always installed in 32-bit Program Files directory # and sets the variable for use in locating other 32-bit installs accordingly. # @@ -222,7 +306,7 @@ LD = link.exe RC = rc.exe !ENDIF -# Check for the MSVC runtime library path macro. Othertise, this value will +# Check for the MSVC runtime library path macro. Otherwise, this value will # default to the 'lib' directory underneath the MSVC installation directory. # !IFNDEF CRTLIBPATH @@ -259,7 +343,7 @@ NCC = $(NCC:\\=\) NCC = $(CC) !ENDIF -# Check for the MSVC native runtime library path macro. Othertise, +# Check for the MSVC native runtime library path macro. Otherwise, # this value will default to the 'lib' directory underneath the MSVC # installation directory. # @@ -269,7 +353,7 @@ NCRTLIBPATH = $(VCINSTALLDIR)\lib NCRTLIBPATH = $(NCRTLIBPATH:\\=\) -# Check for the Platform SDK library path macro. Othertise, this +# Check for the Platform SDK library path macro. Otherwise, this # value will default to the 'lib' directory underneath the Windows # SDK installation directory (the environment variable used appears # to be available when using Visual C++ 2008 or later via the @@ -281,13 +365,23 @@ NSDKLIBPATH = $(WINDOWSSDKDIR)\lib NSDKLIBPATH = $(NSDKLIBPATH:\\=\) +# Check for the UCRT library path macro. Otherwise, this value will +# default to the version-specific, platform-specific 'lib' directory +# underneath the Windows SDK installation directory. +# +!IFNDEF UCRTLIBPATH +UCRTLIBPATH = $(WINDOWSSDKDIR)\lib\$(WINDOWSSDKLIBVERSION)\ucrt\$(PLATFORM) +!ENDIF + +UCRTLIBPATH = $(UCRTLIBPATH:\\=\) + # C compiler and options for use in building executables that # will run on the platform that is doing the build. # !IF $(USE_FULLWARN)!=0 -BCC = $(NCC) -nologo -W4 +BCC = $(NCC) -nologo -W4 $(CCOPTS) $(BCCOPTS) !ELSE -BCC = $(NCC) -nologo -W3 +BCC = $(NCC) -nologo -W3 $(CCOPTS) $(BCCOPTS) !ENDIF # Check if assembly code listings should be generated for the source @@ -315,13 +409,22 @@ NLTLIBPATHS = $(NLTLIBPATHS) "/LIBPATH:$(NUCRTLIBPATH)" # same unless your are cross-compiling.) # !IF $(USE_FULLWARN)!=0 -TCC = $(CC) -nologo -W4 -DINCLUDE_MSVC_H=1 +TCC = $(CC) -nologo -W4 -DINCLUDE_MSVC_H=1 $(CCOPTS) $(TCCOPTS) !ELSE -TCC = $(CC) -nologo -W3 +TCC = $(CC) -nologo -W3 $(CCOPTS) $(TCCOPTS) !ENDIF TCC = $(TCC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src -fp:precise -RCC = $(RC) -DSQLITE_OS_WIN=1 -I$(TOP) -I$(TOP)\src +RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src $(RCOPTS) $(RCCOPTS) + +# Adjust the names of the primary targets for use with Windows 10. +# +!IF $(FOR_WIN10)!=0 +SQLITE3DLL = winsqlite3.dll +SQLITE3LIB = winsqlite3.lib +SQLITE3EXE = winsqlite3shell.exe +SQLITE3EXEPDB = +!ENDIF # Check if we want to use the "stdcall" calling convention when compiling. # This is not supported by the compilers for non-x86 platforms. It should @@ -330,7 +433,7 @@ RCC = $(RC) -DSQLITE_OS_WIN=1 -I$(TOP) -I$(TOP)\src # to how the Tcl library functions are declared and exported (i.e. without # an explicit calling convention, which results in "cdecl"). # -!IF $(USE_STDCALL)!=0 +!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 !IF "$(PLATFORM)"=="x86" CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall @@ -351,7 +454,7 @@ SHELL_CCONV_OPTS = # These are additional compiler options used for the core library. # !IFNDEF CORE_COMPILE_OPTS -!IF $(DYNAMIC_SHELL)!=0 +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 CORE_COMPILE_OPTS = $(CORE_CCONV_OPTS) -DSQLITE_API=__declspec(dllexport) !ELSE CORE_COMPILE_OPTS = $(CORE_CCONV_OPTS) @@ -362,7 +465,7 @@ CORE_COMPILE_OPTS = $(CORE_CCONV_OPTS) # when linking. # !IFNDEF CORE_LINK_DEP -!IF $(DYNAMIC_SHELL)!=0 +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 CORE_LINK_DEP = !ELSE CORE_LINK_DEP = sqlite3.def @@ -372,7 +475,7 @@ CORE_LINK_DEP = sqlite3.def # These are additional linker options used for the core library. # !IFNDEF CORE_LINK_OPTS -!IF $(DYNAMIC_SHELL)!=0 +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 CORE_LINK_OPTS = !ELSE CORE_LINK_OPTS = /DEF:sqlite3.def @@ -382,30 +485,41 @@ CORE_LINK_OPTS = /DEF:sqlite3.def # These are additional compiler options used for the shell executable. # !IFNDEF SHELL_COMPILE_OPTS -!IF $(DYNAMIC_SHELL)!=0 +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 SHELL_COMPILE_OPTS = $(SHELL_CCONV_OPTS) -DSQLITE_API=__declspec(dllimport) !ELSE SHELL_COMPILE_OPTS = $(SHELL_CCONV_OPTS) !ENDIF !ENDIF +# This is the source code that the shell executable should be compiled +# with. +# +!IFNDEF SHELL_CORE_SRC +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 +SHELL_CORE_SRC = +!ELSE +SHELL_CORE_SRC = $(SQLITE3C) +!ENDIF +!ENDIF + # This is the core library that the shell executable should depend on. # !IFNDEF SHELL_CORE_DEP -!IF $(DYNAMIC_SHELL)!=0 -SHELL_CORE_DEP = sqlite3.dll +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 +SHELL_CORE_DEP = $(SQLITE3DLL) !ELSE -SHELL_CORE_DEP = libsqlite3.lib +SHELL_CORE_DEP = !ENDIF !ENDIF # This is the core library that the shell executable should link with. # !IFNDEF SHELL_CORE_LIB -!IF $(DYNAMIC_SHELL)!=0 -SHELL_CORE_LIB = sqlite3.lib +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 +SHELL_CORE_LIB = $(SQLITE3LIB) !ELSE -SHELL_CORE_LIB = libsqlite3.lib +SHELL_CORE_LIB = !ENDIF !ENDIF @@ -434,6 +548,13 @@ TCC = $(TCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP RCC = $(RCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP !ENDIF +# C compiler options for the Windows 10 platform (needs MSVC 2015). +# +!IF $(FOR_WIN10)!=0 +TCC = $(TCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE +BCC = $(BCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE +!ENDIF + # Also, we need to dynamically link to the correct MSVC runtime # when compiling for WinRT (e.g. debug or release) OR if the # USE_CRT_DLL option is set to force dynamically linking to the @@ -457,6 +578,7 @@ BCC = $(BCC) -MT !ENDIF !ENDIF +# <> # The mksqlite3c.tcl and mksqlite3h.tcl scripts will pull in # any extension header files by default. For non-amalgamation # builds, we need to make sure the compiler can find these. @@ -480,6 +602,7 @@ MKSQLITE3C_ARGS = --linemacros MKSQLITE3C_ARGS = !ENDIF !ENDIF +# <> # Define -DNDEBUG to compile without debugging (i.e., for production usage) # Omitting the define will cause extra debugging code to be inserted and @@ -491,14 +614,14 @@ BCC = $(BCC) -DNDEBUG RCC = $(RCC) -DNDEBUG !ENDIF -!IF $(DEBUG)>0 -TCC = $(TCC) -DSQLITE_ENABLE_API_ARMOR -RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR +!IF $(DEBUG)>0 || $(API_ARMOR)!=0 || $(FOR_WIN10)!=0 +TCC = $(TCC) -DSQLITE_ENABLE_API_ARMOR=1 +RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1 !ENDIF !IF $(DEBUG)>2 -TCC = $(TCC) -DSQLITE_DEBUG -RCC = $(RCC) -DSQLITE_DEBUG +TCC = $(TCC) -DSQLITE_DEBUG=1 +RCC = $(RCC) -DSQLITE_DEBUG=1 !ENDIF !IF $(DEBUG)>4 || $(OSTRACE)!=0 @@ -507,8 +630,8 @@ RCC = $(RCC) -DSQLITE_FORCE_OS_TRACE=1 -DSQLITE_DEBUG_OS_TRACE=1 !ENDIF !IF $(DEBUG)>5 -TCC = $(TCC) -DSQLITE_ENABLE_IOTRACE -RCC = $(RCC) -DSQLITE_ENABLE_IOTRACE +TCC = $(TCC) -DSQLITE_ENABLE_IOTRACE=1 +RCC = $(RCC) -DSQLITE_ENABLE_IOTRACE=1 !ENDIF # Prevent warnings about "insecure" MSVC runtime library functions @@ -544,6 +667,7 @@ RCC = $(RCC) -DSQLITE_WIN32_MALLOC_VALIDATE=1 !ENDIF !ENDIF +# <> # The locations of the Tcl header and library files. Also, the library that # non-stubs enabled programs using Tcl must link against. These variables # (TCLINCDIR, TCLLIBDIR, and LIBTCL) may be overridden via the environment @@ -562,6 +686,14 @@ TCLLIBDIR = c:\tcl\lib LIBTCL = tcl85.lib !ENDIF +!IFNDEF LIBTCLSTUB +LIBTCLSTUB = tclstub85.lib +!ENDIF + +!IFNDEF LIBTCLPATH +LIBTCLPATH = c:\tcl\bin +!ENDIF + # The locations of the ICU header and library files. These variables # (ICUINCDIR, ICULIBDIR, and LIBICU) may be overridden via the environment # prior to running nmake in order to match the actual installed location on @@ -587,6 +719,7 @@ LIBICU = icuuc.lib icuin.lib !IFNDEF TCLSH_CMD TCLSH_CMD = tclsh85 !ENDIF +# <> # Compiler options needed for programs that use the readline() library. # @@ -644,8 +777,8 @@ REQ_FEATURE_FLAGS = $(REQ_FEATURE_FLAGS) -DSQLITE_WIN32_USE_UUID=1 # Add the required and optional SQLite compilation options into the command # lines used to invoke the MSVC code and resource compilers. # -TCC = $(TCC) $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) -RCC = $(RCC) $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) +TCC = $(TCC) $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) +RCC = $(RCC) $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) # Add in any optional parameters specified on the commane line, e.g. # nmake /f Makefile.msc all "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1" @@ -685,6 +818,7 @@ TCC = $(TCC) -Zi BCC = $(BCC) -Zi !ENDIF +# <> # If ICU support is enabled, add the compiler options for it. # !IF $(USE_ICU)!=0 @@ -695,6 +829,7 @@ RCC = $(RCC) -I$(TOP)\ext\icu TCC = $(TCC) -I$(ICUINCDIR) RCC = $(RCC) -I$(ICUINCDIR) !ENDIF +# <> # Command line prefixes for compiling code, compiling resources, # linking, etc. @@ -772,9 +907,10 @@ LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelH LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib !ENDIF -# When compiling for UAP, some extra linker options are also required. +# When compiling for UWP or the Windows 10 platform, some extra linker +# options are also required. # -!IF $(FOR_UAP)!=0 +!IF $(FOR_UWP)!=0 || $(FOR_WIN10)!=0 LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE /NODEFAULTLIB:kernel32.lib LTLINKOPTS = $(LTLINKOPTS) mincore.lib !IFDEF PSDKLIBPATH @@ -782,12 +918,24 @@ LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(PSDKLIBPATH)" !ENDIF !ENDIF +!IF $(FOR_WIN10)!=0 +LTLINKOPTS = $(LTLINKOPTS) /guard:cf "/LIBPATH:$(UCRTLIBPATH)" +!IF $(DEBUG)>1 +LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrtd.lib /DEFAULTLIB:ucrtd.lib +!ELSE +LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib +!ENDIF +!ENDIF + # If either debugging or symbols are enabled, enable PDBs. # !IF $(DEBUG)>1 || $(SYMBOLS)!=0 -LDFLAGS = /DEBUG +LDFLAGS = /DEBUG $(LDOPTS) +!ELSE +LDFLAGS = $(LDOPTS) !ENDIF +# <> # Start with the Tcl related linker options. # !IF $(NO_TCL)==0 @@ -801,16 +949,12 @@ LTLIBS = $(LIBTCL) LTLIBPATHS = $(LTLIBPATHS) /LIBPATH:$(ICULIBDIR) LTLIBS = $(LTLIBS) $(LIBICU) !ENDIF - -# nawk compatible awk. -# -!IFNDEF NAWK -NAWK = gawk.exe -!ENDIF +# <> # You should not have to change anything below this line ############################################################################### +# <> # Object files for the SQLite library (non-amalgamation). # LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \ @@ -820,6 +964,7 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \ fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \ fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \ fts3_tokenize_vtab.lo fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \ + fts5.lo \ func.lo global.lo hash.lo \ icu.lo insert.lo journal.lo legacy.lo loadext.lo \ main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \ @@ -827,11 +972,13 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \ mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \ notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ - random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \ - table.lo threads.lo tokenize.lo trigger.lo \ + random.lo resolve.lo rowset.lo rtree.lo select.lo sqlite3rbu.lo status.lo \ + table.lo threads.lo tokenize.lo treeview.lo trigger.lo \ update.lo util.lo vacuum.lo \ vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ - vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo + vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \ + utf.lo vtab.lo +# <> # Object files for the amalgamation. # @@ -839,11 +986,15 @@ LIBOBJS1 = sqlite3.lo # Determine the real value of LIBOBJ based on the 'configure' script # +# <> !IF $(USE_AMALGAMATION)==0 LIBOBJ = $(LIBOBJS0) !ELSE +# <> LIBOBJ = $(LIBOBJS1) +# <> !ENDIF +# <> # Determine if embedded resource compilation and usage are enabled. # @@ -853,9 +1004,10 @@ LIBRESOBJS = sqlite3res.lo LIBRESOBJS = !ENDIF -# All of the source code files. +# <> +# Core source code files, part 1. # -SRC1 = \ +SRC00 = \ $(TOP)\src\alter.c \ $(TOP)\src\analyze.c \ $(TOP)\src\attach.c \ @@ -864,8 +1016,6 @@ SRC1 = \ $(TOP)\src\bitvec.c \ $(TOP)\src\btmutex.c \ $(TOP)\src\btree.c \ - $(TOP)\src\btree.h \ - $(TOP)\src\btreeInt.h \ $(TOP)\src\build.c \ $(TOP)\src\callback.c \ $(TOP)\src\complete.c \ @@ -879,8 +1029,6 @@ SRC1 = \ $(TOP)\src\func.c \ $(TOP)\src\global.c \ $(TOP)\src\hash.c \ - $(TOP)\src\hash.h \ - $(TOP)\src\hwtime.h \ $(TOP)\src\insert.c \ $(TOP)\src\journal.c \ $(TOP)\src\legacy.c \ @@ -893,29 +1041,22 @@ SRC1 = \ $(TOP)\src\mem3.c \ $(TOP)\src\mem5.c \ $(TOP)\src\memjournal.c \ - $(TOP)\src\msvc.h \ $(TOP)\src\mutex.c \ - $(TOP)\src\mutex.h \ $(TOP)\src\mutex_noop.c \ $(TOP)\src\mutex_unix.c \ $(TOP)\src\mutex_w32.c \ $(TOP)\src\notify.c \ $(TOP)\src\os.c \ - $(TOP)\src\os.h \ - $(TOP)\src\os_common.h \ - $(TOP)\src\os_setup.h \ $(TOP)\src\os_unix.c \ - $(TOP)\src\os_win.c \ - $(TOP)\src\os_win.h -SRC2 = \ + $(TOP)\src\os_win.c + +# Core source code files, part 2. +# +SRC01 = \ $(TOP)\src\pager.c \ - $(TOP)\src\pager.h \ - $(TOP)\src\parse.y \ $(TOP)\src\pcache.c \ - $(TOP)\src\pcache.h \ $(TOP)\src\pcache1.c \ $(TOP)\src\pragma.c \ - $(TOP)\src\pragma.h \ $(TOP)\src\prepare.c \ $(TOP)\src\printf.c \ $(TOP)\src\random.c \ @@ -923,93 +1064,143 @@ SRC2 = \ $(TOP)\src\rowset.c \ $(TOP)\src\select.c \ $(TOP)\src\status.c \ - $(TOP)\src\shell.c \ - $(TOP)\src\sqlite.h.in \ - $(TOP)\src\sqlite3ext.h \ - $(TOP)\src\sqliteInt.h \ - $(TOP)\src\sqliteLimit.h \ $(TOP)\src\table.c \ $(TOP)\src\threads.c \ $(TOP)\src\tclsqlite.c \ $(TOP)\src\tokenize.c \ + $(TOP)\src\treeview.c \ $(TOP)\src\trigger.c \ $(TOP)\src\utf.c \ $(TOP)\src\update.c \ $(TOP)\src\util.c \ $(TOP)\src\vacuum.c \ $(TOP)\src\vdbe.c \ - $(TOP)\src\vdbe.h \ $(TOP)\src\vdbeapi.c \ $(TOP)\src\vdbeaux.c \ $(TOP)\src\vdbeblob.c \ $(TOP)\src\vdbemem.c \ $(TOP)\src\vdbesort.c \ $(TOP)\src\vdbetrace.c \ - $(TOP)\src\vdbeInt.h \ $(TOP)\src\vtab.c \ - $(TOP)\src\vxworks.h \ $(TOP)\src\wal.c \ - $(TOP)\src\wal.h \ $(TOP)\src\walker.c \ $(TOP)\src\where.c \ + $(TOP)\src\wherecode.c \ + $(TOP)\src\whereexpr.c + +# Shell source code files. +# +SRC02 = \ + $(TOP)\src\shell.c + +# Core miscellaneous files. +# +SRC03 = \ + $(TOP)\src\parse.y + +# Core header files, part 1. +# +SRC04 = \ + $(TOP)\src\btree.h \ + $(TOP)\src\btreeInt.h \ + $(TOP)\src\hash.h \ + $(TOP)\src\hwtime.h \ + $(TOP)\src\msvc.h \ + $(TOP)\src\mutex.h \ + $(TOP)\src\os.h \ + $(TOP)\src\os_common.h \ + $(TOP)\src\os_setup.h \ + $(TOP)\src\os_win.h + +# Core header files, part 2. +# +SRC05 = \ + $(TOP)\src\pager.h \ + $(TOP)\src\pcache.h \ + $(TOP)\src\pragma.h \ + $(TOP)\src\sqlite.h.in \ + $(TOP)\src\sqlite3ext.h \ + $(TOP)\src\sqliteInt.h \ + $(TOP)\src\sqliteLimit.h \ + $(TOP)\src\vdbe.h \ + $(TOP)\src\vdbeInt.h \ + $(TOP)\src\vxworks.h \ + $(TOP)\src\wal.h \ $(TOP)\src\whereInt.h -# Source code for extensions +# Extension source code files, part 1. # -SRC3 = \ +SRC06 = \ $(TOP)\ext\fts1\fts1.c \ - $(TOP)\ext\fts1\fts1.h \ $(TOP)\ext\fts1\fts1_hash.c \ - $(TOP)\ext\fts1\fts1_hash.h \ $(TOP)\ext\fts1\fts1_porter.c \ - $(TOP)\ext\fts1\fts1_tokenizer.h \ $(TOP)\ext\fts1\fts1_tokenizer1.c \ $(TOP)\ext\fts2\fts2.c \ - $(TOP)\ext\fts2\fts2.h \ $(TOP)\ext\fts2\fts2_hash.c \ - $(TOP)\ext\fts2\fts2_hash.h \ $(TOP)\ext\fts2\fts2_icu.c \ $(TOP)\ext\fts2\fts2_porter.c \ - $(TOP)\ext\fts2\fts2_tokenizer.h \ $(TOP)\ext\fts2\fts2_tokenizer.c \ $(TOP)\ext\fts2\fts2_tokenizer1.c -SRC4 = \ + +# Extension source code files, part 2. +# +SRC07 = \ $(TOP)\ext\fts3\fts3.c \ - $(TOP)\ext\fts3\fts3.h \ - $(TOP)\ext\fts3\fts3Int.h \ $(TOP)\ext\fts3\fts3_aux.c \ $(TOP)\ext\fts3\fts3_expr.c \ $(TOP)\ext\fts3\fts3_hash.c \ - $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_icu.c \ $(TOP)\ext\fts3\fts3_porter.c \ $(TOP)\ext\fts3\fts3_snippet.c \ - $(TOP)\ext\fts3\fts3_tokenizer.h \ $(TOP)\ext\fts3\fts3_tokenizer.c \ $(TOP)\ext\fts3\fts3_tokenizer1.c \ $(TOP)\ext\fts3\fts3_tokenize_vtab.c \ $(TOP)\ext\fts3\fts3_unicode.c \ $(TOP)\ext\fts3\fts3_unicode2.c \ $(TOP)\ext\fts3\fts3_write.c \ - $(TOP)\ext\icu\sqliteicu.h \ $(TOP)\ext\icu\icu.c \ - $(TOP)\ext\rtree\rtree.h \ - $(TOP)\ext\rtree\rtree.c + $(TOP)\ext\rtree\rtree.c \ + $(TOP)\ext\rbu\sqlite3rbu.c \ + $(TOP)\ext\misc\json1.c +# Extension header files, part 1. +# +SRC08 = \ + $(TOP)\ext\fts1\fts1.h \ + $(TOP)\ext\fts1\fts1_hash.h \ + $(TOP)\ext\fts1\fts1_tokenizer.h \ + $(TOP)\ext\fts2\fts2.h \ + $(TOP)\ext\fts2\fts2_hash.h \ + $(TOP)\ext\fts2\fts2_tokenizer.h + +# Extension header files, part 2. +# +SRC09 = \ + $(TOP)\ext\fts3\fts3.h \ + $(TOP)\ext\fts3\fts3Int.h \ + $(TOP)\ext\fts3\fts3_hash.h \ + $(TOP)\ext\fts3\fts3_tokenizer.h \ + $(TOP)\ext\icu\sqliteicu.h \ + $(TOP)\ext\rtree\rtree.h \ + $(TOP)\ext\rbu\sqlite3rbu.h # Generated source code files # -SRC5 = \ - keywordhash.h \ +SRC10 = \ opcodes.c \ + parse.c + +# Generated header files +# +SRC11 = \ + keywordhash.h \ opcodes.h \ - parse.c \ parse.h \ - sqlite3.h + $(SQLITE3H) # All source code files. # -SRC = $(SRC1) $(SRC2) $(SRC3) $(SRC4) $(SRC5) +SRC = $(SRC00) $(SRC01) $(SRC02) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11) # Source code to the test files. # @@ -1052,11 +1243,13 @@ TESTSRC = \ $(TOP)\src\test_tclvar.c \ $(TOP)\src\test_thread.c \ $(TOP)\src\test_vfs.c \ + $(TOP)\src\test_windirent.c \ $(TOP)\src\test_wsd.c \ $(TOP)\ext\fts3\fts3_term.c \ - $(TOP)\ext\fts3\fts3_test.c + $(TOP)\ext\fts3\fts3_test.c \ + $(TOP)\ext\rbu\test_rbu.c -# Statically linked extensions +# Statically linked extensions. # TESTEXT = \ $(TOP)\ext\misc\amatch.c \ @@ -1064,62 +1257,26 @@ TESTEXT = \ $(TOP)\ext\misc\eval.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ + $(TOP)\ext\fts5\fts5_tcl.c \ + $(TOP)\ext\fts5\fts5_test_mi.c \ + $(TOP)\ext\fts5\fts5_test_tok.c \ $(TOP)\ext\misc\ieee754.c \ $(TOP)\ext\misc\nextchar.c \ $(TOP)\ext\misc\percentile.c \ $(TOP)\ext\misc\regexp.c \ + $(TOP)\ext\misc\series.c \ $(TOP)\ext\misc\spellfix.c \ $(TOP)\ext\misc\totype.c \ $(TOP)\ext\misc\wholenumber.c - # Source code to the library files needed by the test fixture # TESTSRC2 = \ - $(TOP)\src\attach.c \ - $(TOP)\src\backup.c \ - $(TOP)\src\bitvec.c \ - $(TOP)\src\btree.c \ - $(TOP)\src\build.c \ - $(TOP)\src\ctime.c \ - $(TOP)\src\date.c \ - $(TOP)\src\dbstat.c \ - $(TOP)\src\expr.c \ - $(TOP)\src\func.c \ - $(TOP)\src\insert.c \ - $(TOP)\src\wal.c \ - $(TOP)\src\main.c \ - $(TOP)\src\mem5.c \ - $(TOP)\src\os.c \ - $(TOP)\src\os_unix.c \ - $(TOP)\src\os_win.c \ - $(TOP)\src\pager.c \ - $(TOP)\src\pragma.c \ - $(TOP)\src\prepare.c \ - $(TOP)\src\printf.c \ - $(TOP)\src\random.c \ - $(TOP)\src\pcache.c \ - $(TOP)\src\pcache1.c \ - $(TOP)\src\select.c \ - $(TOP)\src\tokenize.c \ - $(TOP)\src\utf.c \ - $(TOP)\src\util.c \ - $(TOP)\src\vdbeapi.c \ - $(TOP)\src\vdbeaux.c \ - $(TOP)\src\vdbe.c \ - $(TOP)\src\vdbemem.c \ - $(TOP)\src\vdbesort.c \ - $(TOP)\src\vdbetrace.c \ - $(TOP)\src\where.c \ - parse.c \ - $(TOP)\ext\fts3\fts3.c \ - $(TOP)\ext\fts3\fts3_aux.c \ - $(TOP)\ext\fts3\fts3_expr.c \ - $(TOP)\ext\fts3\fts3_tokenizer.c \ - $(TOP)\ext\fts3\fts3_tokenize_vtab.c \ - $(TOP)\ext\fts3\fts3_unicode.c \ - $(TOP)\ext\fts3\fts3_unicode2.c \ - $(TOP)\ext\fts3\fts3_write.c \ + $(SRC00) \ + $(SRC01) \ + $(SRC06) \ + $(SRC07) \ + $(SRC10) \ $(TOP)\ext\async\sqlite3async.c # Header files used by all library source files. @@ -1141,7 +1298,7 @@ HDR = \ $(TOP)\src\pcache.h \ parse.h \ $(TOP)\src\pragma.h \ - sqlite3.h \ + $(SQLITE3H) \ $(TOP)\src\sqlite3ext.h \ $(TOP)\src\sqliteInt.h \ $(TOP)\src\sqliteLimit.h \ @@ -1172,30 +1329,104 @@ EXTHDR = $(EXTHDR) \ EXTHDR = $(EXTHDR) \ $(TOP)\ext\rtree\sqlite3rtree.h +# executables needed for testing +# +TESTPROGS = \ + testfixture.exe \ + $(SQLITE3EXE) \ + sqlite3_analyzer.exe \ + sqldiff.exe + +# Databases containing fuzzer test cases +# +FUZZDATA = \ + $(TOP)\test\fuzzdata1.db \ + $(TOP)\test\fuzzdata2.db \ + $(TOP)\test\fuzzdata3.db \ + $(TOP)\test\fuzzdata4.db +# <> + +# Additional compiler options for the shell. These are only effective +# when the shell is not being dynamically linked. +# +!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0 +SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS +!ENDIF + +# <> +# Extra compiler options for various test tools. +# +MPTESTER_COMPILE_OPTS = -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS5 +FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 +FUZZCHECK_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 + +# Standard options to testfixture. +# +TESTOPTS = --verbose=file --output=test-out.txt + +# Extra targets for the "all" target that require Tcl. +# +!IF $(NO_TCL)==0 +ALL_TCL_TARGETS = libtclsqlite3.lib +!ELSE +ALL_TCL_TARGETS = +!ENDIF +# <> + # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # -all: dll libsqlite3.lib sqlite3.exe libtclsqlite3.lib +all: dll libsqlite3.lib shell $(ALL_TCL_TARGETS) + +# Dynamic link library section. +# +dll: $(SQLITE3DLL) + +# Shell executable. +# +shell: $(SQLITE3EXE) libsqlite3.lib: $(LIBOBJ) $(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS) +# <> libtclsqlite3.lib: tclsqlite.lo libsqlite3.lib - $(LTLIB) $(LTLIBOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCL:tcl=tclstub) $(TLIBS) + $(LTLIB) $(LTLIBOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCLSTUB) $(TLIBS) +# <> -sqlite3.exe: $(TOP)\src\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3.h - $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\shell.c \ - /link /pdb:sqlite3sh.pdb $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) +$(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP) + $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) -sqldiff.exe: $(TOP)\tool\sqldiff.c sqlite3.c sqlite3.h - $(LTLINK) $(TOP)\tool\sqldiff.c sqlite3.c +# <> +sqlite3.def: libsqlite3.lib + echo EXPORTS > sqlite3.def + dumpbin /all libsqlite3.lib \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3_.*)$$" \1 \ + | sort >> sqlite3.def +# <> -fuzzershell.exe: $(TOP)\tool\fuzzershell.c sqlite3.c sqlite3.h - $(LTLINK) $(TOP)\tool\fuzzershell.c sqlite3.c +$(SQLITE3EXE): $(TOP)\src\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H) + $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\shell.c $(SHELL_CORE_SRC) \ + /link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) -mptester.exe: $(TOP)\mptest\mptest.c $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3.h - $(LTLINK) $(SHELL_COMPILE_OPTS) $(TOP)\mptest\mptest.c \ - /link $(LTLINKOPTS) $(LTLIBPATHS) $(SHELL_LINK_OPTS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) +# <> +sqldiff.exe: $(TOP)\tool\sqldiff.c $(SQLITE3C) $(SQLITE3H) + $(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) + +srcck1.exe: $(TOP)\tool\srcck1.c + $(BCC) $(NO_WARN) -Fe$@ $(TOP)\tool\srcck1.c + +sourcetest: srcck1.exe sqlite3.c + srcck1.exe sqlite3.c + +fuzzershell.exe: $(TOP)\tool\fuzzershell.c $(SQLITE3C) $(SQLITE3H) + $(LTLINK) $(NO_WARN) $(FUZZERSHELL_COMPILE_OPTS) $(TOP)\tool\fuzzershell.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) + +fuzzcheck.exe: $(TOP)\test\fuzzcheck.c $(SQLITE3C) $(SQLITE3H) + $(LTLINK) $(NO_WARN) $(FUZZCHECK_COMPILE_OPTS) $(TOP)\test\fuzzcheck.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) + +mptester.exe: $(TOP)\mptest\mptest.c $(SQLITE3C) $(SQLITE3H) + $(LTLINK) $(NO_WARN) $(MPTESTER_COMPILE_OPTS) $(TOP)\mptest\mptest.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) MPTEST1 = mptester mptest.db $(TOP)\mptest\crash01.test --repeat 20 MPTEST2 = mptester mptest.db $(TOP)\mptest\multiwrite01.test --repeat 20 @@ -1217,49 +1448,50 @@ mptest: mptester.exe # files are automatically generated. This target takes care of # all that automatic generation. # -.target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl +.target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl fts5.c -rmdir /Q/S tsrc 2>NUL -mkdir tsrc - for %i in ($(SRC1)) do copy /Y %i tsrc - for %i in ($(SRC2)) do copy /Y %i tsrc - for %i in ($(SRC3)) do copy /Y %i tsrc - for %i in ($(SRC4)) do copy /Y %i tsrc - for %i in ($(SRC5)) do copy /Y %i tsrc + for %i in ($(SRC00)) do copy /Y %i tsrc + for %i in ($(SRC01)) do copy /Y %i tsrc + for %i in ($(SRC02)) do copy /Y %i tsrc + for %i in ($(SRC03)) do copy /Y %i tsrc + for %i in ($(SRC04)) do copy /Y %i tsrc + for %i in ($(SRC05)) do copy /Y %i tsrc + for %i in ($(SRC06)) do copy /Y %i tsrc + for %i in ($(SRC07)) do copy /Y %i tsrc + for %i in ($(SRC08)) do copy /Y %i tsrc + for %i in ($(SRC09)) do copy /Y %i tsrc + for %i in ($(SRC10)) do copy /Y %i tsrc + for %i in ($(SRC11)) do copy /Y %i tsrc + copy /Y fts5.c tsrc + copy /Y fts5.h tsrc del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new move vdbe.new tsrc\vdbe.c echo > .target_source -sqlite3.c: .target_source $(TOP)\tool\mksqlite3c.tcl +sqlite3.c: .target_source sqlite3ext.h $(TOP)\tool\mksqlite3c.tcl $(TCLSH_CMD) $(TOP)\tool\mksqlite3c.tcl $(MKSQLITE3C_ARGS) copy tsrc\shell.c . - copy tsrc\sqlite3ext.h . sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl $(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl - -# Set the source code file to be used by executables and libraries when -# they need the amalgamation. -# -!IF $(SPLIT_AMALGAMATION)!=0 -SQLITE3C = sqlite3-all.c -!ELSE -SQLITE3C = sqlite3.c -!ENDIF +# <> # Rule to build the amalgamation # sqlite3.lo: $(SQLITE3C) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(SQLITE3C) +# <> # Rules to build the LEMON compiler generator # -lempar.c: $(TOP)\src\lempar.c - copy $(TOP)\src\lempar.c . +lempar.c: $(TOP)\tool\lempar.c + copy $(TOP)\tool\lempar.c . lemon.exe: $(TOP)\tool\lemon.c lempar.c $(BCC) $(NO_WARN) -Daccess=_access \ - -Fe$@ $(TOP)\tool\lemon.c /link $(NLTLINKOPTS) $(NLTLIBPATHS) + -Fe$@ $(TOP)\tool\lemon.c /link $(LDFLAGS) $(NLTLINKOPTS) $(NLTLIBPATHS) # Rules to build individual *.lo files from generated *.c files. This # applies to: @@ -1272,20 +1504,24 @@ parse.lo: parse.c $(HDR) opcodes.lo: opcodes.c $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c opcodes.c +# <> # Rule to build the Win32 resources object file. # !IF $(USE_RC)!=0 -$(LIBRESOBJS): $(TOP)\src\sqlite3.rc $(HDR) +# <> +$(LIBRESOBJS): $(TOP)\src\sqlite3.rc $(SQLITE3H) echo #ifndef SQLITE_RESOURCE_VERSION > sqlite3rc.h for /F %%V in ('type "$(TOP)\VERSION"') do ( \ echo #define SQLITE_RESOURCE_VERSION %%V \ - | $(NAWK) "/.*/ { gsub(/[.]/,\",\");print }" >> sqlite3rc.h \ + | $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact . ^, >> sqlite3rc.h \ ) echo #endif >> sqlite3rc.h $(LTRCOMPILE) -fo $(LIBRESOBJS) $(TOP)\src\sqlite3.rc +# <> !ENDIF +# <> # Rules to build individual *.lo files from files in the src directory. # alter.lo: $(TOP)\src\alter.c $(HDR) @@ -1453,6 +1689,9 @@ threads.lo: $(TOP)\src\threads.c $(HDR) tokenize.lo: $(TOP)\src\tokenize.c keywordhash.h $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\tokenize.c +treeview.lo: $(TOP)\src\treeview.c $(HDR) + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\treeview.c + trigger.lo: $(TOP)\src\trigger.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\trigger.c @@ -1501,40 +1740,49 @@ walker.lo: $(TOP)\src\walker.c $(HDR) where.lo: $(TOP)\src\where.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\where.c +wherecode.lo: $(TOP)\src\wherecode.c $(HDR) + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\wherecode.c + +whereexpr.lo: $(TOP)\src\whereexpr.c $(HDR) + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\whereexpr.c + tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR) $(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c tclsqlite-shell.lo: $(TOP)\src\tclsqlite.c $(HDR) $(LTCOMPILE) $(NO_WARN) -DTCLSH=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c -tclsqlite3.exe: tclsqlite-shell.lo $(SQLITE3C) $(LIBRESOBJS) - $(LTLINK) $(SQLITE3C) /link $(LTLINKOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(LTLIBS) $(TLIBS) +tclsqlite3.exe: tclsqlite-shell.lo $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS) + $(LTLINK) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(LTLIBS) $(TLIBS) # Rules to build opcodes.c and opcodes.h # -opcodes.c: opcodes.h $(TOP)\mkopcodec.awk - $(NAWK) -f $(TOP)\mkopcodec.awk opcodes.h > opcodes.c +opcodes.c: opcodes.h $(TOP)\tool\mkopcodec.tcl + $(TCLSH_CMD) $(TOP)\tool\mkopcodec.tcl opcodes.h > opcodes.c -opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\mkopcodeh.awk - type parse.h $(TOP)\src\vdbe.c | $(NAWK) -f $(TOP)\mkopcodeh.awk > opcodes.h +opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\tool\mkopcodeh.tcl + type parse.h $(TOP)\src\vdbe.c | $(TCLSH_CMD) $(TOP)\tool\mkopcodeh.tcl > opcodes.h # Rules to build parse.c and parse.h - the outputs of lemon. # parse.h: parse.c -parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\addopcodes.awk +parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\tool\addopcodes.tcl del /Q parse.y parse.h parse.h.temp 2>NUL copy $(TOP)\src\parse.y . - .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(OPTS) parse.y + .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) parse.y move parse.h parse.h.temp - $(NAWK) -f $(TOP)\addopcodes.awk parse.h.temp > parse.h + $(TCLSH_CMD) $(TOP)\tool\addopcodes.tcl parse.h.temp > parse.h -sqlite3.h: $(TOP)\src\sqlite.h.in $(TOP)\manifest.uuid $(TOP)\VERSION - $(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > sqlite3.h +$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest.uuid $(TOP)\VERSION + $(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > $(SQLITE3H) + +sqlite3ext.h: .target_source + copy tsrc\sqlite3ext.h . mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c - $(BCC) $(NO_WARN) -Fe$@ $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(OPTS) \ - $(TOP)\tool\mkkeywordhash.c /link $(NLTLINKOPTS) $(NLTLIBPATHS) + $(BCC) $(NO_WARN) -Fe$@ $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) \ + $(TOP)\tool\mkkeywordhash.c /link $(LDFLAGS) $(NLTLINKOPTS) $(NLTLIBPATHS) keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe .\mkkeywordhash.exe > keywordhash.h @@ -1606,6 +1854,47 @@ fts3_write.lo: $(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR) rtree.lo: $(TOP)\ext\rtree\rtree.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\rtree\rtree.c +# FTS5 things +# +FTS5_SRC = \ + $(TOP)\ext\fts5\fts5.h \ + $(TOP)\ext\fts5\fts5Int.h \ + $(TOP)\ext\fts5\fts5_aux.c \ + $(TOP)\ext\fts5\fts5_buffer.c \ + $(TOP)\ext\fts5\fts5_main.c \ + $(TOP)\ext\fts5\fts5_config.c \ + $(TOP)\ext\fts5\fts5_expr.c \ + $(TOP)\ext\fts5\fts5_hash.c \ + $(TOP)\ext\fts5\fts5_index.c \ + fts5parse.c fts5parse.h \ + $(TOP)\ext\fts5\fts5_storage.c \ + $(TOP)\ext\fts5\fts5_tokenize.c \ + $(TOP)\ext\fts5\fts5_unicode2.c \ + $(TOP)\ext\fts5\fts5_varint.c \ + $(TOP)\ext\fts5\fts5_vocab.c + +fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe + copy $(TOP)\ext\fts5\fts5parse.y . + del /Q fts5parse.h 2>NUL + .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) fts5parse.y + +fts5parse.h: fts5parse.c + +fts5.c: $(FTS5_SRC) + $(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl + copy $(TOP)\ext\fts5\fts5.h . + +fts5.lo: fts5.c $(HDR) $(EXTHDR) + $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c fts5.c + +fts5_ext.lo: fts5.c $(HDR) $(EXTHDR) + $(LTCOMPILE) $(NO_WARN) -c fts5.c + +fts5.dll: fts5_ext.lo + $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /OUT:$@ fts5_ext.lo + +sqlite3rbu.lo: $(TOP)\ext\rbu\sqlite3rbu.c $(HDR) $(EXTHDR) + $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\rbu\sqlite3rbu.c # Rules to build the 'testfixture' application. # @@ -1618,7 +1907,7 @@ TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN) -TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) $(SHELL_CORE_DEP) +TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C) !IF $(USE_AMALGAMATION)==0 TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0) @@ -1626,49 +1915,67 @@ TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0) TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC1) !ENDIF -testfixture.exe: $(TESTFIXTURE_SRC) $(LIBRESOBJS) $(HDR) +testfixture.exe: $(TESTFIXTURE_SRC) $(SQLITE3H) $(LIBRESOBJS) $(HDR) $(LTLINK) -DSQLITE_NO_SYNC=1 $(TESTFIXTURE_FLAGS) \ -DBUILD_sqlite -I$(TCLINCDIR) \ $(TESTFIXTURE_SRC) \ - /link $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) + /link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) extensiontest: testfixture.exe testloadext.dll - .\testfixture.exe $(TOP)\test\loadext.test + @set PATH=$(LIBTCLPATH);$(PATH) + .\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS) -fulltest: testfixture.exe sqlite3.exe fuzztest - .\testfixture.exe $(TOP)\test\all.test +fulltest: $(TESTPROGS) fuzztest + @set PATH=$(LIBTCLPATH);$(PATH) + .\testfixture.exe $(TOP)\test\all.test $(TESTOPTS) -soaktest: testfixture.exe sqlite3.exe fuzzoomtest - .\testfixture.exe $(TOP)\test\all.test -soak=1 +soaktest: $(TESTPROGS) + @set PATH=$(LIBTCLPATH);$(PATH) + .\testfixture.exe $(TOP)\test\all.test -soak=1 $(TESTOPTS) -fulltestonly: testfixture.exe sqlite3.exe fuzztest +fulltestonly: $(TESTPROGS) fuzztest + @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\full.test -queryplantest: testfixture.exe sqlite3.exe - .\testfixture.exe $(TOP)\test\permutations.test queryplanner +queryplantest: testfixture.exe shell + @set PATH=$(LIBTCLPATH);$(PATH) + .\testfixture.exe $(TOP)\test\permutations.test queryplanner $(TESTOPTS) -fuzztest: fuzzershell.exe - .\fuzzershell.exe $(TOP)\test\fuzzdata1.txt $(TOP)\test\fuzzdata2.txt +fuzztest: fuzzcheck.exe + .\fuzzcheck.exe $(FUZZDATA) -fuzzoomtest: fuzzershell.exe - .\fuzzershell.exe -f $(TOP)\test\fuzzdata1.txt --oom +fastfuzztest: fuzzcheck.exe + .\fuzzcheck.exe --limit-mem 100M $(FUZZDATA) -test: testfixture.exe sqlite3.exe fuzztest - .\testfixture.exe $(TOP)\test\veryquick.test +# Minimal testing that runs in less than 3 minutes (on a fast machine) +# +quicktest: testfixture.exe sourcetest + @set PATH=$(LIBTCLPATH);$(PATH) + .\testfixture.exe $(TOP)\test\extraquick.test $(TESTOPTS) -smoketest: testfixture.exe - .\testfixture.exe $(TOP)\test\main.test +# This is the common case. Run many tests that do not take too long, +# including fuzzcheck, sqlite3_analyzer, and sqldiff tests. +# +test: $(TESTPROGS) sourcetest fastfuzztest + @set PATH=$(LIBTCLPATH);$(PATH) + .\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS) -sqlite3_analyzer.c: $(SQLITE3C) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl - copy $(SQLITE3C) + $(TOP)\src\tclsqlite.c $@ +smoketest: $(TESTPROGS) + @set PATH=$(LIBTCLPATH);$(PATH) + .\testfixture.exe $(TOP)\test\main.test $(TESTOPTS) + +sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl + echo #define TCLSH 2 > $@ + echo #define SQLITE_ENABLE_DBSTAT_VTAB 1 >> $@ + copy $@ + $(SQLITE3C) + $(TOP)\src\tclsqlite.c $@ echo static const char *tclsh_main_loop(void){ >> $@ echo static const char *zMainloop = >> $@ - $(NAWK) -f $(TOP)\tool\tostr.awk $(TOP)\tool\spaceanal.tcl >> $@ + $(TCLSH_CMD) $(TOP)\tool\tostr.tcl $(TOP)\tool\spaceanal.tcl >> $@ echo ; return zMainloop; } >> $@ sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS) - $(LTLINK) $(NO_WARN) -DBUILD_sqlite -DSQLITE_ENABLE_DBSTAT_VTAB -DTCLSH=2 -I$(TCLINCDIR) sqlite3_analyzer.c \ - /link $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) + $(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \ + /link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) testloadext.lo: $(TOP)\src\test_loadext.c $(LTCOMPILE) $(NO_WARN) -c $(TOP)\src\test_loadext.c @@ -1676,45 +1983,51 @@ testloadext.lo: $(TOP)\src\test_loadext.c testloadext.dll: testloadext.lo $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /OUT:$@ testloadext.lo -showdb.exe: $(TOP)\tool\showdb.c $(SQLITE3C) +showdb.exe: $(TOP)\tool\showdb.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ - $(TOP)\tool\showdb.c $(SQLITE3C) + $(TOP)\tool\showdb.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) -showstat4.exe: $(TOP)\tool\showstat4.c $(SQLITE3C) +showstat4.exe: $(TOP)\tool\showstat4.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ - $(TOP)\tool\showstat4.c $(SQLITE3C) + $(TOP)\tool\showstat4.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) -showjournal.exe: $(TOP)\tool\showjournal.c $(SQLITE3C) +showjournal.exe: $(TOP)\tool\showjournal.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ - $(TOP)\tool\showjournal.c $(SQLITE3C) + $(TOP)\tool\showjournal.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) -showwal.exe: $(TOP)\tool\showwal.c $(SQLITE3C) +showwal.exe: $(TOP)\tool\showwal.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ - $(TOP)\tool\showwal.c $(SQLITE3C) + $(TOP)\tool\showwal.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) -fts3view.exe: $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) +fts3view.exe: $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ - $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) + $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) -rollback-test.exe: $(TOP)\tool\rollback-test.c $(SQLITE3C) +rollback-test.exe: $(TOP)\tool\rollback-test.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ - $(TOP)\tool\rollback-test.c $(SQLITE3C) + $(TOP)\tool\rollback-test.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) -LogEst.exe: $(TOP)\tool\logest.c sqlite3.h - $(LTLINK) $(NO_WARN) -Fe$@ $(TOP)\tool\LogEst.c +LogEst.exe: $(TOP)\tool\logest.c $(SQLITE3H) + $(LTLINK) $(NO_WARN) -Fe$@ $(TOP)\tool\LogEst.c /link $(LDFLAGS) $(LTLINKOPTS) -wordcount.exe: $(TOP)\test\wordcount.c $(SQLITE3C) +wordcount.exe: $(TOP)\test\wordcount.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ - $(TOP)\test\wordcount.c $(SQLITE3C) + $(TOP)\test\wordcount.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) -speedtest1.exe: $(TOP)\test\speedtest1.c $(SQLITE3C) +speedtest1.exe: $(TOP)\test\speedtest1.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \ - $(TOP)\test\speedtest1.c $(SQLITE3C) + $(TOP)\test\speedtest1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) + +rbu.exe: $(TOP)\ext\rbu\rbu.c $(TOP)\ext\rbu\sqlite3rbu.c $(SQLITE3C) $(SQLITE3H) + $(LTLINK) $(NO_WARN) -DSQLITE_ENABLE_RBU -Fe$@ \ + $(TOP)\ext\rbu\rbu.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) +# <> clean: - del /Q *.exp *.lo *.ilk *.lib *.obj *.pdb 2>NUL - del /Q *.cod *.da *.bb *.bbg gmon.out 2>NUL - del /Q sqlite3.h opcodes.c opcodes.h 2>NUL + del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL + del /Q *.bsc *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL +# <> + del /Q $(SQLITE3C) $(SQLITE3H) opcodes.c opcodes.h 2>NUL del /Q lemon.* lempar.c parse.* 2>NUL del /Q mkkeywordhash.* keywordhash.h 2>NUL del /Q notasharedlib.* 2>NUL @@ -1730,23 +2043,13 @@ clean: del /Q testfixture.exe test.db 2>NUL del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe 2>NUL del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL - del /Q mptester.exe wordcount.exe 2>NUL - del /Q sqlite3.exe sqlite3.dll sqlite3.def 2>NUL + del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL + del /Q $(SQLITE3EXE) $(SQLITE3DLL) sqlite3.def 2>NUL del /Q sqlite3.c sqlite3-*.c 2>NUL del /Q sqlite3rc.h 2>NUL del /Q shell.c sqlite3ext.h 2>NUL del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL del /Q sqlite-*-output.vsix 2>NUL - -# Dynamic link library section. -# -dll: sqlite3.dll - -sqlite3.def: libsqlite3.lib - echo EXPORTS > sqlite3.def - dumpbin /all libsqlite3.lib \ - | $(NAWK) "/ 1 _?sqlite3_/ { sub(/^.* _?/,\"\");print }" \ - | sort >> sqlite3.def - -sqlite3.dll: $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP) - $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) + del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe 2>NUL + del /Q fts5.* fts5parse.* 2>NUL +# <> diff --git a/Makefile.vxworks b/Makefile.vxworks deleted file mode 100644 index 706261f..0000000 --- a/Makefile.vxworks +++ /dev/null @@ -1,673 +0,0 @@ -#!/usr/make -# -# Makefile for SQLITE on VxWorks - -ifeq ($(FORCPU),) - FORCPU = SH32gnule -endif - -TOOL_FAMILY = gnu - -include $(WIND_USR)/tool/gnu/make.$(FORCPU) - -#### The toplevel directory of the source tree. This is the directory -# that contains this "Makefile.in" and the "configure.in" script. -# -TOP = . - -#### C Compiler and options for use in building executables that -# will run on the platform that is doing the build. -# -BCC = gcc -g -O2 -#BCC = /opt/ancic/bin/c89 -0 - -#### If the target operating system supports the "usleep()" system -# call, then define the HAVE_USLEEP macro for all C modules. -# -USLEEP = -#USLEEP = -DHAVE_USLEEP=1 - -#### If you want the SQLite library to be safe for use within a -# multi-threaded program, then define the following macro -# appropriately: -# -THREADSAFE = -DSQLITE_THREADSAFE=1 -#THREADSAFE = -DSQLITE_THREADSAFE=0 - -#### Specify any extra linker options needed to make the library -# thread safe -# -#THREADLIB = -lpthread -THREADLIB = - -#### Specify any extra libraries needed to access required functions. -# -ifeq ($(CPU),SH32) - # for SH4 shared library - TLIBS_SHARED += -L$(WIND_USR)/lib/sh/SH32/commonle/PIC -else - # for all other CPUs shared library - TLIBS_SHARED += $(LD_LINK_PATH_ATEND) $(LD_PARTIAL_LAST_FLAGS) -endif -# for static library -TLIBS += $(LD_LINK_PATH_ATEND) $(LD_PARTIAL_LAST_FLAGS) - -#### Leave SQLITE_DEBUG undefined for maximum speed. Use SQLITE_DEBUG=1 -# to check for memory leaks. Use SQLITE_DEBUG=2 to print a log of all -# malloc()s and free()s in order to track down memory leaks. -# -# SQLite uses some expensive assert() statements in the inner loop. -# You can make the library go almost twice as fast if you compile -# with -DNDEBUG=1 -# -#OPTS = -DSQLITE_DEBUG=2 -#OPTS = -DSQLITE_DEBUG=1 -#OPTS = -OPTS = -DNDEBUG=1 -DSQLITE_OS_UNIX=1 $(THREADSAFE) -OPTS += -DSQLITE_OMIT_LOAD_EXTENSION=1 -OPTS += -DSQLITE_ENABLE_LOCKING_STYLE=1 -OPTS += -DSQLITE_THREAD_OVERRIDE_LOCK=0 -OPTS += -DSQLITE_ENABLE_COLUMN_METADATA=1 -OPTS += -DHAVE_FDATASYNC=1 - -#### The suffix to add to executable files. ".exe" for windows. -# Nothing for unix. -# -EXE = .vxe -#EXE = - -#### C Compile and options for use in building executables that -# will run on the target platform. This is usually the same -# as BCC, unless you are cross-compiling. -# -#TCC = gcc -O6 -#TCC = gcc -g -O0 -Wall -#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage -#TCC = /opt/mingw/bin/i386-mingw32-gcc -O6 -TCC = $(CC) $(DEFINE_CC) -O2 -g -mrtp $(CC_ARCH_SPEC) -D_REENTRANT=1 -D_VX_CPU=_VX_$(CPU) -D_VX_TOOL_FAMILY=$(TOOL_FAMILY) -D_VX_TOOL=$(TOOL) -TCC += -I$(WIND_USR)/h -I$(WIND_USR)/h/wrn/coreip -#TCC = /opt/ansic/bin/c89 -O +z -Wl,-a,archive - -#TCC_SHARED = $(TCC) -fPIC -TCC_SHARED = $(TCC) - -#### Tools used to build a static library. -# -#ARX = ar cr -#ARX = /opt/mingw/bin/i386-mingw32-ar cr -AR += cr -#RANLIB = ranlib -#RANLIB = /opt/mingw/bin/i386-mingw32-ranlib - -#MKSHLIB = gcc -shared -#SO = so -#SHPREFIX = lib -MKSHLIB = $(CC) $(DEFINE_CC) -mrtp -shared $(CC_ARCH_SPEC) -D_VX_CPU=_VX_$(CPU) -D_VX_TOOL_FAMILY=$(TOOL_FAMILY) -D_VX_TOOL=$(TOOL) -SO = so -SHPREFIX = lib - -#### Extra compiler options needed for programs that use the TCL library. -# -#TCL_FLAGS = -#TCL_FLAGS = -DSTATIC_BUILD=1 -TCL_FLAGS = -I/home/drh/tcltk/8.5linux -#TCL_FLAGS = -I/home/drh/tcltk/8.5win -DSTATIC_BUILD=1 -#TCL_FLAGS = -I/home/drh/tcltk/8.3hpux - -#### Linker options needed to link against the TCL library. -# -#LIBTCL = -ltcl -lm -ldl -LIBTCL = /home/drh/tcltk/8.5linux/libtcl8.5g.a -lm -ldl -#LIBTCL = /home/drh/tcltk/8.5win/libtcl85s.a -lmsvcrt -#LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc - -#### Additional objects for SQLite library when TCL support is enabled. -TCLOBJ = -#TCLOBJ = tclsqlite.o - -#### Compiler options needed for programs that use the readline() library. -# -READLINE_FLAGS = -#READLINE_FLAGS = -DHAVE_READLINE=1 -I/usr/include/readline - -#### Linker options needed by programs using readline() must link against. -# -LIBREADLINE = -#LIBREADLINE = -static -lreadline -ltermcap - -#### Which "awk" program provides nawk compatibilty -# -# NAWK = nawk -NAWK = awk - - -#### Pasted and adapted main.mk file -############################################################################### -# The following macros should be defined before this script is -# invoked: -# -# TOP The toplevel directory of the source tree. This is the -# directory that contains this "Makefile.in" and the -# "configure.in" script. -# -# BCC C Compiler and options for use in building executables that -# will run on the platform that is doing the build. -# -# THREADLIB Specify any extra linker options needed to make the library -# thread safe -# -# OPTS Extra compiler command-line options. -# -# EXE The suffix to add to executable files. ".exe" for windows -# and "" for Unix. -# -# TCC C Compiler and options for use in building executables that -# will run on the target platform. This is usually the same -# as BCC, unless you are cross-compiling. -# -# AR Tools used to build a static library. -# RANLIB -# -# TCL_FLAGS Extra compiler options needed for programs that use the -# TCL library. -# -# LIBTCL Linker options needed to link against the TCL library. -# -# READLINE_FLAGS Compiler options needed for programs that use the -# readline() library. -# -# LIBREADLINE Linker options needed by programs using readline() must -# link against. -# -# NAWK Nawk compatible awk program. Older (obsolete?) solaris -# systems need this to avoid using the original AT&T AWK. -# -# Once the macros above are defined, the rest of this make script will -# build the SQLite library and testing tools. -################################################################################ - -# This is how we compile -# -TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP) -TCCX_SHARED = $(TCC_SHARED) $(OPTS) -I. -I$(TOP)/src -I$(TOP) \ - -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3 \ - -I$(TOP)/ext/async - -# Object files for the SQLite library. -# -LIBOBJ+= alter.o analyze.o attach.o auth.o \ - backup.o bitvec.o btmutex.o btree.o build.o \ - callback.o complete.o date.o delete.o expr.o fault.o \ - fts3.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \ - fts3_tokenizer.o fts3_tokenizer1.o \ - func.o global.o hash.o \ - icu.o insert.o journal.o legacy.o loadext.o \ - main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \ - memjournal.o \ - mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \ - notify.o opcodes.o os.o os_unix.o os_win.o \ - pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \ - random.o resolve.o rowset.o rtree.o select.o status.o \ - table.o tokenize.o trigger.o \ - update.o util.o vacuum.o \ - vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o \ - walker.o where.o utf.o vtab.o - - - -# All of the source code files. -# -SRC = \ - $(TOP)/src/alter.c \ - $(TOP)/src/analyze.c \ - $(TOP)/src/attach.c \ - $(TOP)/src/auth.c \ - $(TOP)/src/backup.c \ - $(TOP)/src/bitvec.c \ - $(TOP)/src/btmutex.c \ - $(TOP)/src/btree.c \ - $(TOP)/src/btree.h \ - $(TOP)/src/btreeInt.h \ - $(TOP)/src/build.c \ - $(TOP)/src/callback.c \ - $(TOP)/src/complete.c \ - $(TOP)/src/ctime.c \ - $(TOP)/src/date.c \ - $(TOP)/src/delete.c \ - $(TOP)/src/expr.c \ - $(TOP)/src/fault.c \ - $(TOP)/src/func.c \ - $(TOP)/src/global.c \ - $(TOP)/src/hash.c \ - $(TOP)/src/hash.h \ - $(TOP)/src/hwtime.h \ - $(TOP)/src/insert.c \ - $(TOP)/src/journal.c \ - $(TOP)/src/legacy.c \ - $(TOP)/src/loadext.c \ - $(TOP)/src/main.c \ - $(TOP)/src/malloc.c \ - $(TOP)/src/mem0.c \ - $(TOP)/src/mem1.c \ - $(TOP)/src/mem2.c \ - $(TOP)/src/mem3.c \ - $(TOP)/src/mem5.c \ - $(TOP)/src/memjournal.c \ - $(TOP)/src/msvc.h \ - $(TOP)/src/mutex.c \ - $(TOP)/src/mutex.h \ - $(TOP)/src/mutex_noop.c \ - $(TOP)/src/mutex_unix.c \ - $(TOP)/src/mutex_w32.c \ - $(TOP)/src/notify.c \ - $(TOP)/src/os.c \ - $(TOP)/src/os.h \ - $(TOP)/src/os_common.h \ - $(TOP)/src/os_setup.h \ - $(TOP)/src/os_unix.c \ - $(TOP)/src/os_win.c \ - $(TOP)/src/os_win.h \ - $(TOP)/src/pager.c \ - $(TOP)/src/pager.h \ - $(TOP)/src/parse.y \ - $(TOP)/src/pcache.c \ - $(TOP)/src/pcache.h \ - $(TOP)/src/pcache1.c \ - $(TOP)/src/pragma.c \ - $(TOP)/src/prepare.c \ - $(TOP)/src/printf.c \ - $(TOP)/src/random.c \ - $(TOP)/src/resolve.c \ - $(TOP)/src/rowset.c \ - $(TOP)/src/select.c \ - $(TOP)/src/status.c \ - $(TOP)/src/shell.c \ - $(TOP)/src/sqlite.h.in \ - $(TOP)/src/sqlite3ext.h \ - $(TOP)/src/sqliteInt.h \ - $(TOP)/src/sqliteLimit.h \ - $(TOP)/src/table.c \ - $(TOP)/src/tclsqlite.c \ - $(TOP)/src/tokenize.c \ - $(TOP)/src/trigger.c \ - $(TOP)/src/utf.c \ - $(TOP)/src/update.c \ - $(TOP)/src/util.c \ - $(TOP)/src/vacuum.c \ - $(TOP)/src/vdbe.c \ - $(TOP)/src/vdbe.h \ - $(TOP)/src/vdbeapi.c \ - $(TOP)/src/vdbeaux.c \ - $(TOP)/src/vdbeblob.c \ - $(TOP)/src/vdbemem.c \ - $(TOP)/src/vdbeInt.h \ - $(TOP)/src/vtab.c \ - $(TOP)/src/walker.c \ - $(TOP)/src/where.c - -# Source code for extensions -# -SRC += \ - $(TOP)/ext/fts1/fts1.c \ - $(TOP)/ext/fts1/fts1.h \ - $(TOP)/ext/fts1/fts1_hash.c \ - $(TOP)/ext/fts1/fts1_hash.h \ - $(TOP)/ext/fts1/fts1_porter.c \ - $(TOP)/ext/fts1/fts1_tokenizer.h \ - $(TOP)/ext/fts1/fts1_tokenizer1.c -SRC += \ - $(TOP)/ext/fts2/fts2.c \ - $(TOP)/ext/fts2/fts2.h \ - $(TOP)/ext/fts2/fts2_hash.c \ - $(TOP)/ext/fts2/fts2_hash.h \ - $(TOP)/ext/fts2/fts2_icu.c \ - $(TOP)/ext/fts2/fts2_porter.c \ - $(TOP)/ext/fts2/fts2_tokenizer.h \ - $(TOP)/ext/fts2/fts2_tokenizer.c \ - $(TOP)/ext/fts2/fts2_tokenizer1.c -SRC += \ - $(TOP)/ext/fts3/fts3.c \ - $(TOP)/ext/fts3/fts3.h \ - $(TOP)/ext/fts3/fts3_expr.c \ - $(TOP)/ext/fts3/fts3_expr.h \ - $(TOP)/ext/fts3/fts3_hash.c \ - $(TOP)/ext/fts3/fts3_hash.h \ - $(TOP)/ext/fts3/fts3_icu.c \ - $(TOP)/ext/fts3/fts3_porter.c \ - $(TOP)/ext/fts3/fts3_tokenizer.h \ - $(TOP)/ext/fts3/fts3_tokenizer.c \ - $(TOP)/ext/fts3/fts3_tokenizer1.c -SRC += \ - $(TOP)/ext/icu/sqliteicu.h \ - $(TOP)/ext/icu/icu.c -SRC += \ - $(TOP)/ext/rtree/rtree.h \ - $(TOP)/ext/rtree/rtree.c - - -# Generated source code files -# -SRC += \ - keywordhash.h \ - opcodes.c \ - opcodes.h \ - parse.c \ - parse.h \ - sqlite3.h - - -# Source code to the test files. -# -TESTSRC = \ - $(TOP)/src/test1.c \ - $(TOP)/src/test2.c \ - $(TOP)/src/test3.c \ - $(TOP)/src/test4.c \ - $(TOP)/src/test5.c \ - $(TOP)/src/test6.c \ - $(TOP)/src/test7.c \ - $(TOP)/src/test8.c \ - $(TOP)/src/test9.c \ - $(TOP)/src/test_autoext.c \ - $(TOP)/src/test_async.c \ - $(TOP)/src/test_backup.c \ - $(TOP)/src/test_btree.c \ - $(TOP)/src/test_config.c \ - $(TOP)/src/test_devsym.c \ - $(TOP)/src/test_func.c \ - $(TOP)/src/test_hexio.c \ - $(TOP)/src/test_journal.c \ - $(TOP)/src/test_malloc.c \ - $(TOP)/src/test_md5.c \ - $(TOP)/src/test_mutex.c \ - $(TOP)/src/test_onefile.c \ - $(TOP)/src/test_osinst.c \ - $(TOP)/src/test_pcache.c \ - $(TOP)/src/test_schema.c \ - $(TOP)/src/test_server.c \ - $(TOP)/src/test_tclvar.c \ - $(TOP)/src/test_thread.c \ - $(TOP)/src/test_vfs.c \ - $(TOP)/src/test_wsd.c \ - -#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c -#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c - -TESTSRC2 = \ - $(TOP)/src/attach.c $(TOP)/src/backup.c $(TOP)/src/btree.c \ - $(TOP)/src/build.c $(TOP)/src/ctime.c $(TOP)/src/date.c \ - $(TOP)/src/expr.c $(TOP)/src/func.c $(TOP)/src/insert.c $(TOP)/src/os.c \ - $(TOP)/src/os_unix.c $(TOP)/src/os_win.c \ - $(TOP)/src/pager.c $(TOP)/src/pragma.c $(TOP)/src/prepare.c \ - $(TOP)/src/printf.c $(TOP)/src/random.c $(TOP)/src/pcache.c \ - $(TOP)/src/pcache1.c $(TOP)/src/select.c $(TOP)/src/tokenize.c \ - $(TOP)/src/utf.c $(TOP)/src/util.c $(TOP)/src/vdbeapi.c $(TOP)/src/vdbeaux.c \ - $(TOP)/src/vdbe.c $(TOP)/src/vdbemem.c $(TOP)/src/where.c parse.c \ - $(TOP)/ext/fts3/fts3.c $(TOP)/ext/fts3/fts3_expr.c \ - $(TOP)/ext/fts3/fts3_tokenizer.c \ - $(TOP)/ext/async/sqlite3async.c - -# Header files used by all library source files. -# -HDR = \ - $(TOP)/src/btree.h \ - $(TOP)/src/btreeInt.h \ - $(TOP)/src/hash.h \ - $(TOP)/src/hwtime.h \ - keywordhash.h \ - $(TOP)/src/msvc.h \ - $(TOP)/src/mutex.h \ - opcodes.h \ - $(TOP)/src/os.h \ - $(TOP)/src/os_common.h \ - $(TOP)/src/os_setup.h \ - $(TOP)/src/os_win.h \ - $(TOP)/src/pager.h \ - $(TOP)/src/pcache.h \ - parse.h \ - sqlite3.h \ - $(TOP)/src/sqlite3ext.h \ - $(TOP)/src/sqliteInt.h \ - $(TOP)/src/sqliteLimit.h \ - $(TOP)/src/vdbe.h \ - $(TOP)/src/vdbeInt.h - -# Header files used by extensions -# -EXTHDR += \ - $(TOP)/ext/fts1/fts1.h \ - $(TOP)/ext/fts1/fts1_hash.h \ - $(TOP)/ext/fts1/fts1_tokenizer.h -EXTHDR += \ - $(TOP)/ext/fts2/fts2.h \ - $(TOP)/ext/fts2/fts2_hash.h \ - $(TOP)/ext/fts2/fts2_tokenizer.h -EXTHDR += \ - $(TOP)/ext/fts3/fts3.h \ - $(TOP)/ext/fts3/fts3_expr.h \ - $(TOP)/ext/fts3/fts3_hash.h \ - $(TOP)/ext/fts3/fts3_tokenizer.h -EXTHDR += \ - $(TOP)/ext/rtree/rtree.h -EXTHDR += \ - $(TOP)/ext/icu/sqliteicu.h - -# This is the default Makefile target. The objects listed here -# are what get build when you type just "make" with no arguments. -# -all: sqlite3.h libsqlite3.a sqlite3$(EXE) - -libsqlite3.a: $(LIBOBJ) - $(AR) libsqlite3.a $(LIBOBJ) - $(RANLIB) libsqlite3.a - -$(SHPREFIX)sqlite3.$(SO): $(LIBOBJ) - $(MKSHLIB) -o $(SHPREFIX)sqlite3.$(SO) $(LIBOBJ) $(TLIBS_SHARED) - -sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h - $(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) \ - $(TOP)/src/shell.c \ - $(LIBREADLINE) $(TLIBS) $(THREADLIB) -L. -lsqlite3 - -# This target creates a directory named "tsrc" and fills it with -# copies of all of the C source code and header files needed to -# build on the target system. Some of the C source code and header -# files are automatically generated. This target takes care of -# all that automatic generation. -# -target_source: $(SRC) - rm -rf tsrc - mkdir tsrc - cp -f $(SRC) tsrc - rm tsrc/sqlite.h.in tsrc/parse.y - touch target_source - -sqlite3.c: target_source $(TOP)/tool/mksqlite3c.tcl - tclsh $(TOP)/tool/mksqlite3c.tcl - cp sqlite3.c tclsqlite3.c - cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c - -fts2amal.c: target_source $(TOP)/ext/fts2/mkfts2amal.tcl - tclsh $(TOP)/ext/fts2/mkfts2amal.tcl - -fts3amal.c: target_source $(TOP)/ext/fts3/mkfts3amal.tcl - tclsh $(TOP)/ext/fts3/mkfts3amal.tcl - -# Rules to build the LEMON compiler generator -# -lemon: $(TOP)/tool/lemon.c $(TOP)/src/lempar.c - $(BCC) -o lemon $(TOP)/tool/lemon.c - cp $(TOP)/src/lempar.c . - -# Rules to build individual *.o files from generated *.c files. This -# applies to: -# -# parse.o -# opcodes.o -# -%.o: %.c $(HDR) - $(TCCX_SHARED) -c $< - -# Rules to build individual *.o files from files in the src directory. -# -%.o: $(TOP)/src/%.c $(HDR) - $(TCCX_SHARED) -c $< - -tclsqlite.o: $(TOP)/src/tclsqlite.c $(HDR) - $(TCCX_SHARED) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c - - - -# Rules to build opcodes.c and opcodes.h -# -opcodes.c: opcodes.h $(TOP)/mkopcodec.awk - $(NAWK) -f $(TOP)/mkopcodec.awk opcodes.h >opcodes.c - -opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk - cat parse.h $(TOP)/src/vdbe.c | \ - $(NAWK) -f $(TOP)/mkopcodeh.awk >opcodes.h - -# Rules to build parse.c and parse.h - the outputs of lemon. -# -parse.h: parse.c - -parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk - cp $(TOP)/src/parse.y . - rm -f parse.h - ./lemon $(OPTS) parse.y - mv parse.h parse.h.temp - awk -f $(TOP)/addopcodes.awk parse.h.temp >parse.h - -sqlite3.h: $(TOP)/src/sqlite.h.in - sed -e s/--VERS--/`cat ${TOP}/VERSION`/ \ - -e s/--VERSION-NUMBER--/`cat ${TOP}/VERSION | sed 's/[^0-9]/ /g' | $(NAWK) '{printf "%d%03d%03d",$$1,$$2,$$3}'`/ \ - $(TOP)/src/sqlite.h.in >sqlite3.h - -keywordhash.h: $(TOP)/tool/mkkeywordhash.c - $(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c - ./mkkeywordhash >keywordhash.h - - - -# Rules to build the extension objects. -# -icu.o: $(TOP)/ext/icu/icu.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/icu/icu.c - -fts2.o: $(TOP)/ext/fts2/fts2.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2.c - -fts2_hash.o: $(TOP)/ext/fts2/fts2_hash.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_hash.c - -fts2_icu.o: $(TOP)/ext/fts2/fts2_icu.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_icu.c - -fts2_porter.o: $(TOP)/ext/fts2/fts2_porter.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_porter.c - -fts2_tokenizer.o: $(TOP)/ext/fts2/fts2_tokenizer.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_tokenizer.c - -fts2_tokenizer1.o: $(TOP)/ext/fts2/fts2_tokenizer1.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_tokenizer1.c - -fts3.o: $(TOP)/ext/fts3/fts3.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3.c - -fts3_expr.o: $(TOP)/ext/fts3/fts3_expr.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_expr.c - -fts3_hash.o: $(TOP)/ext/fts3/fts3_hash.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_hash.c - -fts3_icu.o: $(TOP)/ext/fts3/fts3_icu.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_icu.c - -fts3_porter.o: $(TOP)/ext/fts3/fts3_porter.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_porter.c - -fts3_tokenizer.o: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer.c - -fts3_tokenizer1.o: $(TOP)/ext/fts3/fts3_tokenizer1.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer1.c - -rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) - $(TCCX_SHARED) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c - - -# Rules for building test programs and for running tests -# -tclsqlite3: $(TOP)/src/tclsqlite.c libsqlite3.a - $(TCCX_SHARED) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite3 \ - $(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) $(THREADLIB) - - -# Rules to build the 'testfixture' application. -# -TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 -TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE - -testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c - $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \ - $(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \ - -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) libsqlite3.a - -amalgamation-testfixture$(EXE): sqlite3.c $(TESTSRC) $(TOP)/src/tclsqlite.c - $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \ - $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c \ - -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) - -fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c - $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \ - -DSQLITE_ENABLE_FTS3=1 \ - $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts3amal.c \ - -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) - -fulltest: testfixture$(EXE) sqlite3$(EXE) - ./testfixture$(EXE) $(TOP)/test/all.test - -soaktest: testfixture$(EXE) sqlite3$(EXE) - ./testfixture$(EXE) $(TOP)/test/all.test -soak=1 - -fulltestonly: testfixture$(EXE) sqlite3$(EXE) - ./testfixture$(EXE) $(TOP)/test/full.test - -test: testfixture$(EXE) sqlite3$(EXE) - ./testfixture$(EXE) $(TOP)/test/veryquick.test - -sqlite3_analyzer$(EXE): $(TOP)/src/tclsqlite.c sqlite3.c $(TESTSRC) \ - $(TOP)/tool/spaceanal.tcl - sed \ - -e '/^#/d' \ - -e 's,\\,\\\\,g' \ - -e 's,",\\",g' \ - -e 's,^,",' \ - -e 's,$$,\\n",' \ - $(TOP)/tool/spaceanal.tcl >spaceanal_tcl.h - $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \ - -DTCLSH=2 -DSQLITE_TEST=1 -DSQLITE_DEBUG=1 -DSQLITE_PRIVATE="" \ - $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c \ - -o sqlite3_analyzer$(EXE) \ - $(LIBTCL) $(THREADLIB) - -TEST_EXTENSION = $(SHPREFIX)testloadext.$(SO) -$(TEST_EXTENSION): $(TOP)/src/test_loadext.c - $(MKSHLIB) $(TOP)/src/test_loadext.c -o $(TEST_EXTENSION) - -extensiontest: testfixture$(EXE) $(TEST_EXTENSION) - ./testfixture$(EXE) $(TOP)/test/loadext.test - -clean: - rm -f *.o sqlite3$(EXE) libsqlite3.a sqlite3.h opcodes.* - rm -f lemon lempar.c parse.* sqlite*.tar.gz mkkeywordhash keywordhash.h - rm -f $(PUBLISH) - rm -f *.da *.bb *.bbg gmon.out - rm -rf quota2a quota2b quota2c - rm -rf tsrc target_source - rm -f testloadext.dll libtestloadext.so - rm -f sqlite3.c fts?amal.c tclsqlite3.c - rm -f sqlite3rc.h - rm -f shell.c sqlite3ext.h - rm -f $(SHPREFIX)sqlite3.$(SO) diff --git a/README.md b/README.md index ff8dc34..dbc0205 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ This repository contains the complete source code for the SQLite database engine. Some test scripts are also include. However, many other test scripts and most of the documentation are managed separately. +If you are reading this on a Git mirror someplace, you are doing it wrong. +The [official repository](https://www.sqlite.org/src/) is better. Go there +now. + ## Compiling First create a directory in which to place @@ -174,7 +178,7 @@ complex code. So there is a lot of complexity in the SQLite implementation. Key files: - * **sqlite3.h** - This file defines the public interface to the SQLite + * **sqlite.h.in** - This file defines the public interface to the SQLite library. Readers will need to be familiar with this interface before trying to understand how the library works internally. @@ -182,7 +186,7 @@ Key files: used internally by SQLite. * **parse.y** - This file describes the LALR(1) grammer that SQLite uses - to parse SQL statements, and the actions that are taken at each stop + to parse SQL statements, and the actions that are taken at each step in the parsing process. * **vdbe.c** - This file implements the virtual machine that runs @@ -206,6 +210,17 @@ Key files: between SQLite and the underlying operating system using the run-time pluggable VFS interface. + * **shell.c** - This file is not part of the core SQLite library. This + is the file that, when linked against sqlite3.a, generates the + "sqlite3.exe" command-line shell. + + * **tclsqlite.c** - This file implements the Tcl bindings for SQLite. It + is not part of the core SQLite library. But as most of the tests in this + repository are written in Tcl, the Tcl language bindings are important. + +There are many other source files. Each has a suscinct header comment that +describes its purpose and role within the larger system. + ## Contacts diff --git a/VERSION b/VERSION index ff280e4..afad818 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.8.10.2 +3.11.0 diff --git a/addopcodes.awk b/addopcodes.awk deleted file mode 100644 index dcd31ef..0000000 --- a/addopcodes.awk +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/awk -# -# This script appends additional token codes to the end of the -# parse.h file that lemon generates. These extra token codes are -# not used by the parser. But they are used by the tokenizer and/or -# the code generator. -# -# -BEGIN { - max = 0 -} -/^#define TK_/ { - print $0 - if( max<$3 ) max = $3 -} -END { - printf "#define TK_%-29s %4d\n", "TO_TEXT", ++max - printf "#define TK_%-29s %4d\n", "TO_BLOB", ++max - printf "#define TK_%-29s %4d\n", "TO_NUMERIC", ++max - printf "#define TK_%-29s %4d\n", "TO_INT", ++max - printf "#define TK_%-29s %4d\n", "TO_REAL", ++max - printf "#define TK_%-29s %4d\n", "ISNOT", ++max - printf "#define TK_%-29s %4d\n", "END_OF_FILE", ++max - printf "#define TK_%-29s %4d\n", "ILLEGAL", ++max - printf "#define TK_%-29s %4d\n", "SPACE", ++max - printf "#define TK_%-29s %4d\n", "UNCLOSED_STRING", ++max - printf "#define TK_%-29s %4d\n", "FUNCTION", ++max - printf "#define TK_%-29s %4d\n", "COLUMN", ++max - printf "#define TK_%-29s %4d\n", "AGG_FUNCTION", ++max - printf "#define TK_%-29s %4d\n", "AGG_COLUMN", ++max - printf "#define TK_%-29s %4d\n", "UMINUS", ++max - printf "#define TK_%-29s %4d\n", "UPLUS", ++max - printf "#define TK_%-29s %4d\n", "REGISTER", ++max -} diff --git a/autoconf/Makefile.am b/autoconf/Makefile.am index 88bc23d..0e09cfc 100644 --- a/autoconf/Makefile.am +++ b/autoconf/Makefile.am @@ -1,17 +1,19 @@ -AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE +AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ @FTS5_FLAGS@ @JSON1_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE lib_LTLIBRARIES = libsqlite3.la libsqlite3_la_SOURCES = sqlite3.c libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8 bin_PROGRAMS = sqlite3 -sqlite3_SOURCES = shell.c sqlite3.h -sqlite3_LDADD = sqlite3.$(OBJEXT) @READLINE_LIBS@ +sqlite3_SOURCES = shell.c sqlite3.c sqlite3.h +sqlite3_LDADD = @READLINE_LIBS@ +sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@ +sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS include_HEADERS = sqlite3.h sqlite3ext.h -EXTRA_DIST = sqlite3.1 tea +EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc README.txt pkgconfigdir = ${libdir}/pkgconfig pkgconfig_DATA = sqlite3.pc diff --git a/autoconf/Makefile.msc b/autoconf/Makefile.msc new file mode 100644 index 0000000..0be42b4 --- /dev/null +++ b/autoconf/Makefile.msc @@ -0,0 +1,921 @@ +#### DO NOT EDIT #### +# This makefile is automatically generated from the Makefile.msc at +# the root of the canonical SQLite source tree (not the +# amalgamation tarball) using the tool/mkmsvcmin.tcl +# script. +# + +# +# nmake Makefile for SQLite +# +############################################################################### +############################## START OF OPTIONS ############################### +############################################################################### + +# The toplevel directory of the source tree. This is the directory +# that contains this "Makefile.msc". +# +TOP = . + + +# Set this non-0 to enable full warnings (-W4, etc) when compiling. +# +!IFNDEF USE_FULLWARN +USE_FULLWARN = 0 +!ENDIF + +# Set this non-0 to use "stdcall" calling convention for the core library +# and shell executable. +# +!IFNDEF USE_STDCALL +USE_STDCALL = 0 +!ENDIF + +# Set this non-0 to have the shell executable link against the core dynamic +# link library. +# +!IFNDEF DYNAMIC_SHELL +DYNAMIC_SHELL = 0 +!ENDIF + +# Set this non-0 to enable extra code that attempts to detect misuse of the +# SQLite API. +# +!IFNDEF API_ARMOR +API_ARMOR = 0 +!ENDIF + +# If necessary, create a list of harmless compiler warnings to disable when +# compiling the various tools. For the SQLite source code itself, warnings, +# if any, will be disabled from within it. +# +!IFNDEF NO_WARN +!IF $(USE_FULLWARN)!=0 +NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206 +NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4305 -wd4306 -wd4702 -wd4706 +!ENDIF +!ENDIF + +# Set this non-0 to use the library paths and other options necessary for +# Windows Phone 8.1. +# +!IFNDEF USE_WP81_OPTS +USE_WP81_OPTS = 0 +!ENDIF + +# Set this non-0 to split the SQLite amalgamation file into chunks to +# be used for debugging with Visual Studio. +# +!IFNDEF SPLIT_AMALGAMATION +SPLIT_AMALGAMATION = 0 +!ENDIF + + +# Set this non-0 to dynamically link to the MSVC runtime library. +# +!IFNDEF USE_CRT_DLL +USE_CRT_DLL = 0 +!ENDIF + +# Set this non-0 to link to the RPCRT4 library. +# +!IFNDEF USE_RPCRT4_LIB +USE_RPCRT4_LIB = 0 +!ENDIF + +# Set this non-0 to generate assembly code listings for the source code +# files. +# +!IFNDEF USE_LISTINGS +USE_LISTINGS = 0 +!ENDIF + +# Set this non-0 to attempt setting the native compiler automatically +# for cross-compiling the command line tools needed during the compilation +# process. +# +!IFNDEF XCOMPILE +XCOMPILE = 0 +!ENDIF + +# Set this non-0 to use the native libraries paths for cross-compiling +# the command line tools needed during the compilation process. +# +!IFNDEF USE_NATIVE_LIBPATHS +USE_NATIVE_LIBPATHS = 0 +!ENDIF + +# Set this 0 to skip the compiling and embedding of version resources. +# +!IFNDEF USE_RC +USE_RC = 1 +!ENDIF + +# Set this non-0 to compile binaries suitable for the WinRT environment. +# This setting does not apply to any binaries that require Tcl to operate +# properly (i.e. the text fixture, etc). +# +!IFNDEF FOR_WINRT +FOR_WINRT = 0 +!ENDIF + +# Set this non-0 to compile binaries suitable for the UWP environment. +# This setting does not apply to any binaries that require Tcl to operate +# properly (i.e. the text fixture, etc). +# +!IFNDEF FOR_UWP +FOR_UWP = 0 +!ENDIF + +# Set this non-0 to compile binaries suitable for the Windows 10 platform. +# +!IFNDEF FOR_WIN10 +FOR_WIN10 = 0 +!ENDIF + + +# Set this to non-0 to create and use PDBs. +# +!IFNDEF SYMBOLS +SYMBOLS = 1 +!ENDIF + +# Set this to non-0 to use the SQLite debugging heap subsystem. +# +!IFNDEF MEMDEBUG +MEMDEBUG = 0 +!ENDIF + +# Set this to non-0 to use the Win32 native heap subsystem. +# +!IFNDEF WIN32HEAP +WIN32HEAP = 0 +!ENDIF + +# Set this to non-0 to enable OSTRACE() macros, which can be useful when +# debugging. +# +!IFNDEF OSTRACE +OSTRACE = 0 +!ENDIF + +# Set this to one of the following values to enable various debugging +# features. Each level includes the debugging options from the previous +# levels. Currently, the recognized values for DEBUG are: +# +# 0 == NDEBUG: Disables assert() and other runtime diagnostics. +# 1 == SQLITE_ENABLE_API_ARMOR: extra attempts to detect misuse of the API. +# 2 == Disables NDEBUG and all optimizations and then enables PDBs. +# 3 == SQLITE_DEBUG: Enables various diagnostics messages and code. +# 4 == SQLITE_WIN32_MALLOC_VALIDATE: Validate the Win32 native heap per call. +# 5 == SQLITE_DEBUG_OS_TRACE: Enables output from the OSTRACE() macros. +# 6 == SQLITE_ENABLE_IOTRACE: Enables output from the IOTRACE() macros. +# +!IFNDEF DEBUG +DEBUG = 0 +!ENDIF + +# Enable use of available compiler optimizations? Normally, this should be +# non-zero. Setting this to zero, thus disabling all compiler optimizations, +# can be useful for testing. +# +!IFNDEF OPTIMIZATIONS +OPTIMIZATIONS = 2 +!ENDIF + +# Set the source code file to be used by executables and libraries when +# they need the amalgamation. +# +!IFNDEF SQLITE3C +!IF $(SPLIT_AMALGAMATION)!=0 +SQLITE3C = sqlite3-all.c +!ELSE +SQLITE3C = sqlite3.c +!ENDIF +!ENDIF + +# Set the include code file to be used by executables and libraries when +# they need SQLite. +# +!IFNDEF SQLITE3H +SQLITE3H = sqlite3.h +!ENDIF + +# This is the name to use for the SQLite dynamic link library (DLL). +# +!IFNDEF SQLITE3DLL +SQLITE3DLL = sqlite3.dll +!ENDIF + +# This is the name to use for the SQLite import library (LIB). +# +!IFNDEF SQLITE3LIB +SQLITE3LIB = sqlite3.lib +!ENDIF + +# This is the name to use for the SQLite shell executable (EXE). +# +!IFNDEF SQLITE3EXE +SQLITE3EXE = sqlite3.exe +!ENDIF + +# This is the argument used to set the program database (PDB) file for the +# SQLite shell executable (EXE). +# +!IFNDEF SQLITE3EXEPDB +SQLITE3EXEPDB = /pdb:sqlite3sh.pdb +!ENDIF + +# These are the "standard" SQLite compilation options used when compiling for +# the Windows platform. +# +!IFNDEF OPT_FEATURE_FLAGS +OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 +OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 +OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 +!ENDIF + +# These are the "extended" SQLite compilation options used when compiling for +# the Windows 10 platform. +# +!IFNDEF EXT_FEATURE_FLAGS +!IF $(FOR_WIN10)!=0 +EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1 +EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_SYSTEM_MALLOC=1 +EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_OMIT_LOCALTIME=1 +!ELSE +EXT_FEATURE_FLAGS = +!ENDIF +!ENDIF + +############################################################################### +############################### END OF OPTIONS ################################ +############################################################################### + +# When compiling for the Windows 10 platform, the PLATFORM macro must be set +# to an appropriate value (e.g. x86, x64, arm, arm64, etc). +# +!IF $(FOR_WIN10)!=0 +!IFNDEF PLATFORM +!ERROR Using the FOR_WIN10 option requires a value for PLATFORM. +!ENDIF +!ENDIF + +# This assumes that MSVC is always installed in 32-bit Program Files directory +# and sets the variable for use in locating other 32-bit installs accordingly. +# +PROGRAMFILES_X86 = $(VCINSTALLDIR)\..\.. +PROGRAMFILES_X86 = $(PROGRAMFILES_X86:\\=\) + +# Check for the predefined command macro CC. This should point to the compiler +# binary for the target platform. If it is not defined, simply define it to +# the legacy default value 'cl.exe'. +# +!IFNDEF CC +CC = cl.exe +!ENDIF + +# Check for the command macro LD. This should point to the linker binary for +# the target platform. If it is not defined, simply define it to the legacy +# default value 'link.exe'. +# +!IFNDEF LD +LD = link.exe +!ENDIF + +# Check for the predefined command macro RC. This should point to the resource +# compiler binary for the target platform. If it is not defined, simply define +# it to the legacy default value 'rc.exe'. +# +!IFNDEF RC +RC = rc.exe +!ENDIF + +# Check for the MSVC runtime library path macro. Otherwise, this value will +# default to the 'lib' directory underneath the MSVC installation directory. +# +!IFNDEF CRTLIBPATH +CRTLIBPATH = $(VCINSTALLDIR)\lib +!ENDIF + +CRTLIBPATH = $(CRTLIBPATH:\\=\) + +# Check for the command macro NCC. This should point to the compiler binary +# for the platform the compilation process is taking place on. If it is not +# defined, simply define it to have the same value as the CC macro. When +# cross-compiling, it is suggested that this macro be modified via the command +# line (since nmake itself does not provide a built-in method to guess it). +# For example, to use the x86 compiler when cross-compiling for x64, a command +# line similar to the following could be used (all on one line): +# +# nmake /f Makefile.msc sqlite3.dll +# XCOMPILE=1 USE_NATIVE_LIBPATHS=1 +# +# Alternatively, the full path and file name to the compiler binary for the +# platform the compilation process is taking place may be specified (all on +# one line): +# +# nmake /f Makefile.msc sqlite3.dll +# "NCC=""%VCINSTALLDIR%\bin\cl.exe""" +# USE_NATIVE_LIBPATHS=1 +# +!IFDEF NCC +NCC = $(NCC:\\=\) +!ELSEIF $(XCOMPILE)!=0 +NCC = "$(VCINSTALLDIR)\bin\$(CC)" +NCC = $(NCC:\\=\) +!ELSE +NCC = $(CC) +!ENDIF + +# Check for the MSVC native runtime library path macro. Otherwise, +# this value will default to the 'lib' directory underneath the MSVC +# installation directory. +# +!IFNDEF NCRTLIBPATH +NCRTLIBPATH = $(VCINSTALLDIR)\lib +!ENDIF + +NCRTLIBPATH = $(NCRTLIBPATH:\\=\) + +# Check for the Platform SDK library path macro. Otherwise, this +# value will default to the 'lib' directory underneath the Windows +# SDK installation directory (the environment variable used appears +# to be available when using Visual C++ 2008 or later via the +# command line). +# +!IFNDEF NSDKLIBPATH +NSDKLIBPATH = $(WINDOWSSDKDIR)\lib +!ENDIF + +NSDKLIBPATH = $(NSDKLIBPATH:\\=\) + +# Check for the UCRT library path macro. Otherwise, this value will +# default to the version-specific, platform-specific 'lib' directory +# underneath the Windows SDK installation directory. +# +!IFNDEF UCRTLIBPATH +UCRTLIBPATH = $(WINDOWSSDKDIR)\lib\$(WINDOWSSDKLIBVERSION)\ucrt\$(PLATFORM) +!ENDIF + +UCRTLIBPATH = $(UCRTLIBPATH:\\=\) + +# C compiler and options for use in building executables that +# will run on the platform that is doing the build. +# +!IF $(USE_FULLWARN)!=0 +BCC = $(NCC) -nologo -W4 $(CCOPTS) $(BCCOPTS) +!ELSE +BCC = $(NCC) -nologo -W3 $(CCOPTS) $(BCCOPTS) +!ENDIF + +# Check if assembly code listings should be generated for the source +# code files to be compiled. +# +!IF $(USE_LISTINGS)!=0 +BCC = $(BCC) -FAcs +!ENDIF + +# Check if the native library paths should be used when compiling +# the command line tools used during the compilation process. If +# so, set the necessary macro now. +# +!IF $(USE_NATIVE_LIBPATHS)!=0 +NLTLIBPATHS = "/LIBPATH:$(NCRTLIBPATH)" "/LIBPATH:$(NSDKLIBPATH)" + +!IFDEF NUCRTLIBPATH +NUCRTLIBPATH = $(NUCRTLIBPATH:\\=\) +NLTLIBPATHS = $(NLTLIBPATHS) "/LIBPATH:$(NUCRTLIBPATH)" +!ENDIF +!ENDIF + +# C compiler and options for use in building executables that +# will run on the target platform. (BCC and TCC are usually the +# same unless your are cross-compiling.) +# +!IF $(USE_FULLWARN)!=0 +TCC = $(CC) -nologo -W4 -DINCLUDE_MSVC_H=1 $(CCOPTS) $(TCCOPTS) +!ELSE +TCC = $(CC) -nologo -W3 $(CCOPTS) $(TCCOPTS) +!ENDIF + +TCC = $(TCC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -fp:precise +RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) $(RCOPTS) $(RCCOPTS) + +# Adjust the names of the primary targets for use with Windows 10. +# +!IF $(FOR_WIN10)!=0 +SQLITE3DLL = winsqlite3.dll +SQLITE3LIB = winsqlite3.lib +SQLITE3EXE = winsqlite3shell.exe +SQLITE3EXEPDB = +!ENDIF + +# Check if we want to use the "stdcall" calling convention when compiling. +# This is not supported by the compilers for non-x86 platforms. It should +# also be noted here that building any target with these "stdcall" options +# will most likely fail if the Tcl library is also required. This is due +# to how the Tcl library functions are declared and exported (i.e. without +# an explicit calling convention, which results in "cdecl"). +# +!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 +!IF "$(PLATFORM)"=="x86" +CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +!ELSE +!IFNDEF PLATFORM +CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_STDCALL=__stdcall +!ELSE +CORE_CCONV_OPTS = +SHELL_CCONV_OPTS = +!ENDIF +!ENDIF +!ELSE +CORE_CCONV_OPTS = +SHELL_CCONV_OPTS = +!ENDIF + +# These are additional compiler options used for the core library. +# +!IFNDEF CORE_COMPILE_OPTS +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 +CORE_COMPILE_OPTS = $(CORE_CCONV_OPTS) -DSQLITE_API=__declspec(dllexport) +!ELSE +CORE_COMPILE_OPTS = $(CORE_CCONV_OPTS) +!ENDIF +!ENDIF + +# These are the additional targets that the core library should depend on +# when linking. +# +!IFNDEF CORE_LINK_DEP +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 +CORE_LINK_DEP = +!ELSE +CORE_LINK_DEP = +!ENDIF +!ENDIF + +# These are additional linker options used for the core library. +# +!IFNDEF CORE_LINK_OPTS +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 +CORE_LINK_OPTS = +!ELSE +CORE_LINK_OPTS = +!ENDIF +!ENDIF + +# These are additional compiler options used for the shell executable. +# +!IFNDEF SHELL_COMPILE_OPTS +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 +SHELL_COMPILE_OPTS = $(SHELL_CCONV_OPTS) -DSQLITE_API=__declspec(dllimport) +!ELSE +SHELL_COMPILE_OPTS = $(SHELL_CCONV_OPTS) +!ENDIF +!ENDIF + +# This is the source code that the shell executable should be compiled +# with. +# +!IFNDEF SHELL_CORE_SRC +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 +SHELL_CORE_SRC = +!ELSE +SHELL_CORE_SRC = $(SQLITE3C) +!ENDIF +!ENDIF + +# This is the core library that the shell executable should depend on. +# +!IFNDEF SHELL_CORE_DEP +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 +SHELL_CORE_DEP = $(SQLITE3DLL) +!ELSE +SHELL_CORE_DEP = +!ENDIF +!ENDIF + +# This is the core library that the shell executable should link with. +# +!IFNDEF SHELL_CORE_LIB +!IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 +SHELL_CORE_LIB = $(SQLITE3LIB) +!ELSE +SHELL_CORE_LIB = +!ENDIF +!ENDIF + +# These are additional linker options used for the shell executable. +# +!IFNDEF SHELL_LINK_OPTS +SHELL_LINK_OPTS = $(SHELL_CORE_LIB) +!ENDIF + +# Check if assembly code listings should be generated for the source +# code files to be compiled. +# +!IF $(USE_LISTINGS)!=0 +TCC = $(TCC) -FAcs +!ENDIF + +# When compiling the library for use in the WinRT environment, +# the following compile-time options must be used as well to +# disable use of Win32 APIs that are not available and to enable +# use of Win32 APIs that are specific to Windows 8 and/or WinRT. +# +!IF $(FOR_WINRT)!=0 +TCC = $(TCC) -DSQLITE_OS_WINRT=1 +RCC = $(RCC) -DSQLITE_OS_WINRT=1 +TCC = $(TCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP +RCC = $(RCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP +!ENDIF + +# C compiler options for the Windows 10 platform (needs MSVC 2015). +# +!IF $(FOR_WIN10)!=0 +TCC = $(TCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE +BCC = $(BCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE +!ENDIF + +# Also, we need to dynamically link to the correct MSVC runtime +# when compiling for WinRT (e.g. debug or release) OR if the +# USE_CRT_DLL option is set to force dynamically linking to the +# MSVC runtime library. +# +!IF $(FOR_WINRT)!=0 || $(USE_CRT_DLL)!=0 +!IF $(DEBUG)>1 +TCC = $(TCC) -MDd +BCC = $(BCC) -MDd +!ELSE +TCC = $(TCC) -MD +BCC = $(BCC) -MD +!ENDIF +!ELSE +!IF $(DEBUG)>1 +TCC = $(TCC) -MTd +BCC = $(BCC) -MTd +!ELSE +TCC = $(TCC) -MT +BCC = $(BCC) -MT +!ENDIF +!ENDIF + + +# Define -DNDEBUG to compile without debugging (i.e., for production usage) +# Omitting the define will cause extra debugging code to be inserted and +# includes extra comments when "EXPLAIN stmt" is used. +# +!IF $(DEBUG)==0 +TCC = $(TCC) -DNDEBUG +BCC = $(BCC) -DNDEBUG +RCC = $(RCC) -DNDEBUG +!ENDIF + +!IF $(DEBUG)>0 || $(API_ARMOR)!=0 || $(FOR_WIN10)!=0 +TCC = $(TCC) -DSQLITE_ENABLE_API_ARMOR=1 +RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1 +!ENDIF + +!IF $(DEBUG)>2 +TCC = $(TCC) -DSQLITE_DEBUG=1 +RCC = $(RCC) -DSQLITE_DEBUG=1 +!ENDIF + +!IF $(DEBUG)>4 || $(OSTRACE)!=0 +TCC = $(TCC) -DSQLITE_FORCE_OS_TRACE=1 -DSQLITE_DEBUG_OS_TRACE=1 +RCC = $(RCC) -DSQLITE_FORCE_OS_TRACE=1 -DSQLITE_DEBUG_OS_TRACE=1 +!ENDIF + +!IF $(DEBUG)>5 +TCC = $(TCC) -DSQLITE_ENABLE_IOTRACE=1 +RCC = $(RCC) -DSQLITE_ENABLE_IOTRACE=1 +!ENDIF + +# Prevent warnings about "insecure" MSVC runtime library functions +# being used. +# +TCC = $(TCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS +BCC = $(BCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS +RCC = $(RCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS + +# Prevent warnings about "deprecated" POSIX functions being used. +# +TCC = $(TCC) -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS +BCC = $(BCC) -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS +RCC = $(RCC) -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS + +# Use the SQLite debugging heap subsystem? +# +!IF $(MEMDEBUG)!=0 +TCC = $(TCC) -DSQLITE_MEMDEBUG=1 +RCC = $(RCC) -DSQLITE_MEMDEBUG=1 + +# Use native Win32 heap subsystem instead of malloc/free? +# +!ELSEIF $(WIN32HEAP)!=0 +TCC = $(TCC) -DSQLITE_WIN32_MALLOC=1 +RCC = $(RCC) -DSQLITE_WIN32_MALLOC=1 + +# Validate the heap on every call into the native Win32 heap subsystem? +# +!IF $(DEBUG)>3 +TCC = $(TCC) -DSQLITE_WIN32_MALLOC_VALIDATE=1 +RCC = $(RCC) -DSQLITE_WIN32_MALLOC_VALIDATE=1 +!ENDIF +!ENDIF + + +# Compiler options needed for programs that use the readline() library. +# +!IFNDEF READLINE_FLAGS +READLINE_FLAGS = -DHAVE_READLINE=0 +!ENDIF + +# The library that programs using readline() must link against. +# +!IFNDEF LIBREADLINE +LIBREADLINE = +!ENDIF + +# Should the database engine be compiled threadsafe +# +TCC = $(TCC) -DSQLITE_THREADSAFE=1 +RCC = $(RCC) -DSQLITE_THREADSAFE=1 + +# Do threads override each others locks by default (1), or do we test (-1) +# +TCC = $(TCC) -DSQLITE_THREAD_OVERRIDE_LOCK=-1 +RCC = $(RCC) -DSQLITE_THREAD_OVERRIDE_LOCK=-1 + +# Any target libraries which libsqlite must be linked against +# +!IFNDEF TLIBS +TLIBS = +!ENDIF + +# Flags controlling use of the in memory btree implementation +# +# SQLITE_TEMP_STORE is 0 to force temporary tables to be in a file, 1 to +# default to file, 2 to default to memory, and 3 to force temporary +# tables to always be in memory. +# +TCC = $(TCC) -DSQLITE_TEMP_STORE=1 +RCC = $(RCC) -DSQLITE_TEMP_STORE=1 + +# Enable/disable loadable extensions, and other optional features +# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*). +# The same set of OMIT and ENABLE flags should be passed to the +# LEMON parser generator and the mkkeywordhash tool as well. + +# These are the required SQLite compilation options used when compiling for +# the Windows platform. +# +REQ_FEATURE_FLAGS = $(REQ_FEATURE_FLAGS) -DSQLITE_MAX_TRIGGER_DEPTH=100 + +# If we are linking to the RPCRT4 library, enable features that need it. +# +!IF $(USE_RPCRT4_LIB)!=0 +REQ_FEATURE_FLAGS = $(REQ_FEATURE_FLAGS) -DSQLITE_WIN32_USE_UUID=1 +!ENDIF + +# Add the required and optional SQLite compilation options into the command +# lines used to invoke the MSVC code and resource compilers. +# +TCC = $(TCC) $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) +RCC = $(RCC) $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) + +# Add in any optional parameters specified on the commane line, e.g. +# nmake /f Makefile.msc all "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1" +# +TCC = $(TCC) $(OPTS) +RCC = $(RCC) $(OPTS) + +# If compiling for debugging, add some defines. +# +!IF $(DEBUG)>1 +TCC = $(TCC) -D_DEBUG +BCC = $(BCC) -D_DEBUG +RCC = $(RCC) -D_DEBUG +!ENDIF + +# If optimizations are enabled or disabled (either implicitly or +# explicitly), add the necessary flags. +# +!IF $(DEBUG)>1 || $(OPTIMIZATIONS)==0 +TCC = $(TCC) -Od +BCC = $(BCC) -Od +!ELSEIF $(OPTIMIZATIONS)>=3 +TCC = $(TCC) -Ox +BCC = $(BCC) -Ox +!ELSEIF $(OPTIMIZATIONS)==2 +TCC = $(TCC) -O2 +BCC = $(BCC) -O2 +!ELSEIF $(OPTIMIZATIONS)==1 +TCC = $(TCC) -O1 +BCC = $(BCC) -O1 +!ENDIF + +# If symbols are enabled (or compiling for debugging), enable PDBs. +# +!IF $(DEBUG)>1 || $(SYMBOLS)!=0 +TCC = $(TCC) -Zi +BCC = $(BCC) -Zi +!ENDIF + + +# Command line prefixes for compiling code, compiling resources, +# linking, etc. +# +LTCOMPILE = $(TCC) -Fo$@ +LTRCOMPILE = $(RCC) -r +LTLIB = lib.exe +LTLINK = $(TCC) -Fe$@ + +# If requested, link to the RPCRT4 library. +# +!IF $(USE_RPCRT4_LIB)!=0 +LTLINK = $(LTLINK) rpcrt4.lib +!ENDIF + +# If a platform was set, force the linker to target that. +# Note that the vcvars*.bat family of batch files typically +# set this for you. Otherwise, the linker will attempt +# to deduce the binary type based on the object files. +!IFDEF PLATFORM +LTLINKOPTS = /NOLOGO /MACHINE:$(PLATFORM) +LTLIBOPTS = /NOLOGO /MACHINE:$(PLATFORM) +!ELSE +LTLINKOPTS = /NOLOGO +LTLIBOPTS = /NOLOGO +!ENDIF + +# When compiling for use in the WinRT environment, the following +# linker option must be used to mark the executable as runnable +# only in the context of an application container. +# +!IF $(FOR_WINRT)!=0 +LTLINKOPTS = $(LTLINKOPTS) /APPCONTAINER +!IF "$(VISUALSTUDIOVERSION)"=="12.0" || "$(VISUALSTUDIOVERSION)"=="14.0" +!IFNDEF STORELIBPATH +!IF "$(PLATFORM)"=="x86" +STORELIBPATH = $(CRTLIBPATH)\store +!ELSEIF "$(PLATFORM)"=="x64" +STORELIBPATH = $(CRTLIBPATH)\store\amd64 +!ELSEIF "$(PLATFORM)"=="ARM" +STORELIBPATH = $(CRTLIBPATH)\store\arm +!ELSE +STORELIBPATH = $(CRTLIBPATH)\store +!ENDIF +!ENDIF +STORELIBPATH = $(STORELIBPATH:\\=\) +LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(STORELIBPATH)" +!ENDIF +!ENDIF + +# When compiling for Windows Phone 8.1, an extra library path is +# required. +# +!IF $(USE_WP81_OPTS)!=0 +!IFNDEF WP81LIBPATH +!IF "$(PLATFORM)"=="x86" +WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86 +!ELSEIF "$(PLATFORM)"=="ARM" +WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\ARM +!ELSE +WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86 +!ENDIF +!ENDIF +!ENDIF + +# When compiling for Windows Phone 8.1, some extra linker options +# are also required. +# +!IF $(USE_WP81_OPTS)!=0 +!IFDEF WP81LIBPATH +LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)" +!ENDIF +LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE +LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib +LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib +!ENDIF + +# When compiling for UWP or the Windows 10 platform, some extra linker +# options are also required. +# +!IF $(FOR_UWP)!=0 || $(FOR_WIN10)!=0 +LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE /NODEFAULTLIB:kernel32.lib +LTLINKOPTS = $(LTLINKOPTS) mincore.lib +!IFDEF PSDKLIBPATH +LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(PSDKLIBPATH)" +!ENDIF +!ENDIF + +!IF $(FOR_WIN10)!=0 +LTLINKOPTS = $(LTLINKOPTS) /guard:cf "/LIBPATH:$(UCRTLIBPATH)" +!IF $(DEBUG)>1 +LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrtd.lib /DEFAULTLIB:ucrtd.lib +!ELSE +LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib +!ENDIF +!ENDIF + +# If either debugging or symbols are enabled, enable PDBs. +# +!IF $(DEBUG)>1 || $(SYMBOLS)!=0 +LDFLAGS = /DEBUG $(LDOPTS) +!ELSE +LDFLAGS = $(LDOPTS) +!ENDIF + + +# You should not have to change anything below this line +############################################################################### + + +# Object files for the amalgamation. +# +LIBOBJS1 = sqlite3.lo + +# Determine the real value of LIBOBJ based on the 'configure' script +# +LIBOBJ = $(LIBOBJS1) + +# Determine if embedded resource compilation and usage are enabled. +# +!IF $(USE_RC)!=0 +LIBRESOBJS = sqlite3res.lo +!ELSE +LIBRESOBJS = +!ENDIF + + +# Additional compiler options for the shell. These are only effective +# when the shell is not being dynamically linked. +# +!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0 +SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS +!ENDIF + + +# This is the default Makefile target. The objects listed here +# are what get build when you type just "make" with no arguments. +# +all: dll libsqlite3.lib shell + +# Dynamic link library section. +# +dll: $(SQLITE3DLL) + +# Shell executable. +# +shell: $(SQLITE3EXE) + +libsqlite3.lib: $(LIBOBJ) + $(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS) + + +$(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP) + $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) + + +$(SQLITE3EXE): $(TOP)\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H) + $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\shell.c $(SHELL_CORE_SRC) \ + /link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) + + +# Rule to build the amalgamation +# +sqlite3.lo: $(SQLITE3C) + $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(SQLITE3C) + + +# Rule to build the Win32 resources object file. +# +!IF $(USE_RC)!=0 +_HASHCHAR=^# +!IF ![echo !IFNDEF VERSION > rcver.vc] && \ + ![for /F "delims=" %V in ('type "$(SQLITE3H)" ^| find "$(_HASHCHAR)define SQLITE_VERSION "') do (echo VERSION = ^^%V >> rcver.vc)] && \ + ![echo !ENDIF >> rcver.vc] +!INCLUDE rcver.vc +!ENDIF + +RESOURCE_VERSION = $(VERSION:^#=) +RESOURCE_VERSION = $(RESOURCE_VERSION:define=) +RESOURCE_VERSION = $(RESOURCE_VERSION:SQLITE_VERSION=) +RESOURCE_VERSION = $(RESOURCE_VERSION:"=) +RESOURCE_VERSION = $(RESOURCE_VERSION:.=,) + +$(LIBRESOBJS): $(TOP)\sqlite3.rc rcver.vc $(SQLITE3H) + echo #ifndef SQLITE_RESOURCE_VERSION > sqlite3rc.h + echo #define SQLITE_RESOURCE_VERSION $(RESOURCE_VERSION) >> sqlite3rc.h + echo #endif >> sqlite3rc.h + $(LTRCOMPILE) -fo $(LIBRESOBJS) -DRC_VERONLY $(TOP)\sqlite3.rc +!ENDIF + + +clean: + del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL + del /Q *.bsc *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL diff --git a/autoconf/README b/autoconf/README deleted file mode 100644 index dd8cca2..0000000 --- a/autoconf/README +++ /dev/null @@ -1,32 +0,0 @@ - -This package contains: - - * the SQLite library amalgamation (single file) source code distribution, - * the shell.c file used to build the sqlite3 shell too, and - * the sqlite3.h and sqlite3ext.h header files required to link programs - and sqlite extensions against the installed libary. - * autoconf/automake installation infrastucture. - -The generic installation instructions for autoconf/automake are found -in the INSTALL file. - -The following SQLite specific boolean options are supported: - - --enable-readline use readline in shell tool [default=yes] - --enable-threadsafe build a thread-safe library [default=yes] - --enable-dynamic-extensions support loadable extensions [default=yes] - -The default value for the CFLAGS variable (options passed to the C -compiler) includes debugging symbols in the build, resulting in larger -binaries than are necessary. Override it on the configure command -line like this: - - $ CFLAGS="-Os" ./configure - -to produce a smaller installation footprint. - -Other SQLite compilation parameters can also be set using CFLAGS. For -example: - - $ CFLAGS="-Os -DSQLITE_OMIT_TRIGGERS" ./configure - diff --git a/autoconf/README.txt b/autoconf/README.txt new file mode 100644 index 0000000..2d6db4f --- /dev/null +++ b/autoconf/README.txt @@ -0,0 +1,113 @@ +This package contains: + + * the SQLite library amalgamation source code file: sqlite3.c + * the sqlite3.h and sqlite3ext.h header files that define the C-language + interface to the sqlite3.c library file + * the shell.c file used to build the sqlite3 command-line shell program + * autoconf/automake installation infrastucture for building on POSIX + compliant systems + * a Makefile.msc and sqlite3.rc for building with Microsoft Visual C++ on + Windows + +SUMMARY OF HOW TO BUILD +======================= + + Unix: ./configure; make + Windows: nmake /f Makefile.msc + +BUILDING ON POSIX +================= + +The generic installation instructions for autoconf/automake are found +in the INSTALL file. + +The following SQLite specific boolean options are supported: + + --enable-readline use readline in shell tool [default=yes] + --enable-threadsafe build a thread-safe library [default=yes] + --enable-dynamic-extensions support loadable extensions [default=yes] + +The default value for the CFLAGS variable (options passed to the C +compiler) includes debugging symbols in the build, resulting in larger +binaries than are necessary. Override it on the configure command +line like this: + + $ CFLAGS="-Os" ./configure + +to produce a smaller installation footprint. + +Other SQLite compilation parameters can also be set using CFLAGS. For +example: + + $ CFLAGS="-Os -DSQLITE_THREADSAFE=0" ./configure + + +BUILDING WITH MICROSOFT VISUAL C++ +================================== + +To compile for Windows using Microsoft Visual C++: + + $ nmake /f Makefile.msc + +Using Microsoft Visual C++ 2005 (or later) is recommended. Several Windows +platform variants may be built by adding additional macros to the NMAKE +command line. + +Building for WinRT 8.0 +---------------------- + + FOR_WINRT=1 + +Using Microsoft Visual C++ 2012 (or later) is required. When using the +above, something like the following macro will need to be added to the +NMAKE command line as well: + + "NSDKLIBPATH=%WindowsSdkDir%\..\8.0\lib\win8\um\x86" + +Building for WinRT 8.1 +---------------------- + + FOR_WINRT=1 + +Using Microsoft Visual C++ 2013 (or later) is required. When using the +above, something like the following macro will need to be added to the +NMAKE command line as well: + + "NSDKLIBPATH=%WindowsSdkDir%\..\8.1\lib\winv6.3\um\x86" + +Building for UWP 10.0 +--------------------- + + FOR_WINRT=1 FOR_UWP=1 + +Using Microsoft Visual C++ 2015 (or later) is required. When using the +above, something like the following macros will need to be added to the +NMAKE command line as well: + + "NSDKLIBPATH=%WindowsSdkDir%\..\10\lib\10.0.10586.0\um\x86" + "PSDKLIBPATH=%WindowsSdkDir%\..\10\lib\10.0.10586.0\um\x86" + "NUCRTLIBPATH=%UniversalCRTSdkDir%\..\10\lib\10.0.10586.0\ucrt\x86" + +Building for the Windows 10 SDK +------------------------------- + + FOR_WIN10=1 + +Using Microsoft Visual C++ 2015 (or later) is required. When using the +above, no other macros should be needed on the NMAKE command line. + +Other preprocessor defines +-------------------------- + +Additionally, preprocessor defines may be specified by using the OPTS macro +on the NMAKE command line. However, not all possible preprocessor defines +may be specified in this manner as some require the amalgamation to be built +with them enabled (see http://www.sqlite.org/compile.html). For example, the +following will work: + + "OPTS=-DSQLITE_ENABLE_STAT4=1 -DSQLITE_ENABLE_JSON1=1" + +However, the following will not compile unless the amalgamation was built +with it enabled: + + "OPTS=-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1" diff --git a/autoconf/config.guess b/autoconf/config.guess deleted file mode 100755 index d622a44..0000000 --- a/autoconf/config.guess +++ /dev/null @@ -1,1530 +0,0 @@ -#! /bin/sh -# Attempt to guess a canonical system name. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011, 2012 Free Software Foundation, Inc. - -timestamp='2012-02-10' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -# Originally written by Per Bothner. Please send patches (context -# diff format) to and include a ChangeLog -# entry. -# -# This script attempts to guess a canonical system name similar to -# config.sub. If it succeeds, it prints the system name on stdout, and -# exits with 0. Otherwise, it exits with 1. -# -# You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] - -Output the configuration name of the system \`$me' is run on. - -Operation modes: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.guess ($timestamp) - -Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 -Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - * ) - break ;; - esac -done - -if test $# != 0; then - echo "$me: too many arguments$help" >&2 - exit 1 -fi - -trap 'exit 1' 1 2 15 - -# CC_FOR_BUILD -- compiler used by this script. Note that the use of a -# compiler to aid in system detection is discouraged as it requires -# temporary files to be created and, as you can see below, it is a -# headache to deal with in a portable fashion. - -# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -# use `HOST_CC' if defined, but it is deprecated. - -# Portable tmp directory creation inspired by the Autoconf team. - -set_cc_for_build=' -trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; -: ${TMPDIR=/tmp} ; - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; -dummy=$tmp/dummy ; -tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; - for c in cc gcc c89 c99 ; do - if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then - CC_FOR_BUILD="$c"; break ; - fi ; - done ; - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found ; - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ; set_cc_for_build= ;' - -# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -# (ghazi@noc.rutgers.edu 1994-08-24) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then - PATH=$PATH:/.attbin ; export PATH -fi - -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -# Note: order is significant - the case branches are not exclusive. - -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - *:NetBSD:*:*) - # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, - # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently - # switched to ELF, *-*-netbsd* would select the old - # object file format. This provides both forward - # compatibility and a consistent mechanism for selecting the - # object file format. - # - # Note: NetBSD doesn't particularly care about the vendor - # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || echo unknown)` - case "${UNAME_MACHINE_ARCH}" in - armeb) machine=armeb-unknown ;; - arm*) machine=arm-unknown ;; - sh3el) machine=shl-unknown ;; - sh3eb) machine=sh-unknown ;; - sh5el) machine=sh5le-unknown ;; - *) machine=${UNAME_MACHINE_ARCH}-unknown ;; - esac - # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. - case "${UNAME_MACHINE_ARCH}" in - arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build - if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ELF__ - then - # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). - # Return netbsd for either. FIX? - os=netbsd - else - os=netbsdelf - fi - ;; - *) - os=netbsd - ;; - esac - # The OS release - # Debian GNU/NetBSD machines have a different userland, and - # thus, need a distinct triplet. However, they do not need - # kernel version information, so it can be replaced with a - # suitable tag, in the style of linux-gnu. - case "${UNAME_VERSION}" in - Debian*) - release='-gnu' - ;; - *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` - ;; - esac - # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: - # contains redundant information, the shorter form: - # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" - exit ;; - *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} - exit ;; - *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} - exit ;; - *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} - exit ;; - macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} - exit ;; - *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} - exit ;; - alpha:OSF1:*:*) - case $UNAME_RELEASE in - *4.0) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - ;; - *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` - ;; - esac - # According to Compaq, /usr/sbin/psrinfo has been available on - # OSF/1 and Tru64 systems produced since 1995. I hope that - # covers most systems running today. This code pipes the CPU - # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` - case "$ALPHA_CPU_TYPE" in - "EV4 (21064)") - UNAME_MACHINE="alpha" ;; - "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; - "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; - "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; - "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; - "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; - "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; - "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; - "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; - "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; - "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; - "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; - "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; - "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; - "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; - esac - # A Pn.n version is a patched version. - # A Vn.n version is a released version. - # A Tn.n version is a released field test version. - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - # Reset EXIT trap before exiting to avoid spurious non-zero exit code. - exitcode=$? - trap '' 0 - exit $exitcode ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit ;; - Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; - *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos - exit ;; - *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos - exit ;; - *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; - *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; - *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} - exit ;; - arm:riscos:*:*|arm:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; - SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; - Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) - # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; - NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; - DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; - DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case `/usr/bin/uname -p` in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; - s390x:SunOS:*:*) - echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux${UNAME_RELEASE} - exit ;; - i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - eval $set_cc_for_build - SUN_ARCH="i386" - # If there is a compiler, see if it is configured for 64-bit objects. - # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. - # This test works for both compilers. - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then - if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - SUN_ARCH="x86_64" - fi - fi - echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in - Series*|S4*) - UNAME_RELEASE=`uname -v` - ;; - esac - # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` - exit ;; - sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} - exit ;; - sun*:*:4.2BSD:*) - UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 - case "`/bin/arch`" in - sun3) - echo m68k-sun-sunos${UNAME_RELEASE} - ;; - sun4) - echo sparc-sun-sunos${UNAME_RELEASE} - ;; - esac - exit ;; - aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} - exit ;; - # The situation for MiNT is a little confusing. The machine name - # can be virtually everything (everything which is not - # "atarist" or "atariste" at least should have a processor - # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally - # the system name "TOS" denotes a system which is actually not - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; - m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} - exit ;; - powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} - exit ;; - RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; - RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} - exit ;; - VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} - exit ;; - 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} - exit ;; - mips:*:*:UMIPS | mips:*:*:RISCos) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c -#ifdef __cplusplus -#include /* for printf() prototype */ - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif - #if defined (host_mips) && defined (MIPSEB) - #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); - #endif - #endif - exit (-1); - } -EOF - $CC_FOR_BUILD -o $dummy $dummy.c && - dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`$dummy $dummyarg` && - { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos${UNAME_RELEASE} - exit ;; - Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; - Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; - m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; - m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; - m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; - AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] - then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ - [ ${TARGET_BINARY_INTERFACE}x = x ] - then - echo m88k-dg-dgux${UNAME_RELEASE} - else - echo m88k-dg-dguxbcs${UNAME_RELEASE} - fi - else - echo i586-dg-dgux${UNAME_RELEASE} - fi - exit ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; - XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; - Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; - *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` - exit ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' - i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; - ia64:AIX:*:*) - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} - fi - echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} - exit ;; - *:AIX:2:3) - if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - - main() - { - if (!__power_pc()) - exit(1); - puts("powerpc-ibm-aix3.2.5"); - exit(0); - } -EOF - if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` - then - echo "$SYSTEM_NAME" - else - echo rs6000-ibm-aix3.2.5 - fi - elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 - else - echo rs6000-ibm-aix3.2 - fi - exit ;; - *:AIX:*:[4567]) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then - IBM_ARCH=rs6000 - else - IBM_ARCH=powerpc - fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} - fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} - exit ;; - *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) - echo romp-ibm-bsd4.4 - exit ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 - *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; - DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; - 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; - 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; - 9000/[678][0-9][0-9]) - if [ -x /usr/bin/getconf ]; then - sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 - esac ;; - esac - fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - - #define _HPUX_SOURCE - #include - #include - - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } -EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` - test -z "$HP_ARCH" && HP_ARCH=hppa - fi ;; - esac - if [ ${HP_ARCH} = "hppa2.0w" ] - then - eval $set_cc_for_build - - # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating - # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler - # generating 64-bit code. GNU and HP use different nomenclature: - # - # $ CC_FOR_BUILD=cc ./config.guess - # => hppa2.0w-hp-hpux11.23 - # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess - # => hppa64-hp-hpux11.23 - - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | - grep -q __LP64__ - then - HP_ARCH="hppa2.0w" - else - HP_ARCH="hppa64" - fi - fi - echo ${HP_ARCH}-hp-hpux${HPUX_REV} - exit ;; - ia64:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux${HPUX_REV} - exit ;; - 3050*:HI-UX:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - /* The order matters, because CPU_IS_HP_MC68K erroneously returns - true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ - if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) - echo hppa1.1-hp-bsd - exit ;; - 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; - *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) - echo hppa1.1-hp-osf - exit ;; - hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; - i*86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk - else - echo ${UNAME_MACHINE}-unknown-osf1 - fi - exit ;; - parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; - CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ - | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ - -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ - -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*SV1:*:*:*) - echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} - exit ;; - sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} - exit ;; - *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} - exit ;; - *:FreeBSD:*:*) - UNAME_PROCESSOR=`/usr/bin/uname -p` - case ${UNAME_PROCESSOR} in - amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - *) - echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - esac - exit ;; - i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin - exit ;; - *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 - exit ;; - i*:MSYS*:*) - echo ${UNAME_MACHINE}-pc-msys - exit ;; - i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 - exit ;; - i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 - exit ;; - *:Interix*:*) - case ${UNAME_MACHINE} in - x86) - echo i586-pc-interix${UNAME_RELEASE} - exit ;; - authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix${UNAME_RELEASE} - exit ;; - IA64) - echo ia64-unknown-interix${UNAME_RELEASE} - exit ;; - esac ;; - [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) - echo i${UNAME_MACHINE}-pc-mks - exit ;; - 8664:Windows_NT:*) - echo x86_64-pc-mks - exit ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i586-pc-interix - exit ;; - i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin - exit ;; - amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin - exit ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit ;; - prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - *:GNU:*:*) - # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` - exit ;; - *:GNU/*:*:*) - # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu - exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix - exit ;; - aarch64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - aarch64_be:Linux:*:*) - UNAME_MACHINE=aarch64_be - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in - EV5) UNAME_MACHINE=alphaev5 ;; - EV56) UNAME_MACHINE=alphaev56 ;; - PCA56) UNAME_MACHINE=alphapca56 ;; - PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi - echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} - exit ;; - arm*:Linux:*:*) - eval $set_cc_for_build - if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_EABI__ - then - echo ${UNAME_MACHINE}-unknown-linux-gnu - else - if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_PCS_VFP - then - echo ${UNAME_MACHINE}-unknown-linux-gnueabi - else - echo ${UNAME_MACHINE}-unknown-linux-gnueabihf - fi - fi - exit ;; - avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - cris:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-gnu - exit ;; - crisv32:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-gnu - exit ;; - frv:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - hexagon:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - i*86:Linux:*:*) - LIBC=gnu - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #ifdef __dietlibc__ - LIBC=dietlibc - #endif -EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` - echo "${UNAME_MACHINE}-pc-linux-${LIBC}" - exit ;; - ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - mips:Linux:*:* | mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef ${UNAME_MACHINE} - #undef ${UNAME_MACHINE}el - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=${UNAME_MACHINE}el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=${UNAME_MACHINE} - #else - CPU= - #endif - #endif -EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } - ;; - or32:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - padre:Linux:*:*) - echo sparc-unknown-linux-gnu - exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-gnu - exit ;; - parisc:Linux:*:* | hppa:Linux:*:*) - # Look for CPU level - case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-gnu ;; - PA8*) echo hppa2.0-unknown-linux-gnu ;; - *) echo hppa-unknown-linux-gnu ;; - esac - exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-gnu - exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-gnu - exit ;; - s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux - exit ;; - sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - tile*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-gnu - exit ;; - x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - i*86:DYNIX/ptx:4*:*) - # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. - # earlier versions are messed up and put the nodename in both - # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; - i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} - exit ;; - i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility - # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx - exit ;; - i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop - exit ;; - i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos - exit ;; - i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable - exit ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} - exit ;; - i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp - exit ;; - i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) - UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} - else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} - fi - exit ;; - i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. - case `/bin/uname -X | grep "^Machine"` in - *486*) UNAME_MACHINE=i486 ;; - *Pentium) UNAME_MACHINE=i586 ;; - *Pent*|*Celeron) UNAME_MACHINE=i686 ;; - esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} - exit ;; - i*86:*:3.2:*) - if test -f /usr/options/cb.name; then - UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` - (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ - && UNAME_MACHINE=i586 - (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ - && UNAME_MACHINE=i686 - (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ - && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL - else - echo ${UNAME_MACHINE}-pc-sysv32 - fi - exit ;; - pc:*:*:*) - # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i586. - # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configury will decide that - # this is a cross-build. - echo i586-pc-msdosdjgpp - exit ;; - Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; - paragon:*:*:*) - echo i860-intel-osf1 - exit ;; - i860:*:4.*:*) # i860-SVR4 - if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 - else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 - fi - exit ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - echo m68010-convergent-sysv - exit ;; - mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; - M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; - M68*:*:R3V[5678]*:*) - test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; - 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) - OS_REL='' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; - NCR*:*:4.2:* | MPRAS*:*:4.2:*) - OS_REL='.3' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } - /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; - m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} - exit ;; - mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; - TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} - exit ;; - rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} - exit ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} - exit ;; - SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} - exit ;; - RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - *:SINIX-*:*:*) - if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 - else - echo ns32k-sni-sysv - fi - exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - exit ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes . - # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; - *:*:*:FTX*) - # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit ;; - i*86:VOS:*:*) - # From Paul.Green@stratus.com. - echo ${UNAME_MACHINE}-stratus-vos - exit ;; - *:VOS:*:*) - # From Paul.Green@stratus.com. - echo hppa1.1-stratus-vos - exit ;; - mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} - exit ;; - news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} - else - echo mips-unknown-sysv${UNAME_RELEASE} - fi - exit ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; - BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; - BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; - BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - echo i586-pc-haiku - exit ;; - SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} - exit ;; - SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} - exit ;; - SX-6:SUPER-UX:*:*) - echo sx6-nec-superux${UNAME_RELEASE} - exit ;; - SX-7:SUPER-UX:*:*) - echo sx7-nec-superux${UNAME_RELEASE} - exit ;; - SX-8:SUPER-UX:*:*) - echo sx8-nec-superux${UNAME_RELEASE} - exit ;; - SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux${UNAME_RELEASE} - exit ;; - Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} - exit ;; - *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} - exit ;; - *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - case $UNAME_PROCESSOR in - i386) - eval $set_cc_for_build - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - UNAME_PROCESSOR="x86_64" - fi - fi ;; - unknown) UNAME_PROCESSOR=powerpc ;; - esac - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} - exit ;; - *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then - UNAME_PROCESSOR=i386 - UNAME_MACHINE=pc - fi - echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} - exit ;; - *:QNX:*:4*) - echo i386-pc-qnx - exit ;; - NEO-?:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk${UNAME_RELEASE} - exit ;; - NSE-?:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} - exit ;; - NSR-?:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk${UNAME_RELEASE} - exit ;; - *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; - BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; - DS/*:UNIX_System_V:*:*) - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} - exit ;; - *:Plan9:*:*) - # "uname -m" is not consistent, so use $cputype instead. 386 - # is converted to i386 for consistency with other x86 - # operating systems. - if test "$cputype" = "386"; then - UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" - fi - echo ${UNAME_MACHINE}-unknown-plan9 - exit ;; - *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; - *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; - KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; - XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; - *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; - *:ITS:*:*) - echo pdp10-unknown-its - exit ;; - SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} - exit ;; - *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` - exit ;; - *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; - esac ;; - *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; - i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' - exit ;; - i*86:rdos:*:*) - echo ${UNAME_MACHINE}-pc-rdos - exit ;; - i*86:AROS:*:*) - echo ${UNAME_MACHINE}-pc-aros - exit ;; - x86_64:VMkernel:*:*) - echo ${UNAME_MACHINE}-unknown-esx - exit ;; -esac - -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - -eval $set_cc_for_build -cat >$dummy.c < -# include -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix\n"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); - -#endif - -#if defined (vax) -# if !defined (ultrix) -# include -# if defined (BSD) -# if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -# else -# if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# endif -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# else - printf ("vax-dec-ultrix\n"); exit (0); -# endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. - -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } - -# Convex versions that predate uname can use getsysinfo(1) - -if [ -x /usr/convex/getsysinfo ] -then - case `getsysinfo -f cpu_type` in - c1*) - echo c1-convex-bsd - exit ;; - c2*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - c34*) - echo c34-convex-bsd - exit ;; - c38*) - echo c38-convex-bsd - exit ;; - c4*) - echo c4-convex-bsd - exit ;; - esac -fi - -cat >&2 < in order to provide the needed -information to handle your system. - -config.guess timestamp = $timestamp - -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null` - -hostinfo = `(hostinfo) 2>/dev/null` -/bin/universe = `(/bin/universe) 2>/dev/null` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` -/bin/arch = `(/bin/arch) 2>/dev/null` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` - -UNAME_MACHINE = ${UNAME_MACHINE} -UNAME_RELEASE = ${UNAME_RELEASE} -UNAME_SYSTEM = ${UNAME_SYSTEM} -UNAME_VERSION = ${UNAME_VERSION} -EOF - -exit 1 - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/autoconf/config.sub b/autoconf/config.sub deleted file mode 100755 index c894da4..0000000 --- a/autoconf/config.sub +++ /dev/null @@ -1,1773 +0,0 @@ -#! /bin/sh -# Configuration validation subroutine script. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011, 2012 Free Software Foundation, Inc. - -timestamp='2012-02-10' - -# This file is (in principle) common to ALL GNU software. -# The presence of a machine in this file suggests that SOME GNU software -# can handle that machine. It does not imply ALL GNU software can. -# -# This file is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -# Please send patches to . Submit a context -# diff and a properly formatted GNU ChangeLog entry. -# -# Configuration subroutine to validate and canonicalize a configuration type. -# Supply the specified configuration type as an argument. -# If it is invalid, we print an error message on stderr and exit with code 1. -# Otherwise, we print the canonical config type on stdout and succeed. - -# You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD - -# This file is supposed to be the same for all GNU packages -# and recognize all the CPU types, system types and aliases -# that are meaningful with *any* GNU software. -# Each package is responsible for reporting which valid configurations -# it does not support. The user should be able to distinguish -# a failure to support a valid configuration from a meaningless -# configuration. - -# The goal of this file is to map all the various variations of a given -# machine specification into a single specification in the form: -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or in some cases, the newer four-part form: -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# It is wrong to echo any other type of specification. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS - $0 [OPTION] ALIAS - -Canonicalize a configuration name. - -Operation modes: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.sub ($timestamp) - -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 -Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" - exit 1 ;; - - *local*) - # First pass through any local machine types. - echo $1 - exit ;; - - * ) - break ;; - esac -done - -case $# in - 0) echo "$me: missing argument$help" >&2 - exit 1;; - 1) ;; - *) echo "$me: too many arguments$help" >&2 - exit 1;; -esac - -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | \ - kopensolaris*-gnu* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - android-linux) - os=-linux-android - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac - -### Let's recognize common machines as not being operating systems so -### that things like config.sub decstation-3100 work. We also -### recognize some manufacturers as not being operating systems, so we -### can provide default operating systems below. -case $os in - -sun*os*) - # Prevent following clause from handling this invalid input. - ;; - -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray | -microblaze) - os= - basic_machine=$1 - ;; - -bluegene*) - os=-cnk - ;; - -sim | -cisco | -oki | -wec | -winbond) - os= - basic_machine=$1 - ;; - -scout) - ;; - -wrs) - os=-vxworks - basic_machine=$1 - ;; - -chorusos*) - os=-chorusos - basic_machine=$1 - ;; - -chorusrdb) - os=-chorusrdb - basic_machine=$1 - ;; - -hiux*) - os=-hiuxwe2 - ;; - -sco6) - os=-sco5v6 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5) - os=-sco3.2v5 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco4) - os=-sco3.2v4 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2.[4-9]*) - os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2v[4-9]*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5v6*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco*) - os=-sco3.2v2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -udk*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -isc) - os=-isc2.2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -clix*) - basic_machine=clipper-intergraph - ;; - -isc*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -lynx*) - os=-lynxos - ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` - ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` - ;; - -psos*) - os=-psos - ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; -esac - -# Decode aliases for certain CPU-COMPANY combinations. -case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ - | aarch64 | aarch64_be \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ - | be32 | be64 \ - | bfin \ - | c4x | clipper \ - | d10v | d30v | dlx | dsp16xx \ - | epiphany \ - | fido | fr30 | frv \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | hexagon \ - | i370 | i860 | i960 | ia64 \ - | ip2k | iq2000 \ - | le32 | le64 \ - | lm32 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | mcore | mep | metag \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | moxie \ - | mt \ - | msp430 \ - | nds32 | nds32le | nds32be \ - | nios | nios2 \ - | ns16k | ns32k \ - | open8 \ - | or32 \ - | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle \ - | pyramid \ - | rl78 | rx \ - | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu \ - | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ - | ubicom32 \ - | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ - | we32k \ - | x86 | xc16x | xstormy16 | xtensa \ - | z8k | z80) - basic_machine=$basic_machine-unknown - ;; - c54x) - basic_machine=tic54x-unknown - ;; - c55x) - basic_machine=tic55x-unknown - ;; - c6x) - basic_machine=tic6x-unknown - ;; - m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) - basic_machine=$basic_machine-unknown - os=-none - ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) - ;; - ms1) - basic_machine=mt-unknown - ;; - - strongarm | thumb | xscale) - basic_machine=arm-unknown - ;; - xgate) - basic_machine=$basic_machine-unknown - os=-none - ;; - xscaleeb) - basic_machine=armeb-unknown - ;; - - xscaleel) - basic_machine=armel-unknown - ;; - - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. - i*86 | x86_64) - basic_machine=$basic_machine-pc - ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ - | aarch64-* | aarch64_be-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ - | be32-* | be64-* \ - | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | hexagon-* \ - | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* | iq2000-* \ - | le32-* | le64-* \ - | lm32-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ - | mips64octeon-* | mips64octeonel-* \ - | mips64orion-* | mips64orionel-* \ - | mips64r5900-* | mips64r5900el-* \ - | mips64vr-* | mips64vrel-* \ - | mips64vr4100-* | mips64vr4100el-* \ - | mips64vr4300-* | mips64vr4300el-* \ - | mips64vr5000-* | mips64vr5000el-* \ - | mips64vr5900-* | mips64vr5900el-* \ - | mipsisa32-* | mipsisa32el-* \ - | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ - | nds32-* | nds32le-* | nds32be-* \ - | nios-* | nios2-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ - | open8-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ - | pyramid-* \ - | rl78-* | romp-* | rs6000-* | rx-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ - | tahoe-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | tile*-* \ - | tron-* \ - | ubicom32-* \ - | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ - | vax-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* \ - | xstormy16-* | xtensa*-* \ - | ymp-* \ - | z8k-* | z80-*) - ;; - # Recognize the basic CPU types without company name, with glob match. - xtensa*) - basic_machine=$basic_machine-unknown - ;; - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att - ;; - 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - abacus) - basic_machine=abacus-unknown - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amd64) - basic_machine=x86_64-pc - ;; - amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-unknown - ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aros) - basic_machine=i386-pc - os=-aros - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux - ;; - blackfin-*) - basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - bluegene*) - basic_machine=powerpc-ibm - os=-cnk - ;; - c54x-*) - basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c55x-*) - basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c6x-*) - basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; - cegcc) - basic_machine=arm-unknown - os=-cegcc - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16 | cr16-*) - basic_machine=cr16-unknown - os=-elf - ;; - crds | unos) - basic_machine=m68k-crds - ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; - cris | cris-* | etrax*) - basic_machine=cris-axis - ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec - ;; - decsystem10* | dec10*) - basic_machine=pdp10-dec - os=-tops10 - ;; - decsystem20* | dec20*) - basic_machine=pdp10-dec - os=-tops20 - ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola - ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dicos) - basic_machine=i686-pc - os=-dicos - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2* | dpx2*-bull) - basic_machine=m68k-bull - os=-sysv3 - ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; - encore | umax | mmax) - basic_machine=ns32k-encore - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose - ;; - fx2800) - basic_machine=i860-alliant - ;; - genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; - h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp - ;; - hp9k3[2-9][0-9]) - basic_machine=m68k-hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm - ;; - i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 - ;; - i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 - ;; - i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv - ;; - i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta - ;; - iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) - ;; - *) - os=-irix4 - ;; - esac - ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux - ;; - m68knommu-*) - basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - microblaze) - basic_machine=microblaze-xilinx - ;; - mingw32) - basic_machine=i386-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; - miniframe) - basic_machine=m68000-convergent - ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; - mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` - ;; - mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - msdos) - basic_machine=i386-pc - os=-msdos - ;; - ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - msys) - basic_machine=i386-pc - os=-msys - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - nacl) - basic_machine=le32-unknown - os=-nacl - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos - ;; - news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) - basic_machine=m68k-next - case $os in - -nextstep* ) - ;; - -ns2*) - os=-nextstep2 - ;; - *) - os=-nextstep3 - ;; - esac - ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; - np1) - basic_machine=np1-gould - ;; - neo-tandem) - basic_machine=neo-tandem - ;; - nse-tandem) - basic_machine=nse-tandem - ;; - nsr-tandem) - basic_machine=nsr-tandem - ;; - op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - openrisc | openrisc-*) - basic_machine=or32-unknown - ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; - pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux - ;; - parisc-*) - basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - pbd) - basic_machine=sparc-tti - ;; - pbb) - basic_machine=m68k-tti - ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 - ;; - pc98) - basic_machine=i386-pc - ;; - pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium | p5 | k5 | k6 | nexgen | viac3) - basic_machine=i586-pc - ;; - pentiumpro | p6 | 6x86 | athlon | athlon_*) - basic_machine=i686-pc - ;; - pentiumii | pentium2 | pentiumiii | pentium3) - basic_machine=i686-pc - ;; - pentium4) - basic_machine=i786-pc - ;; - pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pn) - basic_machine=pn-gould - ;; - power) basic_machine=power-ibm - ;; - ppc | ppcbe) basic_machine=powerpc-unknown - ;; - ppc-* | ppcbe-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle | ppc-le | powerpc-little) - basic_machine=powerpcle-unknown - ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64) basic_machine=powerpc64-unknown - ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) - basic_machine=powerpc64le-unknown - ;; - ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ps2) - basic_machine=i386-ibm - ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; - rm[46]00) - basic_machine=mips-siemens - ;; - rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - s390 | s390-*) - basic_machine=s390-ibm - ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; - sb1) - basic_machine=mipsisa64sb1-unknown - ;; - sb1el) - basic_machine=mipsisa64sb1el-unknown - ;; - sde) - basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux - ;; - sequent) - basic_machine=i386-sequent - ;; - sh) - basic_machine=sh-hitachi - os=-hms - ;; - sh5el) - basic_machine=sh5le-unknown - ;; - sh64) - basic_machine=sh64-unknown - ;; - sparclite-wrs | simso-wrs) - basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 - ;; - spur) - basic_machine=spur-unknown - ;; - st2000) - basic_machine=m68k-tandem - ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; - strongarm-* | thumb-*) - basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - sun2) - basic_machine=m68000-sun - ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; - sun3 | sun3-*) - basic_machine=m68k-sun - ;; - sun4) - basic_machine=sparc-sun - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; - tile*) - basic_machine=$basic_machine-unknown - os=-linux-gnu - ;; - tx39) - basic_machine=mipstx39-unknown - ;; - tx39el) - basic_machine=mipstx39el-unknown - ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; - tower | tower-32) - basic_machine=m68k-ncr - ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; - vpp*|vx|vx-*) - basic_machine=f301-fujitsu - ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - w65*) - basic_machine=w65-wdc - os=-none - ;; - w89k-*) - basic_machine=hppa1.1-winbond - os=-proelf - ;; - xbox) - basic_machine=i686-pc - os=-mingw32 - ;; - xps | xps100) - basic_machine=xps100-honeywell - ;; - xscale-* | xscalee[bl]-*) - basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - z8k-*-coff) - basic_machine=z8k-unknown - os=-sim - ;; - z80-*-coff) - basic_machine=z80-unknown - os=-sim - ;; - none) - basic_machine=none-none - os=-none - ;; - -# Here we handle the default manufacturer of certain CPU types. It is in -# some cases the only manufacturer, in others, it is the most popular. - w89k) - basic_machine=hppa1.1-winbond - ;; - op50n) - basic_machine=hppa1.1-oki - ;; - op60c) - basic_machine=hppa1.1-oki - ;; - romp) - basic_machine=romp-ibm - ;; - mmix) - basic_machine=mmix-knuth - ;; - rs6000) - basic_machine=rs6000-ibm - ;; - vax) - basic_machine=vax-dec - ;; - pdp10) - # there are many clones, so DEC is not a safe bet - basic_machine=pdp10-unknown - ;; - pdp11) - basic_machine=pdp11-dec - ;; - we32k) - basic_machine=we32k-att - ;; - sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) - basic_machine=sh-unknown - ;; - sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) - basic_machine=sparc-sun - ;; - cydra) - basic_machine=cydra-cydrome - ;; - orion) - basic_machine=orion-highlevel - ;; - orion105) - basic_machine=clipper-highlevel - ;; - mac | mpw | mac-mpw) - basic_machine=m68k-apple - ;; - pmac | pmac-mpw) - basic_machine=powerpc-apple - ;; - *-unknown) - # Make sure to match an already-canonicalized machine name. - ;; - *) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; -esac - -# Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` - ;; - *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` - ;; - *) - ;; -esac - -# Decode manufacturer-specific aliases for certain operating systems. - -if [ x"$os" != x"" ] -then -case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -auroraux) - os=-auroraux - ;; - -solaris1 | -solaris1.*) - os=`echo $os | sed -e 's|solaris1|sunos4|'` - ;; - -solaris) - os=-solaris2 - ;; - -svr4*) - os=-sysv4 - ;; - -unixware*) - os=-sysv4.2uw - ;; - -gnu/linux*) - os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` - ;; - # First accept the basic system types. - # The portable systems comes first. - # Each alternative MUST END IN A *, to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -openbsd* | -solidbsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* | -cegcc* \ - | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ - | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) - # Remember, each alternative MUST END IN *, to match a version number. - ;; - -qnx*) - case $basic_machine in - x86-* | i*86-*) - ;; - *) - os=-nto$os - ;; - esac - ;; - -nto-qnx*) - ;; - -nto*) - os=`echo $os | sed -e 's|nto|nto-qnx|'` - ;; - -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ - | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) - ;; - -mac*) - os=`echo $os | sed -e 's|mac|macos|'` - ;; - -linux-dietlibc) - os=-linux-dietlibc - ;; - -linux*) - os=`echo $os | sed -e 's|linux|linux-gnu|'` - ;; - -sunos5*) - os=`echo $os | sed -e 's|sunos5|solaris2|'` - ;; - -sunos6*) - os=`echo $os | sed -e 's|sunos6|solaris3|'` - ;; - -opened*) - os=-openedition - ;; - -os400*) - os=-os400 - ;; - -wince*) - os=-wince - ;; - -osfrose*) - os=-osfrose - ;; - -osf*) - os=-osf - ;; - -utek*) - os=-bsd - ;; - -dynix*) - os=-bsd - ;; - -acis*) - os=-aos - ;; - -atheos*) - os=-atheos - ;; - -syllable*) - os=-syllable - ;; - -386bsd) - os=-bsd - ;; - -ctix* | -uts*) - os=-sysv - ;; - -nova*) - os=-rtmk-nova - ;; - -ns2 ) - os=-nextstep2 - ;; - -nsk*) - os=-nsk - ;; - # Preserve the version number of sinix5. - -sinix5.*) - os=`echo $os | sed -e 's|sinix|sysv|'` - ;; - -sinix*) - os=-sysv4 - ;; - -tpf*) - os=-tpf - ;; - -triton*) - os=-sysv3 - ;; - -oss*) - os=-sysv3 - ;; - -svr4) - os=-sysv4 - ;; - -svr3) - os=-sysv3 - ;; - -sysvr4) - os=-sysv4 - ;; - # This must come after -sysvr4. - -sysv*) - ;; - -ose*) - os=-ose - ;; - -es1800*) - os=-ose - ;; - -xenix) - os=-xenix - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - os=-mint - ;; - -aros*) - os=-aros - ;; - -kaos*) - os=-kaos - ;; - -zvmoe) - os=-zvmoe - ;; - -dicos*) - os=-dicos - ;; - -nacl*) - ;; - -none) - ;; - *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` - echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 - exit 1 - ;; -esac -else - -# Here we handle the default operating systems that come with various machines. -# The value should be what the vendor currently ships out the door with their -# machine or put another way, the most popular os provided with the machine. - -# Note that if you're going to try to match "-MANUFACTURER" here (say, -# "-sun"), then you have to tell the case statement up towards the top -# that MANUFACTURER isn't an operating system. Otherwise, code above -# will signal an error saying that MANUFACTURER isn't an operating -# system, and we'll never get to this point. - -case $basic_machine in - score-*) - os=-elf - ;; - spu-*) - os=-elf - ;; - *-acorn) - os=-riscix1.2 - ;; - arm*-rebel) - os=-linux - ;; - arm*-semi) - os=-aout - ;; - c4x-* | tic4x-*) - os=-coff - ;; - tic54x-*) - os=-coff - ;; - tic55x-*) - os=-coff - ;; - tic6x-*) - os=-coff - ;; - # This must come before the *-dec entry. - pdp10-*) - os=-tops20 - ;; - pdp11-*) - os=-none - ;; - *-dec | vax-*) - os=-ultrix4.2 - ;; - m68*-apollo) - os=-domain - ;; - i386-sun) - os=-sunos4.0.2 - ;; - m68000-sun) - os=-sunos3 - ;; - m68*-cisco) - os=-aout - ;; - mep-*) - os=-elf - ;; - mips*-cisco) - os=-elf - ;; - mips*-*) - os=-elf - ;; - or32-*) - os=-coff - ;; - *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 - ;; - sparc-* | *-sun) - os=-sunos4.1.1 - ;; - *-be) - os=-beos - ;; - *-haiku) - os=-haiku - ;; - *-ibm) - os=-aix - ;; - *-knuth) - os=-mmixware - ;; - *-wec) - os=-proelf - ;; - *-winbond) - os=-proelf - ;; - *-oki) - os=-proelf - ;; - *-hp) - os=-hpux - ;; - *-hitachi) - os=-hiux - ;; - i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv - ;; - *-cbm) - os=-amigaos - ;; - *-dg) - os=-dgux - ;; - *-dolphin) - os=-sysv3 - ;; - m68k-ccur) - os=-rtu - ;; - m88k-omron*) - os=-luna - ;; - *-next ) - os=-nextstep - ;; - *-sequent) - os=-ptx - ;; - *-crds) - os=-unos - ;; - *-ns) - os=-genix - ;; - i370-*) - os=-mvs - ;; - *-next) - os=-nextstep3 - ;; - *-gould) - os=-sysv - ;; - *-highlevel) - os=-bsd - ;; - *-encore) - os=-bsd - ;; - *-sgi) - os=-irix - ;; - *-siemens) - os=-sysv4 - ;; - *-masscomp) - os=-rtu - ;; - f30[01]-fujitsu | f700-fujitsu) - os=-uxpv - ;; - *-rom68k) - os=-coff - ;; - *-*bug) - os=-coff - ;; - *-apple) - os=-macos - ;; - *-atari*) - os=-mint - ;; - *) - os=-none - ;; -esac -fi - -# Here we handle the case where we know the os, and the CPU type, but not the -# manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) - case $os in - -riscix*) - vendor=acorn - ;; - -sunos*) - vendor=sun - ;; - -cnk*|-aix*) - vendor=ibm - ;; - -beos*) - vendor=be - ;; - -hpux*) - vendor=hp - ;; - -mpeix*) - vendor=hp - ;; - -hiux*) - vendor=hitachi - ;; - -unos*) - vendor=crds - ;; - -dgux*) - vendor=dg - ;; - -luna*) - vendor=omron - ;; - -genix*) - vendor=ns - ;; - -mvs* | -opened*) - vendor=ibm - ;; - -os400*) - vendor=ibm - ;; - -ptx*) - vendor=sequent - ;; - -tpf*) - vendor=ibm - ;; - -vxsim* | -vxworks* | -windiss*) - vendor=wrs - ;; - -aux*) - vendor=apple - ;; - -hms*) - vendor=hitachi - ;; - -mpw* | -macos*) - vendor=apple - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - vendor=atari - ;; - -vos*) - vendor=stratus - ;; - esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` - ;; -esac - -echo $basic_machine$os -exit - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/autoconf/configure.ac b/autoconf/configure.ac index 46b6563..9492530 100644 --- a/autoconf/configure.ac +++ b/autoconf/configure.ac @@ -4,11 +4,13 @@ # # --enable-threadsafe # --enable-readline +# --enable-editline +# --enable-static-shell # --enable-dynamic-extensions # AC_PREREQ(2.61) -AC_INIT(sqlite, 3.7.5, http://www.sqlite.org) +AC_INIT(sqlite, --SQLITE-VERSION--, http://www.sqlite.org) AC_CONFIG_SRCDIR([sqlite3.c]) # Use automake. @@ -18,7 +20,6 @@ AC_SYS_LARGEFILE # Check for required programs. AC_PROG_CC -AC_PROG_RANLIB AC_PROG_LIBTOOL AC_PROG_MKDIR_P @@ -30,12 +31,29 @@ AC_CONFIG_FILES([Makefile sqlite3.pc]) AC_SUBST(BUILD_CFLAGS) #----------------------------------------------------------------------- +# --enable-editline # --enable-readline # +AC_ARG_ENABLE(editline, [AS_HELP_STRING( + [--enable-editline], + [use BSD libedit])], + [], [enable_editline=yes]) AC_ARG_ENABLE(readline, [AS_HELP_STRING( [--enable-readline], - [use readline in shell tool (yes, no) [default=yes]])], - [], [enable_readline=yes]) + [use readline])], + [], [enable_readline=no]) +if test x"$enable_editline" != xno ; then + sLIBS=$LIBS + LIBS="" + AC_SEARCH_LIBS([readline],[edit],[enable_readline=no],[enable_editline=no]) + READLINE_LIBS=$LIBS + if test x"$LIBS" != "x"; then + AC_DEFINE([HAVE_EDITLINE],1,Define to use BSD editline) + else + unset ac_cv_search_readline + fi + LIBS=$sLIBS +fi if test x"$enable_readline" != xno ; then sLIBS=$LIBS LIBS="" @@ -58,6 +76,7 @@ THREADSAFE_FLAGS=-DSQLITE_THREADSAFE=0 if test x"$enable_threadsafe" != "xno"; then THREADSAFE_FLAGS="-D_REENTRANT=1 -DSQLITE_THREADSAFE=1" AC_SEARCH_LIBS(pthread_create, pthread) + AC_SEARCH_LIBS(pthread_mutexattr_init, pthread) fi AC_SUBST(THREADSAFE_FLAGS) #----------------------------------------------------------------------- @@ -78,6 +97,46 @@ AC_MSG_RESULT($enable_dynamic_extensions) AC_SUBST(DYNAMIC_EXTENSION_FLAGS) #----------------------------------------------------------------------- +#----------------------------------------------------------------------- +# --enable-fts5 +# +AC_ARG_ENABLE(fts5, [AS_HELP_STRING( + [--enable-fts5], [include fts5 support [default=no]])], + [], [enable_fts5=no]) +if test x"$enable_fts5" == "xyes"; then + AC_SEARCH_LIBS(log, m) + FTS5_FLAGS=-DSQLITE_ENABLE_FTS5 +fi +AC_SUBST(FTS5_FLAGS) +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# --enable-json1 +# +AC_ARG_ENABLE(json1, [AS_HELP_STRING( + [--enable-json1], [include json1 support [default=no]])], + [], [enable_json1=no]) +if test x"$enable_json1" == "xyes"; then + JSON1_FLAGS=-DSQLITE_ENABLE_JSON1 +fi +AC_SUBST(JSON1_FLAGS) +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# --enable-static-shell +# +AC_ARG_ENABLE(static-shell, [AS_HELP_STRING( + [--enable-static-shell], + [statically link libsqlite3 into shell tool [default=yes]])], + [], [enable_static_shell=yes]) +if test x"$enable_static_shell" == "xyes"; then + EXTRA_SHELL_OBJ=sqlite3.$OBJEXT +else + EXTRA_SHELL_OBJ=libsqlite3.la +fi +AC_SUBST(EXTRA_SHELL_OBJ) +#----------------------------------------------------------------------- + AC_CHECK_FUNCS(posix_fallocate) #----------------------------------------------------------------------- diff --git a/autoconf/depcomp b/autoconf/depcomp deleted file mode 100755 index 25a39e6..0000000 --- a/autoconf/depcomp +++ /dev/null @@ -1,708 +0,0 @@ -#! /bin/sh -# depcomp - compile a program generating dependencies as side-effects - -scriptversion=2012-03-27.16; # UTC - -# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010, -# 2011, 2012 Free Software Foundation, Inc. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# Originally written by Alexandre Oliva . - -case $1 in - '') - echo "$0: No command. Try '$0 --help' for more information." 1>&2 - exit 1; - ;; - -h | --h*) - cat <<\EOF -Usage: depcomp [--help] [--version] PROGRAM [ARGS] - -Run PROGRAMS ARGS to compile a file, generating dependencies -as side-effects. - -Environment variables: - depmode Dependency tracking mode. - source Source file read by 'PROGRAMS ARGS'. - object Object file output by 'PROGRAMS ARGS'. - DEPDIR directory where to store dependencies. - depfile Dependency file to output. - tmpdepfile Temporary file to use when outputting dependencies. - libtool Whether libtool is used (yes/no). - -Report bugs to . -EOF - exit $? - ;; - -v | --v*) - echo "depcomp $scriptversion" - exit $? - ;; -esac - -# A tabulation character. -tab=' ' -# A newline character. -nl=' -' - -if test -z "$depmode" || test -z "$source" || test -z "$object"; then - echo "depcomp: Variables source, object and depmode must be set" 1>&2 - exit 1 -fi - -# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. -depfile=${depfile-`echo "$object" | - sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} -tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} - -rm -f "$tmpdepfile" - -# Some modes work just like other modes, but use different flags. We -# parameterize here, but still list the modes in the big case below, -# to make depend.m4 easier to write. Note that we *cannot* use a case -# here, because this file can only contain one case statement. -if test "$depmode" = hp; then - # HP compiler uses -M and no extra arg. - gccflag=-M - depmode=gcc -fi - -if test "$depmode" = dashXmstdout; then - # This is just like dashmstdout with a different argument. - dashmflag=-xM - depmode=dashmstdout -fi - -cygpath_u="cygpath -u -f -" -if test "$depmode" = msvcmsys; then - # This is just like msvisualcpp but w/o cygpath translation. - # Just convert the backslash-escaped backslashes to single forward - # slashes to satisfy depend.m4 - cygpath_u='sed s,\\\\,/,g' - depmode=msvisualcpp -fi - -if test "$depmode" = msvc7msys; then - # This is just like msvc7 but w/o cygpath translation. - # Just convert the backslash-escaped backslashes to single forward - # slashes to satisfy depend.m4 - cygpath_u='sed s,\\\\,/,g' - depmode=msvc7 -fi - -if test "$depmode" = xlc; then - # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations. - gccflag=-qmakedep=gcc,-MF - depmode=gcc -fi - -case "$depmode" in -gcc3) -## gcc 3 implements dependency tracking that does exactly what -## we want. Yay! Note: for some reason libtool 1.4 doesn't like -## it if -MD -MP comes after the -MF stuff. Hmm. -## Unfortunately, FreeBSD c89 acceptance of flags depends upon -## the command line argument order; so add the flags where they -## appear in depend2.am. Note that the slowdown incurred here -## affects only configure: in makefiles, %FASTDEP% shortcuts this. - for arg - do - case $arg in - -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; - *) set fnord "$@" "$arg" ;; - esac - shift # fnord - shift # $arg - done - "$@" - stat=$? - if test $stat -eq 0; then : - else - rm -f "$tmpdepfile" - exit $stat - fi - mv "$tmpdepfile" "$depfile" - ;; - -gcc) -## There are various ways to get dependency output from gcc. Here's -## why we pick this rather obscure method: -## - Don't want to use -MD because we'd like the dependencies to end -## up in a subdir. Having to rename by hand is ugly. -## (We might end up doing this anyway to support other compilers.) -## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like -## -MM, not -M (despite what the docs say). -## - Using -M directly means running the compiler twice (even worse -## than renaming). - if test -z "$gccflag"; then - gccflag=-MD, - fi - "$@" -Wp,"$gccflag$tmpdepfile" - stat=$? - if test $stat -eq 0; then : - else - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - echo "$object : \\" > "$depfile" - alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz -## The second -e expression handles DOS-style file names with drive letters. - sed -e 's/^[^:]*: / /' \ - -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" -## This next piece of magic avoids the "deleted header file" problem. -## The problem is that when a header file which appears in a .P file -## is deleted, the dependency causes make to die (because there is -## typically no way to rebuild the header). We avoid this by adding -## dummy dependencies for each header file. Too bad gcc doesn't do -## this for us directly. - tr ' ' "$nl" < "$tmpdepfile" | -## Some versions of gcc put a space before the ':'. On the theory -## that the space means something, we add a space to the output as -## well. hp depmode also adds that space, but also prefixes the VPATH -## to the object. Take care to not repeat it in the output. -## Some versions of the HPUX 10.20 sed can't process this invocation -## correctly. Breaking it into two sed invocations is a workaround. - sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ - | sed -e 's/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -hp) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -sgi) - if test "$libtool" = yes; then - "$@" "-Wp,-MDupdate,$tmpdepfile" - else - "$@" -MDupdate "$tmpdepfile" - fi - stat=$? - if test $stat -eq 0; then : - else - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - - if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files - echo "$object : \\" > "$depfile" - - # Clip off the initial element (the dependent). Don't try to be - # clever and replace this with sed code, as IRIX sed won't handle - # lines with more than a fixed number of characters (4096 in - # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; - # the IRIX cc adds comments like '#:fec' to the end of the - # dependency line. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ - tr "$nl" ' ' >> "$depfile" - echo >> "$depfile" - - # The second pass generates a dummy entry for each header file. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ - >> "$depfile" - else - # The sourcefile does not contain any dependencies, so just - # store a dummy comment line, to avoid errors with the Makefile - # "include basename.Plo" scheme. - echo "#dummy" > "$depfile" - fi - rm -f "$tmpdepfile" - ;; - -xlc) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -aix) - # The C for AIX Compiler uses -M and outputs the dependencies - # in a .u file. In older versions, this file always lives in the - # current directory. Also, the AIX compiler puts '$object:' at the - # start of each line; $object doesn't have directory information. - # Version 6 uses the directory in both cases. - dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` - test "x$dir" = "x$object" && dir= - base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` - if test "$libtool" = yes; then - tmpdepfile1=$dir$base.u - tmpdepfile2=$base.u - tmpdepfile3=$dir.libs/$base.u - "$@" -Wc,-M - else - tmpdepfile1=$dir$base.u - tmpdepfile2=$dir$base.u - tmpdepfile3=$dir$base.u - "$@" -M - fi - stat=$? - - if test $stat -eq 0; then : - else - rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - exit $stat - fi - - for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - do - test -f "$tmpdepfile" && break - done - if test -f "$tmpdepfile"; then - # Each line is of the form 'foo.o: dependent.h'. - # Do two passes, one to just change these to - # '$object: dependent.h' and one to simply 'dependent.h:'. - sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" - sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" - else - # The sourcefile does not contain any dependencies, so just - # store a dummy comment line, to avoid errors with the Makefile - # "include basename.Plo" scheme. - echo "#dummy" > "$depfile" - fi - rm -f "$tmpdepfile" - ;; - -icc) - # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'. - # However on - # $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c - # ICC 7.0 will fill foo.d with something like - # foo.o: sub/foo.c - # foo.o: sub/foo.h - # which is wrong. We want - # sub/foo.o: sub/foo.c - # sub/foo.o: sub/foo.h - # sub/foo.c: - # sub/foo.h: - # ICC 7.1 will output - # foo.o: sub/foo.c sub/foo.h - # and will wrap long lines using '\': - # foo.o: sub/foo.c ... \ - # sub/foo.h ... \ - # ... - # tcc 0.9.26 (FIXME still under development at the moment of writing) - # will emit a similar output, but also prepend the continuation lines - # with horizontal tabulation characters. - "$@" -MD -MF "$tmpdepfile" - stat=$? - if test $stat -eq 0; then : - else - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - # Each line is of the form 'foo.o: dependent.h', - # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'. - # Do two passes, one to just change these to - # '$object: dependent.h' and one to simply 'dependent.h:'. - sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \ - < "$tmpdepfile" > "$depfile" - sed ' - s/[ '"$tab"'][ '"$tab"']*/ /g - s/^ *// - s/ *\\*$// - s/^[^:]*: *// - /^$/d - /:$/d - s/$/ :/ - ' < "$tmpdepfile" >> "$depfile" - rm -f "$tmpdepfile" - ;; - -hp2) - # The "hp" stanza above does not work with aCC (C++) and HP's ia64 - # compilers, which have integrated preprocessors. The correct option - # to use with these is +Maked; it writes dependencies to a file named - # 'foo.d', which lands next to the object file, wherever that - # happens to be. - # Much of this is similar to the tru64 case; see comments there. - dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` - test "x$dir" = "x$object" && dir= - base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` - if test "$libtool" = yes; then - tmpdepfile1=$dir$base.d - tmpdepfile2=$dir.libs/$base.d - "$@" -Wc,+Maked - else - tmpdepfile1=$dir$base.d - tmpdepfile2=$dir$base.d - "$@" +Maked - fi - stat=$? - if test $stat -eq 0; then : - else - rm -f "$tmpdepfile1" "$tmpdepfile2" - exit $stat - fi - - for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" - do - test -f "$tmpdepfile" && break - done - if test -f "$tmpdepfile"; then - sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" - # Add 'dependent.h:' lines. - sed -ne '2,${ - s/^ *// - s/ \\*$// - s/$/:/ - p - }' "$tmpdepfile" >> "$depfile" - else - echo "#dummy" > "$depfile" - fi - rm -f "$tmpdepfile" "$tmpdepfile2" - ;; - -tru64) - # The Tru64 compiler uses -MD to generate dependencies as a side - # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. - # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put - # dependencies in 'foo.d' instead, so we check for that too. - # Subdirectories are respected. - dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` - test "x$dir" = "x$object" && dir= - base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` - - if test "$libtool" = yes; then - # With Tru64 cc, shared objects can also be used to make a - # static library. This mechanism is used in libtool 1.4 series to - # handle both shared and static libraries in a single compilation. - # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. - # - # With libtool 1.5 this exception was removed, and libtool now - # generates 2 separate objects for the 2 libraries. These two - # compilations output dependencies in $dir.libs/$base.o.d and - # in $dir$base.o.d. We have to check for both files, because - # one of the two compilations can be disabled. We should prefer - # $dir$base.o.d over $dir.libs/$base.o.d because the latter is - # automatically cleaned when .libs/ is deleted, while ignoring - # the former would cause a distcleancheck panic. - tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 - tmpdepfile2=$dir$base.o.d # libtool 1.5 - tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 - tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 - "$@" -Wc,-MD - else - tmpdepfile1=$dir$base.o.d - tmpdepfile2=$dir$base.d - tmpdepfile3=$dir$base.d - tmpdepfile4=$dir$base.d - "$@" -MD - fi - - stat=$? - if test $stat -eq 0; then : - else - rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" - exit $stat - fi - - for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" - do - test -f "$tmpdepfile" && break - done - if test -f "$tmpdepfile"; then - sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" - sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" - else - echo "#dummy" > "$depfile" - fi - rm -f "$tmpdepfile" - ;; - -msvc7) - if test "$libtool" = yes; then - showIncludes=-Wc,-showIncludes - else - showIncludes=-showIncludes - fi - "$@" $showIncludes > "$tmpdepfile" - stat=$? - grep -v '^Note: including file: ' "$tmpdepfile" - if test "$stat" = 0; then : - else - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - echo "$object : \\" > "$depfile" - # The first sed program below extracts the file names and escapes - # backslashes for cygpath. The second sed program outputs the file - # name when reading, but also accumulates all include files in the - # hold buffer in order to output them again at the end. This only - # works with sed implementations that can handle large buffers. - sed < "$tmpdepfile" -n ' -/^Note: including file: *\(.*\)/ { - s//\1/ - s/\\/\\\\/g - p -}' | $cygpath_u | sort -u | sed -n ' -s/ /\\ /g -s/\(.*\)/'"$tab"'\1 \\/p -s/.\(.*\) \\/\1:/ -H -$ { - s/.*/'"$tab"'/ - G - p -}' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -msvc7msys) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -#nosideeffect) - # This comment above is used by automake to tell side-effect - # dependency tracking mechanisms from slower ones. - -dashmstdout) - # Important note: in order to support this mode, a compiler *must* - # always write the preprocessed file to stdout, regardless of -o. - "$@" || exit $? - - # Remove the call to Libtool. - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - - # Remove '-o $object'. - IFS=" " - for arg - do - case $arg in - -o) - shift - ;; - $object) - shift - ;; - *) - set fnord "$@" "$arg" - shift # fnord - shift # $arg - ;; - esac - done - - test -z "$dashmflag" && dashmflag=-M - # Require at least two characters before searching for ':' - # in the target name. This is to cope with DOS-style filenames: - # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. - "$@" $dashmflag | - sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile" - rm -f "$depfile" - cat < "$tmpdepfile" > "$depfile" - tr ' ' "$nl" < "$tmpdepfile" | \ -## Some versions of the HPUX 10.20 sed can't process this invocation -## correctly. Breaking it into two sed invocations is a workaround. - sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -dashXmstdout) - # This case only exists to satisfy depend.m4. It is never actually - # run, as this mode is specially recognized in the preamble. - exit 1 - ;; - -makedepend) - "$@" || exit $? - # Remove any Libtool call - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - # X makedepend - shift - cleared=no eat=no - for arg - do - case $cleared in - no) - set ""; shift - cleared=yes ;; - esac - if test $eat = yes; then - eat=no - continue - fi - case "$arg" in - -D*|-I*) - set fnord "$@" "$arg"; shift ;; - # Strip any option that makedepend may not understand. Remove - # the object too, otherwise makedepend will parse it as a source file. - -arch) - eat=yes ;; - -*|$object) - ;; - *) - set fnord "$@" "$arg"; shift ;; - esac - done - obj_suffix=`echo "$object" | sed 's/^.*\././'` - touch "$tmpdepfile" - ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" - rm -f "$depfile" - # makedepend may prepend the VPATH from the source file name to the object. - # No need to regex-escape $object, excess matching of '.' is harmless. - sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" - sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \ -## Some versions of the HPUX 10.20 sed can't process this invocation -## correctly. Breaking it into two sed invocations is a workaround. - sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" "$tmpdepfile".bak - ;; - -cpp) - # Important note: in order to support this mode, a compiler *must* - # always write the preprocessed file to stdout. - "$@" || exit $? - - # Remove the call to Libtool. - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - - # Remove '-o $object'. - IFS=" " - for arg - do - case $arg in - -o) - shift - ;; - $object) - shift - ;; - *) - set fnord "$@" "$arg" - shift # fnord - shift # $arg - ;; - esac - done - - "$@" -E | - sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ - -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | - sed '$ s: \\$::' > "$tmpdepfile" - rm -f "$depfile" - echo "$object : \\" > "$depfile" - cat < "$tmpdepfile" >> "$depfile" - sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -msvisualcpp) - # Important note: in order to support this mode, a compiler *must* - # always write the preprocessed file to stdout. - "$@" || exit $? - - # Remove the call to Libtool. - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - - IFS=" " - for arg - do - case "$arg" in - -o) - shift - ;; - $object) - shift - ;; - "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") - set fnord "$@" - shift - shift - ;; - *) - set fnord "$@" "$arg" - shift - shift - ;; - esac - done - "$@" -E 2>/dev/null | - sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" - rm -f "$depfile" - echo "$object : \\" > "$depfile" - sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" - echo "$tab" >> "$depfile" - sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -msvcmsys) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -none) - exec "$@" - ;; - -*) - echo "Unknown depmode $depmode" 1>&2 - exit 1 - ;; -esac - -exit 0 - -# Local Variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" -# time-stamp-end: "; # UTC" -# End: diff --git a/autoconf/install-sh b/autoconf/install-sh deleted file mode 100755 index a9244eb..0000000 --- a/autoconf/install-sh +++ /dev/null @@ -1,527 +0,0 @@ -#!/bin/sh -# install - install a program, script, or datafile - -scriptversion=2011-01-19.21; # UTC - -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. - -nl=' -' -IFS=" "" $nl" - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit=${DOITPROG-} -if test -z "$doit"; then - doit_exec=exec -else - doit_exec=$doit -fi - -# Put in absolute file names if you don't have them in your path; -# or use environment vars. - -chgrpprog=${CHGRPPROG-chgrp} -chmodprog=${CHMODPROG-chmod} -chownprog=${CHOWNPROG-chown} -cmpprog=${CMPPROG-cmp} -cpprog=${CPPROG-cp} -mkdirprog=${MKDIRPROG-mkdir} -mvprog=${MVPROG-mv} -rmprog=${RMPROG-rm} -stripprog=${STRIPPROG-strip} - -posix_glob='?' -initialize_posix_glob=' - test "$posix_glob" != "?" || { - if (set -f) 2>/dev/null; then - posix_glob= - else - posix_glob=: - fi - } -' - -posix_mkdir= - -# Desired mode of installed file. -mode=0755 - -chgrpcmd= -chmodcmd=$chmodprog -chowncmd= -mvcmd=$mvprog -rmcmd="$rmprog -f" -stripcmd= - -src= -dst= -dir_arg= -dst_arg= - -copy_on_change=false -no_target_directory= - -usage="\ -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE - or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 [OPTION]... -t DIRECTORY SRCFILES... - or: $0 [OPTION]... -d DIRECTORIES... - -In the 1st form, copy SRCFILE to DSTFILE. -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. -In the 4th, create DIRECTORIES. - -Options: - --help display this help and exit. - --version display version info and exit. - - -c (ignored) - -C install only if different (preserve the last data modification time) - -d create directories instead of installing files. - -g GROUP $chgrpprog installed files to GROUP. - -m MODE $chmodprog installed files to MODE. - -o USER $chownprog installed files to USER. - -s $stripprog installed files. - -t DIRECTORY install into DIRECTORY. - -T report an error if DSTFILE is a directory. - -Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG - RMPROG STRIPPROG -" - -while test $# -ne 0; do - case $1 in - -c) ;; - - -C) copy_on_change=true;; - - -d) dir_arg=true;; - - -g) chgrpcmd="$chgrpprog $2" - shift;; - - --help) echo "$usage"; exit $?;; - - -m) mode=$2 - case $mode in - *' '* | *' '* | *' -'* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; - - -o) chowncmd="$chownprog $2" - shift;; - - -s) stripcmd=$stripprog;; - - -t) dst_arg=$2 - # Protect names problematic for `test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; - - -T) no_target_directory=true;; - - --version) echo "$0 $scriptversion"; exit $?;; - - --) shift - break;; - - -*) echo "$0: invalid option: $1" >&2 - exit 1;; - - *) break;; - esac - shift -done - -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then - # When -d is used, all remaining arguments are directories to create. - # When -t is used, the destination is already specified. - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dst_arg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dst_arg" - shift # fnord - fi - shift # arg - dst_arg=$arg - # Protect names problematic for `test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - done -fi - -if test $# -eq 0; then - if test -z "$dir_arg"; then - echo "$0: no input file specified." >&2 - exit 1 - fi - # It's OK to call `install-sh -d' without argument. - # This can happen when creating conditional directories. - exit 0 -fi - -if test -z "$dir_arg"; then - do_exit='(exit $ret); exit $ret' - trap "ret=129; $do_exit" 1 - trap "ret=130; $do_exit" 2 - trap "ret=141; $do_exit" 13 - trap "ret=143; $do_exit" 15 - - # Set umask so as not to create temps with too-generous modes. - # However, 'strip' requires both read and write access to temps. - case $mode in - # Optimize common cases. - *644) cp_umask=133;; - *755) cp_umask=22;; - - *[0-7]) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw='% 200' - fi - cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; - *) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw=,u+rw - fi - cp_umask=$mode$u_plus_rw;; - esac -fi - -for src -do - # Protect names problematic for `test' and other utilities. - case $src in - -* | [=\(\)!]) src=./$src;; - esac - - if test -n "$dir_arg"; then - dst=$src - dstdir=$dst - test -d "$dstdir" - dstdir_status=$? - else - - # Waiting for this to be detected by the "$cpprog $src $dsttmp" command - # might cause directories to be created, which would be especially bad - # if $src (and thus $dsttmp) contains '*'. - if test ! -f "$src" && test ! -d "$src"; then - echo "$0: $src does not exist." >&2 - exit 1 - fi - - if test -z "$dst_arg"; then - echo "$0: no destination specified." >&2 - exit 1 - fi - dst=$dst_arg - - # If destination is a directory, append the input filename; won't work - # if double slashes aren't ignored. - if test -d "$dst"; then - if test -n "$no_target_directory"; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 - fi - dstdir=$dst - dst=$dstdir/`basename "$src"` - dstdir_status=0 - else - # Prefer dirname, but fall back on a substitute if dirname fails. - dstdir=` - (dirname "$dst") 2>/dev/null || - expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$dst" : 'X\(//\)[^/]' \| \ - X"$dst" : 'X\(//\)$' \| \ - X"$dst" : 'X\(/\)' \| . 2>/dev/null || - echo X"$dst" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q' - ` - - test -d "$dstdir" - dstdir_status=$? - fi - fi - - obsolete_mkdir_used=false - - if test $dstdir_status != 0; then - case $posix_mkdir in - '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 - - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writeable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; - esac - - if - $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" - ) - then : - else - - # The umask is ridiculous, or mkdir does not conform to POSIX, - # or it failed possibly due to a race condition. Create the - # directory the slow way, step by step, checking for races as we go. - - case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; - esac - - eval "$initialize_posix_glob" - - oIFS=$IFS - IFS=/ - $posix_glob set -f - set fnord $dstdir - shift - $posix_glob set +f - IFS=$oIFS - - prefixes= - - for d - do - test X"$d" = X && continue - - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ - done - - if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true - fi - fi - fi - - if test -n "$dir_arg"; then - { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && - { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || - test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 - else - - # Make a couple of temp file names in the proper directory. - dsttmp=$dstdir/_inst.$$_ - rmtmp=$dstdir/_rm.$$_ - - # Trap to clean up those temp files at exit. - trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - - # Copy the file name to the temp name. - (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && - - # and set any options; do chmod last to preserve setuid bits. - # - # If any of these fail, we abort the whole thing. If we want to - # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $cpprog $src $dsttmp" command. - # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && - { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && - { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && - - # If -C, don't bother to copy if it wouldn't change the file. - if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - - eval "$initialize_posix_glob" && - $posix_glob set -f && - set X $old && old=:$2:$4:$5:$6 && - set X $new && new=:$2:$4:$5:$6 && - $posix_glob set +f && - - test "$old" = "$new" && - $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 - then - rm -f "$dsttmp" - else - # Rename the file to the real destination. - $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || - - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" - } - fi || exit 1 - - trap '' 0 - fi -done - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" -# time-stamp-end: "; # UTC" -# End: diff --git a/autoconf/ltmain.sh b/autoconf/ltmain.sh deleted file mode 100644 index 6a2f116..0000000 --- a/autoconf/ltmain.sh +++ /dev/null @@ -1,9655 +0,0 @@ - -# libtool (GNU libtool) 2.4.2 -# Written by Gordon Matzigkeit , 1996 - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, -# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, -# if you distribute this file as part of a program or library that -# is built using GNU Libtool, you may include this file under the -# same distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Libtool; see the file COPYING. If not, a copy -# can be downloaded from http://www.gnu.org/licenses/gpl.html, -# or obtained by writing to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -# Usage: $progname [OPTION]... [MODE-ARG]... -# -# Provide generalized library-building support services. -# -# --config show all configuration variables -# --debug enable verbose shell tracing -# -n, --dry-run display commands without modifying any files -# --features display basic configuration information and exit -# --mode=MODE use operation mode MODE -# --preserve-dup-deps don't remove duplicate dependency libraries -# --quiet, --silent don't print informational messages -# --no-quiet, --no-silent -# print informational messages (default) -# --no-warn don't display warning messages -# --tag=TAG use configuration variables from tag TAG -# -v, --verbose print more informational messages than default -# --no-verbose don't print the extra informational messages -# --version print version information -# -h, --help, --help-all print short, long, or detailed help message -# -# MODE must be one of the following: -# -# clean remove files from the build directory -# compile compile a source file into a libtool object -# execute automatically set library path, then run a program -# finish complete the installation of libtool libraries -# install install libraries or executables -# link create a library or an executable -# uninstall remove libraries from an installed directory -# -# MODE-ARGS vary depending on the MODE. When passed as first option, -# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. -# Try `$progname --help --mode=MODE' for a more detailed description of MODE. -# -# When reporting a bug, please describe a test case to reproduce it and -# include the following information: -# -# host-triplet: $host -# shell: $SHELL -# compiler: $LTCC -# compiler flags: $LTCFLAGS -# linker: $LD (gnu? $with_gnu_ld) -# $progname: (GNU libtool) 2.4.2 -# automake: $automake_version -# autoconf: $autoconf_version -# -# Report bugs to . -# GNU libtool home page: . -# General help using GNU software: . - -PROGRAM=libtool -PACKAGE=libtool -VERSION=2.4.2 -TIMESTAMP="" -package_revision=1.3337 - -# Be Bourne compatible -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac -fi -BIN_SH=xpg4; export BIN_SH # for Tru64 -DUALCASE=1; export DUALCASE # for MKS sh - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' -} - -# NLS nuisances: We save the old values to restore during execute mode. -lt_user_locale= -lt_safe_locale= -for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES -do - eval "if test \"\${$lt_var+set}\" = set; then - save_$lt_var=\$$lt_var - $lt_var=C - export $lt_var - lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" - lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" - fi" -done -LC_ALL=C -LANGUAGE=C -export LANGUAGE LC_ALL - -$lt_unset CDPATH - - -# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh -# is ksh but when the shell is invoked as "sh" and the current value of -# the _XPG environment variable is not equal to 1 (one), the special -# positional parameter $0, within a function call, is the name of the -# function. -progpath="$0" - - - -: ${CP="cp -f"} -test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} -: ${MAKE="make"} -: ${MKDIR="mkdir"} -: ${MV="mv -f"} -: ${RM="rm -f"} -: ${SHELL="${CONFIG_SHELL-/bin/sh}"} -: ${Xsed="$SED -e 1s/^X//"} - -# Global variables: -EXIT_SUCCESS=0 -EXIT_FAILURE=1 -EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. -EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. - -exit_status=$EXIT_SUCCESS - -# Make sure IFS has a sensible default -lt_nl=' -' -IFS=" $lt_nl" - -dirname="s,/[^/]*$,," -basename="s,^.*/,," - -# func_dirname file append nondir_replacement -# Compute the dirname of FILE. If nonempty, add APPEND to the result, -# otherwise set result to NONDIR_REPLACEMENT. -func_dirname () -{ - func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` - if test "X$func_dirname_result" = "X${1}"; then - func_dirname_result="${3}" - else - func_dirname_result="$func_dirname_result${2}" - fi -} # func_dirname may be replaced by extended shell implementation - - -# func_basename file -func_basename () -{ - func_basename_result=`$ECHO "${1}" | $SED "$basename"` -} # func_basename may be replaced by extended shell implementation - - -# func_dirname_and_basename file append nondir_replacement -# perform func_basename and func_dirname in a single function -# call: -# dirname: Compute the dirname of FILE. If nonempty, -# add APPEND to the result, otherwise set result -# to NONDIR_REPLACEMENT. -# value returned in "$func_dirname_result" -# basename: Compute filename of FILE. -# value retuned in "$func_basename_result" -# Implementation must be kept synchronized with func_dirname -# and func_basename. For efficiency, we do not delegate to -# those functions but instead duplicate the functionality here. -func_dirname_and_basename () -{ - # Extract subdirectory from the argument. - func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` - if test "X$func_dirname_result" = "X${1}"; then - func_dirname_result="${3}" - else - func_dirname_result="$func_dirname_result${2}" - fi - func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` -} # func_dirname_and_basename may be replaced by extended shell implementation - - -# func_stripname prefix suffix name -# strip PREFIX and SUFFIX off of NAME. -# PREFIX and SUFFIX must not contain globbing or regex special -# characters, hashes, percent signs, but SUFFIX may contain a leading -# dot (in which case that matches only a dot). -# func_strip_suffix prefix name -func_stripname () -{ - case ${2} in - .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; - *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; - esac -} # func_stripname may be replaced by extended shell implementation - - -# These SED scripts presuppose an absolute path with a trailing slash. -pathcar='s,^/\([^/]*\).*$,\1,' -pathcdr='s,^/[^/]*,,' -removedotparts=':dotsl - s@/\./@/@g - t dotsl - s,/\.$,/,' -collapseslashes='s@/\{1,\}@/@g' -finalslash='s,/*$,/,' - -# func_normal_abspath PATH -# Remove doubled-up and trailing slashes, "." path components, -# and cancel out any ".." path components in PATH after making -# it an absolute path. -# value returned in "$func_normal_abspath_result" -func_normal_abspath () -{ - # Start from root dir and reassemble the path. - func_normal_abspath_result= - func_normal_abspath_tpath=$1 - func_normal_abspath_altnamespace= - case $func_normal_abspath_tpath in - "") - # Empty path, that just means $cwd. - func_stripname '' '/' "`pwd`" - func_normal_abspath_result=$func_stripname_result - return - ;; - # The next three entries are used to spot a run of precisely - # two leading slashes without using negated character classes; - # we take advantage of case's first-match behaviour. - ///*) - # Unusual form of absolute path, do nothing. - ;; - //*) - # Not necessarily an ordinary path; POSIX reserves leading '//' - # and for example Cygwin uses it to access remote file shares - # over CIFS/SMB, so we conserve a leading double slash if found. - func_normal_abspath_altnamespace=/ - ;; - /*) - # Absolute path, do nothing. - ;; - *) - # Relative path, prepend $cwd. - func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath - ;; - esac - # Cancel out all the simple stuff to save iterations. We also want - # the path to end with a slash for ease of parsing, so make sure - # there is one (and only one) here. - func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` - while :; do - # Processed it all yet? - if test "$func_normal_abspath_tpath" = / ; then - # If we ascended to the root using ".." the result may be empty now. - if test -z "$func_normal_abspath_result" ; then - func_normal_abspath_result=/ - fi - break - fi - func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$pathcar"` - func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$pathcdr"` - # Figure out what to do with it - case $func_normal_abspath_tcomponent in - "") - # Trailing empty path component, ignore it. - ;; - ..) - # Parent dir; strip last assembled component from result. - func_dirname "$func_normal_abspath_result" - func_normal_abspath_result=$func_dirname_result - ;; - *) - # Actual path component, append it. - func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent - ;; - esac - done - # Restore leading double-slash if one was found on entry. - func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result -} - -# func_relative_path SRCDIR DSTDIR -# generates a relative path from SRCDIR to DSTDIR, with a trailing -# slash if non-empty, suitable for immediately appending a filename -# without needing to append a separator. -# value returned in "$func_relative_path_result" -func_relative_path () -{ - func_relative_path_result= - func_normal_abspath "$1" - func_relative_path_tlibdir=$func_normal_abspath_result - func_normal_abspath "$2" - func_relative_path_tbindir=$func_normal_abspath_result - - # Ascend the tree starting from libdir - while :; do - # check if we have found a prefix of bindir - case $func_relative_path_tbindir in - $func_relative_path_tlibdir) - # found an exact match - func_relative_path_tcancelled= - break - ;; - $func_relative_path_tlibdir*) - # found a matching prefix - func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" - func_relative_path_tcancelled=$func_stripname_result - if test -z "$func_relative_path_result"; then - func_relative_path_result=. - fi - break - ;; - *) - func_dirname $func_relative_path_tlibdir - func_relative_path_tlibdir=${func_dirname_result} - if test "x$func_relative_path_tlibdir" = x ; then - # Have to descend all the way to the root! - func_relative_path_result=../$func_relative_path_result - func_relative_path_tcancelled=$func_relative_path_tbindir - break - fi - func_relative_path_result=../$func_relative_path_result - ;; - esac - done - - # Now calculate path; take care to avoid doubling-up slashes. - func_stripname '' '/' "$func_relative_path_result" - func_relative_path_result=$func_stripname_result - func_stripname '/' '/' "$func_relative_path_tcancelled" - if test "x$func_stripname_result" != x ; then - func_relative_path_result=${func_relative_path_result}/${func_stripname_result} - fi - - # Normalisation. If bindir is libdir, return empty string, - # else relative path ending with a slash; either way, target - # file name can be directly appended. - if test ! -z "$func_relative_path_result"; then - func_stripname './' '' "$func_relative_path_result/" - func_relative_path_result=$func_stripname_result - fi -} - -# The name of this program: -func_dirname_and_basename "$progpath" -progname=$func_basename_result - -# Make sure we have an absolute path for reexecution: -case $progpath in - [\\/]*|[A-Za-z]:\\*) ;; - *[\\/]*) - progdir=$func_dirname_result - progdir=`cd "$progdir" && pwd` - progpath="$progdir/$progname" - ;; - *) - save_IFS="$IFS" - IFS=${PATH_SEPARATOR-:} - for progdir in $PATH; do - IFS="$save_IFS" - test -x "$progdir/$progname" && break - done - IFS="$save_IFS" - test -n "$progdir" || progdir=`pwd` - progpath="$progdir/$progname" - ;; -esac - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed="${SED}"' -e 1s/^X//' -sed_quote_subst='s/\([`"$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution that turns a string into a regex matching for the -# string literally. -sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' - -# Sed substitution that converts a w32 file name or path -# which contains forward slashes, into one that contains -# (escaped) backslashes. A very naive implementation. -lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' - -# Re-`\' parameter expansions in output of double_quote_subst that were -# `\'-ed in input to the same. If an odd number of `\' preceded a '$' -# in input to double_quote_subst, that '$' was protected from expansion. -# Since each input `\' is now two `\'s, look for any number of runs of -# four `\'s followed by two `\'s and then a '$'. `\' that '$'. -bs='\\' -bs2='\\\\' -bs4='\\\\\\\\' -dollar='\$' -sed_double_backslash="\ - s/$bs4/&\\ -/g - s/^$bs2$dollar/$bs&/ - s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g - s/\n//g" - -# Standard options: -opt_dry_run=false -opt_help=false -opt_quiet=false -opt_verbose=false -opt_warning=: - -# func_echo arg... -# Echo program name prefixed message, along with the current mode -# name if it has been set yet. -func_echo () -{ - $ECHO "$progname: ${opt_mode+$opt_mode: }$*" -} - -# func_verbose arg... -# Echo program name prefixed message in verbose mode only. -func_verbose () -{ - $opt_verbose && func_echo ${1+"$@"} - - # A bug in bash halts the script if the last line of a function - # fails when set -e is in force, so we need another command to - # work around that: - : -} - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "$*" -} - -# func_error arg... -# Echo program name prefixed message to standard error. -func_error () -{ - $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 -} - -# func_warning arg... -# Echo program name prefixed warning message to standard error. -func_warning () -{ - $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 - - # bash bug again: - : -} - -# func_fatal_error arg... -# Echo program name prefixed message to standard error, and exit. -func_fatal_error () -{ - func_error ${1+"$@"} - exit $EXIT_FAILURE -} - -# func_fatal_help arg... -# Echo program name prefixed message to standard error, followed by -# a help hint, and exit. -func_fatal_help () -{ - func_error ${1+"$@"} - func_fatal_error "$help" -} -help="Try \`$progname --help' for more information." ## default - - -# func_grep expression filename -# Check whether EXPRESSION matches any line of FILENAME, without output. -func_grep () -{ - $GREP "$1" "$2" >/dev/null 2>&1 -} - - -# func_mkdir_p directory-path -# Make sure the entire path to DIRECTORY-PATH is available. -func_mkdir_p () -{ - my_directory_path="$1" - my_dir_list= - - if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then - - # Protect directory names starting with `-' - case $my_directory_path in - -*) my_directory_path="./$my_directory_path" ;; - esac - - # While some portion of DIR does not yet exist... - while test ! -d "$my_directory_path"; do - # ...make a list in topmost first order. Use a colon delimited - # list incase some portion of path contains whitespace. - my_dir_list="$my_directory_path:$my_dir_list" - - # If the last portion added has no slash in it, the list is done - case $my_directory_path in */*) ;; *) break ;; esac - - # ...otherwise throw away the child directory and loop - my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` - done - my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` - - save_mkdir_p_IFS="$IFS"; IFS=':' - for my_dir in $my_dir_list; do - IFS="$save_mkdir_p_IFS" - # mkdir can fail with a `File exist' error if two processes - # try to create one of the directories concurrently. Don't - # stop in that case! - $MKDIR "$my_dir" 2>/dev/null || : - done - IFS="$save_mkdir_p_IFS" - - # Bail out if we (or some other process) failed to create a directory. - test -d "$my_directory_path" || \ - func_fatal_error "Failed to create \`$1'" - fi -} - - -# func_mktempdir [string] -# Make a temporary directory that won't clash with other running -# libtool processes, and avoids race conditions if possible. If -# given, STRING is the basename for that directory. -func_mktempdir () -{ - my_template="${TMPDIR-/tmp}/${1-$progname}" - - if test "$opt_dry_run" = ":"; then - # Return a directory name, but don't create it in dry-run mode - my_tmpdir="${my_template}-$$" - else - - # If mktemp works, use that first and foremost - my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` - - if test ! -d "$my_tmpdir"; then - # Failing that, at least try and use $RANDOM to avoid a race - my_tmpdir="${my_template}-${RANDOM-0}$$" - - save_mktempdir_umask=`umask` - umask 0077 - $MKDIR "$my_tmpdir" - umask $save_mktempdir_umask - fi - - # If we're not in dry-run mode, bomb out on failure - test -d "$my_tmpdir" || \ - func_fatal_error "cannot create temporary directory \`$my_tmpdir'" - fi - - $ECHO "$my_tmpdir" -} - - -# func_quote_for_eval arg -# Aesthetically quote ARG to be evaled later. -# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT -# is double-quoted, suitable for a subsequent eval, whereas -# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters -# which are still active within double quotes backslashified. -func_quote_for_eval () -{ - case $1 in - *[\\\`\"\$]*) - func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; - *) - func_quote_for_eval_unquoted_result="$1" ;; - esac - - case $func_quote_for_eval_unquoted_result in - # Double-quote args containing shell metacharacters to delay - # word splitting, command substitution and and variable - # expansion for a subsequent eval. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" - ;; - *) - func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" - esac -} - - -# func_quote_for_expand arg -# Aesthetically quote ARG to be evaled later; same as above, -# but do not quote variable references. -func_quote_for_expand () -{ - case $1 in - *[\\\`\"]*) - my_arg=`$ECHO "$1" | $SED \ - -e "$double_quote_subst" -e "$sed_double_backslash"` ;; - *) - my_arg="$1" ;; - esac - - case $my_arg in - # Double-quote args containing shell metacharacters to delay - # word splitting and command substitution for a subsequent eval. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - my_arg="\"$my_arg\"" - ;; - esac - - func_quote_for_expand_result="$my_arg" -} - - -# func_show_eval cmd [fail_exp] -# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is -# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP -# is given, then evaluate it. -func_show_eval () -{ - my_cmd="$1" - my_fail_exp="${2-:}" - - ${opt_silent-false} || { - func_quote_for_expand "$my_cmd" - eval "func_echo $func_quote_for_expand_result" - } - - if ${opt_dry_run-false}; then :; else - eval "$my_cmd" - my_status=$? - if test "$my_status" -eq 0; then :; else - eval "(exit $my_status); $my_fail_exp" - fi - fi -} - - -# func_show_eval_locale cmd [fail_exp] -# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is -# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP -# is given, then evaluate it. Use the saved locale for evaluation. -func_show_eval_locale () -{ - my_cmd="$1" - my_fail_exp="${2-:}" - - ${opt_silent-false} || { - func_quote_for_expand "$my_cmd" - eval "func_echo $func_quote_for_expand_result" - } - - if ${opt_dry_run-false}; then :; else - eval "$lt_user_locale - $my_cmd" - my_status=$? - eval "$lt_safe_locale" - if test "$my_status" -eq 0; then :; else - eval "(exit $my_status); $my_fail_exp" - fi - fi -} - -# func_tr_sh -# Turn $1 into a string suitable for a shell variable name. -# Result is stored in $func_tr_sh_result. All characters -# not in the set a-zA-Z0-9_ are replaced with '_'. Further, -# if $1 begins with a digit, a '_' is prepended as well. -func_tr_sh () -{ - case $1 in - [0-9]* | *[!a-zA-Z0-9_]*) - func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` - ;; - * ) - func_tr_sh_result=$1 - ;; - esac -} - - -# func_version -# Echo version message to standard output and exit. -func_version () -{ - $opt_debug - - $SED -n '/(C)/!b go - :more - /\./!{ - N - s/\n# / / - b more - } - :go - /^# '$PROGRAM' (GNU /,/# warranty; / { - s/^# // - s/^# *$// - s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ - p - }' < "$progpath" - exit $? -} - -# func_usage -# Echo short help message to standard output and exit. -func_usage () -{ - $opt_debug - - $SED -n '/^# Usage:/,/^# *.*--help/ { - s/^# // - s/^# *$// - s/\$progname/'$progname'/ - p - }' < "$progpath" - echo - $ECHO "run \`$progname --help | more' for full usage" - exit $? -} - -# func_help [NOEXIT] -# Echo long help message to standard output and exit, -# unless 'noexit' is passed as argument. -func_help () -{ - $opt_debug - - $SED -n '/^# Usage:/,/# Report bugs to/ { - :print - s/^# // - s/^# *$// - s*\$progname*'$progname'* - s*\$host*'"$host"'* - s*\$SHELL*'"$SHELL"'* - s*\$LTCC*'"$LTCC"'* - s*\$LTCFLAGS*'"$LTCFLAGS"'* - s*\$LD*'"$LD"'* - s/\$with_gnu_ld/'"$with_gnu_ld"'/ - s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ - s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ - p - d - } - /^# .* home page:/b print - /^# General help using/b print - ' < "$progpath" - ret=$? - if test -z "$1"; then - exit $ret - fi -} - -# func_missing_arg argname -# Echo program name prefixed message to standard error and set global -# exit_cmd. -func_missing_arg () -{ - $opt_debug - - func_error "missing argument for $1." - exit_cmd=exit -} - - -# func_split_short_opt shortopt -# Set func_split_short_opt_name and func_split_short_opt_arg shell -# variables after splitting SHORTOPT after the 2nd character. -func_split_short_opt () -{ - my_sed_short_opt='1s/^\(..\).*$/\1/;q' - my_sed_short_rest='1s/^..\(.*\)$/\1/;q' - - func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` - func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` -} # func_split_short_opt may be replaced by extended shell implementation - - -# func_split_long_opt longopt -# Set func_split_long_opt_name and func_split_long_opt_arg shell -# variables after splitting LONGOPT at the `=' sign. -func_split_long_opt () -{ - my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' - my_sed_long_arg='1s/^--[^=]*=//' - - func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` - func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` -} # func_split_long_opt may be replaced by extended shell implementation - -exit_cmd=: - - - - - -magic="%%%MAGIC variable%%%" -magic_exe="%%%MAGIC EXE variable%%%" - -# Global variables. -nonopt= -preserve_args= -lo2o="s/\\.lo\$/.${objext}/" -o2lo="s/\\.${objext}\$/.lo/" -extracted_archives= -extracted_serial=0 - -# If this variable is set in any of the actions, the command in it -# will be execed at the end. This prevents here-documents from being -# left over by shells. -exec_cmd= - -# func_append var value -# Append VALUE to the end of shell variable VAR. -func_append () -{ - eval "${1}=\$${1}\${2}" -} # func_append may be replaced by extended shell implementation - -# func_append_quoted var value -# Quote VALUE and append to the end of shell variable VAR, separated -# by a space. -func_append_quoted () -{ - func_quote_for_eval "${2}" - eval "${1}=\$${1}\\ \$func_quote_for_eval_result" -} # func_append_quoted may be replaced by extended shell implementation - - -# func_arith arithmetic-term... -func_arith () -{ - func_arith_result=`expr "${@}"` -} # func_arith may be replaced by extended shell implementation - - -# func_len string -# STRING may not start with a hyphen. -func_len () -{ - func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` -} # func_len may be replaced by extended shell implementation - - -# func_lo2o object -func_lo2o () -{ - func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` -} # func_lo2o may be replaced by extended shell implementation - - -# func_xform libobj-or-source -func_xform () -{ - func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` -} # func_xform may be replaced by extended shell implementation - - -# func_fatal_configuration arg... -# Echo program name prefixed message to standard error, followed by -# a configuration failure hint, and exit. -func_fatal_configuration () -{ - func_error ${1+"$@"} - func_error "See the $PACKAGE documentation for more information." - func_fatal_error "Fatal configuration error." -} - - -# func_config -# Display the configuration for all the tags in this script. -func_config () -{ - re_begincf='^# ### BEGIN LIBTOOL' - re_endcf='^# ### END LIBTOOL' - - # Default configuration. - $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" - - # Now print the configurations for the tags. - for tagname in $taglist; do - $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" - done - - exit $? -} - -# func_features -# Display the features supported by this script. -func_features () -{ - echo "host: $host" - if test "$build_libtool_libs" = yes; then - echo "enable shared libraries" - else - echo "disable shared libraries" - fi - if test "$build_old_libs" = yes; then - echo "enable static libraries" - else - echo "disable static libraries" - fi - - exit $? -} - -# func_enable_tag tagname -# Verify that TAGNAME is valid, and either flag an error and exit, or -# enable the TAGNAME tag. We also add TAGNAME to the global $taglist -# variable here. -func_enable_tag () -{ - # Global variable: - tagname="$1" - - re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" - re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" - sed_extractcf="/$re_begincf/,/$re_endcf/p" - - # Validate tagname. - case $tagname in - *[!-_A-Za-z0-9,/]*) - func_fatal_error "invalid tag name: $tagname" - ;; - esac - - # Don't test for the "default" C tag, as we know it's - # there but not specially marked. - case $tagname in - CC) ;; - *) - if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then - taglist="$taglist $tagname" - - # Evaluate the configuration. Be careful to quote the path - # and the sed script, to avoid splitting on whitespace, but - # also don't use non-portable quotes within backquotes within - # quotes we have to do it in 2 steps: - extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` - eval "$extractedcf" - else - func_error "ignoring unknown tag $tagname" - fi - ;; - esac -} - -# func_check_version_match -# Ensure that we are using m4 macros, and libtool script from the same -# release of libtool. -func_check_version_match () -{ - if test "$package_revision" != "$macro_revision"; then - if test "$VERSION" != "$macro_version"; then - if test -z "$macro_version"; then - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, but the -$progname: definition of this LT_INIT comes from an older release. -$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION -$progname: and run autoconf again. -_LT_EOF - else - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, but the -$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. -$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION -$progname: and run autoconf again. -_LT_EOF - fi - else - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, -$progname: but the definition of this LT_INIT comes from revision $macro_revision. -$progname: You should recreate aclocal.m4 with macros from revision $package_revision -$progname: of $PACKAGE $VERSION and run autoconf again. -_LT_EOF - fi - - exit $EXIT_MISMATCH - fi -} - - -# Shorthand for --mode=foo, only valid as the first argument -case $1 in -clean|clea|cle|cl) - shift; set dummy --mode clean ${1+"$@"}; shift - ;; -compile|compil|compi|comp|com|co|c) - shift; set dummy --mode compile ${1+"$@"}; shift - ;; -execute|execut|execu|exec|exe|ex|e) - shift; set dummy --mode execute ${1+"$@"}; shift - ;; -finish|finis|fini|fin|fi|f) - shift; set dummy --mode finish ${1+"$@"}; shift - ;; -install|instal|insta|inst|ins|in|i) - shift; set dummy --mode install ${1+"$@"}; shift - ;; -link|lin|li|l) - shift; set dummy --mode link ${1+"$@"}; shift - ;; -uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) - shift; set dummy --mode uninstall ${1+"$@"}; shift - ;; -esac - - - -# Option defaults: -opt_debug=: -opt_dry_run=false -opt_config=false -opt_preserve_dup_deps=false -opt_features=false -opt_finish=false -opt_help=false -opt_help_all=false -opt_silent=: -opt_warning=: -opt_verbose=: -opt_silent=false -opt_verbose=false - - -# Parse options once, thoroughly. This comes as soon as possible in the -# script to make things like `--version' happen as quickly as we can. -{ - # this just eases exit handling - while test $# -gt 0; do - opt="$1" - shift - case $opt in - --debug|-x) opt_debug='set -x' - func_echo "enabling shell trace mode" - $opt_debug - ;; - --dry-run|--dryrun|-n) - opt_dry_run=: - ;; - --config) - opt_config=: -func_config - ;; - --dlopen|-dlopen) - optarg="$1" - opt_dlopen="${opt_dlopen+$opt_dlopen -}$optarg" - shift - ;; - --preserve-dup-deps) - opt_preserve_dup_deps=: - ;; - --features) - opt_features=: -func_features - ;; - --finish) - opt_finish=: -set dummy --mode finish ${1+"$@"}; shift - ;; - --help) - opt_help=: - ;; - --help-all) - opt_help_all=: -opt_help=': help-all' - ;; - --mode) - test $# = 0 && func_missing_arg $opt && break - optarg="$1" - opt_mode="$optarg" -case $optarg in - # Valid mode arguments: - clean|compile|execute|finish|install|link|relink|uninstall) ;; - - # Catch anything else as an error - *) func_error "invalid argument for $opt" - exit_cmd=exit - break - ;; -esac - shift - ;; - --no-silent|--no-quiet) - opt_silent=false -func_append preserve_args " $opt" - ;; - --no-warning|--no-warn) - opt_warning=false -func_append preserve_args " $opt" - ;; - --no-verbose) - opt_verbose=false -func_append preserve_args " $opt" - ;; - --silent|--quiet) - opt_silent=: -func_append preserve_args " $opt" - opt_verbose=false - ;; - --verbose|-v) - opt_verbose=: -func_append preserve_args " $opt" -opt_silent=false - ;; - --tag) - test $# = 0 && func_missing_arg $opt && break - optarg="$1" - opt_tag="$optarg" -func_append preserve_args " $opt $optarg" -func_enable_tag "$optarg" - shift - ;; - - -\?|-h) func_usage ;; - --help) func_help ;; - --version) func_version ;; - - # Separate optargs to long options: - --*=*) - func_split_long_opt "$opt" - set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} - shift - ;; - - # Separate non-argument short options: - -\?*|-h*|-n*|-v*) - func_split_short_opt "$opt" - set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} - shift - ;; - - --) break ;; - -*) func_fatal_help "unrecognized option \`$opt'" ;; - *) set dummy "$opt" ${1+"$@"}; shift; break ;; - esac - done - - # Validate options: - - # save first non-option argument - if test "$#" -gt 0; then - nonopt="$opt" - shift - fi - - # preserve --debug - test "$opt_debug" = : || func_append preserve_args " --debug" - - case $host in - *cygwin* | *mingw* | *pw32* | *cegcc*) - # don't eliminate duplications in $postdeps and $predeps - opt_duplicate_compiler_generated_deps=: - ;; - *) - opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps - ;; - esac - - $opt_help || { - # Sanity checks first: - func_check_version_match - - if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then - func_fatal_configuration "not configured to build any kind of library" - fi - - # Darwin sucks - eval std_shrext=\"$shrext_cmds\" - - # Only execute mode is allowed to have -dlopen flags. - if test -n "$opt_dlopen" && test "$opt_mode" != execute; then - func_error "unrecognized option \`-dlopen'" - $ECHO "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # Change the help message to a mode-specific one. - generic_help="$help" - help="Try \`$progname --help --mode=$opt_mode' for more information." - } - - - # Bail if the options were screwed - $exit_cmd $EXIT_FAILURE -} - - - - -## ----------- ## -## Main. ## -## ----------- ## - -# func_lalib_p file -# True iff FILE is a libtool `.la' library or `.lo' object file. -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_lalib_p () -{ - test -f "$1" && - $SED -e 4q "$1" 2>/dev/null \ - | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 -} - -# func_lalib_unsafe_p file -# True iff FILE is a libtool `.la' library or `.lo' object file. -# This function implements the same check as func_lalib_p without -# resorting to external programs. To this end, it redirects stdin and -# closes it afterwards, without saving the original file descriptor. -# As a safety measure, use it only where a negative result would be -# fatal anyway. Works if `file' does not exist. -func_lalib_unsafe_p () -{ - lalib_p=no - if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then - for lalib_p_l in 1 2 3 4 - do - read lalib_p_line - case "$lalib_p_line" in - \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; - esac - done - exec 0<&5 5<&- - fi - test "$lalib_p" = yes -} - -# func_ltwrapper_script_p file -# True iff FILE is a libtool wrapper script -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_script_p () -{ - func_lalib_p "$1" -} - -# func_ltwrapper_executable_p file -# True iff FILE is a libtool wrapper executable -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_executable_p () -{ - func_ltwrapper_exec_suffix= - case $1 in - *.exe) ;; - *) func_ltwrapper_exec_suffix=.exe ;; - esac - $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 -} - -# func_ltwrapper_scriptname file -# Assumes file is an ltwrapper_executable -# uses $file to determine the appropriate filename for a -# temporary ltwrapper_script. -func_ltwrapper_scriptname () -{ - func_dirname_and_basename "$1" "" "." - func_stripname '' '.exe' "$func_basename_result" - func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" -} - -# func_ltwrapper_p file -# True iff FILE is a libtool wrapper script or wrapper executable -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_p () -{ - func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" -} - - -# func_execute_cmds commands fail_cmd -# Execute tilde-delimited COMMANDS. -# If FAIL_CMD is given, eval that upon failure. -# FAIL_CMD may read-access the current command in variable CMD! -func_execute_cmds () -{ - $opt_debug - save_ifs=$IFS; IFS='~' - for cmd in $1; do - IFS=$save_ifs - eval cmd=\"$cmd\" - func_show_eval "$cmd" "${2-:}" - done - IFS=$save_ifs -} - - -# func_source file -# Source FILE, adding directory component if necessary. -# Note that it is not necessary on cygwin/mingw to append a dot to -# FILE even if both FILE and FILE.exe exist: automatic-append-.exe -# behavior happens only for exec(3), not for open(2)! Also, sourcing -# `FILE.' does not work on cygwin managed mounts. -func_source () -{ - $opt_debug - case $1 in - */* | *\\*) . "$1" ;; - *) . "./$1" ;; - esac -} - - -# func_resolve_sysroot PATH -# Replace a leading = in PATH with a sysroot. Store the result into -# func_resolve_sysroot_result -func_resolve_sysroot () -{ - func_resolve_sysroot_result=$1 - case $func_resolve_sysroot_result in - =*) - func_stripname '=' '' "$func_resolve_sysroot_result" - func_resolve_sysroot_result=$lt_sysroot$func_stripname_result - ;; - esac -} - -# func_replace_sysroot PATH -# If PATH begins with the sysroot, replace it with = and -# store the result into func_replace_sysroot_result. -func_replace_sysroot () -{ - case "$lt_sysroot:$1" in - ?*:"$lt_sysroot"*) - func_stripname "$lt_sysroot" '' "$1" - func_replace_sysroot_result="=$func_stripname_result" - ;; - *) - # Including no sysroot. - func_replace_sysroot_result=$1 - ;; - esac -} - -# func_infer_tag arg -# Infer tagged configuration to use if any are available and -# if one wasn't chosen via the "--tag" command line option. -# Only attempt this if the compiler in the base compile -# command doesn't match the default compiler. -# arg is usually of the form 'gcc ...' -func_infer_tag () -{ - $opt_debug - if test -n "$available_tags" && test -z "$tagname"; then - CC_quoted= - for arg in $CC; do - func_append_quoted CC_quoted "$arg" - done - CC_expanded=`func_echo_all $CC` - CC_quoted_expanded=`func_echo_all $CC_quoted` - case $@ in - # Blanks in the command may have been stripped by the calling shell, - # but not from the CC environment variable when configure was run. - " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ - " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; - # Blanks at the start of $base_compile will cause this to fail - # if we don't check for them as well. - *) - for z in $available_tags; do - if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then - # Evaluate the configuration. - eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" - CC_quoted= - for arg in $CC; do - # Double-quote args containing other shell metacharacters. - func_append_quoted CC_quoted "$arg" - done - CC_expanded=`func_echo_all $CC` - CC_quoted_expanded=`func_echo_all $CC_quoted` - case "$@ " in - " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ - " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) - # The compiler in the base compile command matches - # the one in the tagged configuration. - # Assume this is the tagged configuration we want. - tagname=$z - break - ;; - esac - fi - done - # If $tagname still isn't set, then no tagged configuration - # was found and let the user know that the "--tag" command - # line option must be used. - if test -z "$tagname"; then - func_echo "unable to infer tagged configuration" - func_fatal_error "specify a tag with \`--tag'" -# else -# func_verbose "using $tagname tagged configuration" - fi - ;; - esac - fi -} - - - -# func_write_libtool_object output_name pic_name nonpic_name -# Create a libtool object file (analogous to a ".la" file), -# but don't create it if we're doing a dry run. -func_write_libtool_object () -{ - write_libobj=${1} - if test "$build_libtool_libs" = yes; then - write_lobj=\'${2}\' - else - write_lobj=none - fi - - if test "$build_old_libs" = yes; then - write_oldobj=\'${3}\' - else - write_oldobj=none - fi - - $opt_dry_run || { - cat >${write_libobj}T </dev/null` - if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then - func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | - $SED -e "$lt_sed_naive_backslashify"` - else - func_convert_core_file_wine_to_w32_result= - fi - fi -} -# end: func_convert_core_file_wine_to_w32 - - -# func_convert_core_path_wine_to_w32 ARG -# Helper function used by path conversion functions when $build is *nix, and -# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly -# configured wine environment available, with the winepath program in $build's -# $PATH. Assumes ARG has no leading or trailing path separator characters. -# -# ARG is path to be converted from $build format to win32. -# Result is available in $func_convert_core_path_wine_to_w32_result. -# Unconvertible file (directory) names in ARG are skipped; if no directory names -# are convertible, then the result may be empty. -func_convert_core_path_wine_to_w32 () -{ - $opt_debug - # unfortunately, winepath doesn't convert paths, only file names - func_convert_core_path_wine_to_w32_result="" - if test -n "$1"; then - oldIFS=$IFS - IFS=: - for func_convert_core_path_wine_to_w32_f in $1; do - IFS=$oldIFS - func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" - if test -n "$func_convert_core_file_wine_to_w32_result" ; then - if test -z "$func_convert_core_path_wine_to_w32_result"; then - func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" - else - func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" - fi - fi - done - IFS=$oldIFS - fi -} -# end: func_convert_core_path_wine_to_w32 - - -# func_cygpath ARGS... -# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when -# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) -# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or -# (2), returns the Cygwin file name or path in func_cygpath_result (input -# file name or path is assumed to be in w32 format, as previously converted -# from $build's *nix or MSYS format). In case (3), returns the w32 file name -# or path in func_cygpath_result (input file name or path is assumed to be in -# Cygwin format). Returns an empty string on error. -# -# ARGS are passed to cygpath, with the last one being the file name or path to -# be converted. -# -# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH -# environment variable; do not put it in $PATH. -func_cygpath () -{ - $opt_debug - if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then - func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` - if test "$?" -ne 0; then - # on failure, ensure result is empty - func_cygpath_result= - fi - else - func_cygpath_result= - func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" - fi -} -#end: func_cygpath - - -# func_convert_core_msys_to_w32 ARG -# Convert file name or path ARG from MSYS format to w32 format. Return -# result in func_convert_core_msys_to_w32_result. -func_convert_core_msys_to_w32 () -{ - $opt_debug - # awkward: cmd appends spaces to result - func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | - $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` -} -#end: func_convert_core_msys_to_w32 - - -# func_convert_file_check ARG1 ARG2 -# Verify that ARG1 (a file name in $build format) was converted to $host -# format in ARG2. Otherwise, emit an error message, but continue (resetting -# func_to_host_file_result to ARG1). -func_convert_file_check () -{ - $opt_debug - if test -z "$2" && test -n "$1" ; then - func_error "Could not determine host file name corresponding to" - func_error " \`$1'" - func_error "Continuing, but uninstalled executables may not work." - # Fallback: - func_to_host_file_result="$1" - fi -} -# end func_convert_file_check - - -# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH -# Verify that FROM_PATH (a path in $build format) was converted to $host -# format in TO_PATH. Otherwise, emit an error message, but continue, resetting -# func_to_host_file_result to a simplistic fallback value (see below). -func_convert_path_check () -{ - $opt_debug - if test -z "$4" && test -n "$3"; then - func_error "Could not determine the host path corresponding to" - func_error " \`$3'" - func_error "Continuing, but uninstalled executables may not work." - # Fallback. This is a deliberately simplistic "conversion" and - # should not be "improved". See libtool.info. - if test "x$1" != "x$2"; then - lt_replace_pathsep_chars="s|$1|$2|g" - func_to_host_path_result=`echo "$3" | - $SED -e "$lt_replace_pathsep_chars"` - else - func_to_host_path_result="$3" - fi - fi -} -# end func_convert_path_check - - -# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG -# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT -# and appending REPL if ORIG matches BACKPAT. -func_convert_path_front_back_pathsep () -{ - $opt_debug - case $4 in - $1 ) func_to_host_path_result="$3$func_to_host_path_result" - ;; - esac - case $4 in - $2 ) func_append func_to_host_path_result "$3" - ;; - esac -} -# end func_convert_path_front_back_pathsep - - -################################################## -# $build to $host FILE NAME CONVERSION FUNCTIONS # -################################################## -# invoked via `$to_host_file_cmd ARG' -# -# In each case, ARG is the path to be converted from $build to $host format. -# Result will be available in $func_to_host_file_result. - - -# func_to_host_file ARG -# Converts the file name ARG from $build format to $host format. Return result -# in func_to_host_file_result. -func_to_host_file () -{ - $opt_debug - $to_host_file_cmd "$1" -} -# end func_to_host_file - - -# func_to_tool_file ARG LAZY -# converts the file name ARG from $build format to toolchain format. Return -# result in func_to_tool_file_result. If the conversion in use is listed -# in (the comma separated) LAZY, no conversion takes place. -func_to_tool_file () -{ - $opt_debug - case ,$2, in - *,"$to_tool_file_cmd",*) - func_to_tool_file_result=$1 - ;; - *) - $to_tool_file_cmd "$1" - func_to_tool_file_result=$func_to_host_file_result - ;; - esac -} -# end func_to_tool_file - - -# func_convert_file_noop ARG -# Copy ARG to func_to_host_file_result. -func_convert_file_noop () -{ - func_to_host_file_result="$1" -} -# end func_convert_file_noop - - -# func_convert_file_msys_to_w32 ARG -# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic -# conversion to w32 is not available inside the cwrapper. Returns result in -# func_to_host_file_result. -func_convert_file_msys_to_w32 () -{ - $opt_debug - func_to_host_file_result="$1" - if test -n "$1"; then - func_convert_core_msys_to_w32 "$1" - func_to_host_file_result="$func_convert_core_msys_to_w32_result" - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_msys_to_w32 - - -# func_convert_file_cygwin_to_w32 ARG -# Convert file name ARG from Cygwin to w32 format. Returns result in -# func_to_host_file_result. -func_convert_file_cygwin_to_w32 () -{ - $opt_debug - func_to_host_file_result="$1" - if test -n "$1"; then - # because $build is cygwin, we call "the" cygpath in $PATH; no need to use - # LT_CYGPATH in this case. - func_to_host_file_result=`cygpath -m "$1"` - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_cygwin_to_w32 - - -# func_convert_file_nix_to_w32 ARG -# Convert file name ARG from *nix to w32 format. Requires a wine environment -# and a working winepath. Returns result in func_to_host_file_result. -func_convert_file_nix_to_w32 () -{ - $opt_debug - func_to_host_file_result="$1" - if test -n "$1"; then - func_convert_core_file_wine_to_w32 "$1" - func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_nix_to_w32 - - -# func_convert_file_msys_to_cygwin ARG -# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. -# Returns result in func_to_host_file_result. -func_convert_file_msys_to_cygwin () -{ - $opt_debug - func_to_host_file_result="$1" - if test -n "$1"; then - func_convert_core_msys_to_w32 "$1" - func_cygpath -u "$func_convert_core_msys_to_w32_result" - func_to_host_file_result="$func_cygpath_result" - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_msys_to_cygwin - - -# func_convert_file_nix_to_cygwin ARG -# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed -# in a wine environment, working winepath, and LT_CYGPATH set. Returns result -# in func_to_host_file_result. -func_convert_file_nix_to_cygwin () -{ - $opt_debug - func_to_host_file_result="$1" - if test -n "$1"; then - # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. - func_convert_core_file_wine_to_w32 "$1" - func_cygpath -u "$func_convert_core_file_wine_to_w32_result" - func_to_host_file_result="$func_cygpath_result" - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_nix_to_cygwin - - -############################################# -# $build to $host PATH CONVERSION FUNCTIONS # -############################################# -# invoked via `$to_host_path_cmd ARG' -# -# In each case, ARG is the path to be converted from $build to $host format. -# The result will be available in $func_to_host_path_result. -# -# Path separators are also converted from $build format to $host format. If -# ARG begins or ends with a path separator character, it is preserved (but -# converted to $host format) on output. -# -# All path conversion functions are named using the following convention: -# file name conversion function : func_convert_file_X_to_Y () -# path conversion function : func_convert_path_X_to_Y () -# where, for any given $build/$host combination the 'X_to_Y' value is the -# same. If conversion functions are added for new $build/$host combinations, -# the two new functions must follow this pattern, or func_init_to_host_path_cmd -# will break. - - -# func_init_to_host_path_cmd -# Ensures that function "pointer" variable $to_host_path_cmd is set to the -# appropriate value, based on the value of $to_host_file_cmd. -to_host_path_cmd= -func_init_to_host_path_cmd () -{ - $opt_debug - if test -z "$to_host_path_cmd"; then - func_stripname 'func_convert_file_' '' "$to_host_file_cmd" - to_host_path_cmd="func_convert_path_${func_stripname_result}" - fi -} - - -# func_to_host_path ARG -# Converts the path ARG from $build format to $host format. Return result -# in func_to_host_path_result. -func_to_host_path () -{ - $opt_debug - func_init_to_host_path_cmd - $to_host_path_cmd "$1" -} -# end func_to_host_path - - -# func_convert_path_noop ARG -# Copy ARG to func_to_host_path_result. -func_convert_path_noop () -{ - func_to_host_path_result="$1" -} -# end func_convert_path_noop - - -# func_convert_path_msys_to_w32 ARG -# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic -# conversion to w32 is not available inside the cwrapper. Returns result in -# func_to_host_path_result. -func_convert_path_msys_to_w32 () -{ - $opt_debug - func_to_host_path_result="$1" - if test -n "$1"; then - # Remove leading and trailing path separator characters from ARG. MSYS - # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; - # and winepath ignores them completely. - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" - func_to_host_path_result="$func_convert_core_msys_to_w32_result" - func_convert_path_check : ";" \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" - fi -} -# end func_convert_path_msys_to_w32 - - -# func_convert_path_cygwin_to_w32 ARG -# Convert path ARG from Cygwin to w32 format. Returns result in -# func_to_host_file_result. -func_convert_path_cygwin_to_w32 () -{ - $opt_debug - func_to_host_path_result="$1" - if test -n "$1"; then - # See func_convert_path_msys_to_w32: - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` - func_convert_path_check : ";" \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" - fi -} -# end func_convert_path_cygwin_to_w32 - - -# func_convert_path_nix_to_w32 ARG -# Convert path ARG from *nix to w32 format. Requires a wine environment and -# a working winepath. Returns result in func_to_host_file_result. -func_convert_path_nix_to_w32 () -{ - $opt_debug - func_to_host_path_result="$1" - if test -n "$1"; then - # See func_convert_path_msys_to_w32: - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" - func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" - func_convert_path_check : ";" \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" - fi -} -# end func_convert_path_nix_to_w32 - - -# func_convert_path_msys_to_cygwin ARG -# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. -# Returns result in func_to_host_file_result. -func_convert_path_msys_to_cygwin () -{ - $opt_debug - func_to_host_path_result="$1" - if test -n "$1"; then - # See func_convert_path_msys_to_w32: - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" - func_cygpath -u -p "$func_convert_core_msys_to_w32_result" - func_to_host_path_result="$func_cygpath_result" - func_convert_path_check : : \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" : "$1" - fi -} -# end func_convert_path_msys_to_cygwin - - -# func_convert_path_nix_to_cygwin ARG -# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a -# a wine environment, working winepath, and LT_CYGPATH set. Returns result in -# func_to_host_file_result. -func_convert_path_nix_to_cygwin () -{ - $opt_debug - func_to_host_path_result="$1" - if test -n "$1"; then - # Remove leading and trailing path separator characters from - # ARG. msys behavior is inconsistent here, cygpath turns them - # into '.;' and ';.', and winepath ignores them completely. - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" - func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" - func_to_host_path_result="$func_cygpath_result" - func_convert_path_check : : \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" : "$1" - fi -} -# end func_convert_path_nix_to_cygwin - - -# func_mode_compile arg... -func_mode_compile () -{ - $opt_debug - # Get the compilation command and the source file. - base_compile= - srcfile="$nonopt" # always keep a non-empty value in "srcfile" - suppress_opt=yes - suppress_output= - arg_mode=normal - libobj= - later= - pie_flag= - - for arg - do - case $arg_mode in - arg ) - # do not "continue". Instead, add this to base_compile - lastarg="$arg" - arg_mode=normal - ;; - - target ) - libobj="$arg" - arg_mode=normal - continue - ;; - - normal ) - # Accept any command-line options. - case $arg in - -o) - test -n "$libobj" && \ - func_fatal_error "you cannot specify \`-o' more than once" - arg_mode=target - continue - ;; - - -pie | -fpie | -fPIE) - func_append pie_flag " $arg" - continue - ;; - - -shared | -static | -prefer-pic | -prefer-non-pic) - func_append later " $arg" - continue - ;; - - -no-suppress) - suppress_opt=no - continue - ;; - - -Xcompiler) - arg_mode=arg # the next one goes into the "base_compile" arg list - continue # The current "srcfile" will either be retained or - ;; # replaced later. I would guess that would be a bug. - - -Wc,*) - func_stripname '-Wc,' '' "$arg" - args=$func_stripname_result - lastarg= - save_ifs="$IFS"; IFS=',' - for arg in $args; do - IFS="$save_ifs" - func_append_quoted lastarg "$arg" - done - IFS="$save_ifs" - func_stripname ' ' '' "$lastarg" - lastarg=$func_stripname_result - - # Add the arguments to base_compile. - func_append base_compile " $lastarg" - continue - ;; - - *) - # Accept the current argument as the source file. - # The previous "srcfile" becomes the current argument. - # - lastarg="$srcfile" - srcfile="$arg" - ;; - esac # case $arg - ;; - esac # case $arg_mode - - # Aesthetically quote the previous argument. - func_append_quoted base_compile "$lastarg" - done # for arg - - case $arg_mode in - arg) - func_fatal_error "you must specify an argument for -Xcompile" - ;; - target) - func_fatal_error "you must specify a target with \`-o'" - ;; - *) - # Get the name of the library object. - test -z "$libobj" && { - func_basename "$srcfile" - libobj="$func_basename_result" - } - ;; - esac - - # Recognize several different file suffixes. - # If the user specifies -o file.o, it is replaced with file.lo - case $libobj in - *.[cCFSifmso] | \ - *.ada | *.adb | *.ads | *.asm | \ - *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ - *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) - func_xform "$libobj" - libobj=$func_xform_result - ;; - esac - - case $libobj in - *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; - *) - func_fatal_error "cannot determine name of library object from \`$libobj'" - ;; - esac - - func_infer_tag $base_compile - - for arg in $later; do - case $arg in - -shared) - test "$build_libtool_libs" != yes && \ - func_fatal_configuration "can not build a shared library" - build_old_libs=no - continue - ;; - - -static) - build_libtool_libs=no - build_old_libs=yes - continue - ;; - - -prefer-pic) - pic_mode=yes - continue - ;; - - -prefer-non-pic) - pic_mode=no - continue - ;; - esac - done - - func_quote_for_eval "$libobj" - test "X$libobj" != "X$func_quote_for_eval_result" \ - && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ - && func_warning "libobj name \`$libobj' may not contain shell special characters." - func_dirname_and_basename "$obj" "/" "" - objname="$func_basename_result" - xdir="$func_dirname_result" - lobj=${xdir}$objdir/$objname - - test -z "$base_compile" && \ - func_fatal_help "you must specify a compilation command" - - # Delete any leftover library objects. - if test "$build_old_libs" = yes; then - removelist="$obj $lobj $libobj ${libobj}T" - else - removelist="$lobj $libobj ${libobj}T" - fi - - # On Cygwin there's no "real" PIC flag so we must build both object types - case $host_os in - cygwin* | mingw* | pw32* | os2* | cegcc*) - pic_mode=default - ;; - esac - if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then - # non-PIC code in shared libraries is not supported - pic_mode=default - fi - - # Calculate the filename of the output object if compiler does - # not support -o with -c - if test "$compiler_c_o" = no; then - output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} - lockfile="$output_obj.lock" - else - output_obj= - need_locks=no - lockfile= - fi - - # Lock this critical section if it is needed - # We use this script file to make the link, it avoids creating a new file - if test "$need_locks" = yes; then - until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do - func_echo "Waiting for $lockfile to be removed" - sleep 2 - done - elif test "$need_locks" = warn; then - if test -f "$lockfile"; then - $ECHO "\ -*** ERROR, $lockfile exists and contains: -`cat $lockfile 2>/dev/null` - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - func_append removelist " $output_obj" - $ECHO "$srcfile" > "$lockfile" - fi - - $opt_dry_run || $RM $removelist - func_append removelist " $lockfile" - trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 - - func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 - srcfile=$func_to_tool_file_result - func_quote_for_eval "$srcfile" - qsrcfile=$func_quote_for_eval_result - - # Only build a PIC object if we are building libtool libraries. - if test "$build_libtool_libs" = yes; then - # Without this assignment, base_compile gets emptied. - fbsd_hideous_sh_bug=$base_compile - - if test "$pic_mode" != no; then - command="$base_compile $qsrcfile $pic_flag" - else - # Don't build PIC code - command="$base_compile $qsrcfile" - fi - - func_mkdir_p "$xdir$objdir" - - if test -z "$output_obj"; then - # Place PIC objects in $objdir - func_append command " -o $lobj" - fi - - func_show_eval_locale "$command" \ - 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' - - if test "$need_locks" = warn && - test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then - $ECHO "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - - # Just move the object if needed, then go on to compile the next one - if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then - func_show_eval '$MV "$output_obj" "$lobj"' \ - 'error=$?; $opt_dry_run || $RM $removelist; exit $error' - fi - - # Allow error messages only from the first compilation. - if test "$suppress_opt" = yes; then - suppress_output=' >/dev/null 2>&1' - fi - fi - - # Only build a position-dependent object if we build old libraries. - if test "$build_old_libs" = yes; then - if test "$pic_mode" != yes; then - # Don't build PIC code - command="$base_compile $qsrcfile$pie_flag" - else - command="$base_compile $qsrcfile $pic_flag" - fi - if test "$compiler_c_o" = yes; then - func_append command " -o $obj" - fi - - # Suppress compiler output if we already did a PIC compilation. - func_append command "$suppress_output" - func_show_eval_locale "$command" \ - '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' - - if test "$need_locks" = warn && - test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then - $ECHO "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - - # Just move the object if needed - if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then - func_show_eval '$MV "$output_obj" "$obj"' \ - 'error=$?; $opt_dry_run || $RM $removelist; exit $error' - fi - fi - - $opt_dry_run || { - func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" - - # Unlock the critical section if it was locked - if test "$need_locks" != no; then - removelist=$lockfile - $RM "$lockfile" - fi - } - - exit $EXIT_SUCCESS -} - -$opt_help || { - test "$opt_mode" = compile && func_mode_compile ${1+"$@"} -} - -func_mode_help () -{ - # We need to display help for each of the modes. - case $opt_mode in - "") - # Generic help is extracted from the usage comments - # at the start of this file. - func_help - ;; - - clean) - $ECHO \ -"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... - -Remove files from the build directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed -to RM. - -If FILE is a libtool library, object or program, all the files associated -with it are deleted. Otherwise, only FILE itself is deleted using RM." - ;; - - compile) - $ECHO \ -"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE - -Compile a source file into a libtool library object. - -This mode accepts the following additional options: - - -o OUTPUT-FILE set the output file name to OUTPUT-FILE - -no-suppress do not suppress compiler output for multiple passes - -prefer-pic try to build PIC objects only - -prefer-non-pic try to build non-PIC objects only - -shared do not build a \`.o' file suitable for static linking - -static only build a \`.o' file suitable for static linking - -Wc,FLAG pass FLAG directly to the compiler - -COMPILE-COMMAND is a command to be used in creating a \`standard' object file -from the given SOURCEFILE. - -The output file name is determined by removing the directory component from -SOURCEFILE, then substituting the C source code suffix \`.c' with the -library object suffix, \`.lo'." - ;; - - execute) - $ECHO \ -"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... - -Automatically set library path, then run a program. - -This mode accepts the following additional options: - - -dlopen FILE add the directory containing FILE to the library path - -This mode sets the library path environment variable according to \`-dlopen' -flags. - -If any of the ARGS are libtool executable wrappers, then they are translated -into their corresponding uninstalled binary, and any of their required library -directories are added to the library path. - -Then, COMMAND is executed, with ARGS as arguments." - ;; - - finish) - $ECHO \ -"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... - -Complete the installation of libtool libraries. - -Each LIBDIR is a directory that contains libtool libraries. - -The commands that this mode executes may require superuser privileges. Use -the \`--dry-run' option if you just want to see what would be executed." - ;; - - install) - $ECHO \ -"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... - -Install executables or libraries. - -INSTALL-COMMAND is the installation command. The first component should be -either the \`install' or \`cp' program. - -The following components of INSTALL-COMMAND are treated specially: - - -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation - -The rest of the components are interpreted as arguments to that command (only -BSD-compatible install options are recognized)." - ;; - - link) - $ECHO \ -"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... - -Link object files or libraries together to form another library, or to -create an executable program. - -LINK-COMMAND is a command using the C compiler that you would use to create -a program from several object files. - -The following components of LINK-COMMAND are treated specially: - - -all-static do not do any dynamic linking at all - -avoid-version do not add a version suffix if possible - -bindir BINDIR specify path to binaries directory (for systems where - libraries must be found in the PATH setting at runtime) - -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime - -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols - -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) - -export-symbols SYMFILE - try to export only the symbols listed in SYMFILE - -export-symbols-regex REGEX - try to export only the symbols matching REGEX - -LLIBDIR search LIBDIR for required installed libraries - -lNAME OUTPUT-FILE requires the installed library libNAME - -module build a library that can dlopened - -no-fast-install disable the fast-install mode - -no-install link a not-installable executable - -no-undefined declare that a library does not refer to external symbols - -o OUTPUT-FILE create OUTPUT-FILE from the specified objects - -objectlist FILE Use a list of object files found in FILE to specify objects - -precious-files-regex REGEX - don't remove output files matching REGEX - -release RELEASE specify package release information - -rpath LIBDIR the created library will eventually be installed in LIBDIR - -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries - -shared only do dynamic linking of libtool libraries - -shrext SUFFIX override the standard shared library file extension - -static do not do any dynamic linking of uninstalled libtool libraries - -static-libtool-libs - do not do any dynamic linking of libtool libraries - -version-info CURRENT[:REVISION[:AGE]] - specify library version info [each variable defaults to 0] - -weak LIBNAME declare that the target provides the LIBNAME interface - -Wc,FLAG - -Xcompiler FLAG pass linker-specific FLAG directly to the compiler - -Wl,FLAG - -Xlinker FLAG pass linker-specific FLAG directly to the linker - -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) - -All other options (arguments beginning with \`-') are ignored. - -Every other argument is treated as a filename. Files ending in \`.la' are -treated as uninstalled libtool libraries, other files are standard or library -object files. - -If the OUTPUT-FILE ends in \`.la', then a libtool library is created, -only library objects (\`.lo' files) may be specified, and \`-rpath' is -required, except when creating a convenience library. - -If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created -using \`ar' and \`ranlib', or on Windows using \`lib'. - -If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file -is created, otherwise an executable program is created." - ;; - - uninstall) - $ECHO \ -"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... - -Remove libraries from an installation directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed -to RM. - -If FILE is a libtool library, all the files associated with it are deleted. -Otherwise, only FILE itself is deleted using RM." - ;; - - *) - func_fatal_help "invalid operation mode \`$opt_mode'" - ;; - esac - - echo - $ECHO "Try \`$progname --help' for more information about other modes." -} - -# Now that we've collected a possible --mode arg, show help if necessary -if $opt_help; then - if test "$opt_help" = :; then - func_mode_help - else - { - func_help noexit - for opt_mode in compile link execute install finish uninstall clean; do - func_mode_help - done - } | sed -n '1p; 2,$s/^Usage:/ or: /p' - { - func_help noexit - for opt_mode in compile link execute install finish uninstall clean; do - echo - func_mode_help - done - } | - sed '1d - /^When reporting/,/^Report/{ - H - d - } - $x - /information about other modes/d - /more detailed .*MODE/d - s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' - fi - exit $? -fi - - -# func_mode_execute arg... -func_mode_execute () -{ - $opt_debug - # The first argument is the command name. - cmd="$nonopt" - test -z "$cmd" && \ - func_fatal_help "you must specify a COMMAND" - - # Handle -dlopen flags immediately. - for file in $opt_dlopen; do - test -f "$file" \ - || func_fatal_help "\`$file' is not a file" - - dir= - case $file in - *.la) - func_resolve_sysroot "$file" - file=$func_resolve_sysroot_result - - # Check to see that this really is a libtool archive. - func_lalib_unsafe_p "$file" \ - || func_fatal_help "\`$lib' is not a valid libtool archive" - - # Read the libtool library. - dlname= - library_names= - func_source "$file" - - # Skip this library if it cannot be dlopened. - if test -z "$dlname"; then - # Warn if it was a shared library. - test -n "$library_names" && \ - func_warning "\`$file' was not linked with \`-export-dynamic'" - continue - fi - - func_dirname "$file" "" "." - dir="$func_dirname_result" - - if test -f "$dir/$objdir/$dlname"; then - func_append dir "/$objdir" - else - if test ! -f "$dir/$dlname"; then - func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" - fi - fi - ;; - - *.lo) - # Just add the directory containing the .lo file. - func_dirname "$file" "" "." - dir="$func_dirname_result" - ;; - - *) - func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" - continue - ;; - esac - - # Get the absolute pathname. - absdir=`cd "$dir" && pwd` - test -n "$absdir" && dir="$absdir" - - # Now add the directory to shlibpath_var. - if eval "test -z \"\$$shlibpath_var\""; then - eval "$shlibpath_var=\"\$dir\"" - else - eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" - fi - done - - # This variable tells wrapper scripts just to set shlibpath_var - # rather than running their programs. - libtool_execute_magic="$magic" - - # Check if any of the arguments is a wrapper script. - args= - for file - do - case $file in - -* | *.la | *.lo ) ;; - *) - # Do a test to see if this is really a libtool program. - if func_ltwrapper_script_p "$file"; then - func_source "$file" - # Transform arg to wrapped name. - file="$progdir/$program" - elif func_ltwrapper_executable_p "$file"; then - func_ltwrapper_scriptname "$file" - func_source "$func_ltwrapper_scriptname_result" - # Transform arg to wrapped name. - file="$progdir/$program" - fi - ;; - esac - # Quote arguments (to preserve shell metacharacters). - func_append_quoted args "$file" - done - - if test "X$opt_dry_run" = Xfalse; then - if test -n "$shlibpath_var"; then - # Export the shlibpath_var. - eval "export $shlibpath_var" - fi - - # Restore saved environment variables - for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES - do - eval "if test \"\${save_$lt_var+set}\" = set; then - $lt_var=\$save_$lt_var; export $lt_var - else - $lt_unset $lt_var - fi" - done - - # Now prepare to actually exec the command. - exec_cmd="\$cmd$args" - else - # Display what would be done. - if test -n "$shlibpath_var"; then - eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" - echo "export $shlibpath_var" - fi - $ECHO "$cmd$args" - exit $EXIT_SUCCESS - fi -} - -test "$opt_mode" = execute && func_mode_execute ${1+"$@"} - - -# func_mode_finish arg... -func_mode_finish () -{ - $opt_debug - libs= - libdirs= - admincmds= - - for opt in "$nonopt" ${1+"$@"} - do - if test -d "$opt"; then - func_append libdirs " $opt" - - elif test -f "$opt"; then - if func_lalib_unsafe_p "$opt"; then - func_append libs " $opt" - else - func_warning "\`$opt' is not a valid libtool archive" - fi - - else - func_fatal_error "invalid argument \`$opt'" - fi - done - - if test -n "$libs"; then - if test -n "$lt_sysroot"; then - sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` - sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" - else - sysroot_cmd= - fi - - # Remove sysroot references - if $opt_dry_run; then - for lib in $libs; do - echo "removing references to $lt_sysroot and \`=' prefixes from $lib" - done - else - tmpdir=`func_mktempdir` - for lib in $libs; do - sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ - > $tmpdir/tmp-la - mv -f $tmpdir/tmp-la $lib - done - ${RM}r "$tmpdir" - fi - fi - - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then - for libdir in $libdirs; do - if test -n "$finish_cmds"; then - # Do each command in the finish commands. - func_execute_cmds "$finish_cmds" 'admincmds="$admincmds -'"$cmd"'"' - fi - if test -n "$finish_eval"; then - # Do the single finish_eval. - eval cmds=\"$finish_eval\" - $opt_dry_run || eval "$cmds" || func_append admincmds " - $cmds" - fi - done - fi - - # Exit here if they wanted silent mode. - $opt_silent && exit $EXIT_SUCCESS - - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then - echo "----------------------------------------------------------------------" - echo "Libraries have been installed in:" - for libdir in $libdirs; do - $ECHO " $libdir" - done - echo - echo "If you ever happen to want to link against installed libraries" - echo "in a given directory, LIBDIR, you must either use libtool, and" - echo "specify the full pathname of the library, or use the \`-LLIBDIR'" - echo "flag during linking and do at least one of the following:" - if test -n "$shlibpath_var"; then - echo " - add LIBDIR to the \`$shlibpath_var' environment variable" - echo " during execution" - fi - if test -n "$runpath_var"; then - echo " - add LIBDIR to the \`$runpath_var' environment variable" - echo " during linking" - fi - if test -n "$hardcode_libdir_flag_spec"; then - libdir=LIBDIR - eval flag=\"$hardcode_libdir_flag_spec\" - - $ECHO " - use the \`$flag' linker flag" - fi - if test -n "$admincmds"; then - $ECHO " - have your system administrator run these commands:$admincmds" - fi - if test -f /etc/ld.so.conf; then - echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" - fi - echo - - echo "See any operating system documentation about shared libraries for" - case $host in - solaris2.[6789]|solaris2.1[0-9]) - echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" - echo "pages." - ;; - *) - echo "more information, such as the ld(1) and ld.so(8) manual pages." - ;; - esac - echo "----------------------------------------------------------------------" - fi - exit $EXIT_SUCCESS -} - -test "$opt_mode" = finish && func_mode_finish ${1+"$@"} - - -# func_mode_install arg... -func_mode_install () -{ - $opt_debug - # There may be an optional sh(1) argument at the beginning of - # install_prog (especially on Windows NT). - if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || - # Allow the use of GNU shtool's install command. - case $nonopt in *shtool*) :;; *) false;; esac; then - # Aesthetically quote it. - func_quote_for_eval "$nonopt" - install_prog="$func_quote_for_eval_result " - arg=$1 - shift - else - install_prog= - arg=$nonopt - fi - - # The real first argument should be the name of the installation program. - # Aesthetically quote it. - func_quote_for_eval "$arg" - func_append install_prog "$func_quote_for_eval_result" - install_shared_prog=$install_prog - case " $install_prog " in - *[\\\ /]cp\ *) install_cp=: ;; - *) install_cp=false ;; - esac - - # We need to accept at least all the BSD install flags. - dest= - files= - opts= - prev= - install_type= - isdir=no - stripme= - no_mode=: - for arg - do - arg2= - if test -n "$dest"; then - func_append files " $dest" - dest=$arg - continue - fi - - case $arg in - -d) isdir=yes ;; - -f) - if $install_cp; then :; else - prev=$arg - fi - ;; - -g | -m | -o) - prev=$arg - ;; - -s) - stripme=" -s" - continue - ;; - -*) - ;; - *) - # If the previous option needed an argument, then skip it. - if test -n "$prev"; then - if test "x$prev" = x-m && test -n "$install_override_mode"; then - arg2=$install_override_mode - no_mode=false - fi - prev= - else - dest=$arg - continue - fi - ;; - esac - - # Aesthetically quote the argument. - func_quote_for_eval "$arg" - func_append install_prog " $func_quote_for_eval_result" - if test -n "$arg2"; then - func_quote_for_eval "$arg2" - fi - func_append install_shared_prog " $func_quote_for_eval_result" - done - - test -z "$install_prog" && \ - func_fatal_help "you must specify an install program" - - test -n "$prev" && \ - func_fatal_help "the \`$prev' option requires an argument" - - if test -n "$install_override_mode" && $no_mode; then - if $install_cp; then :; else - func_quote_for_eval "$install_override_mode" - func_append install_shared_prog " -m $func_quote_for_eval_result" - fi - fi - - if test -z "$files"; then - if test -z "$dest"; then - func_fatal_help "no file or destination specified" - else - func_fatal_help "you must specify a destination" - fi - fi - - # Strip any trailing slash from the destination. - func_stripname '' '/' "$dest" - dest=$func_stripname_result - - # Check to see that the destination is a directory. - test -d "$dest" && isdir=yes - if test "$isdir" = yes; then - destdir="$dest" - destname= - else - func_dirname_and_basename "$dest" "" "." - destdir="$func_dirname_result" - destname="$func_basename_result" - - # Not a directory, so check to see that there is only one file specified. - set dummy $files; shift - test "$#" -gt 1 && \ - func_fatal_help "\`$dest' is not a directory" - fi - case $destdir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - for file in $files; do - case $file in - *.lo) ;; - *) - func_fatal_help "\`$destdir' must be an absolute directory name" - ;; - esac - done - ;; - esac - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic="$magic" - - staticlibs= - future_libdirs= - current_libdirs= - for file in $files; do - - # Do each installation. - case $file in - *.$libext) - # Do the static libraries later. - func_append staticlibs " $file" - ;; - - *.la) - func_resolve_sysroot "$file" - file=$func_resolve_sysroot_result - - # Check to see that this really is a libtool archive. - func_lalib_unsafe_p "$file" \ - || func_fatal_help "\`$file' is not a valid libtool archive" - - library_names= - old_library= - relink_command= - func_source "$file" - - # Add the libdir to current_libdirs if it is the destination. - if test "X$destdir" = "X$libdir"; then - case "$current_libdirs " in - *" $libdir "*) ;; - *) func_append current_libdirs " $libdir" ;; - esac - else - # Note the libdir as a future libdir. - case "$future_libdirs " in - *" $libdir "*) ;; - *) func_append future_libdirs " $libdir" ;; - esac - fi - - func_dirname "$file" "/" "" - dir="$func_dirname_result" - func_append dir "$objdir" - - if test -n "$relink_command"; then - # Determine the prefix the user has applied to our future dir. - inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` - - # Don't allow the user to place us outside of our expected - # location b/c this prevents finding dependent libraries that - # are installed to the same prefix. - # At present, this check doesn't affect windows .dll's that - # are installed into $libdir/../bin (currently, that works fine) - # but it's something to keep an eye on. - test "$inst_prefix_dir" = "$destdir" && \ - func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" - - if test -n "$inst_prefix_dir"; then - # Stick the inst_prefix_dir data into the link command. - relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` - else - relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` - fi - - func_warning "relinking \`$file'" - func_show_eval "$relink_command" \ - 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' - fi - - # See the names of the shared library. - set dummy $library_names; shift - if test -n "$1"; then - realname="$1" - shift - - srcname="$realname" - test -n "$relink_command" && srcname="$realname"T - - # Install the shared library and build the symlinks. - func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ - 'exit $?' - tstripme="$stripme" - case $host_os in - cygwin* | mingw* | pw32* | cegcc*) - case $realname in - *.dll.a) - tstripme="" - ;; - esac - ;; - esac - if test -n "$tstripme" && test -n "$striplib"; then - func_show_eval "$striplib $destdir/$realname" 'exit $?' - fi - - if test "$#" -gt 0; then - # Delete the old symlinks, and create new ones. - # Try `ln -sf' first, because the `ln' binary might depend on - # the symlink we replace! Solaris /bin/ln does not understand -f, - # so we also need to try rm && ln -s. - for linkname - do - test "$linkname" != "$realname" \ - && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" - done - fi - - # Do each command in the postinstall commands. - lib="$destdir/$realname" - func_execute_cmds "$postinstall_cmds" 'exit $?' - fi - - # Install the pseudo-library for information purposes. - func_basename "$file" - name="$func_basename_result" - instname="$dir/$name"i - func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' - - # Maybe install the static library, too. - test -n "$old_library" && func_append staticlibs " $dir/$old_library" - ;; - - *.lo) - # Install (i.e. copy) a libtool object. - - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - func_basename "$file" - destfile="$func_basename_result" - destfile="$destdir/$destfile" - fi - - # Deduce the name of the destination old-style object file. - case $destfile in - *.lo) - func_lo2o "$destfile" - staticdest=$func_lo2o_result - ;; - *.$objext) - staticdest="$destfile" - destfile= - ;; - *) - func_fatal_help "cannot copy a libtool object to \`$destfile'" - ;; - esac - - # Install the libtool object if requested. - test -n "$destfile" && \ - func_show_eval "$install_prog $file $destfile" 'exit $?' - - # Install the old object if enabled. - if test "$build_old_libs" = yes; then - # Deduce the name of the old-style object file. - func_lo2o "$file" - staticobj=$func_lo2o_result - func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' - fi - exit $EXIT_SUCCESS - ;; - - *) - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - func_basename "$file" - destfile="$func_basename_result" - destfile="$destdir/$destfile" - fi - - # If the file is missing, and there is a .exe on the end, strip it - # because it is most likely a libtool script we actually want to - # install - stripped_ext="" - case $file in - *.exe) - if test ! -f "$file"; then - func_stripname '' '.exe' "$file" - file=$func_stripname_result - stripped_ext=".exe" - fi - ;; - esac - - # Do a test to see if this is really a libtool program. - case $host in - *cygwin* | *mingw*) - if func_ltwrapper_executable_p "$file"; then - func_ltwrapper_scriptname "$file" - wrapper=$func_ltwrapper_scriptname_result - else - func_stripname '' '.exe' "$file" - wrapper=$func_stripname_result - fi - ;; - *) - wrapper=$file - ;; - esac - if func_ltwrapper_script_p "$wrapper"; then - notinst_deplibs= - relink_command= - - func_source "$wrapper" - - # Check the variables that should have been set. - test -z "$generated_by_libtool_version" && \ - func_fatal_error "invalid libtool wrapper script \`$wrapper'" - - finalize=yes - for lib in $notinst_deplibs; do - # Check to see that each library is installed. - libdir= - if test -f "$lib"; then - func_source "$lib" - fi - libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test - if test -n "$libdir" && test ! -f "$libfile"; then - func_warning "\`$lib' has not been installed in \`$libdir'" - finalize=no - fi - done - - relink_command= - func_source "$wrapper" - - outputname= - if test "$fast_install" = no && test -n "$relink_command"; then - $opt_dry_run || { - if test "$finalize" = yes; then - tmpdir=`func_mktempdir` - func_basename "$file$stripped_ext" - file="$func_basename_result" - outputname="$tmpdir/$file" - # Replace the output file specification. - relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` - - $opt_silent || { - func_quote_for_expand "$relink_command" - eval "func_echo $func_quote_for_expand_result" - } - if eval "$relink_command"; then : - else - func_error "error: relink \`$file' with the above command before installing it" - $opt_dry_run || ${RM}r "$tmpdir" - continue - fi - file="$outputname" - else - func_warning "cannot relink \`$file'" - fi - } - else - # Install the binary that we compiled earlier. - file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` - fi - fi - - # remove .exe since cygwin /usr/bin/install will append another - # one anyway - case $install_prog,$host in - */usr/bin/install*,*cygwin*) - case $file:$destfile in - *.exe:*.exe) - # this is ok - ;; - *.exe:*) - destfile=$destfile.exe - ;; - *:*.exe) - func_stripname '' '.exe' "$destfile" - destfile=$func_stripname_result - ;; - esac - ;; - esac - func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' - $opt_dry_run || if test -n "$outputname"; then - ${RM}r "$tmpdir" - fi - ;; - esac - done - - for file in $staticlibs; do - func_basename "$file" - name="$func_basename_result" - - # Set up the ranlib parameters. - oldlib="$destdir/$name" - func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 - tool_oldlib=$func_to_tool_file_result - - func_show_eval "$install_prog \$file \$oldlib" 'exit $?' - - if test -n "$stripme" && test -n "$old_striplib"; then - func_show_eval "$old_striplib $tool_oldlib" 'exit $?' - fi - - # Do each command in the postinstall commands. - func_execute_cmds "$old_postinstall_cmds" 'exit $?' - done - - test -n "$future_libdirs" && \ - func_warning "remember to run \`$progname --finish$future_libdirs'" - - if test -n "$current_libdirs"; then - # Maybe just do a dry run. - $opt_dry_run && current_libdirs=" -n$current_libdirs" - exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' - else - exit $EXIT_SUCCESS - fi -} - -test "$opt_mode" = install && func_mode_install ${1+"$@"} - - -# func_generate_dlsyms outputname originator pic_p -# Extract symbols from dlprefiles and create ${outputname}S.o with -# a dlpreopen symbol table. -func_generate_dlsyms () -{ - $opt_debug - my_outputname="$1" - my_originator="$2" - my_pic_p="${3-no}" - my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` - my_dlsyms= - - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - if test -n "$NM" && test -n "$global_symbol_pipe"; then - my_dlsyms="${my_outputname}S.c" - else - func_error "not configured to extract global symbols from dlpreopened files" - fi - fi - - if test -n "$my_dlsyms"; then - case $my_dlsyms in - "") ;; - *.c) - # Discover the nlist of each of the dlfiles. - nlist="$output_objdir/${my_outputname}.nm" - - func_show_eval "$RM $nlist ${nlist}S ${nlist}T" - - # Parse the name list into a source file. - func_verbose "creating $output_objdir/$my_dlsyms" - - $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ -/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ -/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ - -#ifdef __cplusplus -extern \"C\" { -#endif - -#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) -#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" -#endif - -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) -/* DATA imports from DLLs on WIN32 con't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT_DLSYM_CONST -#elif defined(__osf__) -/* This system does not cope well with relocations in const data. */ -# define LT_DLSYM_CONST -#else -# define LT_DLSYM_CONST const -#endif - -/* External symbol declarations for the compiler. */\ -" - - if test "$dlself" = yes; then - func_verbose "generating symbol list for \`$output'" - - $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" - - # Add our own program objects to the symbol list. - progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` - for progfile in $progfiles; do - func_to_tool_file "$progfile" func_convert_file_msys_to_w32 - func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" - $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" - done - - if test -n "$exclude_expsyms"; then - $opt_dry_run || { - eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' - eval '$MV "$nlist"T "$nlist"' - } - fi - - if test -n "$export_symbols_regex"; then - $opt_dry_run || { - eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' - eval '$MV "$nlist"T "$nlist"' - } - fi - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - export_symbols="$output_objdir/$outputname.exp" - $opt_dry_run || { - $RM $export_symbols - eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' - case $host in - *cygwin* | *mingw* | *cegcc* ) - eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' - eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' - ;; - esac - } - else - $opt_dry_run || { - eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' - eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' - eval '$MV "$nlist"T "$nlist"' - case $host in - *cygwin* | *mingw* | *cegcc* ) - eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' - eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' - ;; - esac - } - fi - fi - - for dlprefile in $dlprefiles; do - func_verbose "extracting global C symbols from \`$dlprefile'" - func_basename "$dlprefile" - name="$func_basename_result" - case $host in - *cygwin* | *mingw* | *cegcc* ) - # if an import library, we need to obtain dlname - if func_win32_import_lib_p "$dlprefile"; then - func_tr_sh "$dlprefile" - eval "curr_lafile=\$libfile_$func_tr_sh_result" - dlprefile_dlbasename="" - if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then - # Use subshell, to avoid clobbering current variable values - dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` - if test -n "$dlprefile_dlname" ; then - func_basename "$dlprefile_dlname" - dlprefile_dlbasename="$func_basename_result" - else - # no lafile. user explicitly requested -dlpreopen . - $sharedlib_from_linklib_cmd "$dlprefile" - dlprefile_dlbasename=$sharedlib_from_linklib_result - fi - fi - $opt_dry_run || { - if test -n "$dlprefile_dlbasename" ; then - eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' - else - func_warning "Could not compute DLL name from $name" - eval '$ECHO ": $name " >> "$nlist"' - fi - func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 - eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | - $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" - } - else # not an import lib - $opt_dry_run || { - eval '$ECHO ": $name " >> "$nlist"' - func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 - eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" - } - fi - ;; - *) - $opt_dry_run || { - eval '$ECHO ": $name " >> "$nlist"' - func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 - eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" - } - ;; - esac - done - - $opt_dry_run || { - # Make sure we have at least an empty file. - test -f "$nlist" || : > "$nlist" - - if test -n "$exclude_expsyms"; then - $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T - $MV "$nlist"T "$nlist" - fi - - # Try sorting and uniquifying the output. - if $GREP -v "^: " < "$nlist" | - if sort -k 3 /dev/null 2>&1; then - sort -k 3 - else - sort +2 - fi | - uniq > "$nlist"S; then - : - else - $GREP -v "^: " < "$nlist" > "$nlist"S - fi - - if test -f "$nlist"S; then - eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' - else - echo '/* NONE */' >> "$output_objdir/$my_dlsyms" - fi - - echo >> "$output_objdir/$my_dlsyms" "\ - -/* The mapping between symbol names and symbols. */ -typedef struct { - const char *name; - void *address; -} lt_dlsymlist; -extern LT_DLSYM_CONST lt_dlsymlist -lt_${my_prefix}_LTX_preloaded_symbols[]; -LT_DLSYM_CONST lt_dlsymlist -lt_${my_prefix}_LTX_preloaded_symbols[] = -{\ - { \"$my_originator\", (void *) 0 }," - - case $need_lib_prefix in - no) - eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" - ;; - *) - eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" - ;; - esac - echo >> "$output_objdir/$my_dlsyms" "\ - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt_${my_prefix}_LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif\ -" - } # !$opt_dry_run - - pic_flag_for_symtable= - case "$compile_command " in - *" -static "*) ;; - *) - case $host in - # compiling the symbol table file with pic_flag works around - # a FreeBSD bug that causes programs to crash when -lm is - # linked before any other PIC object. But we must not use - # pic_flag when linking with -static. The problem exists in - # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. - *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) - pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; - *-*-hpux*) - pic_flag_for_symtable=" $pic_flag" ;; - *) - if test "X$my_pic_p" != Xno; then - pic_flag_for_symtable=" $pic_flag" - fi - ;; - esac - ;; - esac - symtab_cflags= - for arg in $LTCFLAGS; do - case $arg in - -pie | -fpie | -fPIE) ;; - *) func_append symtab_cflags " $arg" ;; - esac - done - - # Now compile the dynamic symbol file. - func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' - - # Clean up the generated files. - func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' - - # Transform the symbol file into the correct name. - symfileobj="$output_objdir/${my_outputname}S.$objext" - case $host in - *cygwin* | *mingw* | *cegcc* ) - if test -f "$output_objdir/$my_outputname.def"; then - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` - else - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` - fi - ;; - *) - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` - ;; - esac - ;; - *) - func_fatal_error "unknown suffix for \`$my_dlsyms'" - ;; - esac - else - # We keep going just in case the user didn't refer to - # lt_preloaded_symbols. The linker will fail if global_symbol_pipe - # really was required. - - # Nullify the symbol file. - compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` - fi -} - -# func_win32_libid arg -# return the library type of file 'arg' -# -# Need a lot of goo to handle *both* DLLs and import libs -# Has to be a shell function in order to 'eat' the argument -# that is supplied when $file_magic_command is called. -# Despite the name, also deal with 64 bit binaries. -func_win32_libid () -{ - $opt_debug - win32_libid_type="unknown" - win32_fileres=`file -L $1 2>/dev/null` - case $win32_fileres in - *ar\ archive\ import\ library*) # definitely import - win32_libid_type="x86 archive import" - ;; - *ar\ archive*) # could be an import, or static - # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. - if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | - $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then - func_to_tool_file "$1" func_convert_file_msys_to_w32 - win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | - $SED -n -e ' - 1,100{ - / I /{ - s,.*,import, - p - q - } - }'` - case $win32_nmres in - import*) win32_libid_type="x86 archive import";; - *) win32_libid_type="x86 archive static";; - esac - fi - ;; - *DLL*) - win32_libid_type="x86 DLL" - ;; - *executable*) # but shell scripts are "executable" too... - case $win32_fileres in - *MS\ Windows\ PE\ Intel*) - win32_libid_type="x86 DLL" - ;; - esac - ;; - esac - $ECHO "$win32_libid_type" -} - -# func_cygming_dll_for_implib ARG -# -# Platform-specific function to extract the -# name of the DLL associated with the specified -# import library ARG. -# Invoked by eval'ing the libtool variable -# $sharedlib_from_linklib_cmd -# Result is available in the variable -# $sharedlib_from_linklib_result -func_cygming_dll_for_implib () -{ - $opt_debug - sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` -} - -# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs -# -# The is the core of a fallback implementation of a -# platform-specific function to extract the name of the -# DLL associated with the specified import library LIBNAME. -# -# SECTION_NAME is either .idata$6 or .idata$7, depending -# on the platform and compiler that created the implib. -# -# Echos the name of the DLL associated with the -# specified import library. -func_cygming_dll_for_implib_fallback_core () -{ - $opt_debug - match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` - $OBJDUMP -s --section "$1" "$2" 2>/dev/null | - $SED '/^Contents of section '"$match_literal"':/{ - # Place marker at beginning of archive member dllname section - s/.*/====MARK====/ - p - d - } - # These lines can sometimes be longer than 43 characters, but - # are always uninteresting - /:[ ]*file format pe[i]\{,1\}-/d - /^In archive [^:]*:/d - # Ensure marker is printed - /^====MARK====/p - # Remove all lines with less than 43 characters - /^.\{43\}/!d - # From remaining lines, remove first 43 characters - s/^.\{43\}//' | - $SED -n ' - # Join marker and all lines until next marker into a single line - /^====MARK====/ b para - H - $ b para - b - :para - x - s/\n//g - # Remove the marker - s/^====MARK====// - # Remove trailing dots and whitespace - s/[\. \t]*$// - # Print - /./p' | - # we now have a list, one entry per line, of the stringified - # contents of the appropriate section of all members of the - # archive which possess that section. Heuristic: eliminate - # all those which have a first or second character that is - # a '.' (that is, objdump's representation of an unprintable - # character.) This should work for all archives with less than - # 0x302f exports -- but will fail for DLLs whose name actually - # begins with a literal '.' or a single character followed by - # a '.'. - # - # Of those that remain, print the first one. - $SED -e '/^\./d;/^.\./d;q' -} - -# func_cygming_gnu_implib_p ARG -# This predicate returns with zero status (TRUE) if -# ARG is a GNU/binutils-style import library. Returns -# with nonzero status (FALSE) otherwise. -func_cygming_gnu_implib_p () -{ - $opt_debug - func_to_tool_file "$1" func_convert_file_msys_to_w32 - func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` - test -n "$func_cygming_gnu_implib_tmp" -} - -# func_cygming_ms_implib_p ARG -# This predicate returns with zero status (TRUE) if -# ARG is an MS-style import library. Returns -# with nonzero status (FALSE) otherwise. -func_cygming_ms_implib_p () -{ - $opt_debug - func_to_tool_file "$1" func_convert_file_msys_to_w32 - func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` - test -n "$func_cygming_ms_implib_tmp" -} - -# func_cygming_dll_for_implib_fallback ARG -# Platform-specific function to extract the -# name of the DLL associated with the specified -# import library ARG. -# -# This fallback implementation is for use when $DLLTOOL -# does not support the --identify-strict option. -# Invoked by eval'ing the libtool variable -# $sharedlib_from_linklib_cmd -# Result is available in the variable -# $sharedlib_from_linklib_result -func_cygming_dll_for_implib_fallback () -{ - $opt_debug - if func_cygming_gnu_implib_p "$1" ; then - # binutils import library - sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` - elif func_cygming_ms_implib_p "$1" ; then - # ms-generated import library - sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` - else - # unknown - sharedlib_from_linklib_result="" - fi -} - - -# func_extract_an_archive dir oldlib -func_extract_an_archive () -{ - $opt_debug - f_ex_an_ar_dir="$1"; shift - f_ex_an_ar_oldlib="$1" - if test "$lock_old_archive_extraction" = yes; then - lockfile=$f_ex_an_ar_oldlib.lock - until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do - func_echo "Waiting for $lockfile to be removed" - sleep 2 - done - fi - func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ - 'stat=$?; rm -f "$lockfile"; exit $stat' - if test "$lock_old_archive_extraction" = yes; then - $opt_dry_run || rm -f "$lockfile" - fi - if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then - : - else - func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" - fi -} - - -# func_extract_archives gentop oldlib ... -func_extract_archives () -{ - $opt_debug - my_gentop="$1"; shift - my_oldlibs=${1+"$@"} - my_oldobjs="" - my_xlib="" - my_xabs="" - my_xdir="" - - for my_xlib in $my_oldlibs; do - # Extract the objects. - case $my_xlib in - [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; - *) my_xabs=`pwd`"/$my_xlib" ;; - esac - func_basename "$my_xlib" - my_xlib="$func_basename_result" - my_xlib_u=$my_xlib - while :; do - case " $extracted_archives " in - *" $my_xlib_u "*) - func_arith $extracted_serial + 1 - extracted_serial=$func_arith_result - my_xlib_u=lt$extracted_serial-$my_xlib ;; - *) break ;; - esac - done - extracted_archives="$extracted_archives $my_xlib_u" - my_xdir="$my_gentop/$my_xlib_u" - - func_mkdir_p "$my_xdir" - - case $host in - *-darwin*) - func_verbose "Extracting $my_xabs" - # Do not bother doing anything if just a dry run - $opt_dry_run || { - darwin_orig_dir=`pwd` - cd $my_xdir || exit $? - darwin_archive=$my_xabs - darwin_curdir=`pwd` - darwin_base_archive=`basename "$darwin_archive"` - darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` - if test -n "$darwin_arches"; then - darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` - darwin_arch= - func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" - for darwin_arch in $darwin_arches ; do - func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" - $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" - cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" - func_extract_an_archive "`pwd`" "${darwin_base_archive}" - cd "$darwin_curdir" - $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" - done # $darwin_arches - ## Okay now we've a bunch of thin objects, gotta fatten them up :) - darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` - darwin_file= - darwin_files= - for darwin_file in $darwin_filelist; do - darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` - $LIPO -create -output "$darwin_file" $darwin_files - done # $darwin_filelist - $RM -rf unfat-$$ - cd "$darwin_orig_dir" - else - cd $darwin_orig_dir - func_extract_an_archive "$my_xdir" "$my_xabs" - fi # $darwin_arches - } # !$opt_dry_run - ;; - *) - func_extract_an_archive "$my_xdir" "$my_xabs" - ;; - esac - my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` - done - - func_extract_archives_result="$my_oldobjs" -} - - -# func_emit_wrapper [arg=no] -# -# Emit a libtool wrapper script on stdout. -# Don't directly open a file because we may want to -# incorporate the script contents within a cygwin/mingw -# wrapper executable. Must ONLY be called from within -# func_mode_link because it depends on a number of variables -# set therein. -# -# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR -# variable will take. If 'yes', then the emitted script -# will assume that the directory in which it is stored is -# the $objdir directory. This is a cygwin/mingw-specific -# behavior. -func_emit_wrapper () -{ - func_emit_wrapper_arg1=${1-no} - - $ECHO "\ -#! $SHELL - -# $output - temporary wrapper script for $objdir/$outputname -# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION -# -# The $output program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of the build directory. -# If it is, it will not operate correctly. - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -sed_quote_subst='$sed_quote_subst' - -# Be Bourne compatible -if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac -fi -BIN_SH=xpg4; export BIN_SH # for Tru64 -DUALCASE=1; export DUALCASE # for MKS sh - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -relink_command=\"$relink_command\" - -# This environment variable determines our operation mode. -if test \"\$libtool_install_magic\" = \"$magic\"; then - # install mode needs the following variables: - generated_by_libtool_version='$macro_version' - notinst_deplibs='$notinst_deplibs' -else - # When we are sourced in execute mode, \$file and \$ECHO are already set. - if test \"\$libtool_execute_magic\" != \"$magic\"; then - file=\"\$0\"" - - qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` - $ECHO "\ - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - ECHO=\"$qECHO\" - fi - -# Very basic option parsing. These options are (a) specific to -# the libtool wrapper, (b) are identical between the wrapper -# /script/ and the wrapper /executable/ which is used only on -# windows platforms, and (c) all begin with the string "--lt-" -# (application programs are unlikely to have options which match -# this pattern). -# -# There are only two supported options: --lt-debug and -# --lt-dump-script. There is, deliberately, no --lt-help. -# -# The first argument to this parsing function should be the -# script's $0 value, followed by "$@". -lt_option_debug= -func_parse_lt_options () -{ - lt_script_arg0=\$0 - shift - for lt_opt - do - case \"\$lt_opt\" in - --lt-debug) lt_option_debug=1 ;; - --lt-dump-script) - lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` - test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. - lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` - cat \"\$lt_dump_D/\$lt_dump_F\" - exit 0 - ;; - --lt-*) - \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 - exit 1 - ;; - esac - done - - # Print the debug banner immediately: - if test -n \"\$lt_option_debug\"; then - echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 - fi -} - -# Used when --lt-debug. Prints its arguments to stdout -# (redirection is the responsibility of the caller) -func_lt_dump_args () -{ - lt_dump_args_N=1; - for lt_arg - do - \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" - lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` - done -} - -# Core function for launching the target application -func_exec_program_core () -{ -" - case $host in - # Backslashes separate directories on plain windows - *-*-mingw | *-*-os2* | *-cegcc*) - $ECHO "\ - if test -n \"\$lt_option_debug\"; then - \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 - func_lt_dump_args \${1+\"\$@\"} 1>&2 - fi - exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} -" - ;; - - *) - $ECHO "\ - if test -n \"\$lt_option_debug\"; then - \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 - func_lt_dump_args \${1+\"\$@\"} 1>&2 - fi - exec \"\$progdir/\$program\" \${1+\"\$@\"} -" - ;; - esac - $ECHO "\ - \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 - exit 1 -} - -# A function to encapsulate launching the target application -# Strips options in the --lt-* namespace from \$@ and -# launches target application with the remaining arguments. -func_exec_program () -{ - case \" \$* \" in - *\\ --lt-*) - for lt_wr_arg - do - case \$lt_wr_arg in - --lt-*) ;; - *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; - esac - shift - done ;; - esac - func_exec_program_core \${1+\"\$@\"} -} - - # Parse options - func_parse_lt_options \"\$0\" \${1+\"\$@\"} - - # Find the directory that this script lives in. - thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` - test \"x\$thisdir\" = \"x\$file\" && thisdir=. - - # Follow symbolic links until we get to the real thisdir. - file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` - while test -n \"\$file\"; do - destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` - - # If there was a directory component, then change thisdir. - if test \"x\$destdir\" != \"x\$file\"; then - case \"\$destdir\" in - [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; - *) thisdir=\"\$thisdir/\$destdir\" ;; - esac - fi - - file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` - file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` - done - - # Usually 'no', except on cygwin/mingw when embedded into - # the cwrapper. - WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 - if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then - # special case for '.' - if test \"\$thisdir\" = \".\"; then - thisdir=\`pwd\` - fi - # remove .libs from thisdir - case \"\$thisdir\" in - *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; - $objdir ) thisdir=. ;; - esac - fi - - # Try to get the absolute directory name. - absdir=\`cd \"\$thisdir\" && pwd\` - test -n \"\$absdir\" && thisdir=\"\$absdir\" -" - - if test "$fast_install" = yes; then - $ECHO "\ - program=lt-'$outputname'$exeext - progdir=\"\$thisdir/$objdir\" - - if test ! -f \"\$progdir/\$program\" || - { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ - test \"X\$file\" != \"X\$progdir/\$program\"; }; then - - file=\"\$\$-\$program\" - - if test ! -d \"\$progdir\"; then - $MKDIR \"\$progdir\" - else - $RM \"\$progdir/\$file\" - fi" - - $ECHO "\ - - # relink executable if necessary - if test -n \"\$relink_command\"; then - if relink_command_output=\`eval \$relink_command 2>&1\`; then : - else - $ECHO \"\$relink_command_output\" >&2 - $RM \"\$progdir/\$file\" - exit 1 - fi - fi - - $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || - { $RM \"\$progdir/\$program\"; - $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } - $RM \"\$progdir/\$file\" - fi" - else - $ECHO "\ - program='$outputname' - progdir=\"\$thisdir/$objdir\" -" - fi - - $ECHO "\ - - if test -f \"\$progdir/\$program\"; then" - - # fixup the dll searchpath if we need to. - # - # Fix the DLL searchpath if we need to. Do this before prepending - # to shlibpath, because on Windows, both are PATH and uninstalled - # libraries must come first. - if test -n "$dllsearchpath"; then - $ECHO "\ - # Add the dll search path components to the executable PATH - PATH=$dllsearchpath:\$PATH -" - fi - - # Export our shlibpath_var if we have one. - if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then - $ECHO "\ - # Add our own library path to $shlibpath_var - $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" - - # Some systems cannot cope with colon-terminated $shlibpath_var - # The second colon is a workaround for a bug in BeOS R4 sed - $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` - - export $shlibpath_var -" - fi - - $ECHO "\ - if test \"\$libtool_execute_magic\" != \"$magic\"; then - # Run the actual program with our arguments. - func_exec_program \${1+\"\$@\"} - fi - else - # The program doesn't exist. - \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 - \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 - \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 - exit 1 - fi -fi\ -" -} - - -# func_emit_cwrapperexe_src -# emit the source code for a wrapper executable on stdout -# Must ONLY be called from within func_mode_link because -# it depends on a number of variable set therein. -func_emit_cwrapperexe_src () -{ - cat < -#include -#ifdef _MSC_VER -# include -# include -# include -#else -# include -# include -# ifdef __CYGWIN__ -# include -# endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -/* declarations of non-ANSI functions */ -#if defined(__MINGW32__) -# ifdef __STRICT_ANSI__ -int _putenv (const char *); -# endif -#elif defined(__CYGWIN__) -# ifdef __STRICT_ANSI__ -char *realpath (const char *, char *); -int putenv (char *); -int setenv (const char *, const char *, int); -# endif -/* #elif defined (other platforms) ... */ -#endif - -/* portability defines, excluding path handling macros */ -#if defined(_MSC_VER) -# define setmode _setmode -# define stat _stat -# define chmod _chmod -# define getcwd _getcwd -# define putenv _putenv -# define S_IXUSR _S_IEXEC -# ifndef _INTPTR_T_DEFINED -# define _INTPTR_T_DEFINED -# define intptr_t int -# endif -#elif defined(__MINGW32__) -# define setmode _setmode -# define stat _stat -# define chmod _chmod -# define getcwd _getcwd -# define putenv _putenv -#elif defined(__CYGWIN__) -# define HAVE_SETENV -# define FOPEN_WB "wb" -/* #elif defined (other platforms) ... */ -#endif - -#if defined(PATH_MAX) -# define LT_PATHMAX PATH_MAX -#elif defined(MAXPATHLEN) -# define LT_PATHMAX MAXPATHLEN -#else -# define LT_PATHMAX 1024 -#endif - -#ifndef S_IXOTH -# define S_IXOTH 0 -#endif -#ifndef S_IXGRP -# define S_IXGRP 0 -#endif - -/* path handling portability macros */ -#ifndef DIR_SEPARATOR -# define DIR_SEPARATOR '/' -# define PATH_SEPARATOR ':' -#endif - -#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ - defined (__OS2__) -# define HAVE_DOS_BASED_FILE_SYSTEM -# define FOPEN_WB "wb" -# ifndef DIR_SEPARATOR_2 -# define DIR_SEPARATOR_2 '\\' -# endif -# ifndef PATH_SEPARATOR_2 -# define PATH_SEPARATOR_2 ';' -# endif -#endif - -#ifndef DIR_SEPARATOR_2 -# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) -#else /* DIR_SEPARATOR_2 */ -# define IS_DIR_SEPARATOR(ch) \ - (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) -#endif /* DIR_SEPARATOR_2 */ - -#ifndef PATH_SEPARATOR_2 -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) -#else /* PATH_SEPARATOR_2 */ -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) -#endif /* PATH_SEPARATOR_2 */ - -#ifndef FOPEN_WB -# define FOPEN_WB "w" -#endif -#ifndef _O_BINARY -# define _O_BINARY 0 -#endif - -#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) -#define XFREE(stale) do { \ - if (stale) { free ((void *) stale); stale = 0; } \ -} while (0) - -#if defined(LT_DEBUGWRAPPER) -static int lt_debug = 1; -#else -static int lt_debug = 0; -#endif - -const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ - -void *xmalloc (size_t num); -char *xstrdup (const char *string); -const char *base_name (const char *name); -char *find_executable (const char *wrapper); -char *chase_symlinks (const char *pathspec); -int make_executable (const char *path); -int check_executable (const char *path); -char *strendzap (char *str, const char *pat); -void lt_debugprintf (const char *file, int line, const char *fmt, ...); -void lt_fatal (const char *file, int line, const char *message, ...); -static const char *nonnull (const char *s); -static const char *nonempty (const char *s); -void lt_setenv (const char *name, const char *value); -char *lt_extend_str (const char *orig_value, const char *add, int to_end); -void lt_update_exe_path (const char *name, const char *value); -void lt_update_lib_path (const char *name, const char *value); -char **prepare_spawn (char **argv); -void lt_dump_script (FILE *f); -EOF - - cat <= 0) - && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) - return 1; - else - return 0; -} - -int -make_executable (const char *path) -{ - int rval = 0; - struct stat st; - - lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", - nonempty (path)); - if ((!path) || (!*path)) - return 0; - - if (stat (path, &st) >= 0) - { - rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); - } - return rval; -} - -/* Searches for the full path of the wrapper. Returns - newly allocated full path name if found, NULL otherwise - Does not chase symlinks, even on platforms that support them. -*/ -char * -find_executable (const char *wrapper) -{ - int has_slash = 0; - const char *p; - const char *p_next; - /* static buffer for getcwd */ - char tmp[LT_PATHMAX + 1]; - int tmp_len; - char *concat_name; - - lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", - nonempty (wrapper)); - - if ((wrapper == NULL) || (*wrapper == '\0')) - return NULL; - - /* Absolute path? */ -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') - { - concat_name = xstrdup (wrapper); - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } - else - { -#endif - if (IS_DIR_SEPARATOR (wrapper[0])) - { - concat_name = xstrdup (wrapper); - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - } -#endif - - for (p = wrapper; *p; p++) - if (*p == '/') - { - has_slash = 1; - break; - } - if (!has_slash) - { - /* no slashes; search PATH */ - const char *path = getenv ("PATH"); - if (path != NULL) - { - for (p = path; *p; p = p_next) - { - const char *q; - size_t p_len; - for (q = p; *q; q++) - if (IS_PATH_SEPARATOR (*q)) - break; - p_len = q - p; - p_next = (*q == '\0' ? q : q + 1); - if (p_len == 0) - { - /* empty path: current directory */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", - nonnull (strerror (errno))); - tmp_len = strlen (tmp); - concat_name = - XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - } - else - { - concat_name = - XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, p, p_len); - concat_name[p_len] = '/'; - strcpy (concat_name + p_len + 1, wrapper); - } - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } - } - /* not found in PATH; assume curdir */ - } - /* Relative path | not found in path: prepend cwd */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", - nonnull (strerror (errno))); - tmp_len = strlen (tmp); - concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - return NULL; -} - -char * -chase_symlinks (const char *pathspec) -{ -#ifndef S_ISLNK - return xstrdup (pathspec); -#else - char buf[LT_PATHMAX]; - struct stat s; - char *tmp_pathspec = xstrdup (pathspec); - char *p; - int has_symlinks = 0; - while (strlen (tmp_pathspec) && !has_symlinks) - { - lt_debugprintf (__FILE__, __LINE__, - "checking path component for symlinks: %s\n", - tmp_pathspec); - if (lstat (tmp_pathspec, &s) == 0) - { - if (S_ISLNK (s.st_mode) != 0) - { - has_symlinks = 1; - break; - } - - /* search backwards for last DIR_SEPARATOR */ - p = tmp_pathspec + strlen (tmp_pathspec) - 1; - while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) - p--; - if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) - { - /* no more DIR_SEPARATORS left */ - break; - } - *p = '\0'; - } - else - { - lt_fatal (__FILE__, __LINE__, - "error accessing file \"%s\": %s", - tmp_pathspec, nonnull (strerror (errno))); - } - } - XFREE (tmp_pathspec); - - if (!has_symlinks) - { - return xstrdup (pathspec); - } - - tmp_pathspec = realpath (pathspec, buf); - if (tmp_pathspec == 0) - { - lt_fatal (__FILE__, __LINE__, - "could not follow symlinks for %s", pathspec); - } - return xstrdup (tmp_pathspec); -#endif -} - -char * -strendzap (char *str, const char *pat) -{ - size_t len, patlen; - - assert (str != NULL); - assert (pat != NULL); - - len = strlen (str); - patlen = strlen (pat); - - if (patlen <= len) - { - str += len - patlen; - if (strcmp (str, pat) == 0) - *str = '\0'; - } - return str; -} - -void -lt_debugprintf (const char *file, int line, const char *fmt, ...) -{ - va_list args; - if (lt_debug) - { - (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); - va_start (args, fmt); - (void) vfprintf (stderr, fmt, args); - va_end (args); - } -} - -static void -lt_error_core (int exit_status, const char *file, - int line, const char *mode, - const char *message, va_list ap) -{ - fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); - vfprintf (stderr, message, ap); - fprintf (stderr, ".\n"); - - if (exit_status >= 0) - exit (exit_status); -} - -void -lt_fatal (const char *file, int line, const char *message, ...) -{ - va_list ap; - va_start (ap, message); - lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); - va_end (ap); -} - -static const char * -nonnull (const char *s) -{ - return s ? s : "(null)"; -} - -static const char * -nonempty (const char *s) -{ - return (s && !*s) ? "(empty)" : nonnull (s); -} - -void -lt_setenv (const char *name, const char *value) -{ - lt_debugprintf (__FILE__, __LINE__, - "(lt_setenv) setting '%s' to '%s'\n", - nonnull (name), nonnull (value)); - { -#ifdef HAVE_SETENV - /* always make a copy, for consistency with !HAVE_SETENV */ - char *str = xstrdup (value); - setenv (name, str, 1); -#else - int len = strlen (name) + 1 + strlen (value) + 1; - char *str = XMALLOC (char, len); - sprintf (str, "%s=%s", name, value); - if (putenv (str) != EXIT_SUCCESS) - { - XFREE (str); - } -#endif - } -} - -char * -lt_extend_str (const char *orig_value, const char *add, int to_end) -{ - char *new_value; - if (orig_value && *orig_value) - { - int orig_value_len = strlen (orig_value); - int add_len = strlen (add); - new_value = XMALLOC (char, add_len + orig_value_len + 1); - if (to_end) - { - strcpy (new_value, orig_value); - strcpy (new_value + orig_value_len, add); - } - else - { - strcpy (new_value, add); - strcpy (new_value + add_len, orig_value); - } - } - else - { - new_value = xstrdup (add); - } - return new_value; -} - -void -lt_update_exe_path (const char *name, const char *value) -{ - lt_debugprintf (__FILE__, __LINE__, - "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", - nonnull (name), nonnull (value)); - - if (name && *name && value && *value) - { - char *new_value = lt_extend_str (getenv (name), value, 0); - /* some systems can't cope with a ':'-terminated path #' */ - int len = strlen (new_value); - while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) - { - new_value[len-1] = '\0'; - } - lt_setenv (name, new_value); - XFREE (new_value); - } -} - -void -lt_update_lib_path (const char *name, const char *value) -{ - lt_debugprintf (__FILE__, __LINE__, - "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", - nonnull (name), nonnull (value)); - - if (name && *name && value && *value) - { - char *new_value = lt_extend_str (getenv (name), value, 0); - lt_setenv (name, new_value); - XFREE (new_value); - } -} - -EOF - case $host_os in - mingw*) - cat <<"EOF" - -/* Prepares an argument vector before calling spawn(). - Note that spawn() does not by itself call the command interpreter - (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : - ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&v); - v.dwPlatformId == VER_PLATFORM_WIN32_NT; - }) ? "cmd.exe" : "command.com"). - Instead it simply concatenates the arguments, separated by ' ', and calls - CreateProcess(). We must quote the arguments since Win32 CreateProcess() - interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a - special way: - - Space and tab are interpreted as delimiters. They are not treated as - delimiters if they are surrounded by double quotes: "...". - - Unescaped double quotes are removed from the input. Their only effect is - that within double quotes, space and tab are treated like normal - characters. - - Backslashes not followed by double quotes are not special. - - But 2*n+1 backslashes followed by a double quote become - n backslashes followed by a double quote (n >= 0): - \" -> " - \\\" -> \" - \\\\\" -> \\" - */ -#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" -#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" -char ** -prepare_spawn (char **argv) -{ - size_t argc; - char **new_argv; - size_t i; - - /* Count number of arguments. */ - for (argc = 0; argv[argc] != NULL; argc++) - ; - - /* Allocate new argument vector. */ - new_argv = XMALLOC (char *, argc + 1); - - /* Put quoted arguments into the new argument vector. */ - for (i = 0; i < argc; i++) - { - const char *string = argv[i]; - - if (string[0] == '\0') - new_argv[i] = xstrdup ("\"\""); - else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) - { - int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); - size_t length; - unsigned int backslashes; - const char *s; - char *quoted_string; - char *p; - - length = 0; - backslashes = 0; - if (quote_around) - length++; - for (s = string; *s != '\0'; s++) - { - char c = *s; - if (c == '"') - length += backslashes + 1; - length++; - if (c == '\\') - backslashes++; - else - backslashes = 0; - } - if (quote_around) - length += backslashes + 1; - - quoted_string = XMALLOC (char, length + 1); - - p = quoted_string; - backslashes = 0; - if (quote_around) - *p++ = '"'; - for (s = string; *s != '\0'; s++) - { - char c = *s; - if (c == '"') - { - unsigned int j; - for (j = backslashes + 1; j > 0; j--) - *p++ = '\\'; - } - *p++ = c; - if (c == '\\') - backslashes++; - else - backslashes = 0; - } - if (quote_around) - { - unsigned int j; - for (j = backslashes; j > 0; j--) - *p++ = '\\'; - *p++ = '"'; - } - *p = '\0'; - - new_argv[i] = quoted_string; - } - else - new_argv[i] = (char *) string; - } - new_argv[argc] = NULL; - - return new_argv; -} -EOF - ;; - esac - - cat <<"EOF" -void lt_dump_script (FILE* f) -{ -EOF - func_emit_wrapper yes | - $SED -n -e ' -s/^\(.\{79\}\)\(..*\)/\1\ -\2/ -h -s/\([\\"]\)/\\\1/g -s/$/\\n/ -s/\([^\n]*\).*/ fputs ("\1", f);/p -g -D' - cat <<"EOF" -} -EOF -} -# end: func_emit_cwrapperexe_src - -# func_win32_import_lib_p ARG -# True if ARG is an import lib, as indicated by $file_magic_cmd -func_win32_import_lib_p () -{ - $opt_debug - case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in - *import*) : ;; - *) false ;; - esac -} - -# func_mode_link arg... -func_mode_link () -{ - $opt_debug - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) - # It is impossible to link a dll without this setting, and - # we shouldn't force the makefile maintainer to figure out - # which system we are compiling for in order to pass an extra - # flag for every libtool invocation. - # allow_undefined=no - - # FIXME: Unfortunately, there are problems with the above when trying - # to make a dll which has undefined symbols, in which case not - # even a static library is built. For now, we need to specify - # -no-undefined on the libtool link line when we can be certain - # that all symbols are satisfied, otherwise we get a static library. - allow_undefined=yes - ;; - *) - allow_undefined=yes - ;; - esac - libtool_args=$nonopt - base_compile="$nonopt $@" - compile_command=$nonopt - finalize_command=$nonopt - - compile_rpath= - finalize_rpath= - compile_shlibpath= - finalize_shlibpath= - convenience= - old_convenience= - deplibs= - old_deplibs= - compiler_flags= - linker_flags= - dllsearchpath= - lib_search_path=`pwd` - inst_prefix_dir= - new_inherited_linker_flags= - - avoid_version=no - bindir= - dlfiles= - dlprefiles= - dlself=no - export_dynamic=no - export_symbols= - export_symbols_regex= - generated= - libobjs= - ltlibs= - module=no - no_install=no - objs= - non_pic_objects= - precious_files_regex= - prefer_static_libs=no - preload=no - prev= - prevarg= - release= - rpath= - xrpath= - perm_rpath= - temp_rpath= - thread_safe=no - vinfo= - vinfo_number=no - weak_libs= - single_module="${wl}-single_module" - func_infer_tag $base_compile - - # We need to know -static, to get the right output filenames. - for arg - do - case $arg in - -shared) - test "$build_libtool_libs" != yes && \ - func_fatal_configuration "can not build a shared library" - build_old_libs=no - break - ;; - -all-static | -static | -static-libtool-libs) - case $arg in - -all-static) - if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then - func_warning "complete static linking is impossible in this configuration" - fi - if test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=yes - ;; - -static) - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=built - ;; - -static-libtool-libs) - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=yes - ;; - esac - build_libtool_libs=no - build_old_libs=yes - break - ;; - esac - done - - # See if our shared archives depend on static archives. - test -n "$old_archive_from_new_cmds" && build_old_libs=yes - - # Go through the arguments, transforming them on the way. - while test "$#" -gt 0; do - arg="$1" - shift - func_quote_for_eval "$arg" - qarg=$func_quote_for_eval_unquoted_result - func_append libtool_args " $func_quote_for_eval_result" - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - case $prev in - output) - func_append compile_command " @OUTPUT@" - func_append finalize_command " @OUTPUT@" - ;; - esac - - case $prev in - bindir) - bindir="$arg" - prev= - continue - ;; - dlfiles|dlprefiles) - if test "$preload" = no; then - # Add the symbol object into the linking commands. - func_append compile_command " @SYMFILE@" - func_append finalize_command " @SYMFILE@" - preload=yes - fi - case $arg in - *.la | *.lo) ;; # We handle these cases below. - force) - if test "$dlself" = no; then - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - self) - if test "$prev" = dlprefiles; then - dlself=yes - elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then - dlself=yes - else - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - *) - if test "$prev" = dlfiles; then - func_append dlfiles " $arg" - else - func_append dlprefiles " $arg" - fi - prev= - continue - ;; - esac - ;; - expsyms) - export_symbols="$arg" - test -f "$arg" \ - || func_fatal_error "symbol file \`$arg' does not exist" - prev= - continue - ;; - expsyms_regex) - export_symbols_regex="$arg" - prev= - continue - ;; - framework) - case $host in - *-*-darwin*) - case "$deplibs " in - *" $qarg.ltframework "*) ;; - *) func_append deplibs " $qarg.ltframework" # this is fixed later - ;; - esac - ;; - esac - prev= - continue - ;; - inst_prefix) - inst_prefix_dir="$arg" - prev= - continue - ;; - objectlist) - if test -f "$arg"; then - save_arg=$arg - moreargs= - for fil in `cat "$save_arg"` - do -# func_append moreargs " $fil" - arg=$fil - # A libtool-controlled object. - - # Check to see that this really is a libtool object. - if func_lalib_unsafe_p "$arg"; then - pic_object= - non_pic_object= - - # Read the .lo file - func_source "$arg" - - if test -z "$pic_object" || - test -z "$non_pic_object" || - test "$pic_object" = none && - test "$non_pic_object" = none; then - func_fatal_error "cannot find name of object for \`$arg'" - fi - - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir="$func_dirname_result" - - if test "$pic_object" != none; then - # Prepend the subdirectory the object is found in. - pic_object="$xdir$pic_object" - - if test "$prev" = dlfiles; then - if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then - func_append dlfiles " $pic_object" - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - # CHECK ME: I think I busted this. -Ossama - if test "$prev" = dlprefiles; then - # Preload the old-style object. - func_append dlprefiles " $pic_object" - prev= - fi - - # A PIC object. - func_append libobjs " $pic_object" - arg="$pic_object" - fi - - # Non-PIC object. - if test "$non_pic_object" != none; then - # Prepend the subdirectory the object is found in. - non_pic_object="$xdir$non_pic_object" - - # A standard non-PIC object - func_append non_pic_objects " $non_pic_object" - if test -z "$pic_object" || test "$pic_object" = none ; then - arg="$non_pic_object" - fi - else - # If the PIC object exists, use it instead. - # $xdir was prepended to $pic_object above. - non_pic_object="$pic_object" - func_append non_pic_objects " $non_pic_object" - fi - else - # Only an error if not doing a dry-run. - if $opt_dry_run; then - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir="$func_dirname_result" - - func_lo2o "$arg" - pic_object=$xdir$objdir/$func_lo2o_result - non_pic_object=$xdir$func_lo2o_result - func_append libobjs " $pic_object" - func_append non_pic_objects " $non_pic_object" - else - func_fatal_error "\`$arg' is not a valid libtool object" - fi - fi - done - else - func_fatal_error "link input file \`$arg' does not exist" - fi - arg=$save_arg - prev= - continue - ;; - precious_regex) - precious_files_regex="$arg" - prev= - continue - ;; - release) - release="-$arg" - prev= - continue - ;; - rpath | xrpath) - # We need an absolute path. - case $arg in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - func_fatal_error "only absolute run-paths are allowed" - ;; - esac - if test "$prev" = rpath; then - case "$rpath " in - *" $arg "*) ;; - *) func_append rpath " $arg" ;; - esac - else - case "$xrpath " in - *" $arg "*) ;; - *) func_append xrpath " $arg" ;; - esac - fi - prev= - continue - ;; - shrext) - shrext_cmds="$arg" - prev= - continue - ;; - weak) - func_append weak_libs " $arg" - prev= - continue - ;; - xcclinker) - func_append linker_flags " $qarg" - func_append compiler_flags " $qarg" - prev= - func_append compile_command " $qarg" - func_append finalize_command " $qarg" - continue - ;; - xcompiler) - func_append compiler_flags " $qarg" - prev= - func_append compile_command " $qarg" - func_append finalize_command " $qarg" - continue - ;; - xlinker) - func_append linker_flags " $qarg" - func_append compiler_flags " $wl$qarg" - prev= - func_append compile_command " $wl$qarg" - func_append finalize_command " $wl$qarg" - continue - ;; - *) - eval "$prev=\"\$arg\"" - prev= - continue - ;; - esac - fi # test -n "$prev" - - prevarg="$arg" - - case $arg in - -all-static) - if test -n "$link_static_flag"; then - # See comment for -static flag below, for more details. - func_append compile_command " $link_static_flag" - func_append finalize_command " $link_static_flag" - fi - continue - ;; - - -allow-undefined) - # FIXME: remove this flag sometime in the future. - func_fatal_error "\`-allow-undefined' must not be used because it is the default" - ;; - - -avoid-version) - avoid_version=yes - continue - ;; - - -bindir) - prev=bindir - continue - ;; - - -dlopen) - prev=dlfiles - continue - ;; - - -dlpreopen) - prev=dlprefiles - continue - ;; - - -export-dynamic) - export_dynamic=yes - continue - ;; - - -export-symbols | -export-symbols-regex) - if test -n "$export_symbols" || test -n "$export_symbols_regex"; then - func_fatal_error "more than one -exported-symbols argument is not allowed" - fi - if test "X$arg" = "X-export-symbols"; then - prev=expsyms - else - prev=expsyms_regex - fi - continue - ;; - - -framework) - prev=framework - continue - ;; - - -inst-prefix-dir) - prev=inst_prefix - continue - ;; - - # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* - # so, if we see these flags be careful not to treat them like -L - -L[A-Z][A-Z]*:*) - case $with_gcc/$host in - no/*-*-irix* | /*-*-irix*) - func_append compile_command " $arg" - func_append finalize_command " $arg" - ;; - esac - continue - ;; - - -L*) - func_stripname "-L" '' "$arg" - if test -z "$func_stripname_result"; then - if test "$#" -gt 0; then - func_fatal_error "require no space between \`-L' and \`$1'" - else - func_fatal_error "need path for \`-L' option" - fi - fi - func_resolve_sysroot "$func_stripname_result" - dir=$func_resolve_sysroot_result - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - absdir=`cd "$dir" && pwd` - test -z "$absdir" && \ - func_fatal_error "cannot determine absolute directory name of \`$dir'" - dir="$absdir" - ;; - esac - case "$deplibs " in - *" -L$dir "* | *" $arg "*) - # Will only happen for absolute or sysroot arguments - ;; - *) - # Preserve sysroot, but never include relative directories - case $dir in - [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; - *) func_append deplibs " -L$dir" ;; - esac - func_append lib_search_path " $dir" - ;; - esac - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) - testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` - case :$dllsearchpath: in - *":$dir:"*) ;; - ::) dllsearchpath=$dir;; - *) func_append dllsearchpath ":$dir";; - esac - case :$dllsearchpath: in - *":$testbindir:"*) ;; - ::) dllsearchpath=$testbindir;; - *) func_append dllsearchpath ":$testbindir";; - esac - ;; - esac - continue - ;; - - -l*) - if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) - # These systems don't actually have a C or math library (as such) - continue - ;; - *-*-os2*) - # These systems don't actually have a C library (as such) - test "X$arg" = "X-lc" && continue - ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) - # Do not include libc due to us having libc/libc_r. - test "X$arg" = "X-lc" && continue - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C and math libraries are in the System framework - func_append deplibs " System.ltframework" - continue - ;; - *-*-sco3.2v5* | *-*-sco5v6*) - # Causes problems with __ctype - test "X$arg" = "X-lc" && continue - ;; - *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) - # Compiler inserts libc in the correct place for threads to work - test "X$arg" = "X-lc" && continue - ;; - esac - elif test "X$arg" = "X-lc_r"; then - case $host in - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) - # Do not include libc_r directly, use -pthread flag. - continue - ;; - esac - fi - func_append deplibs " $arg" - continue - ;; - - -module) - module=yes - continue - ;; - - # Tru64 UNIX uses -model [arg] to determine the layout of C++ - # classes, name mangling, and exception handling. - # Darwin uses the -arch flag to determine output architecture. - -model|-arch|-isysroot|--sysroot) - func_append compiler_flags " $arg" - func_append compile_command " $arg" - func_append finalize_command " $arg" - prev=xcompiler - continue - ;; - - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ - |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) - func_append compiler_flags " $arg" - func_append compile_command " $arg" - func_append finalize_command " $arg" - case "$new_inherited_linker_flags " in - *" $arg "*) ;; - * ) func_append new_inherited_linker_flags " $arg" ;; - esac - continue - ;; - - -multi_module) - single_module="${wl}-multi_module" - continue - ;; - - -no-fast-install) - fast_install=no - continue - ;; - - -no-install) - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) - # The PATH hackery in wrapper scripts is required on Windows - # and Darwin in order for the loader to find any dlls it needs. - func_warning "\`-no-install' is ignored for $host" - func_warning "assuming \`-no-fast-install' instead" - fast_install=no - ;; - *) no_install=yes ;; - esac - continue - ;; - - -no-undefined) - allow_undefined=no - continue - ;; - - -objectlist) - prev=objectlist - continue - ;; - - -o) prev=output ;; - - -precious-files-regex) - prev=precious_regex - continue - ;; - - -release) - prev=release - continue - ;; - - -rpath) - prev=rpath - continue - ;; - - -R) - prev=xrpath - continue - ;; - - -R*) - func_stripname '-R' '' "$arg" - dir=$func_stripname_result - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - =*) - func_stripname '=' '' "$dir" - dir=$lt_sysroot$func_stripname_result - ;; - *) - func_fatal_error "only absolute run-paths are allowed" - ;; - esac - case "$xrpath " in - *" $dir "*) ;; - *) func_append xrpath " $dir" ;; - esac - continue - ;; - - -shared) - # The effects of -shared are defined in a previous loop. - continue - ;; - - -shrext) - prev=shrext - continue - ;; - - -static | -static-libtool-libs) - # The effects of -static are defined in a previous loop. - # We used to do the same as -all-static on platforms that - # didn't have a PIC flag, but the assumption that the effects - # would be equivalent was wrong. It would break on at least - # Digital Unix and AIX. - continue - ;; - - -thread-safe) - thread_safe=yes - continue - ;; - - -version-info) - prev=vinfo - continue - ;; - - -version-number) - prev=vinfo - vinfo_number=yes - continue - ;; - - -weak) - prev=weak - continue - ;; - - -Wc,*) - func_stripname '-Wc,' '' "$arg" - args=$func_stripname_result - arg= - save_ifs="$IFS"; IFS=',' - for flag in $args; do - IFS="$save_ifs" - func_quote_for_eval "$flag" - func_append arg " $func_quote_for_eval_result" - func_append compiler_flags " $func_quote_for_eval_result" - done - IFS="$save_ifs" - func_stripname ' ' '' "$arg" - arg=$func_stripname_result - ;; - - -Wl,*) - func_stripname '-Wl,' '' "$arg" - args=$func_stripname_result - arg= - save_ifs="$IFS"; IFS=',' - for flag in $args; do - IFS="$save_ifs" - func_quote_for_eval "$flag" - func_append arg " $wl$func_quote_for_eval_result" - func_append compiler_flags " $wl$func_quote_for_eval_result" - func_append linker_flags " $func_quote_for_eval_result" - done - IFS="$save_ifs" - func_stripname ' ' '' "$arg" - arg=$func_stripname_result - ;; - - -Xcompiler) - prev=xcompiler - continue - ;; - - -Xlinker) - prev=xlinker - continue - ;; - - -XCClinker) - prev=xcclinker - continue - ;; - - # -msg_* for osf cc - -msg_*) - func_quote_for_eval "$arg" - arg="$func_quote_for_eval_result" - ;; - - # Flags to be passed through unchanged, with rationale: - # -64, -mips[0-9] enable 64-bit mode for the SGI compiler - # -r[0-9][0-9]* specify processor for the SGI compiler - # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler - # +DA*, +DD* enable 64-bit mode for the HP compiler - # -q* compiler args for the IBM compiler - # -m*, -t[45]*, -txscale* architecture-specific flags for GCC - # -F/path path to uninstalled frameworks, gcc on darwin - # -p, -pg, --coverage, -fprofile-* profiling flags for GCC - # @file GCC response files - # -tp=* Portland pgcc target processor selection - # --sysroot=* for sysroot support - # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization - -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ - -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ - -O*|-flto*|-fwhopr*|-fuse-linker-plugin) - func_quote_for_eval "$arg" - arg="$func_quote_for_eval_result" - func_append compile_command " $arg" - func_append finalize_command " $arg" - func_append compiler_flags " $arg" - continue - ;; - - # Some other compiler flag. - -* | +*) - func_quote_for_eval "$arg" - arg="$func_quote_for_eval_result" - ;; - - *.$objext) - # A standard object. - func_append objs " $arg" - ;; - - *.lo) - # A libtool-controlled object. - - # Check to see that this really is a libtool object. - if func_lalib_unsafe_p "$arg"; then - pic_object= - non_pic_object= - - # Read the .lo file - func_source "$arg" - - if test -z "$pic_object" || - test -z "$non_pic_object" || - test "$pic_object" = none && - test "$non_pic_object" = none; then - func_fatal_error "cannot find name of object for \`$arg'" - fi - - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir="$func_dirname_result" - - if test "$pic_object" != none; then - # Prepend the subdirectory the object is found in. - pic_object="$xdir$pic_object" - - if test "$prev" = dlfiles; then - if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then - func_append dlfiles " $pic_object" - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - # CHECK ME: I think I busted this. -Ossama - if test "$prev" = dlprefiles; then - # Preload the old-style object. - func_append dlprefiles " $pic_object" - prev= - fi - - # A PIC object. - func_append libobjs " $pic_object" - arg="$pic_object" - fi - - # Non-PIC object. - if test "$non_pic_object" != none; then - # Prepend the subdirectory the object is found in. - non_pic_object="$xdir$non_pic_object" - - # A standard non-PIC object - func_append non_pic_objects " $non_pic_object" - if test -z "$pic_object" || test "$pic_object" = none ; then - arg="$non_pic_object" - fi - else - # If the PIC object exists, use it instead. - # $xdir was prepended to $pic_object above. - non_pic_object="$pic_object" - func_append non_pic_objects " $non_pic_object" - fi - else - # Only an error if not doing a dry-run. - if $opt_dry_run; then - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir="$func_dirname_result" - - func_lo2o "$arg" - pic_object=$xdir$objdir/$func_lo2o_result - non_pic_object=$xdir$func_lo2o_result - func_append libobjs " $pic_object" - func_append non_pic_objects " $non_pic_object" - else - func_fatal_error "\`$arg' is not a valid libtool object" - fi - fi - ;; - - *.$libext) - # An archive. - func_append deplibs " $arg" - func_append old_deplibs " $arg" - continue - ;; - - *.la) - # A libtool-controlled library. - - func_resolve_sysroot "$arg" - if test "$prev" = dlfiles; then - # This library was specified with -dlopen. - func_append dlfiles " $func_resolve_sysroot_result" - prev= - elif test "$prev" = dlprefiles; then - # The library was specified with -dlpreopen. - func_append dlprefiles " $func_resolve_sysroot_result" - prev= - else - func_append deplibs " $func_resolve_sysroot_result" - fi - continue - ;; - - # Some other compiler argument. - *) - # Unknown arguments in both finalize_command and compile_command need - # to be aesthetically quoted because they are evaled later. - func_quote_for_eval "$arg" - arg="$func_quote_for_eval_result" - ;; - esac # arg - - # Now actually substitute the argument into the commands. - if test -n "$arg"; then - func_append compile_command " $arg" - func_append finalize_command " $arg" - fi - done # argument parsing loop - - test -n "$prev" && \ - func_fatal_help "the \`$prevarg' option requires an argument" - - if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then - eval arg=\"$export_dynamic_flag_spec\" - func_append compile_command " $arg" - func_append finalize_command " $arg" - fi - - oldlibs= - # calculate the name of the file, without its directory - func_basename "$output" - outputname="$func_basename_result" - libobjs_save="$libobjs" - - if test -n "$shlibpath_var"; then - # get the directories listed in $shlibpath_var - eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` - else - shlib_search_path= - fi - eval sys_lib_search_path=\"$sys_lib_search_path_spec\" - eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" - - func_dirname "$output" "/" "" - output_objdir="$func_dirname_result$objdir" - func_to_tool_file "$output_objdir/" - tool_output_objdir=$func_to_tool_file_result - # Create the object directory. - func_mkdir_p "$output_objdir" - - # Determine the type of output - case $output in - "") - func_fatal_help "you must specify an output file" - ;; - *.$libext) linkmode=oldlib ;; - *.lo | *.$objext) linkmode=obj ;; - *.la) linkmode=lib ;; - *) linkmode=prog ;; # Anything else should be a program. - esac - - specialdeplibs= - - libs= - # Find all interdependent deplibs by searching for libraries - # that are linked more than once (e.g. -la -lb -la) - for deplib in $deplibs; do - if $opt_preserve_dup_deps ; then - case "$libs " in - *" $deplib "*) func_append specialdeplibs " $deplib" ;; - esac - fi - func_append libs " $deplib" - done - - if test "$linkmode" = lib; then - libs="$predeps $libs $compiler_lib_search_path $postdeps" - - # Compute libraries that are listed more than once in $predeps - # $postdeps and mark them as special (i.e., whose duplicates are - # not to be eliminated). - pre_post_deps= - if $opt_duplicate_compiler_generated_deps; then - for pre_post_dep in $predeps $postdeps; do - case "$pre_post_deps " in - *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; - esac - func_append pre_post_deps " $pre_post_dep" - done - fi - pre_post_deps= - fi - - deplibs= - newdependency_libs= - newlib_search_path= - need_relink=no # whether we're linking any uninstalled libtool libraries - notinst_deplibs= # not-installed libtool libraries - notinst_path= # paths that contain not-installed libtool libraries - - case $linkmode in - lib) - passes="conv dlpreopen link" - for file in $dlfiles $dlprefiles; do - case $file in - *.la) ;; - *) - func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" - ;; - esac - done - ;; - prog) - compile_deplibs= - finalize_deplibs= - alldeplibs=no - newdlfiles= - newdlprefiles= - passes="conv scan dlopen dlpreopen link" - ;; - *) passes="conv" - ;; - esac - - for pass in $passes; do - # The preopen pass in lib mode reverses $deplibs; put it back here - # so that -L comes before libs that need it for instance... - if test "$linkmode,$pass" = "lib,link"; then - ## FIXME: Find the place where the list is rebuilt in the wrong - ## order, and fix it there properly - tmp_deplibs= - for deplib in $deplibs; do - tmp_deplibs="$deplib $tmp_deplibs" - done - deplibs="$tmp_deplibs" - fi - - if test "$linkmode,$pass" = "lib,link" || - test "$linkmode,$pass" = "prog,scan"; then - libs="$deplibs" - deplibs= - fi - if test "$linkmode" = prog; then - case $pass in - dlopen) libs="$dlfiles" ;; - dlpreopen) libs="$dlprefiles" ;; - link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; - esac - fi - if test "$linkmode,$pass" = "lib,dlpreopen"; then - # Collect and forward deplibs of preopened libtool libs - for lib in $dlprefiles; do - # Ignore non-libtool-libs - dependency_libs= - func_resolve_sysroot "$lib" - case $lib in - *.la) func_source "$func_resolve_sysroot_result" ;; - esac - - # Collect preopened libtool deplibs, except any this library - # has declared as weak libs - for deplib in $dependency_libs; do - func_basename "$deplib" - deplib_base=$func_basename_result - case " $weak_libs " in - *" $deplib_base "*) ;; - *) func_append deplibs " $deplib" ;; - esac - done - done - libs="$dlprefiles" - fi - if test "$pass" = dlopen; then - # Collect dlpreopened libraries - save_deplibs="$deplibs" - deplibs= - fi - - for deplib in $libs; do - lib= - found=no - case $deplib in - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ - |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - func_append compiler_flags " $deplib" - if test "$linkmode" = lib ; then - case "$new_inherited_linker_flags " in - *" $deplib "*) ;; - * ) func_append new_inherited_linker_flags " $deplib" ;; - esac - fi - fi - continue - ;; - -l*) - if test "$linkmode" != lib && test "$linkmode" != prog; then - func_warning "\`-l' is ignored for archives/objects" - continue - fi - func_stripname '-l' '' "$deplib" - name=$func_stripname_result - if test "$linkmode" = lib; then - searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" - else - searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" - fi - for searchdir in $searchdirs; do - for search_ext in .la $std_shrext .so .a; do - # Search the libtool library - lib="$searchdir/lib${name}${search_ext}" - if test -f "$lib"; then - if test "$search_ext" = ".la"; then - found=yes - else - found=no - fi - break 2 - fi - done - done - if test "$found" != yes; then - # deplib doesn't seem to be a libtool library - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" - fi - continue - else # deplib is a libtool library - # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, - # We need to do some special things here, and not later. - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $deplib "*) - if func_lalib_p "$lib"; then - library_names= - old_library= - func_source "$lib" - for l in $old_library $library_names; do - ll="$l" - done - if test "X$ll" = "X$old_library" ; then # only static version available - found=no - func_dirname "$lib" "" "." - ladir="$func_dirname_result" - lib=$ladir/$old_library - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" - fi - continue - fi - fi - ;; - *) ;; - esac - fi - fi - ;; # -l - *.ltframework) - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - if test "$linkmode" = lib ; then - case "$new_inherited_linker_flags " in - *" $deplib "*) ;; - * ) func_append new_inherited_linker_flags " $deplib" ;; - esac - fi - fi - continue - ;; - -L*) - case $linkmode in - lib) - deplibs="$deplib $deplibs" - test "$pass" = conv && continue - newdependency_libs="$deplib $newdependency_libs" - func_stripname '-L' '' "$deplib" - func_resolve_sysroot "$func_stripname_result" - func_append newlib_search_path " $func_resolve_sysroot_result" - ;; - prog) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - continue - fi - if test "$pass" = scan; then - deplibs="$deplib $deplibs" - else - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - fi - func_stripname '-L' '' "$deplib" - func_resolve_sysroot "$func_stripname_result" - func_append newlib_search_path " $func_resolve_sysroot_result" - ;; - *) - func_warning "\`-L' is ignored for archives/objects" - ;; - esac # linkmode - continue - ;; # -L - -R*) - if test "$pass" = link; then - func_stripname '-R' '' "$deplib" - func_resolve_sysroot "$func_stripname_result" - dir=$func_resolve_sysroot_result - # Make sure the xrpath contains only unique directories. - case "$xrpath " in - *" $dir "*) ;; - *) func_append xrpath " $dir" ;; - esac - fi - deplibs="$deplib $deplibs" - continue - ;; - *.la) - func_resolve_sysroot "$deplib" - lib=$func_resolve_sysroot_result - ;; - *.$libext) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - continue - fi - case $linkmode in - lib) - # Linking convenience modules into shared libraries is allowed, - # but linking other static libraries is non-portable. - case " $dlpreconveniencelibs " in - *" $deplib "*) ;; - *) - valid_a_lib=no - case $deplibs_check_method in - match_pattern*) - set dummy $deplibs_check_method; shift - match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` - if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ - | $EGREP "$match_pattern_regex" > /dev/null; then - valid_a_lib=yes - fi - ;; - pass_all) - valid_a_lib=yes - ;; - esac - if test "$valid_a_lib" != yes; then - echo - $ECHO "*** Warning: Trying to link with static lib archive $deplib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have" - echo "*** because the file extensions .$libext of this argument makes me believe" - echo "*** that it is just a static archive that I should not use here." - else - echo - $ECHO "*** Warning: Linking the shared library $output against the" - $ECHO "*** static library $deplib is not portable!" - deplibs="$deplib $deplibs" - fi - ;; - esac - continue - ;; - prog) - if test "$pass" != link; then - deplibs="$deplib $deplibs" - else - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - fi - continue - ;; - esac # linkmode - ;; # *.$libext - *.lo | *.$objext) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - elif test "$linkmode" = prog; then - if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then - # If there is no dlopen support or we're linking statically, - # we need to preload. - func_append newdlprefiles " $deplib" - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - func_append newdlfiles " $deplib" - fi - fi - continue - ;; - %DEPLIBS%) - alldeplibs=yes - continue - ;; - esac # case $deplib - - if test "$found" = yes || test -f "$lib"; then : - else - func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" - fi - - # Check to see that this really is a libtool archive. - func_lalib_unsafe_p "$lib" \ - || func_fatal_error "\`$lib' is not a valid libtool archive" - - func_dirname "$lib" "" "." - ladir="$func_dirname_result" - - dlname= - dlopen= - dlpreopen= - libdir= - library_names= - old_library= - inherited_linker_flags= - # If the library was installed with an old release of libtool, - # it will not redefine variables installed, or shouldnotlink - installed=yes - shouldnotlink=no - avoidtemprpath= - - - # Read the .la file - func_source "$lib" - - # Convert "-framework foo" to "foo.ltframework" - if test -n "$inherited_linker_flags"; then - tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` - for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do - case " $new_inherited_linker_flags " in - *" $tmp_inherited_linker_flag "*) ;; - *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; - esac - done - fi - dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - if test "$linkmode,$pass" = "lib,link" || - test "$linkmode,$pass" = "prog,scan" || - { test "$linkmode" != prog && test "$linkmode" != lib; }; then - test -n "$dlopen" && func_append dlfiles " $dlopen" - test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" - fi - - if test "$pass" = conv; then - # Only check for convenience libraries - deplibs="$lib $deplibs" - if test -z "$libdir"; then - if test -z "$old_library"; then - func_fatal_error "cannot find name of link library for \`$lib'" - fi - # It is a libtool convenience library, so add in its objects. - func_append convenience " $ladir/$objdir/$old_library" - func_append old_convenience " $ladir/$objdir/$old_library" - elif test "$linkmode" != prog && test "$linkmode" != lib; then - func_fatal_error "\`$lib' is not a convenience library" - fi - tmp_libs= - for deplib in $dependency_libs; do - deplibs="$deplib $deplibs" - if $opt_preserve_dup_deps ; then - case "$tmp_libs " in - *" $deplib "*) func_append specialdeplibs " $deplib" ;; - esac - fi - func_append tmp_libs " $deplib" - done - continue - fi # $pass = conv - - - # Get the name of the library we link against. - linklib= - if test -n "$old_library" && - { test "$prefer_static_libs" = yes || - test "$prefer_static_libs,$installed" = "built,no"; }; then - linklib=$old_library - else - for l in $old_library $library_names; do - linklib="$l" - done - fi - if test -z "$linklib"; then - func_fatal_error "cannot find name of link library for \`$lib'" - fi - - # This library was specified with -dlopen. - if test "$pass" = dlopen; then - if test -z "$libdir"; then - func_fatal_error "cannot -dlopen a convenience library: \`$lib'" - fi - if test -z "$dlname" || - test "$dlopen_support" != yes || - test "$build_libtool_libs" = no; then - # If there is no dlname, no dlopen support or we're linking - # statically, we need to preload. We also need to preload any - # dependent libraries so libltdl's deplib preloader doesn't - # bomb out in the load deplibs phase. - func_append dlprefiles " $lib $dependency_libs" - else - func_append newdlfiles " $lib" - fi - continue - fi # $pass = dlopen - - # We need an absolute path. - case $ladir in - [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; - *) - abs_ladir=`cd "$ladir" && pwd` - if test -z "$abs_ladir"; then - func_warning "cannot determine absolute directory name of \`$ladir'" - func_warning "passing it literally to the linker, although it might fail" - abs_ladir="$ladir" - fi - ;; - esac - func_basename "$lib" - laname="$func_basename_result" - - # Find the relevant object directory and library name. - if test "X$installed" = Xyes; then - if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then - #func_warning "library \`$lib' was moved." - dir="$ladir" - absdir="$abs_ladir" - libdir="$abs_ladir" - else - dir="$lt_sysroot$libdir" - absdir="$lt_sysroot$libdir" - fi - test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes - else - if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then - dir="$ladir" - absdir="$abs_ladir" - # Remove this search path later - func_append notinst_path " $abs_ladir" - else - dir="$ladir/$objdir" - absdir="$abs_ladir/$objdir" - # Remove this search path later - func_append notinst_path " $abs_ladir" - fi - fi # $installed = yes - func_stripname 'lib' '.la' "$laname" - name=$func_stripname_result - - # This library was specified with -dlpreopen. - if test "$pass" = dlpreopen; then - if test -z "$libdir" && test "$linkmode" = prog; then - func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" - fi - case "$host" in - # special handling for platforms with PE-DLLs. - *cygwin* | *mingw* | *cegcc* ) - # Linker will automatically link against shared library if both - # static and shared are present. Therefore, ensure we extract - # symbols from the import library if a shared library is present - # (otherwise, the dlopen module name will be incorrect). We do - # this by putting the import library name into $newdlprefiles. - # We recover the dlopen module name by 'saving' the la file - # name in a special purpose variable, and (later) extracting the - # dlname from the la file. - if test -n "$dlname"; then - func_tr_sh "$dir/$linklib" - eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" - func_append newdlprefiles " $dir/$linklib" - else - func_append newdlprefiles " $dir/$old_library" - # Keep a list of preopened convenience libraries to check - # that they are being used correctly in the link pass. - test -z "$libdir" && \ - func_append dlpreconveniencelibs " $dir/$old_library" - fi - ;; - * ) - # Prefer using a static library (so that no silly _DYNAMIC symbols - # are required to link). - if test -n "$old_library"; then - func_append newdlprefiles " $dir/$old_library" - # Keep a list of preopened convenience libraries to check - # that they are being used correctly in the link pass. - test -z "$libdir" && \ - func_append dlpreconveniencelibs " $dir/$old_library" - # Otherwise, use the dlname, so that lt_dlopen finds it. - elif test -n "$dlname"; then - func_append newdlprefiles " $dir/$dlname" - else - func_append newdlprefiles " $dir/$linklib" - fi - ;; - esac - fi # $pass = dlpreopen - - if test -z "$libdir"; then - # Link the convenience library - if test "$linkmode" = lib; then - deplibs="$dir/$old_library $deplibs" - elif test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$dir/$old_library $compile_deplibs" - finalize_deplibs="$dir/$old_library $finalize_deplibs" - else - deplibs="$lib $deplibs" # used for prog,scan pass - fi - continue - fi - - - if test "$linkmode" = prog && test "$pass" != link; then - func_append newlib_search_path " $ladir" - deplibs="$lib $deplibs" - - linkalldeplibs=no - if test "$link_all_deplibs" != no || test -z "$library_names" || - test "$build_libtool_libs" = no; then - linkalldeplibs=yes - fi - - tmp_libs= - for deplib in $dependency_libs; do - case $deplib in - -L*) func_stripname '-L' '' "$deplib" - func_resolve_sysroot "$func_stripname_result" - func_append newlib_search_path " $func_resolve_sysroot_result" - ;; - esac - # Need to link against all dependency_libs? - if test "$linkalldeplibs" = yes; then - deplibs="$deplib $deplibs" - else - # Need to hardcode shared library paths - # or/and link against static libraries - newdependency_libs="$deplib $newdependency_libs" - fi - if $opt_preserve_dup_deps ; then - case "$tmp_libs " in - *" $deplib "*) func_append specialdeplibs " $deplib" ;; - esac - fi - func_append tmp_libs " $deplib" - done # for deplib - continue - fi # $linkmode = prog... - - if test "$linkmode,$pass" = "prog,link"; then - if test -n "$library_names" && - { { test "$prefer_static_libs" = no || - test "$prefer_static_libs,$installed" = "built,yes"; } || - test -z "$old_library"; }; then - # We need to hardcode the library path - if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then - # Make sure the rpath contains only unique directories. - case "$temp_rpath:" in - *"$absdir:"*) ;; - *) func_append temp_rpath "$absdir:" ;; - esac - fi - - # Hardcode the library path. - # Skip directories that are in the system default run-time - # search path. - case " $sys_lib_dlsearch_path " in - *" $absdir "*) ;; - *) - case "$compile_rpath " in - *" $absdir "*) ;; - *) func_append compile_rpath " $absdir" ;; - esac - ;; - esac - case " $sys_lib_dlsearch_path " in - *" $libdir "*) ;; - *) - case "$finalize_rpath " in - *" $libdir "*) ;; - *) func_append finalize_rpath " $libdir" ;; - esac - ;; - esac - fi # $linkmode,$pass = prog,link... - - if test "$alldeplibs" = yes && - { test "$deplibs_check_method" = pass_all || - { test "$build_libtool_libs" = yes && - test -n "$library_names"; }; }; then - # We only need to search for static libraries - continue - fi - fi - - link_static=no # Whether the deplib will be linked statically - use_static_libs=$prefer_static_libs - if test "$use_static_libs" = built && test "$installed" = yes; then - use_static_libs=no - fi - if test -n "$library_names" && - { test "$use_static_libs" = no || test -z "$old_library"; }; then - case $host in - *cygwin* | *mingw* | *cegcc*) - # No point in relinking DLLs because paths are not encoded - func_append notinst_deplibs " $lib" - need_relink=no - ;; - *) - if test "$installed" = no; then - func_append notinst_deplibs " $lib" - need_relink=yes - fi - ;; - esac - # This is a shared library - - # Warn about portability, can't link against -module's on some - # systems (darwin). Don't bleat about dlopened modules though! - dlopenmodule="" - for dlpremoduletest in $dlprefiles; do - if test "X$dlpremoduletest" = "X$lib"; then - dlopenmodule="$dlpremoduletest" - break - fi - done - if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then - echo - if test "$linkmode" = prog; then - $ECHO "*** Warning: Linking the executable $output against the loadable module" - else - $ECHO "*** Warning: Linking the shared library $output against the loadable module" - fi - $ECHO "*** $linklib is not portable!" - fi - if test "$linkmode" = lib && - test "$hardcode_into_libs" = yes; then - # Hardcode the library path. - # Skip directories that are in the system default run-time - # search path. - case " $sys_lib_dlsearch_path " in - *" $absdir "*) ;; - *) - case "$compile_rpath " in - *" $absdir "*) ;; - *) func_append compile_rpath " $absdir" ;; - esac - ;; - esac - case " $sys_lib_dlsearch_path " in - *" $libdir "*) ;; - *) - case "$finalize_rpath " in - *" $libdir "*) ;; - *) func_append finalize_rpath " $libdir" ;; - esac - ;; - esac - fi - - if test -n "$old_archive_from_expsyms_cmds"; then - # figure out the soname - set dummy $library_names - shift - realname="$1" - shift - libname=`eval "\\$ECHO \"$libname_spec\""` - # use dlname if we got it. it's perfectly good, no? - if test -n "$dlname"; then - soname="$dlname" - elif test -n "$soname_spec"; then - # bleh windows - case $host in - *cygwin* | mingw* | *cegcc*) - func_arith $current - $age - major=$func_arith_result - versuffix="-$major" - ;; - esac - eval soname=\"$soname_spec\" - else - soname="$realname" - fi - - # Make a new name for the extract_expsyms_cmds to use - soroot="$soname" - func_basename "$soroot" - soname="$func_basename_result" - func_stripname 'lib' '.dll' "$soname" - newlib=libimp-$func_stripname_result.a - - # If the library has no export list, then create one now - if test -f "$output_objdir/$soname-def"; then : - else - func_verbose "extracting exported symbol list from \`$soname'" - func_execute_cmds "$extract_expsyms_cmds" 'exit $?' - fi - - # Create $newlib - if test -f "$output_objdir/$newlib"; then :; else - func_verbose "generating import library for \`$soname'" - func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' - fi - # make sure the library variables are pointing to the new library - dir=$output_objdir - linklib=$newlib - fi # test -n "$old_archive_from_expsyms_cmds" - - if test "$linkmode" = prog || test "$opt_mode" != relink; then - add_shlibpath= - add_dir= - add= - lib_linked=yes - case $hardcode_action in - immediate | unsupported) - if test "$hardcode_direct" = no; then - add="$dir/$linklib" - case $host in - *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; - *-*-sysv4*uw2*) add_dir="-L$dir" ;; - *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ - *-*-unixware7*) add_dir="-L$dir" ;; - *-*-darwin* ) - # if the lib is a (non-dlopened) module then we can not - # link against it, someone is ignoring the earlier warnings - if /usr/bin/file -L $add 2> /dev/null | - $GREP ": [^:]* bundle" >/dev/null ; then - if test "X$dlopenmodule" != "X$lib"; then - $ECHO "*** Warning: lib $linklib is a module, not a shared library" - if test -z "$old_library" ; then - echo - echo "*** And there doesn't seem to be a static archive available" - echo "*** The link will probably fail, sorry" - else - add="$dir/$old_library" - fi - elif test -n "$old_library"; then - add="$dir/$old_library" - fi - fi - esac - elif test "$hardcode_minus_L" = no; then - case $host in - *-*-sunos*) add_shlibpath="$dir" ;; - esac - add_dir="-L$dir" - add="-l$name" - elif test "$hardcode_shlibpath_var" = no; then - add_shlibpath="$dir" - add="-l$name" - else - lib_linked=no - fi - ;; - relink) - if test "$hardcode_direct" = yes && - test "$hardcode_direct_absolute" = no; then - add="$dir/$linklib" - elif test "$hardcode_minus_L" = yes; then - add_dir="-L$absdir" - # Try looking first in the location we're being installed to. - if test -n "$inst_prefix_dir"; then - case $libdir in - [\\/]*) - func_append add_dir " -L$inst_prefix_dir$libdir" - ;; - esac - fi - add="-l$name" - elif test "$hardcode_shlibpath_var" = yes; then - add_shlibpath="$dir" - add="-l$name" - else - lib_linked=no - fi - ;; - *) lib_linked=no ;; - esac - - if test "$lib_linked" != yes; then - func_fatal_configuration "unsupported hardcode properties" - fi - - if test -n "$add_shlibpath"; then - case :$compile_shlibpath: in - *":$add_shlibpath:"*) ;; - *) func_append compile_shlibpath "$add_shlibpath:" ;; - esac - fi - if test "$linkmode" = prog; then - test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" - test -n "$add" && compile_deplibs="$add $compile_deplibs" - else - test -n "$add_dir" && deplibs="$add_dir $deplibs" - test -n "$add" && deplibs="$add $deplibs" - if test "$hardcode_direct" != yes && - test "$hardcode_minus_L" != yes && - test "$hardcode_shlibpath_var" = yes; then - case :$finalize_shlibpath: in - *":$libdir:"*) ;; - *) func_append finalize_shlibpath "$libdir:" ;; - esac - fi - fi - fi - - if test "$linkmode" = prog || test "$opt_mode" = relink; then - add_shlibpath= - add_dir= - add= - # Finalize command for both is simple: just hardcode it. - if test "$hardcode_direct" = yes && - test "$hardcode_direct_absolute" = no; then - add="$libdir/$linklib" - elif test "$hardcode_minus_L" = yes; then - add_dir="-L$libdir" - add="-l$name" - elif test "$hardcode_shlibpath_var" = yes; then - case :$finalize_shlibpath: in - *":$libdir:"*) ;; - *) func_append finalize_shlibpath "$libdir:" ;; - esac - add="-l$name" - elif test "$hardcode_automatic" = yes; then - if test -n "$inst_prefix_dir" && - test -f "$inst_prefix_dir$libdir/$linklib" ; then - add="$inst_prefix_dir$libdir/$linklib" - else - add="$libdir/$linklib" - fi - else - # We cannot seem to hardcode it, guess we'll fake it. - add_dir="-L$libdir" - # Try looking first in the location we're being installed to. - if test -n "$inst_prefix_dir"; then - case $libdir in - [\\/]*) - func_append add_dir " -L$inst_prefix_dir$libdir" - ;; - esac - fi - add="-l$name" - fi - - if test "$linkmode" = prog; then - test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" - test -n "$add" && finalize_deplibs="$add $finalize_deplibs" - else - test -n "$add_dir" && deplibs="$add_dir $deplibs" - test -n "$add" && deplibs="$add $deplibs" - fi - fi - elif test "$linkmode" = prog; then - # Here we assume that one of hardcode_direct or hardcode_minus_L - # is not unsupported. This is valid on all known static and - # shared platforms. - if test "$hardcode_direct" != unsupported; then - test -n "$old_library" && linklib="$old_library" - compile_deplibs="$dir/$linklib $compile_deplibs" - finalize_deplibs="$dir/$linklib $finalize_deplibs" - else - compile_deplibs="-l$name -L$dir $compile_deplibs" - finalize_deplibs="-l$name -L$dir $finalize_deplibs" - fi - elif test "$build_libtool_libs" = yes; then - # Not a shared library - if test "$deplibs_check_method" != pass_all; then - # We're trying link a shared library against a static one - # but the system doesn't support it. - - # Just print a warning and add the library to dependency_libs so - # that the program can be linked against the static library. - echo - $ECHO "*** Warning: This system can not link to static lib archive $lib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have." - if test "$module" = yes; then - echo "*** But as you try to build a module library, libtool will still create " - echo "*** a static module, that should work as long as the dlopening application" - echo "*** is linked with the -dlopen flag to resolve symbols at runtime." - if test -z "$global_symbol_pipe"; then - echo - echo "*** However, this would only work if libtool was able to extract symbol" - echo "*** lists from a program, using \`nm' or equivalent, but libtool could" - echo "*** not find such a program. So, this module is probably useless." - echo "*** \`nm' from GNU binutils and a full rebuild may help." - fi - if test "$build_old_libs" = no; then - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - else - deplibs="$dir/$old_library $deplibs" - link_static=yes - fi - fi # link shared/static library? - - if test "$linkmode" = lib; then - if test -n "$dependency_libs" && - { test "$hardcode_into_libs" != yes || - test "$build_old_libs" = yes || - test "$link_static" = yes; }; then - # Extract -R from dependency_libs - temp_deplibs= - for libdir in $dependency_libs; do - case $libdir in - -R*) func_stripname '-R' '' "$libdir" - temp_xrpath=$func_stripname_result - case " $xrpath " in - *" $temp_xrpath "*) ;; - *) func_append xrpath " $temp_xrpath";; - esac;; - *) func_append temp_deplibs " $libdir";; - esac - done - dependency_libs="$temp_deplibs" - fi - - func_append newlib_search_path " $absdir" - # Link against this library - test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" - # ... and its dependency_libs - tmp_libs= - for deplib in $dependency_libs; do - newdependency_libs="$deplib $newdependency_libs" - case $deplib in - -L*) func_stripname '-L' '' "$deplib" - func_resolve_sysroot "$func_stripname_result";; - *) func_resolve_sysroot "$deplib" ;; - esac - if $opt_preserve_dup_deps ; then - case "$tmp_libs " in - *" $func_resolve_sysroot_result "*) - func_append specialdeplibs " $func_resolve_sysroot_result" ;; - esac - fi - func_append tmp_libs " $func_resolve_sysroot_result" - done - - if test "$link_all_deplibs" != no; then - # Add the search paths of all dependency libraries - for deplib in $dependency_libs; do - path= - case $deplib in - -L*) path="$deplib" ;; - *.la) - func_resolve_sysroot "$deplib" - deplib=$func_resolve_sysroot_result - func_dirname "$deplib" "" "." - dir=$func_dirname_result - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; - *) - absdir=`cd "$dir" && pwd` - if test -z "$absdir"; then - func_warning "cannot determine absolute directory name of \`$dir'" - absdir="$dir" - fi - ;; - esac - if $GREP "^installed=no" $deplib > /dev/null; then - case $host in - *-*-darwin*) - depdepl= - eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` - if test -n "$deplibrary_names" ; then - for tmp in $deplibrary_names ; do - depdepl=$tmp - done - if test -f "$absdir/$objdir/$depdepl" ; then - depdepl="$absdir/$objdir/$depdepl" - darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` - if test -z "$darwin_install_name"; then - darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` - fi - func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" - func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" - path= - fi - fi - ;; - *) - path="-L$absdir/$objdir" - ;; - esac - else - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` - test -z "$libdir" && \ - func_fatal_error "\`$deplib' is not a valid libtool archive" - #test "$absdir" != "$libdir" && \ - # func_warning "\`$deplib' seems to be moved" - - path="-L$absdir" - fi - ;; - esac - case " $deplibs " in - *" $path "*) ;; - *) deplibs="$path $deplibs" ;; - esac - done - fi # link_all_deplibs != no - fi # linkmode = lib - done # for deplib in $libs - if test "$pass" = link; then - if test "$linkmode" = "prog"; then - compile_deplibs="$new_inherited_linker_flags $compile_deplibs" - finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" - else - compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - fi - fi - dependency_libs="$newdependency_libs" - if test "$pass" = dlpreopen; then - # Link the dlpreopened libraries before other libraries - for deplib in $save_deplibs; do - deplibs="$deplib $deplibs" - done - fi - if test "$pass" != dlopen; then - if test "$pass" != conv; then - # Make sure lib_search_path contains only unique directories. - lib_search_path= - for dir in $newlib_search_path; do - case "$lib_search_path " in - *" $dir "*) ;; - *) func_append lib_search_path " $dir" ;; - esac - done - newlib_search_path= - fi - - if test "$linkmode,$pass" != "prog,link"; then - vars="deplibs" - else - vars="compile_deplibs finalize_deplibs" - fi - for var in $vars dependency_libs; do - # Add libraries to $var in reverse order - eval tmp_libs=\"\$$var\" - new_libs= - for deplib in $tmp_libs; do - # FIXME: Pedantically, this is the right thing to do, so - # that some nasty dependency loop isn't accidentally - # broken: - #new_libs="$deplib $new_libs" - # Pragmatically, this seems to cause very few problems in - # practice: - case $deplib in - -L*) new_libs="$deplib $new_libs" ;; - -R*) ;; - *) - # And here is the reason: when a library appears more - # than once as an explicit dependence of a library, or - # is implicitly linked in more than once by the - # compiler, it is considered special, and multiple - # occurrences thereof are not removed. Compare this - # with having the same library being listed as a - # dependency of multiple other libraries: in this case, - # we know (pedantically, we assume) the library does not - # need to be listed more than once, so we keep only the - # last copy. This is not always right, but it is rare - # enough that we require users that really mean to play - # such unportable linking tricks to link the library - # using -Wl,-lname, so that libtool does not consider it - # for duplicate removal. - case " $specialdeplibs " in - *" $deplib "*) new_libs="$deplib $new_libs" ;; - *) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$deplib $new_libs" ;; - esac - ;; - esac - ;; - esac - done - tmp_libs= - for deplib in $new_libs; do - case $deplib in - -L*) - case " $tmp_libs " in - *" $deplib "*) ;; - *) func_append tmp_libs " $deplib" ;; - esac - ;; - *) func_append tmp_libs " $deplib" ;; - esac - done - eval $var=\"$tmp_libs\" - done # for var - fi - # Last step: remove runtime libs from dependency_libs - # (they stay in deplibs) - tmp_libs= - for i in $dependency_libs ; do - case " $predeps $postdeps $compiler_lib_search_path " in - *" $i "*) - i="" - ;; - esac - if test -n "$i" ; then - func_append tmp_libs " $i" - fi - done - dependency_libs=$tmp_libs - done # for pass - if test "$linkmode" = prog; then - dlfiles="$newdlfiles" - fi - if test "$linkmode" = prog || test "$linkmode" = lib; then - dlprefiles="$newdlprefiles" - fi - - case $linkmode in - oldlib) - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - func_warning "\`-dlopen' is ignored for archives" - fi - - case " $deplibs" in - *\ -l* | *\ -L*) - func_warning "\`-l' and \`-L' are ignored for archives" ;; - esac - - test -n "$rpath" && \ - func_warning "\`-rpath' is ignored for archives" - - test -n "$xrpath" && \ - func_warning "\`-R' is ignored for archives" - - test -n "$vinfo" && \ - func_warning "\`-version-info/-version-number' is ignored for archives" - - test -n "$release" && \ - func_warning "\`-release' is ignored for archives" - - test -n "$export_symbols$export_symbols_regex" && \ - func_warning "\`-export-symbols' is ignored for archives" - - # Now set the variables for building old libraries. - build_libtool_libs=no - oldlibs="$output" - func_append objs "$old_deplibs" - ;; - - lib) - # Make sure we only generate libraries of the form `libNAME.la'. - case $outputname in - lib*) - func_stripname 'lib' '.la' "$outputname" - name=$func_stripname_result - eval shared_ext=\"$shrext_cmds\" - eval libname=\"$libname_spec\" - ;; - *) - test "$module" = no && \ - func_fatal_help "libtool library \`$output' must begin with \`lib'" - - if test "$need_lib_prefix" != no; then - # Add the "lib" prefix for modules if required - func_stripname '' '.la' "$outputname" - name=$func_stripname_result - eval shared_ext=\"$shrext_cmds\" - eval libname=\"$libname_spec\" - else - func_stripname '' '.la' "$outputname" - libname=$func_stripname_result - fi - ;; - esac - - if test -n "$objs"; then - if test "$deplibs_check_method" != pass_all; then - func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" - else - echo - $ECHO "*** Warning: Linking the shared library $output against the non-libtool" - $ECHO "*** objects $objs is not portable!" - func_append libobjs " $objs" - fi - fi - - test "$dlself" != no && \ - func_warning "\`-dlopen self' is ignored for libtool libraries" - - set dummy $rpath - shift - test "$#" -gt 1 && \ - func_warning "ignoring multiple \`-rpath's for a libtool library" - - install_libdir="$1" - - oldlibs= - if test -z "$rpath"; then - if test "$build_libtool_libs" = yes; then - # Building a libtool convenience library. - # Some compilers have problems with a `.al' extension so - # convenience libraries should have the same extension an - # archive normally would. - oldlibs="$output_objdir/$libname.$libext $oldlibs" - build_libtool_libs=convenience - build_old_libs=yes - fi - - test -n "$vinfo" && \ - func_warning "\`-version-info/-version-number' is ignored for convenience libraries" - - test -n "$release" && \ - func_warning "\`-release' is ignored for convenience libraries" - else - - # Parse the version information argument. - save_ifs="$IFS"; IFS=':' - set dummy $vinfo 0 0 0 - shift - IFS="$save_ifs" - - test -n "$7" && \ - func_fatal_help "too many parameters to \`-version-info'" - - # convert absolute version numbers to libtool ages - # this retains compatibility with .la files and attempts - # to make the code below a bit more comprehensible - - case $vinfo_number in - yes) - number_major="$1" - number_minor="$2" - number_revision="$3" - # - # There are really only two kinds -- those that - # use the current revision as the major version - # and those that subtract age and use age as - # a minor version. But, then there is irix - # which has an extra 1 added just for fun - # - case $version_type in - # correct linux to gnu/linux during the next big refactor - darwin|linux|osf|windows|none) - func_arith $number_major + $number_minor - current=$func_arith_result - age="$number_minor" - revision="$number_revision" - ;; - freebsd-aout|freebsd-elf|qnx|sunos) - current="$number_major" - revision="$number_minor" - age="0" - ;; - irix|nonstopux) - func_arith $number_major + $number_minor - current=$func_arith_result - age="$number_minor" - revision="$number_minor" - lt_irix_increment=no - ;; - esac - ;; - no) - current="$1" - revision="$2" - age="$3" - ;; - esac - - # Check that each of the things are valid numbers. - case $current in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - func_error "CURRENT \`$current' must be a nonnegative integer" - func_fatal_error "\`$vinfo' is not valid version information" - ;; - esac - - case $revision in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - func_error "REVISION \`$revision' must be a nonnegative integer" - func_fatal_error "\`$vinfo' is not valid version information" - ;; - esac - - case $age in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - func_error "AGE \`$age' must be a nonnegative integer" - func_fatal_error "\`$vinfo' is not valid version information" - ;; - esac - - if test "$age" -gt "$current"; then - func_error "AGE \`$age' is greater than the current interface number \`$current'" - func_fatal_error "\`$vinfo' is not valid version information" - fi - - # Calculate the version variables. - major= - versuffix= - verstring= - case $version_type in - none) ;; - - darwin) - # Like Linux, but with the current version available in - # verstring for coding it into the library header - func_arith $current - $age - major=.$func_arith_result - versuffix="$major.$age.$revision" - # Darwin ld doesn't like 0 for these options... - func_arith $current + 1 - minor_current=$func_arith_result - xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" - verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" - ;; - - freebsd-aout) - major=".$current" - versuffix=".$current.$revision"; - ;; - - freebsd-elf) - major=".$current" - versuffix=".$current" - ;; - - irix | nonstopux) - if test "X$lt_irix_increment" = "Xno"; then - func_arith $current - $age - else - func_arith $current - $age + 1 - fi - major=$func_arith_result - - case $version_type in - nonstopux) verstring_prefix=nonstopux ;; - *) verstring_prefix=sgi ;; - esac - verstring="$verstring_prefix$major.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$revision - while test "$loop" -ne 0; do - func_arith $revision - $loop - iface=$func_arith_result - func_arith $loop - 1 - loop=$func_arith_result - verstring="$verstring_prefix$major.$iface:$verstring" - done - - # Before this point, $major must not contain `.'. - major=.$major - versuffix="$major.$revision" - ;; - - linux) # correct to gnu/linux during the next big refactor - func_arith $current - $age - major=.$func_arith_result - versuffix="$major.$age.$revision" - ;; - - osf) - func_arith $current - $age - major=.$func_arith_result - versuffix=".$current.$age.$revision" - verstring="$current.$age.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$age - while test "$loop" -ne 0; do - func_arith $current - $loop - iface=$func_arith_result - func_arith $loop - 1 - loop=$func_arith_result - verstring="$verstring:${iface}.0" - done - - # Make executables depend on our current version. - func_append verstring ":${current}.0" - ;; - - qnx) - major=".$current" - versuffix=".$current" - ;; - - sunos) - major=".$current" - versuffix=".$current.$revision" - ;; - - windows) - # Use '-' rather than '.', since we only want one - # extension on DOS 8.3 filesystems. - func_arith $current - $age - major=$func_arith_result - versuffix="-$major" - ;; - - *) - func_fatal_configuration "unknown library version type \`$version_type'" - ;; - esac - - # Clear the version info if we defaulted, and they specified a release. - if test -z "$vinfo" && test -n "$release"; then - major= - case $version_type in - darwin) - # we can't check for "0.0" in archive_cmds due to quoting - # problems, so we reset it completely - verstring= - ;; - *) - verstring="0.0" - ;; - esac - if test "$need_version" = no; then - versuffix= - else - versuffix=".0.0" - fi - fi - - # Remove version info from name if versioning should be avoided - if test "$avoid_version" = yes && test "$need_version" = no; then - major= - versuffix= - verstring="" - fi - - # Check to see if the archive will have undefined symbols. - if test "$allow_undefined" = yes; then - if test "$allow_undefined_flag" = unsupported; then - func_warning "undefined symbols not allowed in $host shared libraries" - build_libtool_libs=no - build_old_libs=yes - fi - else - # Don't allow undefined symbols. - allow_undefined_flag="$no_undefined_flag" - fi - - fi - - func_generate_dlsyms "$libname" "$libname" "yes" - func_append libobjs " $symfileobj" - test "X$libobjs" = "X " && libobjs= - - if test "$opt_mode" != relink; then - # Remove our outputs, but don't remove object files since they - # may have been created when compiling PIC objects. - removelist= - tempremovelist=`$ECHO "$output_objdir/*"` - for p in $tempremovelist; do - case $p in - *.$objext | *.gcno) - ;; - $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) - if test "X$precious_files_regex" != "X"; then - if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 - then - continue - fi - fi - func_append removelist " $p" - ;; - *) ;; - esac - done - test -n "$removelist" && \ - func_show_eval "${RM}r \$removelist" - fi - - # Now set the variables for building old libraries. - if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then - func_append oldlibs " $output_objdir/$libname.$libext" - - # Transform .lo files to .o files. - oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` - fi - - # Eliminate all temporary directories. - #for path in $notinst_path; do - # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` - # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` - # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` - #done - - if test -n "$xrpath"; then - # If the user specified any rpath flags, then add them. - temp_xrpath= - for libdir in $xrpath; do - func_replace_sysroot "$libdir" - func_append temp_xrpath " -R$func_replace_sysroot_result" - case "$finalize_rpath " in - *" $libdir "*) ;; - *) func_append finalize_rpath " $libdir" ;; - esac - done - if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then - dependency_libs="$temp_xrpath $dependency_libs" - fi - fi - - # Make sure dlfiles contains only unique files that won't be dlpreopened - old_dlfiles="$dlfiles" - dlfiles= - for lib in $old_dlfiles; do - case " $dlprefiles $dlfiles " in - *" $lib "*) ;; - *) func_append dlfiles " $lib" ;; - esac - done - - # Make sure dlprefiles contains only unique files - old_dlprefiles="$dlprefiles" - dlprefiles= - for lib in $old_dlprefiles; do - case "$dlprefiles " in - *" $lib "*) ;; - *) func_append dlprefiles " $lib" ;; - esac - done - - if test "$build_libtool_libs" = yes; then - if test -n "$rpath"; then - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) - # these systems don't actually have a c library (as such)! - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C library is in the System framework - func_append deplibs " System.ltframework" - ;; - *-*-netbsd*) - # Don't link with libc until the a.out ld.so is fixed. - ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) - # Do not include libc due to us having libc/libc_r. - ;; - *-*-sco3.2v5* | *-*-sco5v6*) - # Causes problems with __ctype - ;; - *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) - # Compiler inserts libc in the correct place for threads to work - ;; - *) - # Add libc to deplibs on all other systems if necessary. - if test "$build_libtool_need_lc" = "yes"; then - func_append deplibs " -lc" - fi - ;; - esac - fi - - # Transform deplibs into only deplibs that can be linked in shared. - name_save=$name - libname_save=$libname - release_save=$release - versuffix_save=$versuffix - major_save=$major - # I'm not sure if I'm treating the release correctly. I think - # release should show up in the -l (ie -lgmp5) so we don't want to - # add it in twice. Is that correct? - release="" - versuffix="" - major="" - newdeplibs= - droppeddeps=no - case $deplibs_check_method in - pass_all) - # Don't check for shared/static. Everything works. - # This might be a little naive. We might want to check - # whether the library exists or not. But this is on - # osf3 & osf4 and I'm not really sure... Just - # implementing what was already the behavior. - newdeplibs=$deplibs - ;; - test_compile) - # This code stresses the "libraries are programs" paradigm to its - # limits. Maybe even breaks it. We compile a program, linking it - # against the deplibs as a proxy for the library. Then we can check - # whether they linked in statically or dynamically with ldd. - $opt_dry_run || $RM conftest.c - cat > conftest.c </dev/null` - $nocaseglob - else - potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` - fi - for potent_lib in $potential_libs; do - # Follow soft links. - if ls -lLd "$potent_lib" 2>/dev/null | - $GREP " -> " >/dev/null; then - continue - fi - # The statement above tries to avoid entering an - # endless loop below, in case of cyclic links. - # We might still enter an endless loop, since a link - # loop can be closed while we follow links, - # but so what? - potlib="$potent_lib" - while test -h "$potlib" 2>/dev/null; do - potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` - case $potliblink in - [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; - *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; - esac - done - if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | - $SED -e 10q | - $EGREP "$file_magic_regex" > /dev/null; then - func_append newdeplibs " $a_deplib" - a_deplib="" - break 2 - fi - done - done - fi - if test -n "$a_deplib" ; then - droppeddeps=yes - echo - $ECHO "*** Warning: linker path does not have real file for library $a_deplib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have" - echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib" ; then - $ECHO "*** with $libname but no candidates were found. (...for file magic test)" - else - $ECHO "*** with $libname and none of the candidates passed a file format test" - $ECHO "*** using a file magic. Last file checked: $potlib" - fi - fi - ;; - *) - # Add a -L argument. - func_append newdeplibs " $a_deplib" - ;; - esac - done # Gone through all deplibs. - ;; - match_pattern*) - set dummy $deplibs_check_method; shift - match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` - for a_deplib in $deplibs; do - case $a_deplib in - -l*) - func_stripname -l '' "$a_deplib" - name=$func_stripname_result - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $a_deplib "*) - func_append newdeplibs " $a_deplib" - a_deplib="" - ;; - esac - fi - if test -n "$a_deplib" ; then - libname=`eval "\\$ECHO \"$libname_spec\""` - for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do - potential_libs=`ls $i/$libname[.-]* 2>/dev/null` - for potent_lib in $potential_libs; do - potlib="$potent_lib" # see symlink-check above in file_magic test - if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ - $EGREP "$match_pattern_regex" > /dev/null; then - func_append newdeplibs " $a_deplib" - a_deplib="" - break 2 - fi - done - done - fi - if test -n "$a_deplib" ; then - droppeddeps=yes - echo - $ECHO "*** Warning: linker path does not have real file for library $a_deplib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have" - echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib" ; then - $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" - else - $ECHO "*** with $libname and none of the candidates passed a file format test" - $ECHO "*** using a regex pattern. Last file checked: $potlib" - fi - fi - ;; - *) - # Add a -L argument. - func_append newdeplibs " $a_deplib" - ;; - esac - done # Gone through all deplibs. - ;; - none | unknown | *) - newdeplibs="" - tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - for i in $predeps $postdeps ; do - # can't use Xsed below, because $i might contain '/' - tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` - done - fi - case $tmp_deplibs in - *[!\ \ ]*) - echo - if test "X$deplibs_check_method" = "Xnone"; then - echo "*** Warning: inter-library dependencies are not supported in this platform." - else - echo "*** Warning: inter-library dependencies are not known to be supported." - fi - echo "*** All declared inter-library dependencies are being dropped." - droppeddeps=yes - ;; - esac - ;; - esac - versuffix=$versuffix_save - major=$major_save - release=$release_save - libname=$libname_save - name=$name_save - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library with the System framework - newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` - ;; - esac - - if test "$droppeddeps" = yes; then - if test "$module" = yes; then - echo - echo "*** Warning: libtool could not satisfy all declared inter-library" - $ECHO "*** dependencies of module $libname. Therefore, libtool will create" - echo "*** a static module, that should work as long as the dlopening" - echo "*** application is linked with the -dlopen flag." - if test -z "$global_symbol_pipe"; then - echo - echo "*** However, this would only work if libtool was able to extract symbol" - echo "*** lists from a program, using \`nm' or equivalent, but libtool could" - echo "*** not find such a program. So, this module is probably useless." - echo "*** \`nm' from GNU binutils and a full rebuild may help." - fi - if test "$build_old_libs" = no; then - oldlibs="$output_objdir/$libname.$libext" - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - else - echo "*** The inter-library dependencies that have been dropped here will be" - echo "*** automatically added whenever a program is linked with this library" - echo "*** or is declared to -dlopen it." - - if test "$allow_undefined" = no; then - echo - echo "*** Since this library must not contain undefined symbols," - echo "*** because either the platform does not support them or" - echo "*** it was explicitly requested with -no-undefined," - echo "*** libtool will only create a static version of it." - if test "$build_old_libs" = no; then - oldlibs="$output_objdir/$libname.$libext" - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - fi - fi - # Done checking deplibs! - deplibs=$newdeplibs - fi - # Time to change all our "foo.ltframework" stuff back to "-framework foo" - case $host in - *-*-darwin*) - newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - ;; - esac - - # move library search paths that coincide with paths to not yet - # installed libraries to the beginning of the library search list - new_libs= - for path in $notinst_path; do - case " $new_libs " in - *" -L$path/$objdir "*) ;; - *) - case " $deplibs " in - *" -L$path/$objdir "*) - func_append new_libs " -L$path/$objdir" ;; - esac - ;; - esac - done - for deplib in $deplibs; do - case $deplib in - -L*) - case " $new_libs " in - *" $deplib "*) ;; - *) func_append new_libs " $deplib" ;; - esac - ;; - *) func_append new_libs " $deplib" ;; - esac - done - deplibs="$new_libs" - - # All the library-specific variables (install_libdir is set above). - library_names= - old_library= - dlname= - - # Test again, we may have decided not to build it any more - if test "$build_libtool_libs" = yes; then - # Remove ${wl} instances when linking with ld. - # FIXME: should test the right _cmds variable. - case $archive_cmds in - *\$LD\ *) wl= ;; - esac - if test "$hardcode_into_libs" = yes; then - # Hardcode the library paths - hardcode_libdirs= - dep_rpath= - rpath="$finalize_rpath" - test "$opt_mode" != relink && rpath="$compile_rpath$rpath" - for libdir in $rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - func_replace_sysroot "$libdir" - libdir=$func_replace_sysroot_result - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - func_append dep_rpath " $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) func_append perm_rpath " $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" - fi - if test -n "$runpath_var" && test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - func_append rpath "$dir:" - done - eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" - fi - test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" - fi - - shlibpath="$finalize_shlibpath" - test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" - if test -n "$shlibpath"; then - eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" - fi - - # Get the real and link names of the library. - eval shared_ext=\"$shrext_cmds\" - eval library_names=\"$library_names_spec\" - set dummy $library_names - shift - realname="$1" - shift - - if test -n "$soname_spec"; then - eval soname=\"$soname_spec\" - else - soname="$realname" - fi - if test -z "$dlname"; then - dlname=$soname - fi - - lib="$output_objdir/$realname" - linknames= - for link - do - func_append linknames " $link" - done - - # Use standard objects if they are pic - test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` - test "X$libobjs" = "X " && libobjs= - - delfiles= - if test -n "$export_symbols" && test -n "$include_expsyms"; then - $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" - export_symbols="$output_objdir/$libname.uexp" - func_append delfiles " $export_symbols" - fi - - orig_export_symbols= - case $host_os in - cygwin* | mingw* | cegcc*) - if test -n "$export_symbols" && test -z "$export_symbols_regex"; then - # exporting using user supplied symfile - if test "x`$SED 1q $export_symbols`" != xEXPORTS; then - # and it's NOT already a .def file. Must figure out - # which of the given symbols are data symbols and tag - # them as such. So, trigger use of export_symbols_cmds. - # export_symbols gets reassigned inside the "prepare - # the list of exported symbols" if statement, so the - # include_expsyms logic still works. - orig_export_symbols="$export_symbols" - export_symbols= - always_export_symbols=yes - fi - fi - ;; - esac - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then - func_verbose "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" - $opt_dry_run || $RM $export_symbols - cmds=$export_symbols_cmds - save_ifs="$IFS"; IFS='~' - for cmd1 in $cmds; do - IFS="$save_ifs" - # Take the normal branch if the nm_file_list_spec branch - # doesn't work or if tool conversion is not needed. - case $nm_file_list_spec~$to_tool_file_cmd in - *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) - try_normal_branch=yes - eval cmd=\"$cmd1\" - func_len " $cmd" - len=$func_len_result - ;; - *) - try_normal_branch=no - ;; - esac - if test "$try_normal_branch" = yes \ - && { test "$len" -lt "$max_cmd_len" \ - || test "$max_cmd_len" -le -1; } - then - func_show_eval "$cmd" 'exit $?' - skipped_export=false - elif test -n "$nm_file_list_spec"; then - func_basename "$output" - output_la=$func_basename_result - save_libobjs=$libobjs - save_output=$output - output=${output_objdir}/${output_la}.nm - func_to_tool_file "$output" - libobjs=$nm_file_list_spec$func_to_tool_file_result - func_append delfiles " $output" - func_verbose "creating $NM input file list: $output" - for obj in $save_libobjs; do - func_to_tool_file "$obj" - $ECHO "$func_to_tool_file_result" - done > "$output" - eval cmd=\"$cmd1\" - func_show_eval "$cmd" 'exit $?' - output=$save_output - libobjs=$save_libobjs - skipped_export=false - else - # The command line is too long to execute in one step. - func_verbose "using reloadable object file for export list..." - skipped_export=: - # Break out early, otherwise skipped_export may be - # set to false by a later but shorter cmd. - break - fi - done - IFS="$save_ifs" - if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then - func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' - func_show_eval '$MV "${export_symbols}T" "$export_symbols"' - fi - fi - fi - - if test -n "$export_symbols" && test -n "$include_expsyms"; then - tmp_export_symbols="$export_symbols" - test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" - $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' - fi - - if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then - # The given exports_symbols file has to be filtered, so filter it. - func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" - # FIXME: $output_objdir/$libname.filter potentially contains lots of - # 's' commands which not all seds can handle. GNU sed should be fine - # though. Also, the filter scales superlinearly with the number of - # global variables. join(1) would be nice here, but unfortunately - # isn't a blessed tool. - $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter - func_append delfiles " $export_symbols $output_objdir/$libname.filter" - export_symbols=$output_objdir/$libname.def - $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols - fi - - tmp_deplibs= - for test_deplib in $deplibs; do - case " $convenience " in - *" $test_deplib "*) ;; - *) - func_append tmp_deplibs " $test_deplib" - ;; - esac - done - deplibs="$tmp_deplibs" - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec" && - test "$compiler_needs_object" = yes && - test -z "$libobjs"; then - # extract the archives, so we have objects to list. - # TODO: could optimize this to just extract one archive. - whole_archive_flag_spec= - fi - if test -n "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - eval libobjs=\"\$libobjs $whole_archive_flag_spec\" - test "X$libobjs" = "X " && libobjs= - else - gentop="$output_objdir/${outputname}x" - func_append generated " $gentop" - - func_extract_archives $gentop $convenience - func_append libobjs " $func_extract_archives_result" - test "X$libobjs" = "X " && libobjs= - fi - fi - - if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then - eval flag=\"$thread_safe_flag_spec\" - func_append linker_flags " $flag" - fi - - # Make a backup of the uninstalled library when relinking - if test "$opt_mode" = relink; then - $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? - fi - - # Do each of the archive commands. - if test "$module" = yes && test -n "$module_cmds" ; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - eval test_cmds=\"$module_expsym_cmds\" - cmds=$module_expsym_cmds - else - eval test_cmds=\"$module_cmds\" - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - eval test_cmds=\"$archive_expsym_cmds\" - cmds=$archive_expsym_cmds - else - eval test_cmds=\"$archive_cmds\" - cmds=$archive_cmds - fi - fi - - if test "X$skipped_export" != "X:" && - func_len " $test_cmds" && - len=$func_len_result && - test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then - : - else - # The command line is too long to link in one step, link piecewise - # or, if using GNU ld and skipped_export is not :, use a linker - # script. - - # Save the value of $output and $libobjs because we want to - # use them later. If we have whole_archive_flag_spec, we - # want to use save_libobjs as it was before - # whole_archive_flag_spec was expanded, because we can't - # assume the linker understands whole_archive_flag_spec. - # This may have to be revisited, in case too many - # convenience libraries get linked in and end up exceeding - # the spec. - if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - fi - save_output=$output - func_basename "$output" - output_la=$func_basename_result - - # Clear the reloadable object creation command queue and - # initialize k to one. - test_cmds= - concat_cmds= - objlist= - last_robj= - k=1 - - if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then - output=${output_objdir}/${output_la}.lnkscript - func_verbose "creating GNU ld script: $output" - echo 'INPUT (' > $output - for obj in $save_libobjs - do - func_to_tool_file "$obj" - $ECHO "$func_to_tool_file_result" >> $output - done - echo ')' >> $output - func_append delfiles " $output" - func_to_tool_file "$output" - output=$func_to_tool_file_result - elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then - output=${output_objdir}/${output_la}.lnk - func_verbose "creating linker input file list: $output" - : > $output - set x $save_libobjs - shift - firstobj= - if test "$compiler_needs_object" = yes; then - firstobj="$1 " - shift - fi - for obj - do - func_to_tool_file "$obj" - $ECHO "$func_to_tool_file_result" >> $output - done - func_append delfiles " $output" - func_to_tool_file "$output" - output=$firstobj\"$file_list_spec$func_to_tool_file_result\" - else - if test -n "$save_libobjs"; then - func_verbose "creating reloadable object files..." - output=$output_objdir/$output_la-${k}.$objext - eval test_cmds=\"$reload_cmds\" - func_len " $test_cmds" - len0=$func_len_result - len=$len0 - - # Loop over the list of objects to be linked. - for obj in $save_libobjs - do - func_len " $obj" - func_arith $len + $func_len_result - len=$func_arith_result - if test "X$objlist" = X || - test "$len" -lt "$max_cmd_len"; then - func_append objlist " $obj" - else - # The command $test_cmds is almost too long, add a - # command to the queue. - if test "$k" -eq 1 ; then - # The first file doesn't have a previous command to add. - reload_objs=$objlist - eval concat_cmds=\"$reload_cmds\" - else - # All subsequent reloadable object files will link in - # the last one created. - reload_objs="$objlist $last_robj" - eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" - fi - last_robj=$output_objdir/$output_la-${k}.$objext - func_arith $k + 1 - k=$func_arith_result - output=$output_objdir/$output_la-${k}.$objext - objlist=" $obj" - func_len " $last_robj" - func_arith $len0 + $func_len_result - len=$func_arith_result - fi - done - # Handle the remaining objects by creating one last - # reloadable object file. All subsequent reloadable object - # files will link in the last one created. - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - reload_objs="$objlist $last_robj" - eval concat_cmds=\"\${concat_cmds}$reload_cmds\" - if test -n "$last_robj"; then - eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" - fi - func_append delfiles " $output" - - else - output= - fi - - if ${skipped_export-false}; then - func_verbose "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" - $opt_dry_run || $RM $export_symbols - libobjs=$output - # Append the command to create the export file. - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" - if test -n "$last_robj"; then - eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" - fi - fi - - test -n "$save_libobjs" && - func_verbose "creating a temporary reloadable object file: $output" - - # Loop through the commands generated above and execute them. - save_ifs="$IFS"; IFS='~' - for cmd in $concat_cmds; do - IFS="$save_ifs" - $opt_silent || { - func_quote_for_expand "$cmd" - eval "func_echo $func_quote_for_expand_result" - } - $opt_dry_run || eval "$cmd" || { - lt_exit=$? - - # Restore the uninstalled library and exit - if test "$opt_mode" = relink; then - ( cd "$output_objdir" && \ - $RM "${realname}T" && \ - $MV "${realname}U" "$realname" ) - fi - - exit $lt_exit - } - done - IFS="$save_ifs" - - if test -n "$export_symbols_regex" && ${skipped_export-false}; then - func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' - func_show_eval '$MV "${export_symbols}T" "$export_symbols"' - fi - fi - - if ${skipped_export-false}; then - if test -n "$export_symbols" && test -n "$include_expsyms"; then - tmp_export_symbols="$export_symbols" - test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" - $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' - fi - - if test -n "$orig_export_symbols"; then - # The given exports_symbols file has to be filtered, so filter it. - func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" - # FIXME: $output_objdir/$libname.filter potentially contains lots of - # 's' commands which not all seds can handle. GNU sed should be fine - # though. Also, the filter scales superlinearly with the number of - # global variables. join(1) would be nice here, but unfortunately - # isn't a blessed tool. - $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter - func_append delfiles " $export_symbols $output_objdir/$libname.filter" - export_symbols=$output_objdir/$libname.def - $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols - fi - fi - - libobjs=$output - # Restore the value of output. - output=$save_output - - if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then - eval libobjs=\"\$libobjs $whole_archive_flag_spec\" - test "X$libobjs" = "X " && libobjs= - fi - # Expand the library linking commands again to reset the - # value of $libobjs for piecewise linking. - - # Do each of the archive commands. - if test "$module" = yes && test -n "$module_cmds" ; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - cmds=$module_expsym_cmds - else - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - cmds=$archive_expsym_cmds - else - cmds=$archive_cmds - fi - fi - fi - - if test -n "$delfiles"; then - # Append the command to remove temporary files to $cmds. - eval cmds=\"\$cmds~\$RM $delfiles\" - fi - - # Add any objects from preloaded convenience libraries - if test -n "$dlprefiles"; then - gentop="$output_objdir/${outputname}x" - func_append generated " $gentop" - - func_extract_archives $gentop $dlprefiles - func_append libobjs " $func_extract_archives_result" - test "X$libobjs" = "X " && libobjs= - fi - - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $opt_silent || { - func_quote_for_expand "$cmd" - eval "func_echo $func_quote_for_expand_result" - } - $opt_dry_run || eval "$cmd" || { - lt_exit=$? - - # Restore the uninstalled library and exit - if test "$opt_mode" = relink; then - ( cd "$output_objdir" && \ - $RM "${realname}T" && \ - $MV "${realname}U" "$realname" ) - fi - - exit $lt_exit - } - done - IFS="$save_ifs" - - # Restore the uninstalled library and exit - if test "$opt_mode" = relink; then - $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? - - if test -n "$convenience"; then - if test -z "$whole_archive_flag_spec"; then - func_show_eval '${RM}r "$gentop"' - fi - fi - - exit $EXIT_SUCCESS - fi - - # Create links to the real library. - for linkname in $linknames; do - if test "$realname" != "$linkname"; then - func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' - fi - done - - # If -module or -export-dynamic was specified, set the dlname. - if test "$module" = yes || test "$export_dynamic" = yes; then - # On all known operating systems, these are identical. - dlname="$soname" - fi - fi - ;; - - obj) - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - func_warning "\`-dlopen' is ignored for objects" - fi - - case " $deplibs" in - *\ -l* | *\ -L*) - func_warning "\`-l' and \`-L' are ignored for objects" ;; - esac - - test -n "$rpath" && \ - func_warning "\`-rpath' is ignored for objects" - - test -n "$xrpath" && \ - func_warning "\`-R' is ignored for objects" - - test -n "$vinfo" && \ - func_warning "\`-version-info' is ignored for objects" - - test -n "$release" && \ - func_warning "\`-release' is ignored for objects" - - case $output in - *.lo) - test -n "$objs$old_deplibs" && \ - func_fatal_error "cannot build library object \`$output' from non-libtool objects" - - libobj=$output - func_lo2o "$libobj" - obj=$func_lo2o_result - ;; - *) - libobj= - obj="$output" - ;; - esac - - # Delete the old objects. - $opt_dry_run || $RM $obj $libobj - - # Objects from convenience libraries. This assumes - # single-version convenience libraries. Whenever we create - # different ones for PIC/non-PIC, this we'll have to duplicate - # the extraction. - reload_conv_objs= - gentop= - # reload_cmds runs $LD directly, so let us get rid of - # -Wl from whole_archive_flag_spec and hope we can get by with - # turning comma into space.. - wl= - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec"; then - eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" - reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` - else - gentop="$output_objdir/${obj}x" - func_append generated " $gentop" - - func_extract_archives $gentop $convenience - reload_conv_objs="$reload_objs $func_extract_archives_result" - fi - fi - - # If we're not building shared, we need to use non_pic_objs - test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" - - # Create the old-style object. - reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test - - output="$obj" - func_execute_cmds "$reload_cmds" 'exit $?' - - # Exit if we aren't doing a library object file. - if test -z "$libobj"; then - if test -n "$gentop"; then - func_show_eval '${RM}r "$gentop"' - fi - - exit $EXIT_SUCCESS - fi - - if test "$build_libtool_libs" != yes; then - if test -n "$gentop"; then - func_show_eval '${RM}r "$gentop"' - fi - - # Create an invalid libtool object if no PIC, so that we don't - # accidentally link it into a program. - # $show "echo timestamp > $libobj" - # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? - exit $EXIT_SUCCESS - fi - - if test -n "$pic_flag" || test "$pic_mode" != default; then - # Only do commands if we really have different PIC objects. - reload_objs="$libobjs $reload_conv_objs" - output="$libobj" - func_execute_cmds "$reload_cmds" 'exit $?' - fi - - if test -n "$gentop"; then - func_show_eval '${RM}r "$gentop"' - fi - - exit $EXIT_SUCCESS - ;; - - prog) - case $host in - *cygwin*) func_stripname '' '.exe' "$output" - output=$func_stripname_result.exe;; - esac - test -n "$vinfo" && \ - func_warning "\`-version-info' is ignored for programs" - - test -n "$release" && \ - func_warning "\`-release' is ignored for programs" - - test "$preload" = yes \ - && test "$dlopen_support" = unknown \ - && test "$dlopen_self" = unknown \ - && test "$dlopen_self_static" = unknown && \ - func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library is the System framework - compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` - finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` - ;; - esac - - case $host in - *-*-darwin*) - # Don't allow lazy linking, it breaks C++ global constructors - # But is supposedly fixed on 10.4 or later (yay!). - if test "$tagname" = CXX ; then - case ${MACOSX_DEPLOYMENT_TARGET-10.0} in - 10.[0123]) - func_append compile_command " ${wl}-bind_at_load" - func_append finalize_command " ${wl}-bind_at_load" - ;; - esac - fi - # Time to change all our "foo.ltframework" stuff back to "-framework foo" - compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - ;; - esac - - - # move library search paths that coincide with paths to not yet - # installed libraries to the beginning of the library search list - new_libs= - for path in $notinst_path; do - case " $new_libs " in - *" -L$path/$objdir "*) ;; - *) - case " $compile_deplibs " in - *" -L$path/$objdir "*) - func_append new_libs " -L$path/$objdir" ;; - esac - ;; - esac - done - for deplib in $compile_deplibs; do - case $deplib in - -L*) - case " $new_libs " in - *" $deplib "*) ;; - *) func_append new_libs " $deplib" ;; - esac - ;; - *) func_append new_libs " $deplib" ;; - esac - done - compile_deplibs="$new_libs" - - - func_append compile_command " $compile_deplibs" - func_append finalize_command " $finalize_deplibs" - - if test -n "$rpath$xrpath"; then - # If the user specified any rpath flags, then add them. - for libdir in $rpath $xrpath; do - # This is the magic to use -rpath. - case "$finalize_rpath " in - *" $libdir "*) ;; - *) func_append finalize_rpath " $libdir" ;; - esac - done - fi - - # Now hardcode the library paths - rpath= - hardcode_libdirs= - for libdir in $compile_rpath $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - func_append rpath " $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) func_append perm_rpath " $libdir" ;; - esac - fi - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) - testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` - case :$dllsearchpath: in - *":$libdir:"*) ;; - ::) dllsearchpath=$libdir;; - *) func_append dllsearchpath ":$libdir";; - esac - case :$dllsearchpath: in - *":$testbindir:"*) ;; - ::) dllsearchpath=$testbindir;; - *) func_append dllsearchpath ":$testbindir";; - esac - ;; - esac - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - compile_rpath="$rpath" - - rpath= - hardcode_libdirs= - for libdir in $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - func_append rpath " $flag" - fi - elif test -n "$runpath_var"; then - case "$finalize_perm_rpath " in - *" $libdir "*) ;; - *) func_append finalize_perm_rpath " $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - finalize_rpath="$rpath" - - if test -n "$libobjs" && test "$build_old_libs" = yes; then - # Transform all the library objects into standard objects. - compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` - finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` - fi - - func_generate_dlsyms "$outputname" "@PROGRAM@" "no" - - # template prelinking step - if test -n "$prelink_cmds"; then - func_execute_cmds "$prelink_cmds" 'exit $?' - fi - - wrappers_required=yes - case $host in - *cegcc* | *mingw32ce*) - # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. - wrappers_required=no - ;; - *cygwin* | *mingw* ) - if test "$build_libtool_libs" != yes; then - wrappers_required=no - fi - ;; - *) - if test "$need_relink" = no || test "$build_libtool_libs" != yes; then - wrappers_required=no - fi - ;; - esac - if test "$wrappers_required" = no; then - # Replace the output file specification. - compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` - link_command="$compile_command$compile_rpath" - - # We have no uninstalled library dependencies, so finalize right now. - exit_status=0 - func_show_eval "$link_command" 'exit_status=$?' - - if test -n "$postlink_cmds"; then - func_to_tool_file "$output" - postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` - func_execute_cmds "$postlink_cmds" 'exit $?' - fi - - # Delete the generated files. - if test -f "$output_objdir/${outputname}S.${objext}"; then - func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' - fi - - exit $exit_status - fi - - if test -n "$compile_shlibpath$finalize_shlibpath"; then - compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" - fi - if test -n "$finalize_shlibpath"; then - finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" - fi - - compile_var= - finalize_var= - if test -n "$runpath_var"; then - if test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - func_append rpath "$dir:" - done - compile_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - if test -n "$finalize_perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $finalize_perm_rpath; do - func_append rpath "$dir:" - done - finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - fi - - if test "$no_install" = yes; then - # We don't need to create a wrapper script. - link_command="$compile_var$compile_command$compile_rpath" - # Replace the output file specification. - link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` - # Delete the old output file. - $opt_dry_run || $RM $output - # Link the executable and exit - func_show_eval "$link_command" 'exit $?' - - if test -n "$postlink_cmds"; then - func_to_tool_file "$output" - postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` - func_execute_cmds "$postlink_cmds" 'exit $?' - fi - - exit $EXIT_SUCCESS - fi - - if test "$hardcode_action" = relink; then - # Fast installation is not supported - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - - func_warning "this platform does not like uninstalled shared libraries" - func_warning "\`$output' will be relinked during installation" - else - if test "$fast_install" != no; then - link_command="$finalize_var$compile_command$finalize_rpath" - if test "$fast_install" = yes; then - relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` - else - # fast_install is set to needless - relink_command= - fi - else - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - fi - fi - - # Replace the output file specification. - link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` - - # Delete the old output files. - $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname - - func_show_eval "$link_command" 'exit $?' - - if test -n "$postlink_cmds"; then - func_to_tool_file "$output_objdir/$outputname" - postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` - func_execute_cmds "$postlink_cmds" 'exit $?' - fi - - # Now create the wrapper script. - func_verbose "creating $output" - - # Quote the relink command for shipping. - if test -n "$relink_command"; then - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - func_quote_for_eval "$var_value" - relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" - fi - done - relink_command="(cd `pwd`; $relink_command)" - relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` - fi - - # Only actually do things if not in dry run mode. - $opt_dry_run || { - # win32 will think the script is a binary if it has - # a .exe suffix, so we strip it off here. - case $output in - *.exe) func_stripname '' '.exe' "$output" - output=$func_stripname_result ;; - esac - # test for cygwin because mv fails w/o .exe extensions - case $host in - *cygwin*) - exeext=.exe - func_stripname '' '.exe' "$outputname" - outputname=$func_stripname_result ;; - *) exeext= ;; - esac - case $host in - *cygwin* | *mingw* ) - func_dirname_and_basename "$output" "" "." - output_name=$func_basename_result - output_path=$func_dirname_result - cwrappersource="$output_path/$objdir/lt-$output_name.c" - cwrapper="$output_path/$output_name.exe" - $RM $cwrappersource $cwrapper - trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 - - func_emit_cwrapperexe_src > $cwrappersource - - # The wrapper executable is built using the $host compiler, - # because it contains $host paths and files. If cross- - # compiling, it, like the target executable, must be - # executed on the $host or under an emulation environment. - $opt_dry_run || { - $LTCC $LTCFLAGS -o $cwrapper $cwrappersource - $STRIP $cwrapper - } - - # Now, create the wrapper script for func_source use: - func_ltwrapper_scriptname $cwrapper - $RM $func_ltwrapper_scriptname_result - trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 - $opt_dry_run || { - # note: this script will not be executed, so do not chmod. - if test "x$build" = "x$host" ; then - $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result - else - func_emit_wrapper no > $func_ltwrapper_scriptname_result - fi - } - ;; - * ) - $RM $output - trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 - - func_emit_wrapper no > $output - chmod +x $output - ;; - esac - } - exit $EXIT_SUCCESS - ;; - esac - - # See if we need to build an old-fashioned archive. - for oldlib in $oldlibs; do - - if test "$build_libtool_libs" = convenience; then - oldobjs="$libobjs_save $symfileobj" - addlibs="$convenience" - build_libtool_libs=no - else - if test "$build_libtool_libs" = module; then - oldobjs="$libobjs_save" - build_libtool_libs=no - else - oldobjs="$old_deplibs $non_pic_objects" - if test "$preload" = yes && test -f "$symfileobj"; then - func_append oldobjs " $symfileobj" - fi - fi - addlibs="$old_convenience" - fi - - if test -n "$addlibs"; then - gentop="$output_objdir/${outputname}x" - func_append generated " $gentop" - - func_extract_archives $gentop $addlibs - func_append oldobjs " $func_extract_archives_result" - fi - - # Do each command in the archive commands. - if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then - cmds=$old_archive_from_new_cmds - else - - # Add any objects from preloaded convenience libraries - if test -n "$dlprefiles"; then - gentop="$output_objdir/${outputname}x" - func_append generated " $gentop" - - func_extract_archives $gentop $dlprefiles - func_append oldobjs " $func_extract_archives_result" - fi - - # POSIX demands no paths to be encoded in archives. We have - # to avoid creating archives with duplicate basenames if we - # might have to extract them afterwards, e.g., when creating a - # static archive out of a convenience library, or when linking - # the entirety of a libtool archive into another (currently - # not supported by libtool). - if (for obj in $oldobjs - do - func_basename "$obj" - $ECHO "$func_basename_result" - done | sort | sort -uc >/dev/null 2>&1); then - : - else - echo "copying selected object files to avoid basename conflicts..." - gentop="$output_objdir/${outputname}x" - func_append generated " $gentop" - func_mkdir_p "$gentop" - save_oldobjs=$oldobjs - oldobjs= - counter=1 - for obj in $save_oldobjs - do - func_basename "$obj" - objbase="$func_basename_result" - case " $oldobjs " in - " ") oldobjs=$obj ;; - *[\ /]"$objbase "*) - while :; do - # Make sure we don't pick an alternate name that also - # overlaps. - newobj=lt$counter-$objbase - func_arith $counter + 1 - counter=$func_arith_result - case " $oldobjs " in - *[\ /]"$newobj "*) ;; - *) if test ! -f "$gentop/$newobj"; then break; fi ;; - esac - done - func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" - func_append oldobjs " $gentop/$newobj" - ;; - *) func_append oldobjs " $obj" ;; - esac - done - fi - func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 - tool_oldlib=$func_to_tool_file_result - eval cmds=\"$old_archive_cmds\" - - func_len " $cmds" - len=$func_len_result - if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then - cmds=$old_archive_cmds - elif test -n "$archiver_list_spec"; then - func_verbose "using command file archive linking..." - for obj in $oldobjs - do - func_to_tool_file "$obj" - $ECHO "$func_to_tool_file_result" - done > $output_objdir/$libname.libcmd - func_to_tool_file "$output_objdir/$libname.libcmd" - oldobjs=" $archiver_list_spec$func_to_tool_file_result" - cmds=$old_archive_cmds - else - # the command line is too long to link in one step, link in parts - func_verbose "using piecewise archive linking..." - save_RANLIB=$RANLIB - RANLIB=: - objlist= - concat_cmds= - save_oldobjs=$oldobjs - oldobjs= - # Is there a better way of finding the last object in the list? - for obj in $save_oldobjs - do - last_oldobj=$obj - done - eval test_cmds=\"$old_archive_cmds\" - func_len " $test_cmds" - len0=$func_len_result - len=$len0 - for obj in $save_oldobjs - do - func_len " $obj" - func_arith $len + $func_len_result - len=$func_arith_result - func_append objlist " $obj" - if test "$len" -lt "$max_cmd_len"; then - : - else - # the above command should be used before it gets too long - oldobjs=$objlist - if test "$obj" = "$last_oldobj" ; then - RANLIB=$save_RANLIB - fi - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" - objlist= - len=$len0 - fi - done - RANLIB=$save_RANLIB - oldobjs=$objlist - if test "X$oldobjs" = "X" ; then - eval cmds=\"\$concat_cmds\" - else - eval cmds=\"\$concat_cmds~\$old_archive_cmds\" - fi - fi - fi - func_execute_cmds "$cmds" 'exit $?' - done - - test -n "$generated" && \ - func_show_eval "${RM}r$generated" - - # Now create the libtool archive. - case $output in - *.la) - old_library= - test "$build_old_libs" = yes && old_library="$libname.$libext" - func_verbose "creating $output" - - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - func_quote_for_eval "$var_value" - relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" - fi - done - # Quote the link command for shipping. - relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" - relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` - if test "$hardcode_automatic" = yes ; then - relink_command= - fi - - # Only create the output if not a dry run. - $opt_dry_run || { - for installed in no yes; do - if test "$installed" = yes; then - if test -z "$install_libdir"; then - break - fi - output="$output_objdir/$outputname"i - # Replace all uninstalled libtool libraries with the installed ones - newdependency_libs= - for deplib in $dependency_libs; do - case $deplib in - *.la) - func_basename "$deplib" - name="$func_basename_result" - func_resolve_sysroot "$deplib" - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` - test -z "$libdir" && \ - func_fatal_error "\`$deplib' is not a valid libtool archive" - func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" - ;; - -L*) - func_stripname -L '' "$deplib" - func_replace_sysroot "$func_stripname_result" - func_append newdependency_libs " -L$func_replace_sysroot_result" - ;; - -R*) - func_stripname -R '' "$deplib" - func_replace_sysroot "$func_stripname_result" - func_append newdependency_libs " -R$func_replace_sysroot_result" - ;; - *) func_append newdependency_libs " $deplib" ;; - esac - done - dependency_libs="$newdependency_libs" - newdlfiles= - - for lib in $dlfiles; do - case $lib in - *.la) - func_basename "$lib" - name="$func_basename_result" - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - test -z "$libdir" && \ - func_fatal_error "\`$lib' is not a valid libtool archive" - func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" - ;; - *) func_append newdlfiles " $lib" ;; - esac - done - dlfiles="$newdlfiles" - newdlprefiles= - for lib in $dlprefiles; do - case $lib in - *.la) - # Only pass preopened files to the pseudo-archive (for - # eventual linking with the app. that links it) if we - # didn't already link the preopened objects directly into - # the library: - func_basename "$lib" - name="$func_basename_result" - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - test -z "$libdir" && \ - func_fatal_error "\`$lib' is not a valid libtool archive" - func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" - ;; - esac - done - dlprefiles="$newdlprefiles" - else - newdlfiles= - for lib in $dlfiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; - *) abs=`pwd`"/$lib" ;; - esac - func_append newdlfiles " $abs" - done - dlfiles="$newdlfiles" - newdlprefiles= - for lib in $dlprefiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; - *) abs=`pwd`"/$lib" ;; - esac - func_append newdlprefiles " $abs" - done - dlprefiles="$newdlprefiles" - fi - $RM $output - # place dlname in correct position for cygwin - # In fact, it would be nice if we could use this code for all target - # systems that can't hard-code library paths into their executables - # and that have no shared library path variable independent of PATH, - # but it turns out we can't easily determine that from inspecting - # libtool variables, so we have to hard-code the OSs to which it - # applies here; at the moment, that means platforms that use the PE - # object format with DLL files. See the long comment at the top of - # tests/bindir.at for full details. - tdlname=$dlname - case $host,$output,$installed,$module,$dlname in - *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) - # If a -bindir argument was supplied, place the dll there. - if test "x$bindir" != x ; - then - func_relative_path "$install_libdir" "$bindir" - tdlname=$func_relative_path_result$dlname - else - # Otherwise fall back on heuristic. - tdlname=../bin/$dlname - fi - ;; - esac - $ECHO > $output "\ -# $outputname - a libtool library file -# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# The name that we can dlopen(3). -dlname='$tdlname' - -# Names of this library. -library_names='$library_names' - -# The name of the static archive. -old_library='$old_library' - -# Linker flags that can not go in dependency_libs. -inherited_linker_flags='$new_inherited_linker_flags' - -# Libraries that this one depends upon. -dependency_libs='$dependency_libs' - -# Names of additional weak libraries provided by this library -weak_library_names='$weak_libs' - -# Version information for $libname. -current=$current -age=$age -revision=$revision - -# Is this an already installed library? -installed=$installed - -# Should we warn about portability when linking against -modules? -shouldnotlink=$module - -# Files to dlopen/dlpreopen -dlopen='$dlfiles' -dlpreopen='$dlprefiles' - -# Directory that this library needs to be installed in: -libdir='$install_libdir'" - if test "$installed" = no && test "$need_relink" = yes; then - $ECHO >> $output "\ -relink_command=\"$relink_command\"" - fi - done - } - - # Do a symbolic link so that the libtool archive can be found in - # LD_LIBRARY_PATH before the program is installed. - func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' - ;; - esac - exit $EXIT_SUCCESS -} - -{ test "$opt_mode" = link || test "$opt_mode" = relink; } && - func_mode_link ${1+"$@"} - - -# func_mode_uninstall arg... -func_mode_uninstall () -{ - $opt_debug - RM="$nonopt" - files= - rmforce= - exit_status=0 - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic="$magic" - - for arg - do - case $arg in - -f) func_append RM " $arg"; rmforce=yes ;; - -*) func_append RM " $arg" ;; - *) func_append files " $arg" ;; - esac - done - - test -z "$RM" && \ - func_fatal_help "you must specify an RM program" - - rmdirs= - - for file in $files; do - func_dirname "$file" "" "." - dir="$func_dirname_result" - if test "X$dir" = X.; then - odir="$objdir" - else - odir="$dir/$objdir" - fi - func_basename "$file" - name="$func_basename_result" - test "$opt_mode" = uninstall && odir="$dir" - - # Remember odir for removal later, being careful to avoid duplicates - if test "$opt_mode" = clean; then - case " $rmdirs " in - *" $odir "*) ;; - *) func_append rmdirs " $odir" ;; - esac - fi - - # Don't error if the file doesn't exist and rm -f was used. - if { test -L "$file"; } >/dev/null 2>&1 || - { test -h "$file"; } >/dev/null 2>&1 || - test -f "$file"; then - : - elif test -d "$file"; then - exit_status=1 - continue - elif test "$rmforce" = yes; then - continue - fi - - rmfiles="$file" - - case $name in - *.la) - # Possibly a libtool archive, so verify it. - if func_lalib_p "$file"; then - func_source $dir/$name - - # Delete the libtool libraries and symlinks. - for n in $library_names; do - func_append rmfiles " $odir/$n" - done - test -n "$old_library" && func_append rmfiles " $odir/$old_library" - - case "$opt_mode" in - clean) - case " $library_names " in - *" $dlname "*) ;; - *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; - esac - test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" - ;; - uninstall) - if test -n "$library_names"; then - # Do each command in the postuninstall commands. - func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' - fi - - if test -n "$old_library"; then - # Do each command in the old_postuninstall commands. - func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' - fi - # FIXME: should reinstall the best remaining shared library. - ;; - esac - fi - ;; - - *.lo) - # Possibly a libtool object, so verify it. - if func_lalib_p "$file"; then - - # Read the .lo file - func_source $dir/$name - - # Add PIC object to the list of files to remove. - if test -n "$pic_object" && - test "$pic_object" != none; then - func_append rmfiles " $dir/$pic_object" - fi - - # Add non-PIC object to the list of files to remove. - if test -n "$non_pic_object" && - test "$non_pic_object" != none; then - func_append rmfiles " $dir/$non_pic_object" - fi - fi - ;; - - *) - if test "$opt_mode" = clean ; then - noexename=$name - case $file in - *.exe) - func_stripname '' '.exe' "$file" - file=$func_stripname_result - func_stripname '' '.exe' "$name" - noexename=$func_stripname_result - # $file with .exe has already been added to rmfiles, - # add $file without .exe - func_append rmfiles " $file" - ;; - esac - # Do a test to see if this is a libtool program. - if func_ltwrapper_p "$file"; then - if func_ltwrapper_executable_p "$file"; then - func_ltwrapper_scriptname "$file" - relink_command= - func_source $func_ltwrapper_scriptname_result - func_append rmfiles " $func_ltwrapper_scriptname_result" - else - relink_command= - func_source $dir/$noexename - fi - - # note $name still contains .exe if it was in $file originally - # as does the version of $file that was added into $rmfiles - func_append rmfiles " $odir/$name $odir/${name}S.${objext}" - if test "$fast_install" = yes && test -n "$relink_command"; then - func_append rmfiles " $odir/lt-$name" - fi - if test "X$noexename" != "X$name" ; then - func_append rmfiles " $odir/lt-${noexename}.c" - fi - fi - fi - ;; - esac - func_show_eval "$RM $rmfiles" 'exit_status=1' - done - - # Try to remove the ${objdir}s in the directories where we deleted files - for dir in $rmdirs; do - if test -d "$dir"; then - func_show_eval "rmdir $dir >/dev/null 2>&1" - fi - done - - exit $exit_status -} - -{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && - func_mode_uninstall ${1+"$@"} - -test -z "$opt_mode" && { - help="$generic_help" - func_fatal_help "you must specify a MODE" -} - -test -z "$exec_cmd" && \ - func_fatal_help "invalid operation mode \`$opt_mode'" - -if test -n "$exec_cmd"; then - eval exec "$exec_cmd" - exit $EXIT_FAILURE -fi - -exit $exit_status - - -# The TAGs below are defined such that we never get into a situation -# in which we disable both kinds of libraries. Given conflicting -# choices, we go for a static library, that is the most portable, -# since we can't tell whether shared libraries were disabled because -# the user asked for that or because the platform doesn't support -# them. This is particularly important on AIX, because we don't -# support having both static and shared libraries enabled at the same -# time on that platform, so we default to a shared-only configuration. -# If a disable-shared tag is given, we'll fallback to a static-only -# configuration. But we'll never go from static-only to shared-only. - -# ### BEGIN LIBTOOL TAG CONFIG: disable-shared -build_libtool_libs=no -build_old_libs=yes -# ### END LIBTOOL TAG CONFIG: disable-shared - -# ### BEGIN LIBTOOL TAG CONFIG: disable-static -build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` -# ### END LIBTOOL TAG CONFIG: disable-static - -# Local Variables: -# mode:shell-script -# sh-indentation:2 -# End: -# vi:sw=2 - diff --git a/autoconf/missing b/autoconf/missing deleted file mode 100755 index 86a8fc3..0000000 --- a/autoconf/missing +++ /dev/null @@ -1,331 +0,0 @@ -#! /bin/sh -# Common stub for a few missing GNU programs while installing. - -scriptversion=2012-01-06.13; # UTC - -# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, -# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. -# Originally by Fran,cois Pinard , 1996. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -if test $# -eq 0; then - echo 1>&2 "Try \`$0 --help' for more information" - exit 1 -fi - -run=: -sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' -sed_minuso='s/.* -o \([^ ]*\).*/\1/p' - -# In the cases where this matters, `missing' is being run in the -# srcdir already. -if test -f configure.ac; then - configure_ac=configure.ac -else - configure_ac=configure.in -fi - -msg="missing on your system" - -case $1 in ---run) - # Try to run requested program, and just exit if it succeeds. - run= - shift - "$@" && exit 0 - # Exit code 63 means version mismatch. This often happens - # when the user try to use an ancient version of a tool on - # a file that requires a minimum version. In this case we - # we should proceed has if the program had been absent, or - # if --run hadn't been passed. - if test $? = 63; then - run=: - msg="probably too old" - fi - ;; - - -h|--h|--he|--hel|--help) - echo "\ -$0 [OPTION]... PROGRAM [ARGUMENT]... - -Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an -error status if there is no known handling for PROGRAM. - -Options: - -h, --help display this help and exit - -v, --version output version information and exit - --run try to run the given command, and emulate it if it fails - -Supported PROGRAM values: - aclocal touch file \`aclocal.m4' - autoconf touch file \`configure' - autoheader touch file \`config.h.in' - autom4te touch the output file, or create a stub one - automake touch all \`Makefile.in' files - bison create \`y.tab.[ch]', if possible, from existing .[ch] - flex create \`lex.yy.c', if possible, from existing .c - help2man touch the output file - lex create \`lex.yy.c', if possible, from existing .c - makeinfo touch the output file - yacc create \`y.tab.[ch]', if possible, from existing .[ch] - -Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and -\`g' are ignored when checking the name. - -Send bug reports to ." - exit $? - ;; - - -v|--v|--ve|--ver|--vers|--versi|--versio|--version) - echo "missing $scriptversion (GNU Automake)" - exit $? - ;; - - -*) - echo 1>&2 "$0: Unknown \`$1' option" - echo 1>&2 "Try \`$0 --help' for more information" - exit 1 - ;; - -esac - -# normalize program name to check for. -program=`echo "$1" | sed ' - s/^gnu-//; t - s/^gnu//; t - s/^g//; t'` - -# Now exit if we have it, but it failed. Also exit now if we -# don't have it and --version was passed (most likely to detect -# the program). This is about non-GNU programs, so use $1 not -# $program. -case $1 in - lex*|yacc*) - # Not GNU programs, they don't have --version. - ;; - - *) - if test -z "$run" && ($1 --version) > /dev/null 2>&1; then - # We have it, but it failed. - exit 1 - elif test "x$2" = "x--version" || test "x$2" = "x--help"; then - # Could not run --version or --help. This is probably someone - # running `$TOOL --version' or `$TOOL --help' to check whether - # $TOOL exists and not knowing $TOOL uses missing. - exit 1 - fi - ;; -esac - -# If it does not exist, or fails to run (possibly an outdated version), -# try to emulate it. -case $program in - aclocal*) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified \`acinclude.m4' or \`${configure_ac}'. You might want - to install the \`Automake' and \`Perl' packages. Grab them from - any GNU archive site." - touch aclocal.m4 - ;; - - autoconf*) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified \`${configure_ac}'. You might want to install the - \`Autoconf' and \`GNU m4' packages. Grab them from any GNU - archive site." - touch configure - ;; - - autoheader*) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified \`acconfig.h' or \`${configure_ac}'. You might want - to install the \`Autoconf' and \`GNU m4' packages. Grab them - from any GNU archive site." - files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` - test -z "$files" && files="config.h" - touch_files= - for f in $files; do - case $f in - *:*) touch_files="$touch_files "`echo "$f" | - sed -e 's/^[^:]*://' -e 's/:.*//'`;; - *) touch_files="$touch_files $f.in";; - esac - done - touch $touch_files - ;; - - automake*) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. - You might want to install the \`Automake' and \`Perl' packages. - Grab them from any GNU archive site." - find . -type f -name Makefile.am -print | - sed 's/\.am$/.in/' | - while read f; do touch "$f"; done - ;; - - autom4te*) - echo 1>&2 "\ -WARNING: \`$1' is needed, but is $msg. - You might have modified some files without having the - proper tools for further handling them. - You can get \`$1' as part of \`Autoconf' from any GNU - archive site." - - file=`echo "$*" | sed -n "$sed_output"` - test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` - if test -f "$file"; then - touch $file - else - test -z "$file" || exec >$file - echo "#! /bin/sh" - echo "# Created by GNU Automake missing as a replacement of" - echo "# $ $@" - echo "exit 0" - chmod +x $file - exit 1 - fi - ;; - - bison*|yacc*) - echo 1>&2 "\ -WARNING: \`$1' $msg. You should only need it if - you modified a \`.y' file. You may need the \`Bison' package - in order for those modifications to take effect. You can get - \`Bison' from any GNU archive site." - rm -f y.tab.c y.tab.h - if test $# -ne 1; then - eval LASTARG=\${$#} - case $LASTARG in - *.y) - SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` - if test -f "$SRCFILE"; then - cp "$SRCFILE" y.tab.c - fi - SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` - if test -f "$SRCFILE"; then - cp "$SRCFILE" y.tab.h - fi - ;; - esac - fi - if test ! -f y.tab.h; then - echo >y.tab.h - fi - if test ! -f y.tab.c; then - echo 'main() { return 0; }' >y.tab.c - fi - ;; - - lex*|flex*) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified a \`.l' file. You may need the \`Flex' package - in order for those modifications to take effect. You can get - \`Flex' from any GNU archive site." - rm -f lex.yy.c - if test $# -ne 1; then - eval LASTARG=\${$#} - case $LASTARG in - *.l) - SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` - if test -f "$SRCFILE"; then - cp "$SRCFILE" lex.yy.c - fi - ;; - esac - fi - if test ! -f lex.yy.c; then - echo 'main() { return 0; }' >lex.yy.c - fi - ;; - - help2man*) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified a dependency of a manual page. You may need the - \`Help2man' package in order for those modifications to take - effect. You can get \`Help2man' from any GNU archive site." - - file=`echo "$*" | sed -n "$sed_output"` - test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` - if test -f "$file"; then - touch $file - else - test -z "$file" || exec >$file - echo ".ab help2man is required to generate this page" - exit $? - fi - ;; - - makeinfo*) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified a \`.texi' or \`.texinfo' file, or any other file - indirectly affecting the aspect of the manual. The spurious - call might also be the consequence of using a buggy \`make' (AIX, - DU, IRIX). You might want to install the \`Texinfo' package or - the \`GNU make' package. Grab either from any GNU archive site." - # The file to touch is that specified with -o ... - file=`echo "$*" | sed -n "$sed_output"` - test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` - if test -z "$file"; then - # ... or it is the one specified with @setfilename ... - infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` - file=`sed -n ' - /^@setfilename/{ - s/.* \([^ ]*\) *$/\1/ - p - q - }' $infile` - # ... or it is derived from the source name (dir/f.texi becomes f.info) - test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info - fi - # If the file does not exist, the user really needs makeinfo; - # let's fail without touching anything. - test -f $file || exit 1 - touch $file - ;; - - *) - echo 1>&2 "\ -WARNING: \`$1' is needed, and is $msg. - You might have modified some files without having the - proper tools for further handling them. Check the \`README' file, - it often tells you about the needed prerequisites for installing - this package. You may also peek at any GNU archive site, in case - some other package would contain this missing \`$1' program." - exit 1 - ;; -esac - -exit 0 - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" -# time-stamp-end: "; # UTC" -# End: diff --git a/autoconf/tea/Makefile.in b/autoconf/tea/Makefile.in index a870897..3e481da 100644 --- a/autoconf/tea/Makefile.in +++ b/autoconf/tea/Makefile.in @@ -348,7 +348,7 @@ clean: distclean: clean -rm -f *.tab.c -rm -f $(CONFIG_CLEAN_FILES) - -rm -f config.cache config.log config.status + -rm -f config.h config.cache config.log config.status #======================================================================== # Install binary object libraries. On Windows this includes both .dll and diff --git a/autoconf/tea/win/nmakehlp.c b/autoconf/tea/win/nmakehlp.c index 2868857..e00f1b4 100644 --- a/autoconf/tea/win/nmakehlp.c +++ b/autoconf/tea/win/nmakehlp.c @@ -603,8 +603,8 @@ SubstituteFile( sp = fopen(substitutions, "rt"); if (sp != NULL) { while (fgets(szBuffer, cbBuffer, sp) != NULL) { - char *ks, *ke, *vs, *ve; - ks = szBuffer; + unsigned char *ks, *ke, *vs, *ve; + ks = (unsigned char*)szBuffer; while (ks && *ks && isspace(*ks)) ++ks; ke = ks; while (ke && *ke && !isspace(*ke)) ++ke; @@ -613,7 +613,7 @@ SubstituteFile( ve = vs; while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve; *ke = 0, *ve = 0; - list_insert(&substPtr, ks, vs); + list_insert(&substPtr, (char*)ks, (char*)vs); } fclose(sp); } diff --git a/configure b/configure index c73b820..b2cb4d1 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.69 for sqlite 3.8.10.2. +# Generated by GNU Autoconf 2.69 for sqlite 3.11.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -726,8 +726,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.8.10.2' -PACKAGE_STRING='sqlite 3.8.10.2' +PACKAGE_VERSION='3.11.0' +PACKAGE_STRING='sqlite 3.11.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -774,6 +774,7 @@ USE_GCOV OPT_FEATURE_FLAGS USE_AMALGAMATION TARGET_DEBUG +TARGET_HAVE_EDITLINE TARGET_HAVE_READLINE TARGET_READLINE_INC TARGET_READLINE_LIBS @@ -803,7 +804,6 @@ VERSION program_prefix TCLLIBDIR TCLSH_CMD -AWK INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM @@ -896,12 +896,18 @@ enable_releasemode enable_tempstore enable_tcl with_tcl +enable_editline enable_readline with_readline_lib with_readline_inc enable_debug enable_amalgamation enable_load_extension +enable_fts3 +enable_fts4 +enable_fts5 +enable_json1 +enable_rtree enable_gcov ' ac_precious_vars='build_alias @@ -1454,7 +1460,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.8.10.2 to adapt to many kinds of systems. +\`configure' configures sqlite 3.11.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1519,7 +1525,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.8.10.2:";; + short | recursive ) echo "Configuration of sqlite 3.11.0:";; esac cat <<\_ACEOF @@ -1538,12 +1544,18 @@ Optional Features: --enable-tempstore Use an in-ram database for temporary tables (never,no,yes,always) --disable-tcl do not build TCL extension - --disable-readline disable readline support [default=detect] + --enable-editline enable BSD editline support + --disable-readline disable readline support --enable-debug enable debugging & verbose explain --disable-amalgamation Disable the amalgamation and instead build all files separately --disable-load-extension Disable loading of external extensions + --enable-fts3 Enable the FTS3 extension + --enable-fts4 Enable the FTS4 extension + --enable-fts5 Enable the FTS5 extension + --enable-json1 Enable the JSON1 extension + --enable-rtree Enable the RTREE extension --enable-gcov Enable coverage testing using gcov Optional Packages: @@ -1634,7 +1646,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.8.10.2 +sqlite configure 3.11.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2053,7 +2065,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.8.10.2, which was +It was created by sqlite $as_me 3.11.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3911,13 +3923,13 @@ if ${lt_cv_nm_interface+:} false; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:3914: $ac_compile\"" >&5) + (eval echo "\"\$as_me:3926: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:3917: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:3929: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:3920: output\"" >&5) + (eval echo "\"\$as_me:3932: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -5123,7 +5135,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5126 "configure"' > conftest.$ac_ext + echo '#line 5138 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -6648,11 +6660,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6651: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6663: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6655: \$? = $ac_status" >&5 + echo "$as_me:6667: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -6987,11 +6999,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6990: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7002: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6994: \$? = $ac_status" >&5 + echo "$as_me:7006: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7092,11 +7104,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7095: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7107: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7099: \$? = $ac_status" >&5 + echo "$as_me:7111: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -7147,11 +7159,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7150: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7162: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7154: \$? = $ac_status" >&5 + echo "$as_me:7166: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -9527,7 +9539,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9530 "configure" +#line 9542 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -9623,7 +9635,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9626 "configure" +#line 9638 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -9943,48 +9955,6 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' -for ac_prog in gawk mawk nawk awk -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AWK+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AWK="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -$as_echo "$AWK" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$AWK" && break -done - ######### # Enable large file support (if special flags are necessary) @@ -10548,6 +10518,62 @@ ac_res=$ac_cv_search_pthread_create if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_mutexattr_init" >&5 +$as_echo_n "checking for library containing pthread_mutexattr_init... " >&6; } +if ${ac_cv_search_pthread_mutexattr_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_mutexattr_init (); +int +main () +{ +return pthread_mutexattr_init (); + ; + return 0; +} +_ACEOF +for ac_lib in '' pthread; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_pthread_mutexattr_init=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_pthread_mutexattr_init+:} false; then : + break +fi +done +if ${ac_cv_search_pthread_mutexattr_init+:} false; then : + +else + ac_cv_search_pthread_mutexattr_init=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_mutexattr_init" >&5 +$as_echo "$ac_cv_search_pthread_mutexattr_init" >&6; } +ac_res=$ac_cv_search_pthread_mutexattr_init +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + fi fi @@ -10715,6 +10741,20 @@ else fi fi + # On ubuntu 14.10, $auto_path on tclsh is not quite correct. + # So try again after applying corrections. + if test x"${ac_cv_c_tclconfig}" = x ; then + if test x"$cross_compiling" = xno; then + for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD} | sed 's,/tcltk/tcl,/tcl,g'` + do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="$i" + break + fi + done + fi + fi + # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ @@ -10851,6 +10891,14 @@ fi TARGET_READLINE_LIBS="" TARGET_READLINE_INC="" TARGET_HAVE_READLINE=0 +TARGET_HAVE_EDITLINE=0 +# Check whether --enable-editline was given. +if test "${enable_editline+set}" = set; then : + enableval=$enable_editline; with_editline=$enableval +else + with_editline=auto +fi + # Check whether --enable-readline was given. if test "${enable_readline+set}" = set; then : enableval=$enable_readline; with_readline=$enableval @@ -10859,6 +10907,71 @@ else fi +if test x"$with_editline" != xno; then + sLIBS=$LIBS + LIBS="" + TARGET_HAVE_EDITLINE=1 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing readline" >&5 +$as_echo_n "checking for library containing readline... " >&6; } +if ${ac_cv_search_readline+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char readline (); +int +main () +{ +return readline (); + ; + return 0; +} +_ACEOF +for ac_lib in '' edit; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_readline=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_readline+:} false; then : + break +fi +done +if ${ac_cv_search_readline+:} false; then : + +else + ac_cv_search_readline=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_readline" >&5 +$as_echo "$ac_cv_search_readline" >&6; } +ac_res=$ac_cv_search_readline +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + with_readline=no +else + TARGET_HAVE_EDITLINE=0 +fi + + TARGET_READLINE_LIBS=$LIBS + LIBS=$sLIBS +fi if test x"$with_readline" != xno; then found="yes" @@ -11047,6 +11160,7 @@ fi + ########## # Figure out what C libraries are required to compile programs # that use "fdatasync()" function. @@ -11209,6 +11323,177 @@ else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi +######### +# See whether we should enable Full Text Search extensions +# Check whether --enable-fts3 was given. +if test "${enable_fts3+set}" = set; then : + enableval=$enable_fts3; enable_fts3=yes +else + enable_fts3=no +fi + +if test "${enable_fts3}" = "yes" ; then + OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3" +fi +# Check whether --enable-fts4 was given. +if test "${enable_fts4+set}" = set; then : + enableval=$enable_fts4; enable_fts4=yes +else + enable_fts4=no +fi + +if test "${enable_fts4}" = "yes" ; then + OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5 +$as_echo_n "checking for library containing log... " >&6; } +if ${ac_cv_search_log+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char log (); +int +main () +{ +return log (); + ; + return 0; +} +_ACEOF +for ac_lib in '' m; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_log=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_log+:} false; then : + break +fi +done +if ${ac_cv_search_log+:} false; then : + +else + ac_cv_search_log=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_log" >&5 +$as_echo "$ac_cv_search_log" >&6; } +ac_res=$ac_cv_search_log +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +fi +# Check whether --enable-fts5 was given. +if test "${enable_fts5+set}" = set; then : + enableval=$enable_fts5; enable_fts5=yes +else + enable_fts5=no +fi + +if test "${enable_fts5}" = "yes" ; then + OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5 +$as_echo_n "checking for library containing log... " >&6; } +if ${ac_cv_search_log+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char log (); +int +main () +{ +return log (); + ; + return 0; +} +_ACEOF +for ac_lib in '' m; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_log=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_log+:} false; then : + break +fi +done +if ${ac_cv_search_log+:} false; then : + +else + ac_cv_search_log=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_log" >&5 +$as_echo "$ac_cv_search_log" >&6; } +ac_res=$ac_cv_search_log +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +fi + +######### +# See whether we should enable JSON1 +# Check whether --enable-json1 was given. +if test "${enable_json1+set}" = set; then : + enableval=$enable_json1; enable_json1=yes +else + enable_json1=no +fi + +if test "${enable_json1}" = "yes" ; then + OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1" +fi + +######### +# See whether we should enable RTREE +# Check whether --enable-rtree was given. +if test "${enable_rtree+set}" = set; then : + enableval=$enable_rtree; enable_rtree=yes +else + enable_rtree=no +fi + +if test "${enable_rtree}" = "yes" ; then + OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" +fi + ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS @@ -11794,7 +12079,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=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.8.10.2, which was +This file was extended by sqlite $as_me 3.11.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -11860,7 +12145,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -sqlite config.status 3.8.10.2 +sqlite config.status 3.11.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -11871,7 +12156,6 @@ gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' -AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF diff --git a/configure.ac b/configure.ac index 6a11888..19f85dc 100644 --- a/configure.ac +++ b/configure.ac @@ -90,7 +90,6 @@ fi # AC_PROG_LIBTOOL AC_PROG_INSTALL -AC_PROG_AWK ######### # Enable large file support (if special flags are necessary) @@ -196,6 +195,7 @@ AC_SUBST(SQLITE_THREADSAFE) if test "$SQLITE_THREADSAFE" = "1"; then AC_SEARCH_LIBS(pthread_create, pthread) + AC_SEARCH_LIBS(pthread_mutexattr_init, pthread) fi ########## @@ -320,6 +320,20 @@ if test "${use_tcl}" = "yes" ; then fi fi + # On ubuntu 14.10, $auto_path on tclsh is not quite correct. + # So try again after applying corrections. + if test x"${ac_cv_c_tclconfig}" = x ; then + if test x"$cross_compiling" = xno; then + for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD} | sed 's,/tcltk/tcl,/tcl,g'` + do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="$i" + break + fi + done + fi + fi + # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ @@ -447,11 +461,24 @@ AC_SUBST(HAVE_TCL) TARGET_READLINE_LIBS="" TARGET_READLINE_INC="" TARGET_HAVE_READLINE=0 +TARGET_HAVE_EDITLINE=0 +AC_ARG_ENABLE([editline], + [AC_HELP_STRING([--enable-editline],[enable BSD editline support])], + [with_editline=$enableval], + [with_editline=auto]) AC_ARG_ENABLE([readline], - [AC_HELP_STRING([--disable-readline],[disable readline support [default=detect]])], + [AC_HELP_STRING([--disable-readline],[disable readline support])], [with_readline=$enableval], [with_readline=auto]) +if test x"$with_editline" != xno; then + sLIBS=$LIBS + LIBS="" + TARGET_HAVE_EDITLINE=1 + AC_SEARCH_LIBS(readline,edit,[with_readline=no],[TARGET_HAVE_EDITLINE=0]) + TARGET_READLINE_LIBS=$LIBS + LIBS=$sLIBS +fi if test x"$with_readline" != xno; then found="yes" @@ -506,6 +533,7 @@ fi AC_SUBST(TARGET_READLINE_LIBS) AC_SUBST(TARGET_READLINE_INC) AC_SUBST(TARGET_HAVE_READLINE) +AC_SUBST(TARGET_HAVE_EDITLINE) ########## # Figure out what C libraries are required to compile programs @@ -546,6 +574,47 @@ else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi +######### +# See whether we should enable Full Text Search extensions +AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3], + [Enable the FTS3 extension]), + [enable_fts3=yes],[enable_fts3=no]) +if test "${enable_fts3}" = "yes" ; then + OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3" +fi +AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4], + [Enable the FTS4 extension]), + [enable_fts4=yes],[enable_fts4=no]) +if test "${enable_fts4}" = "yes" ; then + OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4" + AC_SEARCH_LIBS([log],[m]) +fi +AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5], + [Enable the FTS5 extension]), + [enable_fts5=yes],[enable_fts5=no]) +if test "${enable_fts5}" = "yes" ; then + OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5" + AC_SEARCH_LIBS([log],[m]) +fi + +######### +# See whether we should enable JSON1 +AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1], + [Enable the JSON1 extension]), + [enable_json1=yes],[enable_json1=no]) +if test "${enable_json1}" = "yes" ; then + OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1" +fi + +######### +# See whether we should enable RTREE +AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree], + [Enable the RTREE extension]), + [enable_rtree=yes],[enable_rtree=no]) +if test "${enable_rtree}" = "yes" ; then + OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" +fi + ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS diff --git a/ext/async/sqlite3async.c b/ext/async/sqlite3async.c index 4ab39ca..b6f4a4b 100644 --- a/ext/async/sqlite3async.c +++ b/ext/async/sqlite3async.c @@ -1636,6 +1636,7 @@ void sqlite3async_run(void){ ** Control/configure the asynchronous IO system. */ int sqlite3async_control(int op, ...){ + int rc = SQLITE_OK; va_list ap; va_start(ap, op); switch( op ){ @@ -1645,7 +1646,8 @@ int sqlite3async_control(int op, ...){ && eWhen!=SQLITEASYNC_HALT_NOW && eWhen!=SQLITEASYNC_HALT_IDLE ){ - return SQLITE_MISUSE; + rc = SQLITE_MISUSE; + break; } async.eHalt = eWhen; async_mutex_enter(ASYNC_MUTEX_QUEUE); @@ -1657,7 +1659,8 @@ int sqlite3async_control(int op, ...){ case SQLITEASYNC_DELAY: { int iDelay = va_arg(ap, int); if( iDelay<0 ){ - return SQLITE_MISUSE; + rc = SQLITE_MISUSE; + break; } async.ioDelay = iDelay; break; @@ -1668,7 +1671,8 @@ int sqlite3async_control(int op, ...){ async_mutex_enter(ASYNC_MUTEX_QUEUE); if( async.nFile || async.pQueueFirst ){ async_mutex_leave(ASYNC_MUTEX_QUEUE); - return SQLITE_MISUSE; + rc = SQLITE_MISUSE; + break; } async.bLockFiles = bLock; async_mutex_leave(ASYNC_MUTEX_QUEUE); @@ -1692,9 +1696,11 @@ int sqlite3async_control(int op, ...){ } default: - return SQLITE_ERROR; + rc = SQLITE_ERROR; + break; } - return SQLITE_OK; + va_end(ap); + return rc; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO) */ diff --git a/ext/fts1/fts1.c b/ext/fts1/fts1.c index 482cf75..77fa9e2 100644 --- a/ext/fts1/fts1.c +++ b/ext/fts1/fts1.c @@ -205,13 +205,13 @@ static int getVarint32(const char *p, int *pi){ */ /* TODO(shess) Is __isascii() a portable version of (c&0x80)==0? */ static int safe_isspace(char c){ - return (c&0x80)==0 ? isspace(c) : 0; + return (c&0x80)==0 ? isspace((unsigned char)c) : 0; } static int safe_tolower(char c){ - return (c&0x80)==0 ? tolower(c) : c; + return (c&0x80)==0 ? tolower((unsigned char)c) : c; } static int safe_isalnum(char c){ - return (c&0x80)==0 ? isalnum(c) : 0; + return (c&0x80)==0 ? isalnum((unsigned char)c) : 0; } typedef enum DocListType { diff --git a/ext/fts1/simple_tokenizer.c b/ext/fts1/simple_tokenizer.c index d00a770..0ddc705 100644 --- a/ext/fts1/simple_tokenizer.c +++ b/ext/fts1/simple_tokenizer.c @@ -138,7 +138,7 @@ static int simpleNext( ** case-insensitivity. */ char ch = c->pCurrent[ii]; - c->zToken[ii] = (unsigned char)ch<0x80 ? tolower(ch) : ch; + c->zToken[ii] = (unsigned char)ch<0x80 ? tolower((unsigned char)ch):ch; } c->zToken[n] = '\0'; *ppToken = c->zToken; diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index e7958d9..748faef 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -1517,6 +1517,19 @@ static void fts3SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ #endif } +/* +** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this +** extension is currently being used by a version of SQLite too old to +** support index-info flags. In that case this function is a no-op. +*/ +static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){ +#if SQLITE_VERSION_NUMBER>=3008012 + if( sqlite3_libversion_number()>=3008012 ){ + pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; + } +#endif +} + /* ** Implementation of the xBestIndex method for FTS3 tables. There ** are three possible strategies, in order of preference: @@ -1607,6 +1620,9 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ } } + /* If using a docid=? or rowid=? strategy, set the UNIQUE flag. */ + if( pInfo->idxNum==FTS3_DOCID_SEARCH ) fts3SetUniqueFlag(pInfo); + iIdx = 1; if( iCons>=0 ){ pInfo->aConstraintUsage[iCons].argvIndex = iIdx++; @@ -1675,7 +1691,7 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){ sqlite3Fts3ExprFree(pCsr->pExpr); sqlite3Fts3FreeDeferredTokens(pCsr); sqlite3_free(pCsr->aDoclist); - sqlite3_free(pCsr->aMatchinfo); + sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); sqlite3_free(pCsr); return SQLITE_OK; @@ -3176,7 +3192,7 @@ static int fts3FilterMethod( /* In case the cursor has been used before, clear it now. */ sqlite3_finalize(pCsr->pStmt); sqlite3_free(pCsr->aDoclist); - sqlite3_free(pCsr->aMatchinfo); + sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); sqlite3Fts3ExprFree(pCsr->pExpr); memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); @@ -4231,7 +4247,6 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){ int bIncrOk = (bOptOk && pCsr->bDesc==pTab->bDescIdx && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0 - && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0 #ifdef SQLITE_TEST && pTab->bNoIncrDoclist==0 #endif @@ -4351,6 +4366,7 @@ void sqlite3Fts3DoclistNext( p += sqlite3Fts3GetVarint(p, piDocid); }else{ fts3PoslistCopy(0, &p); + while( p<&aDoclist[nDoclist] && *p==0 ) p++; if( p>=&aDoclist[nDoclist] ){ *pbEof = 1; }else{ @@ -5074,7 +5090,7 @@ static int fts3EvalNearTrim( ** 2. NEAR is treated as AND. If the expression is "x NEAR y", it is ** advanced to point to the next row that matches "x AND y". ** -** See fts3EvalTestDeferredAndNear() for details on testing if a row is +** See sqlite3Fts3EvalTestDeferred() for details on testing if a row is ** really a match, taking into account deferred tokens and NEAR operators. */ static void fts3EvalNextRow( @@ -5294,7 +5310,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ } /* -** This function is a helper function for fts3EvalTestDeferredAndNear(). +** This function is a helper function for sqlite3Fts3EvalTestDeferred(). ** Assuming no error occurs or has occurred, It returns non-zero if the ** expression passed as the second argument matches the row that pCsr ** currently points to, or zero if it does not. @@ -5415,7 +5431,7 @@ static int fts3EvalTestExpr( ** Or, if no error occurs and it seems the current row does match the FTS ** query, return 0. */ -static int fts3EvalTestDeferredAndNear(Fts3Cursor *pCsr, int *pRc){ +int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc){ int rc = *pRc; int bMiss = 0; if( rc==SQLITE_OK ){ @@ -5462,7 +5478,7 @@ static int fts3EvalNext(Fts3Cursor *pCsr){ pCsr->isRequireSeek = 1; pCsr->isMatchinfoNeeded = 1; pCsr->iPrevId = pExpr->iDocid; - }while( pCsr->isEof==0 && fts3EvalTestDeferredAndNear(pCsr, &rc) ); + }while( pCsr->isEof==0 && sqlite3Fts3EvalTestDeferred(pCsr, &rc) ); } /* Check if the cursor is past the end of the docid range specified @@ -5623,7 +5639,7 @@ static int fts3EvalGatherStats( pCsr->iPrevId = pRoot->iDocid; }while( pCsr->isEof==0 && pRoot->eType==FTSQUERY_NEAR - && fts3EvalTestDeferredAndNear(pCsr, &rc) + && sqlite3Fts3EvalTestDeferred(pCsr, &rc) ); if( rc==SQLITE_OK && pCsr->isEof==0 ){ @@ -5648,7 +5664,6 @@ static int fts3EvalGatherStats( fts3EvalNextRow(pCsr, pRoot, &rc); assert( pRoot->bEof==0 ); }while( pRoot->iDocid!=iDocid && rc==SQLITE_OK ); - fts3EvalTestDeferredAndNear(pCsr, &rc); } } return rc; @@ -5758,10 +5773,10 @@ int sqlite3Fts3EvalPhrasePoslist( int rc = SQLITE_OK; int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */ int bOr = 0; - u8 bEof = 0; u8 bTreeEof = 0; Fts3Expr *p; /* Used to iterate from pExpr to root */ Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */ + int bMatch; /* Check if this phrase descends from an OR expression node. If not, ** return NULL. Otherwise, the entry that corresponds to docid @@ -5795,31 +5810,47 @@ int sqlite3Fts3EvalPhrasePoslist( } if( rc!=SQLITE_OK ) return rc; - pIter = pPhrase->pOrPoslist; - iDocid = pPhrase->iOrDocid; - if( pCsr->bDesc==bDescDoclist ){ - bEof = !pPhrase->doclist.nAll || - (pIter >= (pPhrase->doclist.aAll + pPhrase->doclist.nAll)); - while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){ - sqlite3Fts3DoclistNext( - bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll, - &pIter, &iDocid, &bEof - ); - } - }else{ - bEof = !pPhrase->doclist.nAll || (pIter && pIter<=pPhrase->doclist.aAll); - while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){ - int dummy; - sqlite3Fts3DoclistPrev( - bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll, - &pIter, &iDocid, &dummy, &bEof - ); - } - } - pPhrase->pOrPoslist = pIter; - pPhrase->iOrDocid = iDocid; + bMatch = 1; + for(p=pNear; p; p=p->pLeft){ + u8 bEof = 0; + Fts3Expr *pTest = p; + Fts3Phrase *pPh; + assert( pTest->eType==FTSQUERY_NEAR || pTest->eType==FTSQUERY_PHRASE ); + if( pTest->eType==FTSQUERY_NEAR ) pTest = pTest->pRight; + assert( pTest->eType==FTSQUERY_PHRASE ); + pPh = pTest->pPhrase; - if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0; + pIter = pPh->pOrPoslist; + iDocid = pPh->iOrDocid; + if( pCsr->bDesc==bDescDoclist ){ + bEof = !pPh->doclist.nAll || + (pIter >= (pPh->doclist.aAll + pPh->doclist.nAll)); + while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){ + sqlite3Fts3DoclistNext( + bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll, + &pIter, &iDocid, &bEof + ); + } + }else{ + bEof = !pPh->doclist.nAll || (pIter && pIter<=pPh->doclist.aAll); + while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){ + int dummy; + sqlite3Fts3DoclistPrev( + bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll, + &pIter, &iDocid, &dummy, &bEof + ); + } + } + pPh->pOrPoslist = pIter; + pPh->iOrDocid = iDocid; + if( bEof || iDocid!=pCsr->iPrevId ) bMatch = 0; + } + + if( bMatch ){ + pIter = pPhrase->pOrPoslist; + }else{ + pIter = 0; + } } if( pIter==0 ) return SQLITE_OK; diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index 0748d91..0c86c42 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -18,6 +18,12 @@ # define NDEBUG 1 #endif +/* FTS3/FTS4 require virtual tables */ +#ifdef SQLITE_OMIT_VIRTUALTABLE +# undef SQLITE_ENABLE_FTS3 +# undef SQLITE_ENABLE_FTS4 +#endif + /* ** FTS4 is really an extension for FTS3. It is enabled using the ** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all @@ -197,6 +203,8 @@ typedef struct Fts3DeferredToken Fts3DeferredToken; typedef struct Fts3SegReader Fts3SegReader; typedef struct Fts3MultiSegReader Fts3MultiSegReader; +typedef struct MatchinfoBuffer MatchinfoBuffer; + /* ** A connection to a fulltext index is an instance of the following ** structure. The xCreate and xConnect methods create an instance @@ -262,6 +270,7 @@ struct Fts3Table { int nPendingData; /* Current bytes of pending data */ sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */ int iPrevLangid; /* Langid of recently inserted document */ + int bPrevDelete; /* True if last operation was a delete */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) /* State variables used for validating that the transaction control @@ -306,9 +315,7 @@ struct Fts3Cursor { i64 iMinDocid; /* Minimum docid to return */ i64 iMaxDocid; /* Maximum docid to return */ int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */ - u32 *aMatchinfo; /* Information about most recent match */ - int nMatchinfo; /* Number of elements in aMatchinfo[] */ - char *zMatchinfo; /* Matchinfo specification */ + MatchinfoBuffer *pMIBuffer; /* Buffer for matchinfo data */ }; #define FTS3_EVAL_FILTER 0 @@ -428,7 +435,9 @@ struct Fts3Expr { u8 bStart; /* True if iDocid is valid */ u8 bDeferred; /* True if this expression is entirely deferred */ - u32 *aMI; + /* The following are used by the fts3_snippet.c module. */ + int iPhrase; /* Index of this phrase in matchinfo() results */ + u32 *aMI; /* See above */ }; /* @@ -549,6 +558,7 @@ void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*); int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *); int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *); void sqlite3Fts3CreateStatTable(int*, Fts3Table*); +int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc); /* fts3_tokenizer.c */ const char *sqlite3Fts3NextToken(const char *, int *); @@ -564,6 +574,7 @@ void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *, const char *, const char *, int, int ); void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); +void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p); /* fts3_expr.c */ int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int, diff --git a/ext/fts3/fts3_expr.c b/ext/fts3/fts3_expr.c index d7cabd9..788e502 100644 --- a/ext/fts3/fts3_expr.c +++ b/ext/fts3/fts3_expr.c @@ -793,125 +793,151 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){ rc = SQLITE_ERROR; } - if( rc==SQLITE_OK && (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){ - Fts3Expr **apLeaf; - apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth); - if( 0==apLeaf ){ - rc = SQLITE_NOMEM; - }else{ - memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth); - } - - if( rc==SQLITE_OK ){ - int i; - Fts3Expr *p; - - /* Set $p to point to the left-most leaf in the tree of eType nodes. */ - for(p=pRoot; p->eType==eType; p=p->pLeft){ - assert( p->pParent==0 || p->pParent->pLeft==p ); - assert( p->pLeft && p->pRight ); - } - - /* This loop runs once for each leaf in the tree of eType nodes. */ - while( 1 ){ - int iLvl; - Fts3Expr *pParent = p->pParent; /* Current parent of p */ - - assert( pParent==0 || pParent->pLeft==p ); - p->pParent = 0; - if( pParent ){ - pParent->pLeft = 0; - }else{ - pRoot = 0; - } - rc = fts3ExprBalance(&p, nMaxDepth-1); - if( rc!=SQLITE_OK ) break; - - for(iLvl=0; p && iLvlpLeft = apLeaf[iLvl]; - pFree->pRight = p; - pFree->pLeft->pParent = pFree; - pFree->pRight->pParent = pFree; - - p = pFree; - pFree = pFree->pParent; - p->pParent = 0; - apLeaf[iLvl] = 0; - } - } - if( p ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_TOOBIG; - break; - } - - /* If that was the last leaf node, break out of the loop */ - if( pParent==0 ) break; - - /* Set $p to point to the next leaf in the tree of eType nodes */ - for(p=pParent->pRight; p->eType==eType; p=p->pLeft); - - /* Remove pParent from the original tree. */ - assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent ); - pParent->pRight->pParent = pParent->pParent; - if( pParent->pParent ){ - pParent->pParent->pLeft = pParent->pRight; - }else{ - assert( pParent==pRoot ); - pRoot = pParent->pRight; - } - - /* Link pParent into the free node list. It will be used as an - ** internal node of the new tree. */ - pParent->pParent = pFree; - pFree = pParent; + if( rc==SQLITE_OK ){ + if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){ + Fts3Expr **apLeaf; + apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth); + if( 0==apLeaf ){ + rc = SQLITE_NOMEM; + }else{ + memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth); } if( rc==SQLITE_OK ){ - p = 0; - for(i=0; ipParent = 0; + int i; + Fts3Expr *p; + + /* Set $p to point to the left-most leaf in the tree of eType nodes. */ + for(p=pRoot; p->eType==eType; p=p->pLeft){ + assert( p->pParent==0 || p->pParent->pLeft==p ); + assert( p->pLeft && p->pRight ); + } + + /* This loop runs once for each leaf in the tree of eType nodes. */ + while( 1 ){ + int iLvl; + Fts3Expr *pParent = p->pParent; /* Current parent of p */ + + assert( pParent==0 || pParent->pLeft==p ); + p->pParent = 0; + if( pParent ){ + pParent->pLeft = 0; + }else{ + pRoot = 0; + } + rc = fts3ExprBalance(&p, nMaxDepth-1); + if( rc!=SQLITE_OK ) break; + + for(iLvl=0; p && iLvlpLeft = apLeaf[iLvl]; pFree->pRight = p; - pFree->pLeft = apLeaf[i]; pFree->pLeft->pParent = pFree; pFree->pRight->pParent = pFree; p = pFree; pFree = pFree->pParent; p->pParent = 0; + apLeaf[iLvl] = 0; } } + if( p ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_TOOBIG; + break; + } + + /* If that was the last leaf node, break out of the loop */ + if( pParent==0 ) break; + + /* Set $p to point to the next leaf in the tree of eType nodes */ + for(p=pParent->pRight; p->eType==eType; p=p->pLeft); + + /* Remove pParent from the original tree. */ + assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent ); + pParent->pRight->pParent = pParent->pParent; + if( pParent->pParent ){ + pParent->pParent->pLeft = pParent->pRight; + }else{ + assert( pParent==pRoot ); + pRoot = pParent->pRight; + } + + /* Link pParent into the free node list. It will be used as an + ** internal node of the new tree. */ + pParent->pParent = pFree; + pFree = pParent; } - pRoot = p; - }else{ - /* An error occurred. Delete the contents of the apLeaf[] array - ** and pFree list. Everything else is cleaned up by the call to - ** sqlite3Fts3ExprFree(pRoot) below. */ - Fts3Expr *pDel; - for(i=0; ipParent; - sqlite3_free(pDel); + + if( rc==SQLITE_OK ){ + p = 0; + for(i=0; ipParent = 0; + }else{ + assert( pFree!=0 ); + pFree->pRight = p; + pFree->pLeft = apLeaf[i]; + pFree->pLeft->pParent = pFree; + pFree->pRight->pParent = pFree; + + p = pFree; + pFree = pFree->pParent; + p->pParent = 0; + } + } + } + pRoot = p; + }else{ + /* An error occurred. Delete the contents of the apLeaf[] array + ** and pFree list. Everything else is cleaned up by the call to + ** sqlite3Fts3ExprFree(pRoot) below. */ + Fts3Expr *pDel; + for(i=0; ipParent; + sqlite3_free(pDel); + } } + + assert( pFree==0 ); + sqlite3_free( apLeaf ); + } + }else if( eType==FTSQUERY_NOT ){ + Fts3Expr *pLeft = pRoot->pLeft; + Fts3Expr *pRight = pRoot->pRight; + + pRoot->pLeft = 0; + pRoot->pRight = 0; + pLeft->pParent = 0; + pRight->pParent = 0; + + rc = fts3ExprBalance(&pLeft, nMaxDepth-1); + if( rc==SQLITE_OK ){ + rc = fts3ExprBalance(&pRight, nMaxDepth-1); } - assert( pFree==0 ); - sqlite3_free( apLeaf ); + if( rc!=SQLITE_OK ){ + sqlite3Fts3ExprFree(pRight); + sqlite3Fts3ExprFree(pLeft); + }else{ + assert( pLeft && pRight ); + pRoot->pLeft = pLeft; + pLeft->pParent = pRoot; + pRoot->pRight = pRight; + pRight->pParent = pRoot; + } } } - + if( rc!=SQLITE_OK ){ sqlite3Fts3ExprFree(pRoot); pRoot = 0; diff --git a/ext/fts3/fts3_icu.c b/ext/fts3/fts3_icu.c index 52df8c7..6f90e1e 100644 --- a/ext/fts3/fts3_icu.c +++ b/ext/fts3/fts3_icu.c @@ -240,12 +240,13 @@ static int icuNext( ** The set of routines that implement the simple tokenizer */ static const sqlite3_tokenizer_module icuTokenizerModule = { - 0, /* iVersion */ - icuCreate, /* xCreate */ - icuDestroy, /* xCreate */ - icuOpen, /* xOpen */ - icuClose, /* xClose */ - icuNext, /* xNext */ + 0, /* iVersion */ + icuCreate, /* xCreate */ + icuDestroy, /* xCreate */ + icuOpen, /* xOpen */ + icuClose, /* xClose */ + icuNext, /* xNext */ + 0, /* xLanguageid */ }; /* diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c index 6abb169..a0771c0 100644 --- a/ext/fts3/fts3_snippet.c +++ b/ext/fts3/fts3_snippet.c @@ -28,6 +28,7 @@ #define FTS3_MATCHINFO_LCS 's' /* nCol values */ #define FTS3_MATCHINFO_HITS 'x' /* 3*nCol*nPhrase values */ #define FTS3_MATCHINFO_LHITS 'y' /* nCol*nPhrase values */ +#define FTS3_MATCHINFO_LHITS_BM 'b' /* nCol*nPhrase values */ /* ** The default value for the second argument to matchinfo(). @@ -89,9 +90,22 @@ struct MatchInfo { int nCol; /* Number of columns in table */ int nPhrase; /* Number of matchable phrases in query */ sqlite3_int64 nDoc; /* Number of docs in database */ + char flag; u32 *aMatchinfo; /* Pre-allocated buffer */ }; +/* +** An instance of this structure is used to manage a pair of buffers, each +** (nElem * sizeof(u32)) bytes in size. See the MatchinfoBuffer code below +** for details. +*/ +struct MatchinfoBuffer { + u8 aRef[3]; + int nElem; + int bGlobal; /* Set if global data is loaded */ + char *zMatchinfo; + u32 aMatchinfo[1]; +}; /* @@ -107,6 +121,97 @@ struct StrBuffer { }; +/************************************************************************* +** Start of MatchinfoBuffer code. +*/ + +/* +** Allocate a two-slot MatchinfoBuffer object. +*/ +static MatchinfoBuffer *fts3MIBufferNew(int nElem, const char *zMatchinfo){ + MatchinfoBuffer *pRet; + int nByte = sizeof(u32) * (2*nElem + 1) + sizeof(MatchinfoBuffer); + int nStr = (int)strlen(zMatchinfo); + + pRet = sqlite3_malloc(nByte + nStr+1); + if( pRet ){ + memset(pRet, 0, nByte); + pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; + pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*(nElem+1); + pRet->nElem = nElem; + pRet->zMatchinfo = ((char*)pRet) + nByte; + memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1); + pRet->aRef[0] = 1; + } + + return pRet; +} + +static void fts3MIBufferFree(void *p){ + MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]); + + assert( (u32*)p==&pBuf->aMatchinfo[1] + || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2] + ); + if( (u32*)p==&pBuf->aMatchinfo[1] ){ + pBuf->aRef[1] = 0; + }else{ + pBuf->aRef[2] = 0; + } + + if( pBuf->aRef[0]==0 && pBuf->aRef[1]==0 && pBuf->aRef[2]==0 ){ + sqlite3_free(pBuf); + } +} + +static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ + void (*xRet)(void*) = 0; + u32 *aOut = 0; + + if( p->aRef[1]==0 ){ + p->aRef[1] = 1; + aOut = &p->aMatchinfo[1]; + xRet = fts3MIBufferFree; + } + else if( p->aRef[2]==0 ){ + p->aRef[2] = 1; + aOut = &p->aMatchinfo[p->nElem+2]; + xRet = fts3MIBufferFree; + }else{ + aOut = (u32*)sqlite3_malloc(p->nElem * sizeof(u32)); + if( aOut ){ + xRet = sqlite3_free; + if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32)); + } + } + + *paOut = aOut; + return xRet; +} + +static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){ + p->bGlobal = 1; + memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32)); +} + +/* +** Free a MatchinfoBuffer object allocated using fts3MIBufferNew() +*/ +void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){ + if( p ){ + assert( p->aRef[0]==1 ); + p->aRef[0] = 0; + if( p->aRef[0]==0 && p->aRef[1]==0 && p->aRef[2]==0 ){ + sqlite3_free(p); + } + } +} + +/* +** End of MatchinfoBuffer code. +*************************************************************************/ + + /* ** This function is used to help iterate through a position-list. A position ** list is a list of unique integers, sorted from smallest to largest. Each @@ -143,7 +248,7 @@ static int fts3ExprIterate2( void *pCtx /* Second argument to pass to callback */ ){ int rc; /* Return code */ - int eType = pExpr->eType; /* Type of expression node pExpr */ + int eType = pExpr->eType; /* Type of expression node pExpr */ if( eType!=FTSQUERY_PHRASE ){ assert( pExpr->pLeft && pExpr->pRight ); @@ -177,6 +282,7 @@ static int fts3ExprIterate( return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx); } + /* ** This is an fts3ExprIterate() callback used while loading the doclists ** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also @@ -221,8 +327,7 @@ static int fts3ExprLoadDoclists( static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ (*(int *)ctx)++; - UNUSED_PARAMETER(pExpr); - UNUSED_PARAMETER(iPhrase); + pExpr->iPhrase = iPhrase; return SQLITE_OK; } static int fts3ExprPhraseCount(Fts3Expr *pExpr){ @@ -443,7 +548,7 @@ static int fts3BestSnippet( sIter.nSnippet = nSnippet; sIter.nPhrase = nList; sIter.iCurrent = -1; - rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter); + rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter); if( rc==SQLITE_OK ){ /* Set the *pmSeen output variable. */ @@ -744,6 +849,60 @@ static int fts3ColumnlistCount(char **ppCollist){ return nEntry; } +/* +** This function gathers 'y' or 'b' data for a single phrase. +*/ +static void fts3ExprLHits( + Fts3Expr *pExpr, /* Phrase expression node */ + MatchInfo *p /* Matchinfo context */ +){ + Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab; + int iStart; + Fts3Phrase *pPhrase = pExpr->pPhrase; + char *pIter = pPhrase->doclist.pList; + int iCol = 0; + + assert( p->flag==FTS3_MATCHINFO_LHITS_BM || p->flag==FTS3_MATCHINFO_LHITS ); + if( p->flag==FTS3_MATCHINFO_LHITS ){ + iStart = pExpr->iPhrase * p->nCol; + }else{ + iStart = pExpr->iPhrase * ((p->nCol + 31) / 32); + } + + while( 1 ){ + int nHit = fts3ColumnlistCount(&pIter); + if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){ + if( p->flag==FTS3_MATCHINFO_LHITS ){ + p->aMatchinfo[iStart + iCol] = (u32)nHit; + }else if( nHit ){ + p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F)); + } + } + assert( *pIter==0x00 || *pIter==0x01 ); + if( *pIter!=0x01 ) break; + pIter++; + pIter += fts3GetVarint32(pIter, &iCol); + } +} + +/* +** Gather the results for matchinfo directives 'y' and 'b'. +*/ +static void fts3ExprLHitGather( + Fts3Expr *pExpr, + MatchInfo *p +){ + assert( (pExpr->pLeft==0)==(pExpr->pRight==0) ); + if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){ + if( pExpr->pLeft ){ + fts3ExprLHitGather(pExpr->pLeft, p); + fts3ExprLHitGather(pExpr->pRight, p); + }else{ + fts3ExprLHits(pExpr, p); + } + } +} + /* ** fts3ExprIterate() callback used to collect the "global" matchinfo stats ** for a single query. @@ -810,51 +969,6 @@ static int fts3ExprLocalHitsCb( return rc; } -/* -** fts3ExprIterate() callback used to gather information for the matchinfo -** directive 'y'. -*/ -static int fts3ExprLHitsCb( - Fts3Expr *pExpr, /* Phrase expression node */ - int iPhrase, /* Phrase number */ - void *pCtx /* Pointer to MatchInfo structure */ -){ - MatchInfo *p = (MatchInfo *)pCtx; - Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab; - int rc = SQLITE_OK; - int iStart = iPhrase * p->nCol; - Fts3Expr *pEof; /* Ancestor node already at EOF */ - - /* This must be a phrase */ - assert( pExpr->pPhrase ); - - /* Initialize all output integers to zero. */ - memset(&p->aMatchinfo[iStart], 0, sizeof(u32) * p->nCol); - - /* Check if this or any parent node is at EOF. If so, then all output - ** values are zero. */ - for(pEof=pExpr; pEof && pEof->bEof==0; pEof=pEof->pParent); - - if( pEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){ - Fts3Phrase *pPhrase = pExpr->pPhrase; - char *pIter = pPhrase->doclist.pList; - int iCol = 0; - - while( 1 ){ - int nHit = fts3ColumnlistCount(&pIter); - if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){ - p->aMatchinfo[iStart + iCol] = (u32)nHit; - } - assert( *pIter==0x00 || *pIter==0x01 ); - if( *pIter!=0x01 ) break; - pIter++; - pIter += fts3GetVarint32(pIter, &iCol); - } - } - - return rc; -} - static int fts3MatchinfoCheck( Fts3Table *pTab, char cArg, @@ -868,6 +982,7 @@ static int fts3MatchinfoCheck( || (cArg==FTS3_MATCHINFO_LCS) || (cArg==FTS3_MATCHINFO_HITS) || (cArg==FTS3_MATCHINFO_LHITS) + || (cArg==FTS3_MATCHINFO_LHITS_BM) ){ return SQLITE_OK; } @@ -895,6 +1010,10 @@ static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ nVal = pInfo->nCol * pInfo->nPhrase; break; + case FTS3_MATCHINFO_LHITS_BM: + nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32); + break; + default: assert( cArg==FTS3_MATCHINFO_HITS ); nVal = pInfo->nCol * pInfo->nPhrase * 3; @@ -1089,7 +1208,7 @@ static int fts3MatchinfoValues( sqlite3_stmt *pSelect = 0; for(i=0; rc==SQLITE_OK && zArg[i]; i++){ - + pInfo->flag = zArg[i]; switch( zArg[i] ){ case FTS3_MATCHINFO_NPHRASE: if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nPhrase; @@ -1149,9 +1268,13 @@ static int fts3MatchinfoValues( } break; - case FTS3_MATCHINFO_LHITS: - (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLHitsCb, (void*)pInfo); + case FTS3_MATCHINFO_LHITS_BM: + case FTS3_MATCHINFO_LHITS: { + int nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); + memset(pInfo->aMatchinfo, 0, nZero); + fts3ExprLHitGather(pCsr->pExpr, pInfo); break; + } default: { Fts3Expr *pExpr; @@ -1165,6 +1288,7 @@ static int fts3MatchinfoValues( if( rc!=SQLITE_OK ) break; } rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo); + sqlite3Fts3EvalTestDeferred(pCsr, &rc); if( rc!=SQLITE_OK ) break; } (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo); @@ -1184,7 +1308,8 @@ static int fts3MatchinfoValues( ** Populate pCsr->aMatchinfo[] with data for the current row. The ** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32). */ -static int fts3GetMatchinfo( +static void fts3GetMatchinfo( + sqlite3_context *pCtx, /* Return results here */ Fts3Cursor *pCsr, /* FTS3 Cursor object */ const char *zArg /* Second argument to matchinfo() function */ ){ @@ -1193,6 +1318,9 @@ static int fts3GetMatchinfo( int rc = SQLITE_OK; int bGlobal = 0; /* Collect 'global' stats as well as local */ + u32 *aOut = 0; + void (*xDestroyOut)(void*) = 0; + memset(&sInfo, 0, sizeof(MatchInfo)); sInfo.pCursor = pCsr; sInfo.nCol = pTab->nColumn; @@ -1200,21 +1328,18 @@ static int fts3GetMatchinfo( /* If there is cached matchinfo() data, but the format string for the ** cache does not match the format string for this request, discard ** the cached data. */ - if( pCsr->zMatchinfo && strcmp(pCsr->zMatchinfo, zArg) ){ - assert( pCsr->aMatchinfo ); - sqlite3_free(pCsr->aMatchinfo); - pCsr->zMatchinfo = 0; - pCsr->aMatchinfo = 0; + if( pCsr->pMIBuffer && strcmp(pCsr->pMIBuffer->zMatchinfo, zArg) ){ + sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); + pCsr->pMIBuffer = 0; } - /* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the + /* If Fts3Cursor.pMIBuffer is NULL, then this is the first time the ** matchinfo function has been called for this query. In this case ** allocate the array used to accumulate the matchinfo data and ** initialize those elements that are constant for every row. */ - if( pCsr->aMatchinfo==0 ){ + if( pCsr->pMIBuffer==0 ){ int nMatchinfo = 0; /* Number of u32 elements in match-info */ - int nArg; /* Bytes in zArg */ int i; /* Used to iterate through zArg */ /* Determine the number of phrases in the query */ @@ -1223,30 +1348,46 @@ static int fts3GetMatchinfo( /* Determine the number of integers in the buffer returned by this call. */ for(i=0; zArg[i]; i++){ + char *zErr = 0; + if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){ + sqlite3_result_error(pCtx, zErr, -1); + sqlite3_free(zErr); + return; + } nMatchinfo += fts3MatchinfoSize(&sInfo, zArg[i]); } /* Allocate space for Fts3Cursor.aMatchinfo[] and Fts3Cursor.zMatchinfo. */ - nArg = (int)strlen(zArg); - pCsr->aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo + nArg + 1); - if( !pCsr->aMatchinfo ) return SQLITE_NOMEM; + pCsr->pMIBuffer = fts3MIBufferNew(nMatchinfo, zArg); + if( !pCsr->pMIBuffer ) rc = SQLITE_NOMEM; - pCsr->zMatchinfo = (char *)&pCsr->aMatchinfo[nMatchinfo]; - pCsr->nMatchinfo = nMatchinfo; - memcpy(pCsr->zMatchinfo, zArg, nArg+1); - memset(pCsr->aMatchinfo, 0, sizeof(u32)*nMatchinfo); pCsr->isMatchinfoNeeded = 1; bGlobal = 1; } - sInfo.aMatchinfo = pCsr->aMatchinfo; - sInfo.nPhrase = pCsr->nPhrase; - if( pCsr->isMatchinfoNeeded ){ - rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg); - pCsr->isMatchinfoNeeded = 0; + if( rc==SQLITE_OK ){ + xDestroyOut = fts3MIBufferAlloc(pCsr->pMIBuffer, &aOut); + if( xDestroyOut==0 ){ + rc = SQLITE_NOMEM; + } } - return rc; + if( rc==SQLITE_OK ){ + sInfo.aMatchinfo = aOut; + sInfo.nPhrase = pCsr->nPhrase; + rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg); + if( bGlobal ){ + fts3MIBufferSetGlobal(pCsr->pMIBuffer); + } + } + + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(pCtx, rc); + if( xDestroyOut ) xDestroyOut(aOut); + }else{ + int n = pCsr->pMIBuffer->nElem * sizeof(u32); + sqlite3_result_blob(pCtx, aOut, n, xDestroyOut); + } } /* @@ -1452,7 +1593,7 @@ void sqlite3Fts3Offsets( */ sCtx.iCol = iCol; sCtx.iTerm = 0; - (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void *)&sCtx); + (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx); /* Retreive the text stored in column iCol. If an SQL NULL is stored ** in column iCol, jump immediately to the next iteration of the loop. @@ -1544,19 +1685,9 @@ void sqlite3Fts3Matchinfo( const char *zArg /* Second arg to matchinfo() function */ ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - int rc; - int i; const char *zFormat; if( zArg ){ - for(i=0; zArg[i]; i++){ - char *zErr = 0; - if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){ - sqlite3_result_error(pContext, zErr, -1); - sqlite3_free(zErr); - return; - } - } zFormat = zArg; }else{ zFormat = FTS3_MATCHINFO_DEFAULT; @@ -1565,17 +1696,10 @@ void sqlite3Fts3Matchinfo( if( !pCsr->pExpr ){ sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC); return; - } - - /* Retrieve matchinfo() data. */ - rc = fts3GetMatchinfo(pCsr, zFormat); - sqlite3Fts3SegmentsClose(pTab); - - if( rc!=SQLITE_OK ){ - sqlite3_result_error_code(pContext, rc); }else{ - int n = pCsr->nMatchinfo * sizeof(u32); - sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT); + /* Retrieve matchinfo() data. */ + fts3GetMatchinfo(pContext, pCsr, zFormat); + sqlite3Fts3SegmentsClose(pTab); } } diff --git a/ext/fts3/fts3_tokenizer.c b/ext/fts3/fts3_tokenizer.c index 64cfe07..fcabe5c 100644 --- a/ext/fts3/fts3_tokenizer.c +++ b/ext/fts3/fts3_tokenizer.c @@ -67,6 +67,7 @@ static void scalarFunc( nName = sqlite3_value_bytes(argv[0])+1; if( argc==2 ){ +#ifdef SQLITE_ENABLE_FTS3_TOKENIZER void *pOld; int n = sqlite3_value_bytes(argv[1]); if( zName==0 || n!=sizeof(pPtr) ){ @@ -79,7 +80,14 @@ static void scalarFunc( sqlite3_result_error(context, "out of memory", -1); return; } - }else{ +#else + sqlite3_result_error(context, "fts3tokenize: " + "disabled - rebuild with -DSQLITE_ENABLE_FTS3_TOKENIZER", -1 + ); + return; +#endif /* SQLITE_ENABLE_FTS3_TOKENIZER */ + }else + { if( zName ){ pPtr = sqlite3Fts3HashFind(pHash, zName, nName); } @@ -328,6 +336,7 @@ finish: Tcl_DecrRefCount(pRet); } +#ifdef SQLITE_ENABLE_FTS3_TOKENIZER static int registerTokenizer( sqlite3 *db, @@ -349,6 +358,8 @@ int registerTokenizer( return sqlite3_finalize(pStmt); } +#endif /* SQLITE_ENABLE_FTS3_TOKENIZER */ + static int queryTokenizer( @@ -420,11 +431,13 @@ static void intTestFunc( assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") ); /* Test the storage function */ +#ifdef SQLITE_ENABLE_FTS3_TOKENIZER rc = registerTokenizer(db, "nosuchtokenizer", p1); assert( rc==SQLITE_OK ); rc = queryTokenizer(db, "nosuchtokenizer", &p2); assert( rc==SQLITE_OK ); assert( p2==p1 ); +#endif sqlite3_result_text(context, "ok", -1, SQLITE_STATIC); } diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 4cd2aeb..d5a4082 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -860,10 +860,12 @@ static int fts3PendingTermsAdd( */ static int fts3PendingTermsDocid( Fts3Table *p, /* Full-text table handle */ + int bDelete, /* True if this op is a delete */ int iLangid, /* Language id of row being written */ sqlite_int64 iDocid /* Docid of row being written */ ){ assert( iLangid>=0 ); + assert( bDelete==1 || bDelete==0 ); /* TODO(shess) Explore whether partially flushing the buffer on ** forced-flush would provide better performance. I suspect that if @@ -871,7 +873,8 @@ static int fts3PendingTermsDocid( ** buffer was half empty, that would let the less frequent terms ** generate longer doclists. */ - if( iDocid<=p->iPrevDocid + if( iDocidiPrevDocid + || (iDocid==p->iPrevDocid && p->bPrevDelete==0) || p->iPrevLangid!=iLangid || p->nPendingData>p->nMaxPendingData ){ @@ -880,6 +883,7 @@ static int fts3PendingTermsDocid( } p->iPrevDocid = iDocid; p->iPrevLangid = iLangid; + p->bPrevDelete = bDelete; return SQLITE_OK; } @@ -1069,7 +1073,8 @@ static void fts3DeleteTerms( if( SQLITE_ROW==sqlite3_step(pSelect) ){ int i; int iLangid = langidFromSelect(p, pSelect); - rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pSelect, 0)); + i64 iDocid = sqlite3_column_int64(pSelect, 0); + rc = fts3PendingTermsDocid(p, 1, iLangid, iDocid); for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){ int iCol = i-1; if( p->abNotindexed[iCol]==0 ){ @@ -1317,14 +1322,19 @@ static int fts3SegReaderNext( if( fts3SegReaderIsPending(pReader) ){ Fts3HashElem *pElem = *(pReader->ppNextElem); - if( pElem==0 ){ - pReader->aNode = 0; - }else{ + sqlite3_free(pReader->aNode); + pReader->aNode = 0; + if( pElem ){ + char *aCopy; PendingList *pList = (PendingList *)fts3HashData(pElem); + int nCopy = pList->nData+1; pReader->zTerm = (char *)fts3HashKey(pElem); pReader->nTerm = fts3HashKeysize(pElem); - pReader->nNode = pReader->nDoclist = pList->nData + 1; - pReader->aNode = pReader->aDoclist = pList->aData; + aCopy = (char*)sqlite3_malloc(nCopy); + if( !aCopy ) return SQLITE_NOMEM; + memcpy(aCopy, pList->aData, nCopy); + pReader->nNode = pReader->nDoclist = nCopy; + pReader->aNode = pReader->aDoclist = aCopy; pReader->ppNextElem++; assert( pReader->aNode ); } @@ -1564,12 +1574,14 @@ int sqlite3Fts3MsrOvfl( ** second argument. */ void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ - if( pReader && !fts3SegReaderIsPending(pReader) ){ - sqlite3_free(pReader->zTerm); + if( pReader ){ + if( !fts3SegReaderIsPending(pReader) ){ + sqlite3_free(pReader->zTerm); + } if( !fts3SegReaderIsRootOnly(pReader) ){ sqlite3_free(pReader->aNode); - sqlite3_blob_close(pReader->pBlob); } + sqlite3_blob_close(pReader->pBlob); } sqlite3_free(pReader); } @@ -3512,7 +3524,7 @@ static int fts3DoRebuild(Fts3Table *p){ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ int iCol; int iLangid = langidFromSelect(p, pStmt); - rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pStmt, 0)); + rc = fts3PendingTermsDocid(p, 0, iLangid, sqlite3_column_int64(pStmt, 0)); memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1)); for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ if( p->abNotindexed[iCol]==0 ){ @@ -5617,7 +5629,7 @@ int sqlite3Fts3UpdateMethod( } } if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){ - rc = fts3PendingTermsDocid(p, iLangid, *pRowid); + rc = fts3PendingTermsDocid(p, 0, iLangid, *pRowid); } if( rc==SQLITE_OK ){ assert( p->iPrevDocid==*pRowid ); diff --git a/ext/fts3/tool/fts3view.c b/ext/fts3/tool/fts3view.c index 6dada35..a8d7981 100644 --- a/ext/fts3/tool/fts3view.c +++ b/ext/fts3/tool/fts3view.c @@ -398,7 +398,7 @@ static void showSegmentStats(sqlite3 *db, const char *zTab){ if( sqlite3_step(pStmt)==SQLITE_ROW && (nLeaf = sqlite3_column_int(pStmt, 0))>0 ){ - int nIdx = sqlite3_column_int(pStmt, 5); + nIdx = sqlite3_column_int(pStmt, 5); sqlite3_int64 sz; printf("For level %d:\n", i); printf(" Number of indexes...................... %9d\n", nIdx); diff --git a/ext/fts3/unicode/mkunicode.tcl b/ext/fts3/unicode/mkunicode.tcl index c3083ee..aafb4e9 100644 --- a/ext/fts3/unicode/mkunicode.tcl +++ b/ext/fts3/unicode/mkunicode.tcl @@ -1,77 +1,5 @@ -# -# Parameter $zName must be a path to the file UnicodeData.txt. This command -# reads the file and returns a list of mappings required to remove all -# diacritical marks from a unicode string. Each mapping is itself a list -# consisting of two elements - the unicode codepoint and the single ASCII -# character that it should be replaced with, or an empty string if the -# codepoint should simply be removed from the input. Examples: -# -# { 224 a } (replace codepoint 224 to "a") -# { 769 "" } (remove codepoint 769 from input) -# -# Mappings are only returned for non-upper case codepoints. It is assumed -# that the input has already been folded to lower case. -# -proc rd_load_unicodedata_text {zName} { - global tl_lookup_table - - set fd [open $zName] - set lField { - code - character_name - general_category - canonical_combining_classes - bidirectional_category - character_decomposition_mapping - decimal_digit_value - digit_value - numeric_value - mirrored - unicode_1_name - iso10646_comment_field - uppercase_mapping - lowercase_mapping - titlecase_mapping - } - set lRet [list] - - while { ![eof $fd] } { - set line [gets $fd] - if {$line == ""} continue - - set fields [split $line ";"] - if {[llength $fields] != [llength $lField]} { error "parse error: $line" } - foreach $lField $fields {} - if { [llength $character_decomposition_mapping]!=2 - || [string is xdigit [lindex $character_decomposition_mapping 0]]==0 - } { - continue - } - - set iCode [expr "0x$code"] - set iAscii [expr "0x[lindex $character_decomposition_mapping 0]"] - set iDia [expr "0x[lindex $character_decomposition_mapping 1]"] - - if {[info exists tl_lookup_table($iCode)]} continue - - if { ($iAscii >= 97 && $iAscii <= 122) - || ($iAscii >= 65 && $iAscii <= 90) - } { - lappend lRet [list $iCode [string tolower [format %c $iAscii]]] - set dia($iDia) 1 - } - } - - foreach d [array names dia] { - lappend lRet [list $d ""] - } - set lRet [lsort -integer -index 0 $lRet] - - close $fd - set lRet -} - +source [file join [file dirname [info script]] parseunicode.tcl] proc print_rd {map} { global tl_lookup_table @@ -117,7 +45,7 @@ proc print_rd {map} { puts "** E\"). The resuls of passing a codepoint that corresponds to an" puts "** uppercase letter are undefined." puts "*/" - puts "static int remove_diacritic(int c)\{" + puts "static int ${::remove_diacritic}(int c)\{" puts " unsigned short aDia\[\] = \{" puts -nonewline " 0, " set i 1 @@ -204,53 +132,6 @@ proc print_isdiacritic {zFunc map} { #------------------------------------------------------------------------- -# Parameter $zName must be a path to the file UnicodeData.txt. This command -# reads the file and returns a list of codepoints (integers). The list -# contains all codepoints in the UnicodeData.txt assigned to any "General -# Category" that is not a "Letter" or "Number". -# -proc an_load_unicodedata_text {zName} { - set fd [open $zName] - set lField { - code - character_name - general_category - canonical_combining_classes - bidirectional_category - character_decomposition_mapping - decimal_digit_value - digit_value - numeric_value - mirrored - unicode_1_name - iso10646_comment_field - uppercase_mapping - lowercase_mapping - titlecase_mapping - } - set lRet [list] - - while { ![eof $fd] } { - set line [gets $fd] - if {$line == ""} continue - - set fields [split $line ";"] - if {[llength $fields] != [llength $lField]} { error "parse error: $line" } - foreach $lField $fields {} - - set iCode [expr "0x$code"] - set bAlnum [expr { - [lsearch {L N} [string range $general_category 0 0]] >= 0 - || $general_category=="Co" - }] - - if { !$bAlnum } { lappend lRet $iCode } - } - - close $fd - set lRet -} - proc an_load_separator_ranges {} { global unicodedata.txt set lSep [an_load_unicodedata_text ${unicodedata.txt}] @@ -345,9 +226,9 @@ proc print_isalnum {zFunc lRange} { an_print_range_array $lRange an_print_ascii_bitmap $lRange puts { - if( c<128 ){ + if( (unsigned int)c<128 ){ return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 ); - }else if( c<(1<<22) ){ + }else if( (unsigned int)c<(1<<22) ){ unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; int iRes = 0; int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; @@ -440,29 +321,6 @@ proc print_test_isalnum {zFunc lRange} { #------------------------------------------------------------------------- -proc tl_load_casefolding_txt {zName} { - global tl_lookup_table - - set fd [open $zName] - while { ![eof $fd] } { - set line [gets $fd] - if {[string range $line 0 0] == "#"} continue - if {$line == ""} continue - - foreach x {a b c d} {unset -nocomplain $x} - foreach {a b c d} [split $line ";"] {} - - set a2 [list] - set c2 [list] - foreach elem $a { lappend a2 [expr "0x[string trim $elem]"] } - foreach elem $c { lappend c2 [expr "0x[string trim $elem]"] } - set b [string trim $b] - set d [string trim $d] - - if {$b=="C" || $b=="S"} { set tl_lookup_table($a2) $c2 } - } -} - proc tl_create_records {} { global tl_lookup_table @@ -626,19 +484,20 @@ proc print_fold {zFunc} { tl_print_table_footer toggle tl_print_ioff_table $liOff - puts { + puts [subst -nocommands { int ret = c; - assert( c>=0 ); assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 ); if( c<128 ){ if( c>='A' && c<='Z' ) ret = c + ('a' - 'A'); }else if( c<65536 ){ + const struct TableEntry *p; int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; int iLo = 0; int iRes = -1; + assert( c>aEntry[0].iCode ); while( iHi>=iLo ){ int iTest = (iHi + iLo) / 2; int cmp = (c - aEntry[iTest].iCode); @@ -649,19 +508,17 @@ proc print_fold {zFunc} { iHi = iTest-1; } } - assert( iRes<0 || c>=aEntry[iRes].iCode ); - if( iRes>=0 ){ - const struct TableEntry *p = &aEntry[iRes]; - if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ - ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; - assert( ret>0 ); - } + assert( iRes>=0 && c>=aEntry[iRes].iCode ); + p = &aEntry[iRes]; + if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ + ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; + assert( ret>0 ); } - if( bRemoveDiacritic ) ret = remove_diacritic(ret); - } + if( bRemoveDiacritic ) ret = ${::remove_diacritic}(ret); } + }] foreach entry $lHigh { tl_print_if_entry $entry @@ -732,8 +589,12 @@ proc print_fileheader {} { */ }] puts "" - puts "#ifndef SQLITE_DISABLE_FTS3_UNICODE" - puts "#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)" + if {$::generate_fts5_code} { + # no-op + } else { + puts "#ifndef SQLITE_DISABLE_FTS3_UNICODE" + puts "#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)" + } puts "" puts "#include " puts "" @@ -760,22 +621,40 @@ proc print_test_main {} { # our liking. # proc usage {} { - puts -nonewline stderr "Usage: $::argv0 ?-test? " + puts -nonewline stderr "Usage: $::argv0 ?-test? ?-fts5? " puts stderr " " exit 1 } -if {[llength $argv]!=2 && [llength $argv]!=3} usage -if {[llength $argv]==3 && [lindex $argv 0]!="-test"} usage +if {[llength $argv]<2} usage set unicodedata.txt [lindex $argv end] set casefolding.txt [lindex $argv end-1] -set generate_test_code [expr {[llength $argv]==3}] + +set remove_diacritic remove_diacritic +set generate_test_code 0 +set generate_fts5_code 0 +set function_prefix "sqlite3Fts" +for {set i 0} {$i < [llength $argv]-2} {incr i} { + switch -- [lindex $argv $i] { + -test { + set generate_test_code 1 + } + -fts5 { + set function_prefix sqlite3Fts5 + set generate_fts5_code 1 + set remove_diacritic fts5_remove_diacritic + } + default { + usage + } + } +} print_fileheader # Print the isalnum() function to stdout. # set lRange [an_load_separator_ranges] -print_isalnum sqlite3FtsUnicodeIsalnum $lRange +print_isalnum ${function_prefix}UnicodeIsalnum $lRange # Leave a gap between the two generated C functions. # @@ -790,22 +669,26 @@ set mappings [rd_load_unicodedata_text ${unicodedata.txt}] print_rd $mappings puts "" puts "" -print_isdiacritic sqlite3FtsUnicodeIsdiacritic $mappings +print_isdiacritic ${function_prefix}UnicodeIsdiacritic $mappings puts "" puts "" # Print the fold() function to stdout. # -print_fold sqlite3FtsUnicodeFold +print_fold ${function_prefix}UnicodeFold # Print the test routines and main() function to stdout, if -test # was specified. # if {$::generate_test_code} { - print_test_isalnum sqlite3FtsUnicodeIsalnum $lRange - print_fold_test sqlite3FtsUnicodeFold $mappings + print_test_isalnum ${function_prefix}UnicodeIsalnum $lRange + print_fold_test ${function_prefix}UnicodeFold $mappings print_test_main } -puts "#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */" -puts "#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */" +if {$generate_fts5_code} { + # no-op +} else { + puts "#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */" + puts "#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */" +} diff --git a/ext/fts3/unicode/parseunicode.tcl b/ext/fts3/unicode/parseunicode.tcl new file mode 100644 index 0000000..0cb2c83 --- /dev/null +++ b/ext/fts3/unicode/parseunicode.tcl @@ -0,0 +1,146 @@ + +#-------------------------------------------------------------------------- +# Parameter $zName must be a path to the file UnicodeData.txt. This command +# reads the file and returns a list of mappings required to remove all +# diacritical marks from a unicode string. Each mapping is itself a list +# consisting of two elements - the unicode codepoint and the single ASCII +# character that it should be replaced with, or an empty string if the +# codepoint should simply be removed from the input. Examples: +# +# { 224 a } (replace codepoint 224 to "a") +# { 769 "" } (remove codepoint 769 from input) +# +# Mappings are only returned for non-upper case codepoints. It is assumed +# that the input has already been folded to lower case. +# +proc rd_load_unicodedata_text {zName} { + global tl_lookup_table + + set fd [open $zName] + set lField { + code + character_name + general_category + canonical_combining_classes + bidirectional_category + character_decomposition_mapping + decimal_digit_value + digit_value + numeric_value + mirrored + unicode_1_name + iso10646_comment_field + uppercase_mapping + lowercase_mapping + titlecase_mapping + } + set lRet [list] + + while { ![eof $fd] } { + set line [gets $fd] + if {$line == ""} continue + + set fields [split $line ";"] + if {[llength $fields] != [llength $lField]} { error "parse error: $line" } + foreach $lField $fields {} + if { [llength $character_decomposition_mapping]!=2 + || [string is xdigit [lindex $character_decomposition_mapping 0]]==0 + } { + continue + } + + set iCode [expr "0x$code"] + set iAscii [expr "0x[lindex $character_decomposition_mapping 0]"] + set iDia [expr "0x[lindex $character_decomposition_mapping 1]"] + + if {[info exists tl_lookup_table($iCode)]} continue + + if { ($iAscii >= 97 && $iAscii <= 122) + || ($iAscii >= 65 && $iAscii <= 90) + } { + lappend lRet [list $iCode [string tolower [format %c $iAscii]]] + set dia($iDia) 1 + } + } + + foreach d [array names dia] { + lappend lRet [list $d ""] + } + set lRet [lsort -integer -index 0 $lRet] + + close $fd + set lRet +} + +#------------------------------------------------------------------------- +# Parameter $zName must be a path to the file UnicodeData.txt. This command +# reads the file and returns a list of codepoints (integers). The list +# contains all codepoints in the UnicodeData.txt assigned to any "General +# Category" that is not a "Letter" or "Number". +# +proc an_load_unicodedata_text {zName} { + set fd [open $zName] + set lField { + code + character_name + general_category + canonical_combining_classes + bidirectional_category + character_decomposition_mapping + decimal_digit_value + digit_value + numeric_value + mirrored + unicode_1_name + iso10646_comment_field + uppercase_mapping + lowercase_mapping + titlecase_mapping + } + set lRet [list] + + while { ![eof $fd] } { + set line [gets $fd] + if {$line == ""} continue + + set fields [split $line ";"] + if {[llength $fields] != [llength $lField]} { error "parse error: $line" } + foreach $lField $fields {} + + set iCode [expr "0x$code"] + set bAlnum [expr { + [lsearch {L N} [string range $general_category 0 0]] >= 0 + || $general_category=="Co" + }] + + if { !$bAlnum } { lappend lRet $iCode } + } + + close $fd + set lRet +} + +proc tl_load_casefolding_txt {zName} { + global tl_lookup_table + + set fd [open $zName] + while { ![eof $fd] } { + set line [gets $fd] + if {[string range $line 0 0] == "#"} continue + if {$line == ""} continue + + foreach x {a b c d} {unset -nocomplain $x} + foreach {a b c d} [split $line ";"] {} + + set a2 [list] + set c2 [list] + foreach elem $a { lappend a2 [expr "0x[string trim $elem]"] } + foreach elem $c { lappend c2 [expr "0x[string trim $elem]"] } + set b [string trim $b] + set d [string trim $d] + + if {$b=="C" || $b=="S"} { set tl_lookup_table($a2) $c2 } + } +} + + diff --git a/ext/fts5/extract_api_docs.tcl b/ext/fts5/extract_api_docs.tcl new file mode 100644 index 0000000..2320d70 --- /dev/null +++ b/ext/fts5/extract_api_docs.tcl @@ -0,0 +1,252 @@ +# +# 2014 August 24 +# +# 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 script extracts the documentation for the API used by fts5 auxiliary +# functions from header file fts5.h. It outputs html text on stdout that +# is included in the documentation on the web. +# + +set ::fts5_docs_output "" +if {[info commands hd_putsnl]==""} { + if {[llength $argv]>0} { set ::extract_api_docs_mode [lindex $argv 0] } + proc output {text} { + puts $text + } +} else { + proc output {text} { + append ::fts5_docs_output "$text\n" + } +} +if {[info exists ::extract_api_docs_mode]==0} {set ::extract_api_docs_mode api} + + +set input_file [file join [file dir [info script]] fts5.h] +set fd [open $input_file] +set data [read $fd] +close $fd + + +# Argument $data is the entire text of the fts5.h file. This function +# extracts the definition of the Fts5ExtensionApi structure from it and +# returns a key/value list of structure member names and definitions. i.e. +# +# iVersion {int iVersion} xUserData {void *(*xUserData)(Fts5Context*)} ... +# +proc get_struct_members {data} { + + # Extract the structure definition from the fts5.h file. + regexp "struct Fts5ExtensionApi {(.*?)};" $data -> defn + + # Remove all comments from the structure definition + regsub -all {/[*].*?[*]/} $defn {} defn2 + + set res [list] + foreach member [split $defn2 {;}] { + + set member [string trim $member] + if {$member!=""} { + catch { set name [lindex $member end] } + regexp {.*?[(][*]([^)]*)[)]} $member -> name + lappend res $name $member + } + } + + set res +} + +proc get_struct_docs {data names} { + # Extract the structure definition from the fts5.h file. + regexp {EXTENSION API FUNCTIONS(.*?)[*]/} $data -> docs + + set current_doc "" + set current_header "" + + foreach line [split $docs "\n"] { + regsub {[*]*} $line {} line + if {[regexp {^ } $line]} { + append current_doc "$line\n" + } elseif {[string trim $line]==""} { + if {$current_header!=""} { append current_doc "\n" } + } else { + if {$current_doc != ""} { + lappend res $current_header $current_doc + set current_doc "" + } + set subject n/a + regexp {^ *([[:alpha:]]*)} $line -> subject + if {[lsearch $names $subject]>=0} { + set current_header $subject + } else { + set current_header [string trim $line] + } + } + } + + if {$current_doc != ""} { + lappend res $current_header $current_doc + } + + set res +} + +proc get_tokenizer_docs {data} { + regexp {(xCreate:.*?)[*]/} $data -> docs + + set res "
    \n" + foreach line [split [string trim $docs] "\n"] { + regexp {[*][*](.*)} $line -> line + if {[regexp {^ ?x.*:} $line]} { + append res "
    $line

    \n" + continue + } + if {[regexp {SYNONYM SUPPORT} $line]} { + set line "

    Synonym Support

    " + } + if {[string trim $line] == ""} { + append res "

    \n" + } else { + append res "$line\n" + } + } + + set res +} + +proc get_api_docs {data} { + # Initialize global array M as a map from Fts5StructureApi member name + # to member definition. i.e. + # + # iVersion -> {int iVersion} + # xUserData -> {void *(*xUserData)(Fts5Context*)} + # ... + # + array set M [get_struct_members $data] + + # Initialize global list D as a map from section name to documentation + # text. Most (all?) section names are structure member names. + # + set D [get_struct_docs $data [array names M]] + + output "

    " + foreach {sub docs} $D { + if {[info exists M($sub)]} { + set hdr $M($sub) + set link " id=$sub" + } else { + set link "" + } + + #output "
    " + #set style "padding-left:6ex;font-size:1.4em;display:block" + #output "
    $hdr
    " + + regsub -line {^ *[)]} $hdr ")" hdr + output "
    " + output "$hdr
    " + + set mode "" + set margin " style=margin-top:0.1em" + foreach line [split [string trim $docs] "\n"] { + if {[string trim $line]==""} { + if {$mode != ""} {output ""} + set mode "" + } elseif {$mode == ""} { + if {[regexp {^ } $line]} { + set mode codeblock + } else { + set mode p + } + output "<$mode$margin>" + set margin "" + } + output $line + } + if {$mode != ""} {output ""} + output "
    " + } + output "
    " +} + +proc get_fts5_struct {data start end} { + set res "" + set bOut 0 + foreach line [split $data "\n"] { + if {$bOut==0} { + if {[regexp $start $line]} { + set bOut 1 + } + } + + if {$bOut} { + append res "$line\n" + } + + if {$bOut} { + if {[regexp $end $line]} { + set bOut 0 + } + } + } + + set map [list /* /* */ */] + string map $map $res +} + +proc main {data} { + switch $::extract_api_docs_mode { + fts5_api { + output [get_fts5_struct $data "typedef struct fts5_api" "^\};"] + } + + fts5_tokenizer { + output [get_fts5_struct $data "typedef struct Fts5Tokenizer" "^\};"] + output [get_fts5_struct $data \ + "Flags that may be passed as the third argument to xTokenize()" \ + "#define FTS5_TOKEN_COLOCATED" + ] + } + + fts5_extension { + output [get_fts5_struct $data "typedef.*Fts5ExtensionApi" "^.;"] + } + + Fts5ExtensionApi { + set struct [get_fts5_struct $data "^struct Fts5ExtensionApi" "^.;"] + set map [list] + foreach {k v} [get_struct_members $data] { + if {[string match x* $k]==0} continue + lappend map $k "
    $k" + } + output [string map $map $struct] + } + + api { + get_api_docs $data + } + + tokenizer_api { + output [get_tokenizer_docs $data] + } + + default { + } + } +} +main $data + +set ::fts5_docs_output + + + + + diff --git a/ext/fts5/fts5.h b/ext/fts5/fts5.h new file mode 100644 index 0000000..96ecb38 --- /dev/null +++ b/ext/fts5/fts5.h @@ -0,0 +1,578 @@ +/* +** 2014 May 31 +** +** 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. +** +****************************************************************************** +** +** Interfaces to extend FTS5. Using the interfaces defined in this file, +** FTS5 may be extended with: +** +** * custom tokenizers, and +** * custom auxiliary functions. +*/ + + +#ifndef _FTS5_H +#define _FTS5_H + +#include "sqlite3.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************* +** CUSTOM AUXILIARY FUNCTIONS +** +** Virtual table implementations may overload SQL functions by implementing +** the sqlite3_module.xFindFunction() method. +*/ + +typedef struct Fts5ExtensionApi Fts5ExtensionApi; +typedef struct Fts5Context Fts5Context; +typedef struct Fts5PhraseIter Fts5PhraseIter; + +typedef void (*fts5_extension_function)( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +); + +struct Fts5PhraseIter { + const unsigned char *a; + const unsigned char *b; +}; + +/* +** EXTENSION API FUNCTIONS +** +** xUserData(pFts): +** Return a copy of the context pointer the extension function was +** registered with. +** +** xColumnTotalSize(pFts, iCol, pnToken): +** If parameter iCol is less than zero, set output variable *pnToken +** to the total number of tokens in the FTS5 table. Or, if iCol is +** non-negative but less than the number of columns in the table, return +** the total number of tokens in column iCol, considering all rows in +** the FTS5 table. +** +** If parameter iCol is greater than or equal to the number of columns +** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. +** an OOM condition or IO error), an appropriate SQLite error code is +** returned. +** +** xColumnCount(pFts): +** Return the number of columns in the table. +** +** xColumnSize(pFts, iCol, pnToken): +** If parameter iCol is less than zero, set output variable *pnToken +** to the total number of tokens in the current row. Or, if iCol is +** non-negative but less than the number of columns in the table, set +** *pnToken to the number of tokens in column iCol of the current row. +** +** If parameter iCol is greater than or equal to the number of columns +** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. +** an OOM condition or IO error), an appropriate SQLite error code is +** returned. +** +** This function may be quite inefficient if used with an FTS5 table +** created with the "columnsize=0" option. +** +** xColumnText: +** This function attempts to retrieve the text of column iCol of the +** current document. If successful, (*pz) is set to point to a buffer +** containing the text in utf-8 encoding, (*pn) is set to the size in bytes +** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, +** if an error occurs, an SQLite error code is returned and the final values +** of (*pz) and (*pn) are undefined. +** +** xPhraseCount: +** Returns the number of phrases in the current query expression. +** +** xPhraseSize: +** Returns the number of tokens in phrase iPhrase of the query. Phrases +** are numbered starting from zero. +** +** xInstCount: +** Set *pnInst to the total number of occurrences of all phrases within +** the query within the current row. Return SQLITE_OK if successful, or +** an error code (i.e. SQLITE_NOMEM) if an error occurs. +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always returns 0. +** +** xInst: +** Query for the details of phrase match iIdx within the current row. +** Phrase matches are numbered starting from zero, so the iIdx argument +** should be greater than or equal to zero and smaller than the value +** output by xInstCount(). +** +** Usually, output parameter *piPhrase is set to the phrase number, *piCol +** to the column in which it occurs and *piOff the token offset of the +** first token of the phrase. The exception is if the table was created +** with the offsets=0 option specified. In this case *piOff is always +** set to -1. +** +** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) +** if an error occurs. +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. +** +** xRowid: +** Returns the rowid of the current row. +** +** xTokenize: +** Tokenize text using the tokenizer belonging to the FTS5 table. +** +** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback): +** This API function is used to query the FTS table for phrase iPhrase +** of the current query. Specifically, a query equivalent to: +** +** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid +** +** with $p set to a phrase equivalent to the phrase iPhrase of the +** current query is executed. For each row visited, the callback function +** passed as the fourth argument is invoked. The context and API objects +** passed to the callback function may be used to access the properties of +** each matched row. Invoking Api.xUserData() returns a copy of the pointer +** passed as the third argument to pUserData. +** +** If the callback function returns any value other than SQLITE_OK, the +** query is abandoned and the xQueryPhrase function returns immediately. +** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. +** Otherwise, the error code is propagated upwards. +** +** If the query runs to completion without incident, SQLITE_OK is returned. +** Or, if some error occurs before the query completes or is aborted by +** the callback, an SQLite error code is returned. +** +** +** xSetAuxdata(pFts5, pAux, xDelete) +** +** Save the pointer passed as the second argument as the extension functions +** "auxiliary data". The pointer may then be retrieved by the current or any +** future invocation of the same fts5 extension function made as part of +** of the same MATCH query using the xGetAuxdata() API. +** +** Each extension function is allocated a single auxiliary data slot for +** each FTS query (MATCH expression). If the extension function is invoked +** more than once for a single FTS query, then all invocations share a +** single auxiliary data context. +** +** If there is already an auxiliary data pointer when this function is +** invoked, then it is replaced by the new pointer. If an xDelete callback +** was specified along with the original pointer, it is invoked at this +** point. +** +** The xDelete callback, if one is specified, is also invoked on the +** auxiliary data pointer after the FTS5 query has finished. +** +** If an error (e.g. an OOM condition) occurs within this function, an +** the auxiliary data is set to NULL and an error code returned. If the +** xDelete parameter was not NULL, it is invoked on the auxiliary data +** pointer before returning. +** +** +** xGetAuxdata(pFts5, bClear) +** +** Returns the current auxiliary data pointer for the fts5 extension +** function. See the xSetAuxdata() method for details. +** +** If the bClear argument is non-zero, then the auxiliary data is cleared +** (set to NULL) before this function returns. In this case the xDelete, +** if any, is not invoked. +** +** +** xRowCount(pFts5, pnRow) +** +** This function is used to retrieve the total number of rows in the table. +** In other words, the same value that would be returned by: +** +** SELECT count(*) FROM ftstable; +** +** xPhraseFirst() +** This function is used, along with type Fts5PhraseIter and the xPhraseNext +** method, to iterate through all instances of a single query phrase within +** the current row. This is the same information as is accessible via the +** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient +** to use, this API may be faster under some circumstances. To iterate +** through instances of phrase iPhrase, use the following code: +** +** Fts5PhraseIter iter; +** int iCol, iOff; +** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); +** iCol>=0; +** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) +** ){ +** // An instance of phrase iPhrase at offset iOff of column iCol +** } +** +** The Fts5PhraseIter structure is defined above. Applications should not +** modify this structure directly - it should only be used as shown above +** with the xPhraseFirst() and xPhraseNext() API methods (and by +** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always iterates +** through an empty set (all calls to xPhraseFirst() set iCol to -1). +** +** xPhraseNext() +** See xPhraseFirst above. +** +** xPhraseFirstColumn() +** This function and xPhraseNextColumn() are similar to the xPhraseFirst() +** and xPhraseNext() APIs described above. The difference is that instead +** of iterating through all instances of a phrase in the current row, these +** APIs are used to iterate through the set of columns in the current row +** that contain one or more instances of a specified phrase. For example: +** +** Fts5PhraseIter iter; +** int iCol; +** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); +** iCol>=0; +** pApi->xPhraseNextColumn(pFts, &iter, &iCol) +** ){ +** // Column iCol contains at least one instance of phrase iPhrase +** } +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" option. If the FTS5 table is created with either +** "detail=none" "content=" option (i.e. if it is a contentless table), +** then this API always iterates through an empty set (all calls to +** xPhraseFirstColumn() set iCol to -1). +** +** The information accessed using this API and its companion +** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext +** (or xInst/xInstCount). The chief advantage of this API is that it is +** significantly more efficient than those alternatives when used with +** "detail=column" tables. +** +** xPhraseNextColumn() +** See xPhraseFirstColumn above. +*/ +struct Fts5ExtensionApi { + int iVersion; /* Currently always set to 3 */ + + void *(*xUserData)(Fts5Context*); + + int (*xColumnCount)(Fts5Context*); + int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); + int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); + + int (*xTokenize)(Fts5Context*, + const char *pText, int nText, /* Text to tokenize */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ + ); + + int (*xPhraseCount)(Fts5Context*); + int (*xPhraseSize)(Fts5Context*, int iPhrase); + + int (*xInstCount)(Fts5Context*, int *pnInst); + int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff); + + sqlite3_int64 (*xRowid)(Fts5Context*); + int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn); + int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken); + + int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData, + int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) + ); + int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); + void *(*xGetAuxdata)(Fts5Context*, int bClear); + + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); + void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); + + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); +}; + +/* +** CUSTOM AUXILIARY FUNCTIONS +*************************************************************************/ + +/************************************************************************* +** CUSTOM TOKENIZERS +** +** Applications may also register custom tokenizer types. A tokenizer +** is registered by providing fts5 with a populated instance of the +** following structure. All structure methods must be defined, setting +** any member of the fts5_tokenizer struct to NULL leads to undefined +** behaviour. The structure methods are expected to function as follows: +** +** xCreate: +** This function is used to allocate and inititalize a tokenizer instance. +** A tokenizer instance is required to actually tokenize text. +** +** The first argument passed to this function is a copy of the (void*) +** pointer provided by the application when the fts5_tokenizer object +** was registered with FTS5 (the third argument to xCreateTokenizer()). +** The second and third arguments are an array of nul-terminated strings +** containing the tokenizer arguments, if any, specified following the +** tokenizer name as part of the CREATE VIRTUAL TABLE statement used +** to create the FTS5 table. +** +** The final argument is an output variable. If successful, (*ppOut) +** should be set to point to the new tokenizer handle and SQLITE_OK +** returned. If an error occurs, some value other than SQLITE_OK should +** be returned. In this case, fts5 assumes that the final value of *ppOut +** is undefined. +** +** xDelete: +** This function is invoked to delete a tokenizer handle previously +** allocated using xCreate(). Fts5 guarantees that this function will +** be invoked exactly once for each successful call to xCreate(). +** +** xTokenize: +** This function is expected to tokenize the nText byte string indicated +** by argument pText. pText may or may not be nul-terminated. The first +** argument passed to this function is a pointer to an Fts5Tokenizer object +** returned by an earlier call to xCreate(). +** +** The second argument indicates the reason that FTS5 is requesting +** tokenization of the supplied text. This is always one of the following +** four values: +** +**
    • FTS5_TOKENIZE_DOCUMENT - A document is being inserted into +** or removed from the FTS table. The tokenizer is being invoked to +** determine the set of tokens to add to (or delete from) the +** FTS index. +** +**
    • FTS5_TOKENIZE_QUERY - A MATCH query is being executed +** against the FTS index. The tokenizer is being called to tokenize +** a bareword or quoted string specified as part of the query. +** +**
    • (FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) - Same as +** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is +** followed by a "*" character, indicating that the last token +** returned by the tokenizer will be treated as a token prefix. +** +**
    • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to +** satisfy an fts5_api.xTokenize() request made by an auxiliary +** function. Or an fts5_api.xColumnSize() request made by the same +** on a columnsize=0 database. +**
    +** +** For each token in the input string, the supplied callback xToken() must +** be invoked. The first argument to it should be a copy of the pointer +** passed as the second argument to xTokenize(). The third and fourth +** arguments are a pointer to a buffer containing the token text, and the +** size of the token in bytes. The 4th and 5th arguments are the byte offsets +** of the first byte of and first byte immediately following the text from +** which the token is derived within the input. +** +** The second argument passed to the xToken() callback ("tflags") should +** normally be set to 0. The exception is if the tokenizer supports +** synonyms. In this case see the discussion below for details. +** +** FTS5 assumes the xToken() callback is invoked for each token in the +** order that they occur within the input text. +** +** If an xToken() callback returns any value other than SQLITE_OK, then +** the tokenization should be abandoned and the xTokenize() method should +** immediately return a copy of the xToken() return value. Or, if the +** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally, +** if an error occurs with the xTokenize() implementation itself, it +** may abandon the tokenization and return any error code other than +** SQLITE_OK or SQLITE_DONE. +** +** SYNONYM SUPPORT +** +** Custom tokenizers may also support synonyms. Consider a case in which a +** user wishes to query for a phrase such as "first place". Using the +** built-in tokenizers, the FTS5 query 'first + place' will match instances +** of "first place" within the document set, but not alternative forms +** such as "1st place". In some applications, it would be better to match +** all instances of "first place" or "1st place" regardless of which form +** the user specified in the MATCH query text. +** +** There are several ways to approach this in FTS5: +** +**
    1. By mapping all synonyms to a single token. In this case, the +** In the above example, this means that the tokenizer returns the +** same token for inputs "first" and "1st". Say that token is in +** fact "first", so that when the user inserts the document "I won +** 1st place" entries are added to the index for tokens "i", "won", +** "first" and "place". If the user then queries for '1st + place', +** the tokenizer substitutes "first" for "1st" and the query works +** as expected. +** +**
    2. By adding multiple synonyms for a single term to the FTS index. +** In this case, when tokenizing query text, the tokenizer may +** provide multiple synonyms for a single term within the document. +** FTS5 then queries the index for each synonym individually. For +** example, faced with the query: +** +** +** ... MATCH 'first place' +** +** the tokenizer offers both "1st" and "first" as synonyms for the +** first token in the MATCH query and FTS5 effectively runs a query +** similar to: +** +** +** ... MATCH '(first OR 1st) place' +** +** except that, for the purposes of auxiliary functions, the query +** still appears to contain just two phrases - "(first OR 1st)" +** being treated as a single phrase. +** +**
    3. By adding multiple synonyms for a single term to the FTS index. +** Using this method, when tokenizing document text, the tokenizer +** provides multiple synonyms for each token. So that when a +** document such as "I won first place" is tokenized, entries are +** added to the FTS index for "i", "won", "first", "1st" and +** "place". +** +** This way, even if the tokenizer does not provide synonyms +** when tokenizing query text (it should not - to do would be +** inefficient), it doesn't matter if the user queries for +** 'first + place' or '1st + place', as there are entires in the +** FTS index corresponding to both forms of the first token. +**
    +** +** Whether it is parsing document or query text, any call to xToken that +** specifies a tflags argument with the FTS5_TOKEN_COLOCATED bit +** is considered to supply a synonym for the previous token. For example, +** when parsing the document "I won first place", a tokenizer that supports +** synonyms would call xToken() 5 times, as follows: +** +** +** xToken(pCtx, 0, "i", 1, 0, 1); +** xToken(pCtx, 0, "won", 3, 2, 5); +** xToken(pCtx, 0, "first", 5, 6, 11); +** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11); +** xToken(pCtx, 0, "place", 5, 12, 17); +** +** +** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time +** xToken() is called. Multiple synonyms may be specified for a single token +** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. +** There is no limit to the number of synonyms that may be provided for a +** single token. +** +** In many cases, method (1) above is the best approach. It does not add +** extra data to the FTS index or require FTS5 to query for multiple terms, +** so it is efficient in terms of disk space and query speed. However, it +** does not support prefix queries very well. If, as suggested above, the +** token "first" is subsituted for "1st" by the tokenizer, then the query: +** +** +** ... MATCH '1s*' +** +** will not match documents that contain the token "1st" (as the tokenizer +** will probably not map "1s" to any prefix of "first"). +** +** For full prefix support, method (3) may be preferred. In this case, +** because the index contains entries for both "first" and "1st", prefix +** queries such as 'fi*' or '1s*' will match correctly. However, because +** extra entries are added to the FTS index, this method uses more space +** within the database. +** +** Method (2) offers a midpoint between (1) and (3). Using this method, +** a query such as '1s*' will match documents that contain the literal +** token "1st", but not "first" (assuming the tokenizer is not able to +** provide synonyms for prefixes). However, a non-prefix query like '1st' +** will match against "1st" and "first". This method does not require +** extra disk space, as no extra entries are added to the FTS index. +** On the other hand, it may require more CPU cycles to run MATCH queries, +** as separate queries of the FTS index are required for each synonym. +** +** When using methods (2) or (3), it is important that the tokenizer only +** provide synonyms when tokenizing document text (method (2)) or query +** text (method (3)), not both. Doing so will not cause any errors, but is +** inefficient. +*/ +typedef struct Fts5Tokenizer Fts5Tokenizer; +typedef struct fts5_tokenizer fts5_tokenizer; +struct fts5_tokenizer { + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); + void (*xDelete)(Fts5Tokenizer*); + int (*xTokenize)(Fts5Tokenizer*, + void *pCtx, + int flags, /* Mask of FTS5_TOKENIZE_* flags */ + const char *pText, int nText, + int (*xToken)( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStart, /* Byte offset of token within input text */ + int iEnd /* Byte offset of end of token within input text */ + ) + ); +}; + +/* Flags that may be passed as the third argument to xTokenize() */ +#define FTS5_TOKENIZE_QUERY 0x0001 +#define FTS5_TOKENIZE_PREFIX 0x0002 +#define FTS5_TOKENIZE_DOCUMENT 0x0004 +#define FTS5_TOKENIZE_AUX 0x0008 + +/* Flags that may be passed by the tokenizer implementation back to FTS5 +** as the third argument to the supplied xToken callback. */ +#define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */ + +/* +** END OF CUSTOM TOKENIZERS +*************************************************************************/ + +/************************************************************************* +** FTS5 EXTENSION REGISTRATION API +*/ +typedef struct fts5_api fts5_api; +struct fts5_api { + int iVersion; /* Currently always set to 2 */ + + /* Create a new tokenizer */ + int (*xCreateTokenizer)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_tokenizer *pTokenizer, + void (*xDestroy)(void*) + ); + + /* Find an existing tokenizer */ + int (*xFindTokenizer)( + fts5_api *pApi, + const char *zName, + void **ppContext, + fts5_tokenizer *pTokenizer + ); + + /* Create a new auxiliary function */ + int (*xCreateFunction)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_extension_function xFunction, + void (*xDestroy)(void*) + ); +}; + +/* +** END OF REGISTRATION API +*************************************************************************/ + +#ifdef __cplusplus +} /* end of the 'extern "C"' block */ +#endif + +#endif /* _FTS5_H */ + diff --git a/ext/fts5/fts5Int.h b/ext/fts5/fts5Int.h new file mode 100644 index 0000000..af40412 --- /dev/null +++ b/ext/fts5/fts5Int.h @@ -0,0 +1,776 @@ +/* +** 2014 May 31 +** +** 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. +** +****************************************************************************** +** +*/ +#ifndef _FTS5INT_H +#define _FTS5INT_H + +#include "fts5.h" +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 + +#include +#include + +#ifndef SQLITE_AMALGAMATION + +typedef unsigned char u8; +typedef unsigned int u32; +typedef unsigned short u16; +typedef short i16; +typedef sqlite3_int64 i64; +typedef sqlite3_uint64 u64; + +#define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0]))) + +#define testcase(x) +#define ALWAYS(x) 1 +#define NEVER(x) 0 + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) + +/* +** Constants for the largest and smallest possible 64-bit signed integers. +*/ +# define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) +# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) + +#endif + + +/* +** Maximum number of prefix indexes on single FTS5 table. This must be +** less than 32. If it is set to anything large than that, an #error +** directive in fts5_index.c will cause the build to fail. +*/ +#define FTS5_MAX_PREFIX_INDEXES 31 + +#define FTS5_DEFAULT_NEARDIST 10 +#define FTS5_DEFAULT_RANK "bm25" + +/* Name of rank and rowid columns */ +#define FTS5_RANK_NAME "rank" +#define FTS5_ROWID_NAME "rowid" + +#ifdef SQLITE_DEBUG +# define FTS5_CORRUPT sqlite3Fts5Corrupt() +int sqlite3Fts5Corrupt(void); +#else +# define FTS5_CORRUPT SQLITE_CORRUPT_VTAB +#endif + +/* +** The assert_nc() macro is similar to the assert() macro, except that it +** is used for assert() conditions that are true only if it can be +** guranteed that the database is not corrupt. +*/ +#ifdef SQLITE_DEBUG +extern int sqlite3_fts5_may_be_corrupt; +# define assert_nc(x) assert(sqlite3_fts5_may_be_corrupt || (x)) +#else +# define assert_nc(x) assert(x) +#endif + +/* Mark a function parameter as unused, to suppress nuisance compiler +** warnings. */ +#ifndef UNUSED_PARAM +# define UNUSED_PARAM(X) (void)(X) +#endif + +#ifndef UNUSED_PARAM2 +# define UNUSED_PARAM2(X, Y) (void)(X), (void)(Y) +#endif + +typedef struct Fts5Global Fts5Global; +typedef struct Fts5Colset Fts5Colset; + +/* If a NEAR() clump or phrase may only match a specific set of columns, +** then an object of the following type is used to record the set of columns. +** Each entry in the aiCol[] array is a column that may be matched. +** +** This object is used by fts5_expr.c and fts5_index.c. +*/ +struct Fts5Colset { + int nCol; + int aiCol[1]; +}; + + + +/************************************************************************** +** Interface to code in fts5_config.c. fts5_config.c contains contains code +** to parse the arguments passed to the CREATE VIRTUAL TABLE statement. +*/ + +typedef struct Fts5Config Fts5Config; + +/* +** An instance of the following structure encodes all information that can +** be gleaned from the CREATE VIRTUAL TABLE statement. +** +** And all information loaded from the %_config table. +** +** nAutomerge: +** The minimum number of segments that an auto-merge operation should +** attempt to merge together. A value of 1 sets the object to use the +** compile time default. Zero disables auto-merge altogether. +** +** zContent: +** +** zContentRowid: +** The value of the content_rowid= option, if one was specified. Or +** the string "rowid" otherwise. This text is not quoted - if it is +** used as part of an SQL statement it needs to be quoted appropriately. +** +** zContentExprlist: +** +** pzErrmsg: +** This exists in order to allow the fts5_index.c module to return a +** decent error message if it encounters a file-format version it does +** not understand. +** +** bColumnsize: +** True if the %_docsize table is created. +** +** bPrefixIndex: +** This is only used for debugging. If set to false, any prefix indexes +** are ignored. This value is configured using: +** +** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex); +** +*/ +struct Fts5Config { + sqlite3 *db; /* Database handle */ + char *zDb; /* Database holding FTS index (e.g. "main") */ + char *zName; /* Name of FTS index */ + int nCol; /* Number of columns */ + char **azCol; /* Column names */ + u8 *abUnindexed; /* True for unindexed columns */ + int nPrefix; /* Number of prefix indexes */ + int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */ + int eContent; /* An FTS5_CONTENT value */ + char *zContent; /* content table */ + char *zContentRowid; /* "content_rowid=" option value */ + int bColumnsize; /* "columnsize=" option value (dflt==1) */ + int eDetail; /* FTS5_DETAIL_XXX value */ + char *zContentExprlist; + Fts5Tokenizer *pTok; + fts5_tokenizer *pTokApi; + + /* Values loaded from the %_config table */ + int iCookie; /* Incremented when %_config is modified */ + int pgsz; /* Approximate page size used in %_data */ + int nAutomerge; /* 'automerge' setting */ + int nCrisisMerge; /* Maximum allowed segments per level */ + int nHashSize; /* Bytes of memory for in-memory hash */ + char *zRank; /* Name of rank function */ + char *zRankArgs; /* Arguments to rank function */ + + /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */ + char **pzErrmsg; + +#ifdef SQLITE_DEBUG + int bPrefixIndex; /* True to use prefix-indexes */ +#endif +}; + +/* Current expected value of %_config table 'version' field */ +#define FTS5_CURRENT_VERSION 4 + +#define FTS5_CONTENT_NORMAL 0 +#define FTS5_CONTENT_NONE 1 +#define FTS5_CONTENT_EXTERNAL 2 + +#define FTS5_DETAIL_FULL 0 +#define FTS5_DETAIL_NONE 1 +#define FTS5_DETAIL_COLUMNS 2 + + + +int sqlite3Fts5ConfigParse( + Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char** +); +void sqlite3Fts5ConfigFree(Fts5Config*); + +int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig); + +int sqlite3Fts5Tokenize( + Fts5Config *pConfig, /* FTS5 Configuration object */ + int flags, /* FTS5_TOKENIZE_* flags */ + const char *pText, int nText, /* Text to tokenize */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ +); + +void sqlite3Fts5Dequote(char *z); + +/* Load the contents of the %_config table */ +int sqlite3Fts5ConfigLoad(Fts5Config*, int); + +/* Set the value of a single config attribute */ +int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, int*); + +int sqlite3Fts5ConfigParseRank(const char*, char**, char**); + +/* +** End of interface to code in fts5_config.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_buffer.c. +*/ + +/* +** Buffer object for the incremental building of string data. +*/ +typedef struct Fts5Buffer Fts5Buffer; +struct Fts5Buffer { + u8 *p; + int n; + int nSpace; +}; + +int sqlite3Fts5BufferSize(int*, Fts5Buffer*, u32); +void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64); +void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, u32, const u8*); +void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*); +void sqlite3Fts5BufferFree(Fts5Buffer*); +void sqlite3Fts5BufferZero(Fts5Buffer*); +void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*); +void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...); + +char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...); + +#define fts5BufferZero(x) sqlite3Fts5BufferZero(x) +#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c) +#define fts5BufferFree(a) sqlite3Fts5BufferFree(a) +#define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d) +#define fts5BufferSet(a,b,c,d) sqlite3Fts5BufferSet(a,b,c,d) + +#define fts5BufferGrow(pRc,pBuf,nn) ( \ + (u32)((pBuf)->n) + (u32)(nn) <= (u32)((pBuf)->nSpace) ? 0 : \ + sqlite3Fts5BufferSize((pRc),(pBuf),(nn)+(pBuf)->n) \ +) + +/* Write and decode big-endian 32-bit integer values */ +void sqlite3Fts5Put32(u8*, int); +int sqlite3Fts5Get32(const u8*); + +#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32) +#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0xFFFFFFFF) + +typedef struct Fts5PoslistReader Fts5PoslistReader; +struct Fts5PoslistReader { + /* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */ + const u8 *a; /* Position list to iterate through */ + int n; /* Size of buffer at a[] in bytes */ + int i; /* Current offset in a[] */ + + u8 bFlag; /* For client use (any custom purpose) */ + + /* Output variables */ + u8 bEof; /* Set to true at EOF */ + i64 iPos; /* (iCol<<32) + iPos */ +}; +int sqlite3Fts5PoslistReaderInit( + const u8 *a, int n, /* Poslist buffer to iterate through */ + Fts5PoslistReader *pIter /* Iterator object to initialize */ +); +int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader*); + +typedef struct Fts5PoslistWriter Fts5PoslistWriter; +struct Fts5PoslistWriter { + i64 iPrev; +}; +int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64); +void sqlite3Fts5PoslistSafeAppend(Fts5Buffer*, i64*, i64); + +int sqlite3Fts5PoslistNext64( + const u8 *a, int n, /* Buffer containing poslist */ + int *pi, /* IN/OUT: Offset within a[] */ + i64 *piOff /* IN/OUT: Current offset */ +); + +/* Malloc utility */ +void *sqlite3Fts5MallocZero(int *pRc, int nByte); +char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn); + +/* Character set tests (like isspace(), isalpha() etc.) */ +int sqlite3Fts5IsBareword(char t); + + +/* Bucket of terms object used by the integrity-check in offsets=0 mode. */ +typedef struct Fts5Termset Fts5Termset; +int sqlite3Fts5TermsetNew(Fts5Termset**); +int sqlite3Fts5TermsetAdd(Fts5Termset*, int, const char*, int, int *pbPresent); +void sqlite3Fts5TermsetFree(Fts5Termset*); + +/* +** End of interface to code in fts5_buffer.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_index.c. fts5_index.c contains contains code +** to access the data stored in the %_data table. +*/ + +typedef struct Fts5Index Fts5Index; +typedef struct Fts5IndexIter Fts5IndexIter; + +struct Fts5IndexIter { + i64 iRowid; + const u8 *pData; + int nData; + u8 bEof; +}; + +#define sqlite3Fts5IterEof(x) ((x)->bEof) + +/* +** Values used as part of the flags argument passed to IndexQuery(). +*/ +#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */ +#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */ +#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */ +#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */ + +/* The following are used internally by the fts5_index.c module. They are +** defined here only to make it easier to avoid clashes with the flags +** above. */ +#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010 +#define FTS5INDEX_QUERY_NOOUTPUT 0x0020 + +/* +** Create/destroy an Fts5Index object. +*/ +int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**); +int sqlite3Fts5IndexClose(Fts5Index *p); + +/* +** Return a simple checksum value based on the arguments. +*/ +u64 sqlite3Fts5IndexEntryCksum( + i64 iRowid, + int iCol, + int iPos, + int iIdx, + const char *pTerm, + int nTerm +); + +/* +** Argument p points to a buffer containing utf-8 text that is n bytes in +** size. Return the number of bytes in the nChar character prefix of the +** buffer, or 0 if there are less than nChar characters in total. +*/ +int sqlite3Fts5IndexCharlenToBytelen( + const char *p, + int nByte, + int nChar +); + +/* +** Open a new iterator to iterate though all rowids that match the +** specified token or token prefix. +*/ +int sqlite3Fts5IndexQuery( + Fts5Index *p, /* FTS index to query */ + const char *pToken, int nToken, /* Token (or prefix) to query for */ + int flags, /* Mask of FTS5INDEX_QUERY_X flags */ + Fts5Colset *pColset, /* Match these columns only */ + Fts5IndexIter **ppIter /* OUT: New iterator object */ +); + +/* +** The various operations on open token or token prefix iterators opened +** using sqlite3Fts5IndexQuery(). +*/ +int sqlite3Fts5IterNext(Fts5IndexIter*); +int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch); + +/* +** Close an iterator opened by sqlite3Fts5IndexQuery(). +*/ +void sqlite3Fts5IterClose(Fts5IndexIter*); + +/* +** This interface is used by the fts5vocab module. +*/ +const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*); +int sqlite3Fts5IterNextScan(Fts5IndexIter*); + + +/* +** Insert or remove data to or from the index. Each time a document is +** added to or removed from the index, this function is called one or more +** times. +** +** For an insert, it must be called once for each token in the new document. +** If the operation is a delete, it must be called (at least) once for each +** unique token in the document with an iCol value less than zero. The iPos +** argument is ignored for a delete. +*/ +int sqlite3Fts5IndexWrite( + Fts5Index *p, /* Index to write to */ + int iCol, /* Column token appears in (-ve -> delete) */ + int iPos, /* Position of token within column */ + const char *pToken, int nToken /* Token to add or remove to or from index */ +); + +/* +** Indicate that subsequent calls to sqlite3Fts5IndexWrite() pertain to +** document iDocid. +*/ +int sqlite3Fts5IndexBeginWrite( + Fts5Index *p, /* Index to write to */ + int bDelete, /* True if current operation is a delete */ + i64 iDocid /* Docid to add or remove data from */ +); + +/* +** Flush any data stored in the in-memory hash tables to the database. +** If the bCommit flag is true, also close any open blob handles. +*/ +int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit); + +/* +** Discard any data stored in the in-memory hash tables. Do not write it +** to the database. Additionally, assume that the contents of the %_data +** table may have changed on disk. So any in-memory caches of %_data +** records must be invalidated. +*/ +int sqlite3Fts5IndexRollback(Fts5Index *p); + +/* +** Get or set the "averages" values. +*/ +int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize); +int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int); + +/* +** Functions called by the storage module as part of integrity-check. +*/ +int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum); + +/* +** Called during virtual module initialization to register UDF +** fts5_decode() with SQLite +*/ +int sqlite3Fts5IndexInit(sqlite3*); + +int sqlite3Fts5IndexSetCookie(Fts5Index*, int); + +/* +** Return the total number of entries read from the %_data table by +** this connection since it was created. +*/ +int sqlite3Fts5IndexReads(Fts5Index *p); + +int sqlite3Fts5IndexReinit(Fts5Index *p); +int sqlite3Fts5IndexOptimize(Fts5Index *p); +int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge); + +int sqlite3Fts5IndexLoadConfig(Fts5Index *p); + +/* +** End of interface to code in fts5_index.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_varint.c. +*/ +int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v); +int sqlite3Fts5GetVarintLen(u32 iVal); +u8 sqlite3Fts5GetVarint(const unsigned char*, u64*); +int sqlite3Fts5PutVarint(unsigned char *p, u64 v); + +#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b) +#define fts5GetVarint sqlite3Fts5GetVarint + +#define fts5FastGetVarint32(a, iOff, nVal) { \ + nVal = (a)[iOff++]; \ + if( nVal & 0x80 ){ \ + iOff--; \ + iOff += fts5GetVarint32(&(a)[iOff], nVal); \ + } \ +} + + +/* +** End of interface to code in fts5_varint.c. +**************************************************************************/ + + +/************************************************************************** +** Interface to code in fts5.c. +*/ + +int sqlite3Fts5GetTokenizer( + Fts5Global*, + const char **azArg, + int nArg, + Fts5Tokenizer**, + fts5_tokenizer**, + char **pzErr +); + +Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, Fts5Config **); + +/* +** End of interface to code in fts5.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_hash.c. +*/ +typedef struct Fts5Hash Fts5Hash; + +/* +** Create a hash table, free a hash table. +*/ +int sqlite3Fts5HashNew(Fts5Config*, Fts5Hash**, int *pnSize); +void sqlite3Fts5HashFree(Fts5Hash*); + +int sqlite3Fts5HashWrite( + Fts5Hash*, + i64 iRowid, /* Rowid for this entry */ + int iCol, /* Column token appears in (-ve -> delete) */ + int iPos, /* Position of token within column */ + char bByte, + const char *pToken, int nToken /* Token to add or remove to or from index */ +); + +/* +** Empty (but do not delete) a hash table. +*/ +void sqlite3Fts5HashClear(Fts5Hash*); + +int sqlite3Fts5HashQuery( + Fts5Hash*, /* Hash table to query */ + const char *pTerm, int nTerm, /* Query term */ + const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */ + int *pnDoclist /* OUT: Size of doclist in bytes */ +); + +int sqlite3Fts5HashScanInit( + Fts5Hash*, /* Hash table to query */ + const char *pTerm, int nTerm /* Query prefix */ +); +void sqlite3Fts5HashScanNext(Fts5Hash*); +int sqlite3Fts5HashScanEof(Fts5Hash*); +void sqlite3Fts5HashScanEntry(Fts5Hash *, + const char **pzTerm, /* OUT: term (nul-terminated) */ + const u8 **ppDoclist, /* OUT: pointer to doclist */ + int *pnDoclist /* OUT: size of doclist in bytes */ +); + + +/* +** End of interface to code in fts5_hash.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_storage.c. fts5_storage.c contains contains +** code to access the data stored in the %_content and %_docsize tables. +*/ + +#define FTS5_STMT_SCAN_ASC 0 /* SELECT rowid, * FROM ... ORDER BY 1 ASC */ +#define FTS5_STMT_SCAN_DESC 1 /* SELECT rowid, * FROM ... ORDER BY 1 DESC */ +#define FTS5_STMT_LOOKUP 2 /* SELECT rowid, * FROM ... WHERE rowid=? */ + +typedef struct Fts5Storage Fts5Storage; + +int sqlite3Fts5StorageOpen(Fts5Config*, Fts5Index*, int, Fts5Storage**, char**); +int sqlite3Fts5StorageClose(Fts5Storage *p); +int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName); + +int sqlite3Fts5DropAll(Fts5Config*); +int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); + +int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**); +int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); +int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); + +int sqlite3Fts5StorageIntegrity(Fts5Storage *p); + +int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**); +void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*); + +int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol); +int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg); +int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow); + +int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit); +int sqlite3Fts5StorageRollback(Fts5Storage *p); + +int sqlite3Fts5StorageConfigValue( + Fts5Storage *p, const char*, sqlite3_value*, int +); + +int sqlite3Fts5StorageDeleteAll(Fts5Storage *p); +int sqlite3Fts5StorageRebuild(Fts5Storage *p); +int sqlite3Fts5StorageOptimize(Fts5Storage *p); +int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge); + +/* +** End of interface to code in fts5_storage.c. +**************************************************************************/ + + +/************************************************************************** +** Interface to code in fts5_expr.c. +*/ +typedef struct Fts5Expr Fts5Expr; +typedef struct Fts5ExprNode Fts5ExprNode; +typedef struct Fts5Parse Fts5Parse; +typedef struct Fts5Token Fts5Token; +typedef struct Fts5ExprPhrase Fts5ExprPhrase; +typedef struct Fts5ExprNearset Fts5ExprNearset; + +struct Fts5Token { + const char *p; /* Token text (not NULL terminated) */ + int n; /* Size of buffer p in bytes */ +}; + +/* Parse a MATCH expression. */ +int sqlite3Fts5ExprNew( + Fts5Config *pConfig, + const char *zExpr, + Fts5Expr **ppNew, + char **pzErr +); + +/* +** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc); +** rc==SQLITE_OK && 0==sqlite3Fts5ExprEof(pExpr); +** rc = sqlite3Fts5ExprNext(pExpr) +** ){ +** // The document with rowid iRowid matches the expression! +** i64 iRowid = sqlite3Fts5ExprRowid(pExpr); +** } +*/ +int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, int bDesc); +int sqlite3Fts5ExprNext(Fts5Expr*, i64 iMax); +int sqlite3Fts5ExprEof(Fts5Expr*); +i64 sqlite3Fts5ExprRowid(Fts5Expr*); + +void sqlite3Fts5ExprFree(Fts5Expr*); + +/* Called during startup to register a UDF with SQLite */ +int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*); + +int sqlite3Fts5ExprPhraseCount(Fts5Expr*); +int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase); +int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **); + +typedef struct Fts5PoslistPopulator Fts5PoslistPopulator; +Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int); +int sqlite3Fts5ExprPopulatePoslists( + Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int +); +void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64); +void sqlite3Fts5ExprClearEof(Fts5Expr*); + +int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**); + +int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *); + +/******************************************* +** The fts5_expr.c API above this point is used by the other hand-written +** C code in this module. The interfaces below this point are called by +** the parser code in fts5parse.y. */ + +void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...); + +Fts5ExprNode *sqlite3Fts5ParseNode( + Fts5Parse *pParse, + int eType, + Fts5ExprNode *pLeft, + Fts5ExprNode *pRight, + Fts5ExprNearset *pNear +); + +Fts5ExprPhrase *sqlite3Fts5ParseTerm( + Fts5Parse *pParse, + Fts5ExprPhrase *pPhrase, + Fts5Token *pToken, + int bPrefix +); + +Fts5ExprNearset *sqlite3Fts5ParseNearset( + Fts5Parse*, + Fts5ExprNearset*, + Fts5ExprPhrase* +); + +Fts5Colset *sqlite3Fts5ParseColset( + Fts5Parse*, + Fts5Colset*, + Fts5Token * +); + +void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase*); +void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*); +void sqlite3Fts5ParseNodeFree(Fts5ExprNode*); + +void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*); +void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*); +void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p); +void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*); + +/* +** End of interface to code in fts5_expr.c. +**************************************************************************/ + + + +/************************************************************************** +** Interface to code in fts5_aux.c. +*/ + +int sqlite3Fts5AuxInit(fts5_api*); +/* +** End of interface to code in fts5_aux.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_tokenizer.c. +*/ + +int sqlite3Fts5TokenizerInit(fts5_api*); +/* +** End of interface to code in fts5_tokenizer.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_vocab.c. +*/ + +int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*); + +/* +** End of interface to code in fts5_vocab.c. +**************************************************************************/ + + +/************************************************************************** +** Interface to automatically generated code in fts5_unicode2.c. +*/ +int sqlite3Fts5UnicodeIsalnum(int c); +int sqlite3Fts5UnicodeIsdiacritic(int c); +int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); +/* +** End of interface to code in fts5_unicode2.c. +**************************************************************************/ + +#endif diff --git a/ext/fts5/fts5_aux.c b/ext/fts5/fts5_aux.c new file mode 100644 index 0000000..836de8a --- /dev/null +++ b/ext/fts5/fts5_aux.c @@ -0,0 +1,562 @@ +/* +** 2014 May 31 +** +** 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. +** +****************************************************************************** +*/ + + +#include "fts5Int.h" +#include /* amalgamator: keep */ + +/* +** Object used to iterate through all "coalesced phrase instances" in +** a single column of the current row. If the phrase instances in the +** column being considered do not overlap, this object simply iterates +** through them. Or, if they do overlap (share one or more tokens in +** common), each set of overlapping instances is treated as a single +** match. See documentation for the highlight() auxiliary function for +** details. +** +** Usage is: +** +** for(rc = fts5CInstIterNext(pApi, pFts, iCol, &iter); +** (rc==SQLITE_OK && 0==fts5CInstIterEof(&iter); +** rc = fts5CInstIterNext(&iter) +** ){ +** printf("instance starts at %d, ends at %d\n", iter.iStart, iter.iEnd); +** } +** +*/ +typedef struct CInstIter CInstIter; +struct CInstIter { + const Fts5ExtensionApi *pApi; /* API offered by current FTS version */ + Fts5Context *pFts; /* First arg to pass to pApi functions */ + int iCol; /* Column to search */ + int iInst; /* Next phrase instance index */ + int nInst; /* Total number of phrase instances */ + + /* Output variables */ + int iStart; /* First token in coalesced phrase instance */ + int iEnd; /* Last token in coalesced phrase instance */ +}; + +/* +** Advance the iterator to the next coalesced phrase instance. Return +** an SQLite error code if an error occurs, or SQLITE_OK otherwise. +*/ +static int fts5CInstIterNext(CInstIter *pIter){ + int rc = SQLITE_OK; + pIter->iStart = -1; + pIter->iEnd = -1; + + while( rc==SQLITE_OK && pIter->iInstnInst ){ + int ip; int ic; int io; + rc = pIter->pApi->xInst(pIter->pFts, pIter->iInst, &ip, &ic, &io); + if( rc==SQLITE_OK ){ + if( ic==pIter->iCol ){ + int iEnd = io - 1 + pIter->pApi->xPhraseSize(pIter->pFts, ip); + if( pIter->iStart<0 ){ + pIter->iStart = io; + pIter->iEnd = iEnd; + }else if( io<=pIter->iEnd ){ + if( iEnd>pIter->iEnd ) pIter->iEnd = iEnd; + }else{ + break; + } + } + pIter->iInst++; + } + } + + return rc; +} + +/* +** Initialize the iterator object indicated by the final parameter to +** iterate through coalesced phrase instances in column iCol. +*/ +static int fts5CInstIterInit( + const Fts5ExtensionApi *pApi, + Fts5Context *pFts, + int iCol, + CInstIter *pIter +){ + int rc; + + memset(pIter, 0, sizeof(CInstIter)); + pIter->pApi = pApi; + pIter->pFts = pFts; + pIter->iCol = iCol; + rc = pApi->xInstCount(pFts, &pIter->nInst); + + if( rc==SQLITE_OK ){ + rc = fts5CInstIterNext(pIter); + } + + return rc; +} + + + +/************************************************************************* +** Start of highlight() implementation. +*/ +typedef struct HighlightContext HighlightContext; +struct HighlightContext { + CInstIter iter; /* Coalesced Instance Iterator */ + int iPos; /* Current token offset in zIn[] */ + int iRangeStart; /* First token to include */ + int iRangeEnd; /* If non-zero, last token to include */ + const char *zOpen; /* Opening highlight */ + const char *zClose; /* Closing highlight */ + const char *zIn; /* Input text */ + int nIn; /* Size of input text in bytes */ + int iOff; /* Current offset within zIn[] */ + char *zOut; /* Output value */ +}; + +/* +** Append text to the HighlightContext output string - p->zOut. Argument +** z points to a buffer containing n bytes of text to append. If n is +** negative, everything up until the first '\0' is appended to the output. +** +** If *pRc is set to any value other than SQLITE_OK when this function is +** called, it is a no-op. If an error (i.e. an OOM condition) is encountered, +** *pRc is set to an error code before returning. +*/ +static void fts5HighlightAppend( + int *pRc, + HighlightContext *p, + const char *z, int n +){ + if( *pRc==SQLITE_OK ){ + if( n<0 ) n = (int)strlen(z); + p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z); + if( p->zOut==0 ) *pRc = SQLITE_NOMEM; + } +} + +/* +** Tokenizer callback used by implementation of highlight() function. +*/ +static int fts5HighlightCb( + void *pContext, /* Pointer to HighlightContext object */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStartOff, /* Start offset of token */ + int iEndOff /* End offset of token */ +){ + HighlightContext *p = (HighlightContext*)pContext; + int rc = SQLITE_OK; + int iPos; + + UNUSED_PARAM2(pToken, nToken); + + if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK; + iPos = p->iPos++; + + if( p->iRangeEnd>0 ){ + if( iPosiRangeStart || iPos>p->iRangeEnd ) return SQLITE_OK; + if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff; + } + + if( iPos==p->iter.iStart ){ + fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iStartOff - p->iOff); + fts5HighlightAppend(&rc, p, p->zOpen, -1); + p->iOff = iStartOff; + } + + if( iPos==p->iter.iEnd ){ + if( p->iRangeEnd && p->iter.iStartiRangeStart ){ + fts5HighlightAppend(&rc, p, p->zOpen, -1); + } + fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); + fts5HighlightAppend(&rc, p, p->zClose, -1); + p->iOff = iEndOff; + if( rc==SQLITE_OK ){ + rc = fts5CInstIterNext(&p->iter); + } + } + + if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){ + fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); + p->iOff = iEndOff; + if( iPositer.iEnd ){ + fts5HighlightAppend(&rc, p, p->zClose, -1); + } + } + + return rc; +} + +/* +** Implementation of highlight() function. +*/ +static void fts5HighlightFunction( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +){ + HighlightContext ctx; + int rc; + int iCol; + + if( nVal!=3 ){ + const char *zErr = "wrong number of arguments to function highlight()"; + sqlite3_result_error(pCtx, zErr, -1); + return; + } + + iCol = sqlite3_value_int(apVal[0]); + memset(&ctx, 0, sizeof(HighlightContext)); + ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); + ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); + rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn); + + if( ctx.zIn ){ + if( rc==SQLITE_OK ){ + rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter); + } + + if( rc==SQLITE_OK ){ + rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); + } + fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); + + if( rc==SQLITE_OK ){ + sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT); + } + sqlite3_free(ctx.zOut); + } + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(pCtx, rc); + } +} +/* +** End of highlight() implementation. +**************************************************************************/ + +/* +** Implementation of snippet() function. +*/ +static void fts5SnippetFunction( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +){ + HighlightContext ctx; + int rc = SQLITE_OK; /* Return code */ + int iCol; /* 1st argument to snippet() */ + const char *zEllips; /* 4th argument to snippet() */ + int nToken; /* 5th argument to snippet() */ + int nInst = 0; /* Number of instance matches this row */ + int i; /* Used to iterate through instances */ + int nPhrase; /* Number of phrases in query */ + unsigned char *aSeen; /* Array of "seen instance" flags */ + int iBestCol; /* Column containing best snippet */ + int iBestStart = 0; /* First token of best snippet */ + int iBestLast; /* Last token of best snippet */ + int nBestScore = 0; /* Score of best snippet */ + int nColSize = 0; /* Total size of iBestCol in tokens */ + + if( nVal!=5 ){ + const char *zErr = "wrong number of arguments to function snippet()"; + sqlite3_result_error(pCtx, zErr, -1); + return; + } + + memset(&ctx, 0, sizeof(HighlightContext)); + iCol = sqlite3_value_int(apVal[0]); + ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); + ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); + zEllips = (const char*)sqlite3_value_text(apVal[3]); + nToken = sqlite3_value_int(apVal[4]); + iBestLast = nToken-1; + + iBestCol = (iCol>=0 ? iCol : 0); + nPhrase = pApi->xPhraseCount(pFts); + aSeen = sqlite3_malloc(nPhrase); + if( aSeen==0 ){ + rc = SQLITE_NOMEM; + } + + if( rc==SQLITE_OK ){ + rc = pApi->xInstCount(pFts, &nInst); + } + for(i=0; rc==SQLITE_OK && ixInst(pFts, i, &ip, &iSnippetCol, &iStart); + if( rc==SQLITE_OK && (iCol<0 || iSnippetCol==iCol) ){ + int nScore = 1000; + int iLast = iStart - 1 + pApi->xPhraseSize(pFts, ip); + int j; + aSeen[ip] = 1; + + for(j=i+1; rc==SQLITE_OK && jxInst(pFts, j, &ip, &ic, &io); + iFinal = io + pApi->xPhraseSize(pFts, ip) - 1; + if( rc==SQLITE_OK && ic==iSnippetCol && iLastiLast ) iLast = iFinal; + } + } + + if( rc==SQLITE_OK && nScore>nBestScore ){ + iBestCol = iSnippetCol; + iBestStart = iStart; + iBestLast = iLast; + nBestScore = nScore; + } + } + } + + if( rc==SQLITE_OK ){ + rc = pApi->xColumnSize(pFts, iBestCol, &nColSize); + } + if( rc==SQLITE_OK ){ + rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn); + } + if( ctx.zIn ){ + if( rc==SQLITE_OK ){ + rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter); + } + + if( (iBestStart+nToken-1)>iBestLast ){ + iBestStart -= (iBestStart+nToken-1-iBestLast) / 2; + } + if( iBestStart+nToken>nColSize ){ + iBestStart = nColSize - nToken; + } + if( iBestStart<0 ) iBestStart = 0; + + ctx.iRangeStart = iBestStart; + ctx.iRangeEnd = iBestStart + nToken - 1; + + if( iBestStart>0 ){ + fts5HighlightAppend(&rc, &ctx, zEllips, -1); + } + if( rc==SQLITE_OK ){ + rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); + } + if( ctx.iRangeEnd>=(nColSize-1) ){ + fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); + }else{ + fts5HighlightAppend(&rc, &ctx, zEllips, -1); + } + + if( rc==SQLITE_OK ){ + sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT); + }else{ + sqlite3_result_error_code(pCtx, rc); + } + sqlite3_free(ctx.zOut); + } + sqlite3_free(aSeen); +} + +/************************************************************************/ + +/* +** The first time the bm25() function is called for a query, an instance +** of the following structure is allocated and populated. +*/ +typedef struct Fts5Bm25Data Fts5Bm25Data; +struct Fts5Bm25Data { + int nPhrase; /* Number of phrases in query */ + double avgdl; /* Average number of tokens in each row */ + double *aIDF; /* IDF for each phrase */ + double *aFreq; /* Array used to calculate phrase freq. */ +}; + +/* +** Callback used by fts5Bm25GetData() to count the number of rows in the +** table matched by each individual phrase within the query. +*/ +static int fts5CountCb( + const Fts5ExtensionApi *pApi, + Fts5Context *pFts, + void *pUserData /* Pointer to sqlite3_int64 variable */ +){ + sqlite3_int64 *pn = (sqlite3_int64*)pUserData; + UNUSED_PARAM2(pApi, pFts); + (*pn)++; + return SQLITE_OK; +} + +/* +** Set *ppData to point to the Fts5Bm25Data object for the current query. +** If the object has not already been allocated, allocate and populate it +** now. +*/ +static int fts5Bm25GetData( + const Fts5ExtensionApi *pApi, + Fts5Context *pFts, + Fts5Bm25Data **ppData /* OUT: bm25-data object for this query */ +){ + int rc = SQLITE_OK; /* Return code */ + Fts5Bm25Data *p; /* Object to return */ + + p = pApi->xGetAuxdata(pFts, 0); + if( p==0 ){ + int nPhrase; /* Number of phrases in query */ + sqlite3_int64 nRow = 0; /* Number of rows in table */ + sqlite3_int64 nToken = 0; /* Number of tokens in table */ + int nByte; /* Bytes of space to allocate */ + int i; + + /* Allocate the Fts5Bm25Data object */ + nPhrase = pApi->xPhraseCount(pFts); + nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double); + p = (Fts5Bm25Data*)sqlite3_malloc(nByte); + if( p==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(p, 0, nByte); + p->nPhrase = nPhrase; + p->aIDF = (double*)&p[1]; + p->aFreq = &p->aIDF[nPhrase]; + } + + /* Calculate the average document length for this FTS5 table */ + if( rc==SQLITE_OK ) rc = pApi->xRowCount(pFts, &nRow); + if( rc==SQLITE_OK ) rc = pApi->xColumnTotalSize(pFts, -1, &nToken); + if( rc==SQLITE_OK ) p->avgdl = (double)nToken / (double)nRow; + + /* Calculate an IDF for each phrase in the query */ + for(i=0; rc==SQLITE_OK && ixQueryPhrase(pFts, i, (void*)&nHit, fts5CountCb); + if( rc==SQLITE_OK ){ + /* Calculate the IDF (Inverse Document Frequency) for phrase i. + ** This is done using the standard BM25 formula as found on wikipedia: + ** + ** IDF = log( (N - nHit + 0.5) / (nHit + 0.5) ) + ** + ** where "N" is the total number of documents in the set and nHit + ** is the number that contain at least one instance of the phrase + ** under consideration. + ** + ** The problem with this is that if (N < 2*nHit), the IDF is + ** negative. Which is undesirable. So the mimimum allowable IDF is + ** (1e-6) - roughly the same as a term that appears in just over + ** half of set of 5,000,000 documents. */ + double idf = log( (nRow - nHit + 0.5) / (nHit + 0.5) ); + if( idf<=0.0 ) idf = 1e-6; + p->aIDF[i] = idf; + } + } + + if( rc!=SQLITE_OK ){ + sqlite3_free(p); + }else{ + rc = pApi->xSetAuxdata(pFts, p, sqlite3_free); + } + if( rc!=SQLITE_OK ) p = 0; + } + *ppData = p; + return rc; +} + +/* +** Implementation of bm25() function. +*/ +static void fts5Bm25Function( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +){ + const double k1 = 1.2; /* Constant "k1" from BM25 formula */ + const double b = 0.75; /* Constant "b" from BM25 formula */ + int rc = SQLITE_OK; /* Error code */ + double score = 0.0; /* SQL function return value */ + Fts5Bm25Data *pData; /* Values allocated/calculated once only */ + int i; /* Iterator variable */ + int nInst = 0; /* Value returned by xInstCount() */ + double D = 0.0; /* Total number of tokens in row */ + double *aFreq = 0; /* Array of phrase freq. for current row */ + + /* Calculate the phrase frequency (symbol "f(qi,D)" in the documentation) + ** for each phrase in the query for the current row. */ + rc = fts5Bm25GetData(pApi, pFts, &pData); + if( rc==SQLITE_OK ){ + aFreq = pData->aFreq; + memset(aFreq, 0, sizeof(double) * pData->nPhrase); + rc = pApi->xInstCount(pFts, &nInst); + } + for(i=0; rc==SQLITE_OK && ixInst(pFts, i, &ip, &ic, &io); + if( rc==SQLITE_OK ){ + double w = (nVal > ic) ? sqlite3_value_double(apVal[ic]) : 1.0; + aFreq[ip] += w; + } + } + + /* Figure out the total size of the current row in tokens. */ + if( rc==SQLITE_OK ){ + int nTok; + rc = pApi->xColumnSize(pFts, -1, &nTok); + D = (double)nTok; + } + + /* Determine the BM25 score for the current row. */ + for(i=0; rc==SQLITE_OK && inPhrase; i++){ + score += pData->aIDF[i] * ( + ( aFreq[i] * (k1 + 1.0) ) / + ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) ) + ); + } + + /* If no error has occurred, return the calculated score. Otherwise, + ** throw an SQL exception. */ + if( rc==SQLITE_OK ){ + sqlite3_result_double(pCtx, -1.0 * score); + }else{ + sqlite3_result_error_code(pCtx, rc); + } +} + +int sqlite3Fts5AuxInit(fts5_api *pApi){ + struct Builtin { + const char *zFunc; /* Function name (nul-terminated) */ + void *pUserData; /* User-data pointer */ + fts5_extension_function xFunc;/* Callback function */ + void (*xDestroy)(void*); /* Destructor function */ + } aBuiltin [] = { + { "snippet", 0, fts5SnippetFunction, 0 }, + { "highlight", 0, fts5HighlightFunction, 0 }, + { "bm25", 0, fts5Bm25Function, 0 }, + }; + int rc = SQLITE_OK; /* Return code */ + int i; /* To iterate through builtin functions */ + + for(i=0; rc==SQLITE_OK && ixCreateFunction(pApi, + aBuiltin[i].zFunc, + aBuiltin[i].pUserData, + aBuiltin[i].xFunc, + aBuiltin[i].xDestroy + ); + } + + return rc; +} + + diff --git a/ext/fts5/fts5_buffer.c b/ext/fts5/fts5_buffer.c new file mode 100644 index 0000000..0098846 --- /dev/null +++ b/ext/fts5/fts5_buffer.c @@ -0,0 +1,392 @@ +/* +** 2014 May 31 +** +** 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. +** +****************************************************************************** +*/ + + + +#include "fts5Int.h" + +int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){ + if( (u32)pBuf->nSpacenSpace ? pBuf->nSpace : 64; + u8 *pNew; + while( nNewp, nNew); + if( pNew==0 ){ + *pRc = SQLITE_NOMEM; + return 1; + }else{ + pBuf->nSpace = nNew; + pBuf->p = pNew; + } + } + return 0; +} + + +/* +** Encode value iVal as an SQLite varint and append it to the buffer object +** pBuf. If an OOM error occurs, set the error code in p. +*/ +void sqlite3Fts5BufferAppendVarint(int *pRc, Fts5Buffer *pBuf, i64 iVal){ + if( fts5BufferGrow(pRc, pBuf, 9) ) return; + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iVal); +} + +void sqlite3Fts5Put32(u8 *aBuf, int iVal){ + aBuf[0] = (iVal>>24) & 0x00FF; + aBuf[1] = (iVal>>16) & 0x00FF; + aBuf[2] = (iVal>> 8) & 0x00FF; + aBuf[3] = (iVal>> 0) & 0x00FF; +} + +int sqlite3Fts5Get32(const u8 *aBuf){ + return (aBuf[0] << 24) + (aBuf[1] << 16) + (aBuf[2] << 8) + aBuf[3]; +} + +/* +** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set +** the error code in p. If an error has already occurred when this function +** is called, it is a no-op. +*/ +void sqlite3Fts5BufferAppendBlob( + int *pRc, + Fts5Buffer *pBuf, + u32 nData, + const u8 *pData +){ + assert_nc( *pRc || nData>=0 ); + if( fts5BufferGrow(pRc, pBuf, nData) ) return; + memcpy(&pBuf->p[pBuf->n], pData, nData); + pBuf->n += nData; +} + +/* +** Append the nul-terminated string zStr to the buffer pBuf. This function +** ensures that the byte following the buffer data is set to 0x00, even +** though this byte is not included in the pBuf->n count. +*/ +void sqlite3Fts5BufferAppendString( + int *pRc, + Fts5Buffer *pBuf, + const char *zStr +){ + int nStr = (int)strlen(zStr); + sqlite3Fts5BufferAppendBlob(pRc, pBuf, nStr+1, (const u8*)zStr); + pBuf->n--; +} + +/* +** Argument zFmt is a printf() style format string. This function performs +** the printf() style processing, then appends the results to buffer pBuf. +** +** Like sqlite3Fts5BufferAppendString(), this function ensures that the byte +** following the buffer data is set to 0x00, even though this byte is not +** included in the pBuf->n count. +*/ +void sqlite3Fts5BufferAppendPrintf( + int *pRc, + Fts5Buffer *pBuf, + char *zFmt, ... +){ + if( *pRc==SQLITE_OK ){ + char *zTmp; + va_list ap; + va_start(ap, zFmt); + zTmp = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + + if( zTmp==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + sqlite3Fts5BufferAppendString(pRc, pBuf, zTmp); + sqlite3_free(zTmp); + } + } +} + +char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...){ + char *zRet = 0; + if( *pRc==SQLITE_OK ){ + va_list ap; + va_start(ap, zFmt); + zRet = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + if( zRet==0 ){ + *pRc = SQLITE_NOMEM; + } + } + return zRet; +} + + +/* +** Free any buffer allocated by pBuf. Zero the structure before returning. +*/ +void sqlite3Fts5BufferFree(Fts5Buffer *pBuf){ + sqlite3_free(pBuf->p); + memset(pBuf, 0, sizeof(Fts5Buffer)); +} + +/* +** Zero the contents of the buffer object. But do not free the associated +** memory allocation. +*/ +void sqlite3Fts5BufferZero(Fts5Buffer *pBuf){ + pBuf->n = 0; +} + +/* +** Set the buffer to contain nData/pData. If an OOM error occurs, leave an +** the error code in p. If an error has already occurred when this function +** is called, it is a no-op. +*/ +void sqlite3Fts5BufferSet( + int *pRc, + Fts5Buffer *pBuf, + int nData, + const u8 *pData +){ + pBuf->n = 0; + sqlite3Fts5BufferAppendBlob(pRc, pBuf, nData, pData); +} + +int sqlite3Fts5PoslistNext64( + const u8 *a, int n, /* Buffer containing poslist */ + int *pi, /* IN/OUT: Offset within a[] */ + i64 *piOff /* IN/OUT: Current offset */ +){ + int i = *pi; + if( i>=n ){ + /* EOF */ + *piOff = -1; + return 1; + }else{ + i64 iOff = *piOff; + int iVal; + fts5FastGetVarint32(a, i, iVal); + if( iVal==1 ){ + fts5FastGetVarint32(a, i, iVal); + iOff = ((i64)iVal) << 32; + fts5FastGetVarint32(a, i, iVal); + } + *piOff = iOff + (iVal-2); + *pi = i; + return 0; + } +} + + +/* +** Advance the iterator object passed as the only argument. Return true +** if the iterator reaches EOF, or false otherwise. +*/ +int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader *pIter){ + if( sqlite3Fts5PoslistNext64(pIter->a, pIter->n, &pIter->i, &pIter->iPos) ){ + pIter->bEof = 1; + } + return pIter->bEof; +} + +int sqlite3Fts5PoslistReaderInit( + const u8 *a, int n, /* Poslist buffer to iterate through */ + Fts5PoslistReader *pIter /* Iterator object to initialize */ +){ + memset(pIter, 0, sizeof(*pIter)); + pIter->a = a; + pIter->n = n; + sqlite3Fts5PoslistReaderNext(pIter); + return pIter->bEof; +} + +/* +** Append position iPos to the position list being accumulated in buffer +** pBuf, which must be already be large enough to hold the new data. +** The previous position written to this list is *piPrev. *piPrev is set +** to iPos before returning. +*/ +void sqlite3Fts5PoslistSafeAppend( + Fts5Buffer *pBuf, + i64 *piPrev, + i64 iPos +){ + static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32; + if( (iPos & colmask) != (*piPrev & colmask) ){ + pBuf->p[pBuf->n++] = 1; + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32)); + *piPrev = (iPos & colmask); + } + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2); + *piPrev = iPos; +} + +int sqlite3Fts5PoslistWriterAppend( + Fts5Buffer *pBuf, + Fts5PoslistWriter *pWriter, + i64 iPos +){ + int rc = 0; /* Initialized only to suppress erroneous warning from Clang */ + if( fts5BufferGrow(&rc, pBuf, 5+5+5) ) return rc; + sqlite3Fts5PoslistSafeAppend(pBuf, &pWriter->iPrev, iPos); + return SQLITE_OK; +} + +void *sqlite3Fts5MallocZero(int *pRc, int nByte){ + void *pRet = 0; + if( *pRc==SQLITE_OK ){ + pRet = sqlite3_malloc(nByte); + if( pRet==0 && nByte>0 ){ + *pRc = SQLITE_NOMEM; + }else{ + memset(pRet, 0, nByte); + } + } + return pRet; +} + +/* +** Return a nul-terminated copy of the string indicated by pIn. If nIn +** is non-negative, then it is the length of the string in bytes. Otherwise, +** the length of the string is determined using strlen(). +** +** It is the responsibility of the caller to eventually free the returned +** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned. +*/ +char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){ + char *zRet = 0; + if( *pRc==SQLITE_OK ){ + if( nIn<0 ){ + nIn = (int)strlen(pIn); + } + zRet = (char*)sqlite3_malloc(nIn+1); + if( zRet ){ + memcpy(zRet, pIn, nIn); + zRet[nIn] = '\0'; + }else{ + *pRc = SQLITE_NOMEM; + } + } + return zRet; +} + + +/* +** Return true if character 't' may be part of an FTS5 bareword, or false +** otherwise. Characters that may be part of barewords: +** +** * All non-ASCII characters, +** * The 52 upper and lower case ASCII characters, and +** * The 10 integer ASCII characters. +** * The underscore character "_" (0x5F). +** * The unicode "subsitute" character (0x1A). +*/ +int sqlite3Fts5IsBareword(char t){ + u8 aBareword[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 .. 0x0F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* 0x10 .. 0x1F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 .. 0x2F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30 .. 0x3F */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 .. 0x4F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50 .. 0x5F */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 .. 0x6F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70 .. 0x7F */ + }; + + return (t & 0x80) || aBareword[(int)t]; +} + + +/************************************************************************* +*/ +typedef struct Fts5TermsetEntry Fts5TermsetEntry; +struct Fts5TermsetEntry { + char *pTerm; + int nTerm; + int iIdx; /* Index (main or aPrefix[] entry) */ + Fts5TermsetEntry *pNext; +}; + +struct Fts5Termset { + Fts5TermsetEntry *apHash[512]; +}; + +int sqlite3Fts5TermsetNew(Fts5Termset **pp){ + int rc = SQLITE_OK; + *pp = sqlite3Fts5MallocZero(&rc, sizeof(Fts5Termset)); + return rc; +} + +int sqlite3Fts5TermsetAdd( + Fts5Termset *p, + int iIdx, + const char *pTerm, int nTerm, + int *pbPresent +){ + int rc = SQLITE_OK; + *pbPresent = 0; + if( p ){ + int i; + u32 hash = 13; + Fts5TermsetEntry *pEntry; + + /* Calculate a hash value for this term. This is the same hash checksum + ** used by the fts5_hash.c module. This is not important for correct + ** operation of the module, but is necessary to ensure that some tests + ** designed to produce hash table collisions really do work. */ + for(i=nTerm-1; i>=0; i--){ + hash = (hash << 3) ^ hash ^ pTerm[i]; + } + hash = (hash << 3) ^ hash ^ iIdx; + hash = hash % ArraySize(p->apHash); + + for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){ + if( pEntry->iIdx==iIdx + && pEntry->nTerm==nTerm + && memcmp(pEntry->pTerm, pTerm, nTerm)==0 + ){ + *pbPresent = 1; + break; + } + } + + if( pEntry==0 ){ + pEntry = sqlite3Fts5MallocZero(&rc, sizeof(Fts5TermsetEntry) + nTerm); + if( pEntry ){ + pEntry->pTerm = (char*)&pEntry[1]; + pEntry->nTerm = nTerm; + pEntry->iIdx = iIdx; + memcpy(pEntry->pTerm, pTerm, nTerm); + pEntry->pNext = p->apHash[hash]; + p->apHash[hash] = pEntry; + } + } + } + + return rc; +} + +void sqlite3Fts5TermsetFree(Fts5Termset *p){ + if( p ){ + u32 i; + for(i=0; iapHash); i++){ + Fts5TermsetEntry *pEntry = p->apHash[i]; + while( pEntry ){ + Fts5TermsetEntry *pDel = pEntry; + pEntry = pEntry->pNext; + sqlite3_free(pDel); + } + } + sqlite3_free(p); + } +} diff --git a/ext/fts5/fts5_config.c b/ext/fts5/fts5_config.c new file mode 100644 index 0000000..f49cede --- /dev/null +++ b/ext/fts5/fts5_config.c @@ -0,0 +1,945 @@ +/* +** 2014 Jun 09 +** +** 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 is an SQLite module implementing full-text search. +*/ + + +#include "fts5Int.h" + +#define FTS5_DEFAULT_PAGE_SIZE 4050 +#define FTS5_DEFAULT_AUTOMERGE 4 +#define FTS5_DEFAULT_CRISISMERGE 16 +#define FTS5_DEFAULT_HASHSIZE (1024*1024) + +/* Maximum allowed page size */ +#define FTS5_MAX_PAGE_SIZE (128*1024) + +static int fts5_iswhitespace(char x){ + return (x==' '); +} + +static int fts5_isopenquote(char x){ + return (x=='"' || x=='\'' || x=='[' || x=='`'); +} + +/* +** Argument pIn points to a character that is part of a nul-terminated +** string. Return a pointer to the first character following *pIn in +** the string that is not a white-space character. +*/ +static const char *fts5ConfigSkipWhitespace(const char *pIn){ + const char *p = pIn; + if( p ){ + while( fts5_iswhitespace(*p) ){ p++; } + } + return p; +} + +/* +** Argument pIn points to a character that is part of a nul-terminated +** string. Return a pointer to the first character following *pIn in +** the string that is not a "bareword" character. +*/ +static const char *fts5ConfigSkipBareword(const char *pIn){ + const char *p = pIn; + while ( sqlite3Fts5IsBareword(*p) ) p++; + if( p==pIn ) p = 0; + return p; +} + +static int fts5_isdigit(char a){ + return (a>='0' && a<='9'); +} + + + +static const char *fts5ConfigSkipLiteral(const char *pIn){ + const char *p = pIn; + switch( *p ){ + case 'n': case 'N': + if( sqlite3_strnicmp("null", p, 4)==0 ){ + p = &p[4]; + }else{ + p = 0; + } + break; + + case 'x': case 'X': + p++; + if( *p=='\'' ){ + p++; + while( (*p>='a' && *p<='f') + || (*p>='A' && *p<='F') + || (*p>='0' && *p<='9') + ){ + p++; + } + if( *p=='\'' && 0==((p-pIn)%2) ){ + p++; + }else{ + p = 0; + } + }else{ + p = 0; + } + break; + + case '\'': + p++; + while( p ){ + if( *p=='\'' ){ + p++; + if( *p!='\'' ) break; + } + p++; + if( *p==0 ) p = 0; + } + break; + + default: + /* maybe a number */ + if( *p=='+' || *p=='-' ) p++; + while( fts5_isdigit(*p) ) p++; + + /* At this point, if the literal was an integer, the parse is + ** finished. Or, if it is a floating point value, it may continue + ** with either a decimal point or an 'E' character. */ + if( *p=='.' && fts5_isdigit(p[1]) ){ + p += 2; + while( fts5_isdigit(*p) ) p++; + } + if( p==pIn ) p = 0; + + break; + } + + return p; +} + +/* +** The first character of the string pointed to by argument z is guaranteed +** to be an open-quote character (see function fts5_isopenquote()). +** +** This function searches for the corresponding close-quote character within +** the string and, if found, dequotes the string in place and adds a new +** nul-terminator byte. +** +** If the close-quote is found, the value returned is the byte offset of +** the character immediately following it. Or, if the close-quote is not +** found, -1 is returned. If -1 is returned, the buffer is left in an +** undefined state. +*/ +static int fts5Dequote(char *z){ + char q; + int iIn = 1; + int iOut = 0; + q = z[0]; + + /* Set stack variable q to the close-quote character */ + assert( q=='[' || q=='\'' || q=='"' || q=='`' ); + if( q=='[' ) q = ']'; + + while( ALWAYS(z[iIn]) ){ + if( z[iIn]==q ){ + if( z[iIn+1]!=q ){ + /* Character iIn was the close quote. */ + iIn++; + break; + }else{ + /* Character iIn and iIn+1 form an escaped quote character. Skip + ** the input cursor past both and copy a single quote character + ** to the output buffer. */ + iIn += 2; + z[iOut++] = q; + } + }else{ + z[iOut++] = z[iIn++]; + } + } + + z[iOut] = '\0'; + return iIn; +} + +/* +** Convert an SQL-style quoted string into a normal string by removing +** the quote characters. The conversion is done in-place. If the +** input does not begin with a quote character, then this routine +** is a no-op. +** +** Examples: +** +** "abc" becomes abc +** 'xyz' becomes xyz +** [pqr] becomes pqr +** `mno` becomes mno +*/ +void sqlite3Fts5Dequote(char *z){ + char quote; /* Quote character (if any ) */ + + assert( 0==fts5_iswhitespace(z[0]) ); + quote = z[0]; + if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){ + fts5Dequote(z); + } +} + + +struct Fts5Enum { + const char *zName; + int eVal; +}; +typedef struct Fts5Enum Fts5Enum; + +static int fts5ConfigSetEnum( + const Fts5Enum *aEnum, + const char *zEnum, + int *peVal +){ + int nEnum = (int)strlen(zEnum); + int i; + int iVal = -1; + + for(i=0; aEnum[i].zName; i++){ + if( sqlite3_strnicmp(aEnum[i].zName, zEnum, nEnum)==0 ){ + if( iVal>=0 ) return SQLITE_ERROR; + iVal = aEnum[i].eVal; + } + } + + *peVal = iVal; + return iVal<0 ? SQLITE_ERROR : SQLITE_OK; +} + +/* +** Parse a "special" CREATE VIRTUAL TABLE directive and update +** configuration object pConfig as appropriate. +** +** If successful, object pConfig is updated and SQLITE_OK returned. If +** an error occurs, an SQLite error code is returned and an error message +** may be left in *pzErr. It is the responsibility of the caller to +** eventually free any such error message using sqlite3_free(). +*/ +static int fts5ConfigParseSpecial( + Fts5Global *pGlobal, + Fts5Config *pConfig, /* Configuration object to update */ + const char *zCmd, /* Special command to parse */ + const char *zArg, /* Argument to parse */ + char **pzErr /* OUT: Error message */ +){ + int rc = SQLITE_OK; + int nCmd = (int)strlen(zCmd); + if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){ + const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES; + const char *p; + int bFirst = 1; + if( pConfig->aPrefix==0 ){ + pConfig->aPrefix = sqlite3Fts5MallocZero(&rc, nByte); + if( rc ) return rc; + } + + p = zArg; + while( 1 ){ + int nPre = 0; + + while( p[0]==' ' ) p++; + if( bFirst==0 && p[0]==',' ){ + p++; + while( p[0]==' ' ) p++; + }else if( p[0]=='\0' ){ + break; + } + if( p[0]<'0' || p[0]>'9' ){ + *pzErr = sqlite3_mprintf("malformed prefix=... directive"); + rc = SQLITE_ERROR; + break; + } + + if( pConfig->nPrefix==FTS5_MAX_PREFIX_INDEXES ){ + *pzErr = sqlite3_mprintf( + "too many prefix indexes (max %d)", FTS5_MAX_PREFIX_INDEXES + ); + rc = SQLITE_ERROR; + break; + } + + while( p[0]>='0' && p[0]<='9' && nPre<1000 ){ + nPre = nPre*10 + (p[0] - '0'); + p++; + } + + if( nPre<=0 || nPre>=1000 ){ + *pzErr = sqlite3_mprintf("prefix length out of range (max 999)"); + rc = SQLITE_ERROR; + break; + } + + pConfig->aPrefix[pConfig->nPrefix] = nPre; + pConfig->nPrefix++; + bFirst = 0; + } + assert( pConfig->nPrefix<=FTS5_MAX_PREFIX_INDEXES ); + return rc; + } + + if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){ + const char *p = (const char*)zArg; + int nArg = (int)strlen(zArg) + 1; + char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg); + char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2); + char *pSpace = pDel; + + if( azArg && pSpace ){ + if( pConfig->pTok ){ + *pzErr = sqlite3_mprintf("multiple tokenize=... directives"); + rc = SQLITE_ERROR; + }else{ + for(nArg=0; p && *p; nArg++){ + const char *p2 = fts5ConfigSkipWhitespace(p); + if( *p2=='\'' ){ + p = fts5ConfigSkipLiteral(p2); + }else{ + p = fts5ConfigSkipBareword(p2); + } + if( p ){ + memcpy(pSpace, p2, p-p2); + azArg[nArg] = pSpace; + sqlite3Fts5Dequote(pSpace); + pSpace += (p - p2) + 1; + p = fts5ConfigSkipWhitespace(p); + } + } + if( p==0 ){ + *pzErr = sqlite3_mprintf("parse error in tokenize directive"); + rc = SQLITE_ERROR; + }else{ + rc = sqlite3Fts5GetTokenizer(pGlobal, + (const char**)azArg, nArg, &pConfig->pTok, &pConfig->pTokApi, + pzErr + ); + } + } + } + + sqlite3_free(azArg); + sqlite3_free(pDel); + return rc; + } + + if( sqlite3_strnicmp("content", zCmd, nCmd)==0 ){ + if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){ + *pzErr = sqlite3_mprintf("multiple content=... directives"); + rc = SQLITE_ERROR; + }else{ + if( zArg[0] ){ + pConfig->eContent = FTS5_CONTENT_EXTERNAL; + pConfig->zContent = sqlite3Fts5Mprintf(&rc, "%Q.%Q", pConfig->zDb,zArg); + }else{ + pConfig->eContent = FTS5_CONTENT_NONE; + } + } + return rc; + } + + if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){ + if( pConfig->zContentRowid ){ + *pzErr = sqlite3_mprintf("multiple content_rowid=... directives"); + rc = SQLITE_ERROR; + }else{ + pConfig->zContentRowid = sqlite3Fts5Strndup(&rc, zArg, -1); + } + return rc; + } + + if( sqlite3_strnicmp("columnsize", zCmd, nCmd)==0 ){ + if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ + *pzErr = sqlite3_mprintf("malformed columnsize=... directive"); + rc = SQLITE_ERROR; + }else{ + pConfig->bColumnsize = (zArg[0]=='1'); + } + return rc; + } + + if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){ + const Fts5Enum aDetail[] = { + { "none", FTS5_DETAIL_NONE }, + { "full", FTS5_DETAIL_FULL }, + { "columns", FTS5_DETAIL_COLUMNS }, + { 0, 0 } + }; + + if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){ + *pzErr = sqlite3_mprintf("malformed detail=... directive"); + } + return rc; + } + + *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd); + return SQLITE_ERROR; +} + +/* +** Allocate an instance of the default tokenizer ("simple") at +** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error +** code if an error occurs. +*/ +static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){ + assert( pConfig->pTok==0 && pConfig->pTokApi==0 ); + return sqlite3Fts5GetTokenizer( + pGlobal, 0, 0, &pConfig->pTok, &pConfig->pTokApi, 0 + ); +} + +/* +** Gobble up the first bareword or quoted word from the input buffer zIn. +** Return a pointer to the character immediately following the last in +** the gobbled word if successful, or a NULL pointer otherwise (failed +** to find close-quote character). +** +** Before returning, set pzOut to point to a new buffer containing a +** nul-terminated, dequoted copy of the gobbled word. If the word was +** quoted, *pbQuoted is also set to 1 before returning. +** +** If *pRc is other than SQLITE_OK when this function is called, it is +** a no-op (NULL is returned). Otherwise, if an OOM occurs within this +** function, *pRc is set to SQLITE_NOMEM before returning. *pRc is *not* +** set if a parse error (failed to find close quote) occurs. +*/ +static const char *fts5ConfigGobbleWord( + int *pRc, /* IN/OUT: Error code */ + const char *zIn, /* Buffer to gobble string/bareword from */ + char **pzOut, /* OUT: malloc'd buffer containing str/bw */ + int *pbQuoted /* OUT: Set to true if dequoting required */ +){ + const char *zRet = 0; + + int nIn = (int)strlen(zIn); + char *zOut = sqlite3_malloc(nIn+1); + + assert( *pRc==SQLITE_OK ); + *pbQuoted = 0; + *pzOut = 0; + + if( zOut==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + memcpy(zOut, zIn, nIn+1); + if( fts5_isopenquote(zOut[0]) ){ + int ii = fts5Dequote(zOut); + zRet = &zIn[ii]; + *pbQuoted = 1; + }else{ + zRet = fts5ConfigSkipBareword(zIn); + zOut[zRet-zIn] = '\0'; + } + } + + if( zRet==0 ){ + sqlite3_free(zOut); + }else{ + *pzOut = zOut; + } + + return zRet; +} + +static int fts5ConfigParseColumn( + Fts5Config *p, + char *zCol, + char *zArg, + char **pzErr +){ + int rc = SQLITE_OK; + if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME) + || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME) + ){ + *pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zCol); + rc = SQLITE_ERROR; + }else if( zArg ){ + if( 0==sqlite3_stricmp(zArg, "unindexed") ){ + p->abUnindexed[p->nCol] = 1; + }else{ + *pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg); + rc = SQLITE_ERROR; + } + } + + p->azCol[p->nCol++] = zCol; + return rc; +} + +/* +** Populate the Fts5Config.zContentExprlist string. +*/ +static int fts5ConfigMakeExprlist(Fts5Config *p){ + int i; + int rc = SQLITE_OK; + Fts5Buffer buf = {0, 0, 0}; + + sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid); + if( p->eContent!=FTS5_CONTENT_NONE ){ + for(i=0; inCol; i++){ + if( p->eContent==FTS5_CONTENT_EXTERNAL ){ + sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]); + }else{ + sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i); + } + } + } + + assert( p->zContentExprlist==0 ); + p->zContentExprlist = (char*)buf.p; + return rc; +} + +/* +** Arguments nArg/azArg contain the string arguments passed to the xCreate +** or xConnect method of the virtual table. This function attempts to +** allocate an instance of Fts5Config containing the results of parsing +** those arguments. +** +** If successful, SQLITE_OK is returned and *ppOut is set to point to the +** new Fts5Config object. If an error occurs, an SQLite error code is +** returned, *ppOut is set to NULL and an error message may be left in +** *pzErr. It is the responsibility of the caller to eventually free any +** such error message using sqlite3_free(). +*/ +int sqlite3Fts5ConfigParse( + Fts5Global *pGlobal, + sqlite3 *db, + int nArg, /* Number of arguments */ + const char **azArg, /* Array of nArg CREATE VIRTUAL TABLE args */ + Fts5Config **ppOut, /* OUT: Results of parse */ + char **pzErr /* OUT: Error message */ +){ + int rc = SQLITE_OK; /* Return code */ + Fts5Config *pRet; /* New object to return */ + int i; + int nByte; + + *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config)); + if( pRet==0 ) return SQLITE_NOMEM; + memset(pRet, 0, sizeof(Fts5Config)); + pRet->db = db; + pRet->iCookie = -1; + + nByte = nArg * (sizeof(char*) + sizeof(u8)); + pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte); + pRet->abUnindexed = (u8*)&pRet->azCol[nArg]; + pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1); + pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1); + pRet->bColumnsize = 1; + pRet->eDetail = FTS5_DETAIL_FULL; +#ifdef SQLITE_DEBUG + pRet->bPrefixIndex = 1; +#endif + if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){ + *pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName); + rc = SQLITE_ERROR; + } + + for(i=3; rc==SQLITE_OK && ipTok==0 ){ + rc = fts5ConfigDefaultTokenizer(pGlobal, pRet); + } + + /* If no zContent option was specified, fill in the default values. */ + if( rc==SQLITE_OK && pRet->zContent==0 ){ + const char *zTail = 0; + assert( pRet->eContent==FTS5_CONTENT_NORMAL + || pRet->eContent==FTS5_CONTENT_NONE + ); + if( pRet->eContent==FTS5_CONTENT_NORMAL ){ + zTail = "content"; + }else if( pRet->bColumnsize ){ + zTail = "docsize"; + } + + if( zTail ){ + pRet->zContent = sqlite3Fts5Mprintf( + &rc, "%Q.'%q_%s'", pRet->zDb, pRet->zName, zTail + ); + } + } + + if( rc==SQLITE_OK && pRet->zContentRowid==0 ){ + pRet->zContentRowid = sqlite3Fts5Strndup(&rc, "rowid", -1); + } + + /* Formulate the zContentExprlist text */ + if( rc==SQLITE_OK ){ + rc = fts5ConfigMakeExprlist(pRet); + } + + if( rc!=SQLITE_OK ){ + sqlite3Fts5ConfigFree(pRet); + *ppOut = 0; + } + return rc; +} + +/* +** Free the configuration object passed as the only argument. +*/ +void sqlite3Fts5ConfigFree(Fts5Config *pConfig){ + if( pConfig ){ + int i; + if( pConfig->pTok ){ + pConfig->pTokApi->xDelete(pConfig->pTok); + } + sqlite3_free(pConfig->zDb); + sqlite3_free(pConfig->zName); + for(i=0; inCol; i++){ + sqlite3_free(pConfig->azCol[i]); + } + sqlite3_free(pConfig->azCol); + sqlite3_free(pConfig->aPrefix); + sqlite3_free(pConfig->zRank); + sqlite3_free(pConfig->zRankArgs); + sqlite3_free(pConfig->zContent); + sqlite3_free(pConfig->zContentRowid); + sqlite3_free(pConfig->zContentExprlist); + sqlite3_free(pConfig); + } +} + +/* +** Call sqlite3_declare_vtab() based on the contents of the configuration +** object passed as the only argument. Return SQLITE_OK if successful, or +** an SQLite error code if an error occurs. +*/ +int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){ + int i; + int rc = SQLITE_OK; + char *zSql; + + zSql = sqlite3Fts5Mprintf(&rc, "CREATE TABLE x("); + for(i=0; zSql && inCol; i++){ + const char *zSep = (i==0?"":", "); + zSql = sqlite3Fts5Mprintf(&rc, "%z%s%Q", zSql, zSep, pConfig->azCol[i]); + } + zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)", + zSql, pConfig->zName, FTS5_RANK_NAME + ); + + assert( zSql || rc==SQLITE_NOMEM ); + if( zSql ){ + rc = sqlite3_declare_vtab(pConfig->db, zSql); + sqlite3_free(zSql); + } + + return rc; +} + +/* +** Tokenize the text passed via the second and third arguments. +** +** The callback is invoked once for each token in the input text. The +** arguments passed to it are, in order: +** +** void *pCtx // Copy of 4th argument to sqlite3Fts5Tokenize() +** const char *pToken // Pointer to buffer containing token +** int nToken // Size of token in bytes +** int iStart // Byte offset of start of token within input text +** int iEnd // Byte offset of end of token within input text +** int iPos // Position of token in input (first token is 0) +** +** If the callback returns a non-zero value the tokenization is abandoned +** and no further callbacks are issued. +** +** This function returns SQLITE_OK if successful or an SQLite error code +** if an error occurs. If the tokenization was abandoned early because +** the callback returned SQLITE_DONE, this is not an error and this function +** still returns SQLITE_OK. Or, if the tokenization was abandoned early +** because the callback returned another non-zero value, it is assumed +** to be an SQLite error code and returned to the caller. +*/ +int sqlite3Fts5Tokenize( + Fts5Config *pConfig, /* FTS5 Configuration object */ + int flags, /* FTS5_TOKENIZE_* flags */ + const char *pText, int nText, /* Text to tokenize */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ +){ + if( pText==0 ) return SQLITE_OK; + return pConfig->pTokApi->xTokenize( + pConfig->pTok, pCtx, flags, pText, nText, xToken + ); +} + +/* +** Argument pIn points to the first character in what is expected to be +** a comma-separated list of SQL literals followed by a ')' character. +** If it actually is this, return a pointer to the ')'. Otherwise, return +** NULL to indicate a parse error. +*/ +static const char *fts5ConfigSkipArgs(const char *pIn){ + const char *p = pIn; + + while( 1 ){ + p = fts5ConfigSkipWhitespace(p); + p = fts5ConfigSkipLiteral(p); + p = fts5ConfigSkipWhitespace(p); + if( p==0 || *p==')' ) break; + if( *p!=',' ){ + p = 0; + break; + } + p++; + } + + return p; +} + +/* +** Parameter zIn contains a rank() function specification. The format of +** this is: +** +** + Bareword (function name) +** + Open parenthesis - "(" +** + Zero or more SQL literals in a comma separated list +** + Close parenthesis - ")" +*/ +int sqlite3Fts5ConfigParseRank( + const char *zIn, /* Input string */ + char **pzRank, /* OUT: Rank function name */ + char **pzRankArgs /* OUT: Rank function arguments */ +){ + const char *p = zIn; + const char *pRank; + char *zRank = 0; + char *zRankArgs = 0; + int rc = SQLITE_OK; + + *pzRank = 0; + *pzRankArgs = 0; + + if( p==0 ){ + rc = SQLITE_ERROR; + }else{ + p = fts5ConfigSkipWhitespace(p); + pRank = p; + p = fts5ConfigSkipBareword(p); + + if( p ){ + zRank = sqlite3Fts5MallocZero(&rc, 1 + p - pRank); + if( zRank ) memcpy(zRank, pRank, p-pRank); + }else{ + rc = SQLITE_ERROR; + } + + if( rc==SQLITE_OK ){ + p = fts5ConfigSkipWhitespace(p); + if( *p!='(' ) rc = SQLITE_ERROR; + p++; + } + if( rc==SQLITE_OK ){ + const char *pArgs; + p = fts5ConfigSkipWhitespace(p); + pArgs = p; + if( *p!=')' ){ + p = fts5ConfigSkipArgs(p); + if( p==0 ){ + rc = SQLITE_ERROR; + }else{ + zRankArgs = sqlite3Fts5MallocZero(&rc, 1 + p - pArgs); + if( zRankArgs ) memcpy(zRankArgs, pArgs, p-pArgs); + } + } + } + } + + if( rc!=SQLITE_OK ){ + sqlite3_free(zRank); + assert( zRankArgs==0 ); + }else{ + *pzRank = zRank; + *pzRankArgs = zRankArgs; + } + return rc; +} + +int sqlite3Fts5ConfigSetValue( + Fts5Config *pConfig, + const char *zKey, + sqlite3_value *pVal, + int *pbBadkey +){ + int rc = SQLITE_OK; + + if( 0==sqlite3_stricmp(zKey, "pgsz") ){ + int pgsz = 0; + if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ + pgsz = sqlite3_value_int(pVal); + } + if( pgsz<=0 || pgsz>FTS5_MAX_PAGE_SIZE ){ + *pbBadkey = 1; + }else{ + pConfig->pgsz = pgsz; + } + } + + else if( 0==sqlite3_stricmp(zKey, "hashsize") ){ + int nHashSize = -1; + if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ + nHashSize = sqlite3_value_int(pVal); + } + if( nHashSize<=0 ){ + *pbBadkey = 1; + }else{ + pConfig->nHashSize = nHashSize; + } + } + + else if( 0==sqlite3_stricmp(zKey, "automerge") ){ + int nAutomerge = -1; + if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ + nAutomerge = sqlite3_value_int(pVal); + } + if( nAutomerge<0 || nAutomerge>64 ){ + *pbBadkey = 1; + }else{ + if( nAutomerge==1 ) nAutomerge = FTS5_DEFAULT_AUTOMERGE; + pConfig->nAutomerge = nAutomerge; + } + } + + else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){ + int nCrisisMerge = -1; + if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ + nCrisisMerge = sqlite3_value_int(pVal); + } + if( nCrisisMerge<0 ){ + *pbBadkey = 1; + }else{ + if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; + pConfig->nCrisisMerge = nCrisisMerge; + } + } + + else if( 0==sqlite3_stricmp(zKey, "rank") ){ + const char *zIn = (const char*)sqlite3_value_text(pVal); + char *zRank; + char *zRankArgs; + rc = sqlite3Fts5ConfigParseRank(zIn, &zRank, &zRankArgs); + if( rc==SQLITE_OK ){ + sqlite3_free(pConfig->zRank); + sqlite3_free(pConfig->zRankArgs); + pConfig->zRank = zRank; + pConfig->zRankArgs = zRankArgs; + }else if( rc==SQLITE_ERROR ){ + rc = SQLITE_OK; + *pbBadkey = 1; + } + }else{ + *pbBadkey = 1; + } + return rc; +} + +/* +** Load the contents of the %_config table into memory. +*/ +int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ + const char *zSelect = "SELECT k, v FROM %Q.'%q_config'"; + char *zSql; + sqlite3_stmt *p = 0; + int rc = SQLITE_OK; + int iVersion = 0; + + /* Set default values */ + pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE; + pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE; + pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; + pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE; + + zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName); + if( zSql ){ + rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p, 0); + sqlite3_free(zSql); + } + + assert( rc==SQLITE_OK || p==0 ); + if( rc==SQLITE_OK ){ + while( SQLITE_ROW==sqlite3_step(p) ){ + const char *zK = (const char*)sqlite3_column_text(p, 0); + sqlite3_value *pVal = sqlite3_column_value(p, 1); + if( 0==sqlite3_stricmp(zK, "version") ){ + iVersion = sqlite3_value_int(pVal); + }else{ + int bDummy = 0; + sqlite3Fts5ConfigSetValue(pConfig, zK, pVal, &bDummy); + } + } + rc = sqlite3_finalize(p); + } + + if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){ + rc = SQLITE_ERROR; + if( pConfig->pzErrmsg ){ + assert( 0==*pConfig->pzErrmsg ); + *pConfig->pzErrmsg = sqlite3_mprintf( + "invalid fts5 file format (found %d, expected %d) - run 'rebuild'", + iVersion, FTS5_CURRENT_VERSION + ); + } + } + + if( rc==SQLITE_OK ){ + pConfig->iCookie = iCookie; + } + return rc; +} diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c new file mode 100644 index 0000000..d3f801b --- /dev/null +++ b/ext/fts5/fts5_expr.c @@ -0,0 +1,2560 @@ +/* +** 2014 May 31 +** +** 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. +** +****************************************************************************** +** +*/ + + + +#include "fts5Int.h" +#include "fts5parse.h" + +/* +** All token types in the generated fts5parse.h file are greater than 0. +*/ +#define FTS5_EOF 0 + +#define FTS5_LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) + +typedef struct Fts5ExprTerm Fts5ExprTerm; + +/* +** Functions generated by lemon from fts5parse.y. +*/ +void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(u64)); +void sqlite3Fts5ParserFree(void*, void (*freeProc)(void*)); +void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*); +#ifndef NDEBUG +#include +void sqlite3Fts5ParserTrace(FILE*, char*); +#endif + + +struct Fts5Expr { + Fts5Index *pIndex; + Fts5Config *pConfig; + Fts5ExprNode *pRoot; + int bDesc; /* Iterate in descending rowid order */ + int nPhrase; /* Number of phrases in expression */ + Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */ +}; + +/* +** eType: +** Expression node type. Always one of: +** +** FTS5_AND (nChild, apChild valid) +** FTS5_OR (nChild, apChild valid) +** FTS5_NOT (nChild, apChild valid) +** FTS5_STRING (pNear valid) +** FTS5_TERM (pNear valid) +*/ +struct Fts5ExprNode { + int eType; /* Node type */ + int bEof; /* True at EOF */ + int bNomatch; /* True if entry is not a match */ + + /* Next method for this node. */ + int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64); + + i64 iRowid; /* Current rowid */ + Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */ + + /* Child nodes. For a NOT node, this array always contains 2 entries. For + ** AND or OR nodes, it contains 2 or more entries. */ + int nChild; /* Number of child nodes */ + Fts5ExprNode *apChild[1]; /* Array of child nodes */ +}; + +#define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING) + +/* +** Invoke the xNext method of an Fts5ExprNode object. This macro should be +** used as if it has the same signature as the xNext() methods themselves. +*/ +#define fts5ExprNodeNext(a,b,c,d) (b)->xNext((a), (b), (c), (d)) + +/* +** An instance of the following structure represents a single search term +** or term prefix. +*/ +struct Fts5ExprTerm { + int bPrefix; /* True for a prefix term */ + char *zTerm; /* nul-terminated term */ + Fts5IndexIter *pIter; /* Iterator for this term */ + Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */ +}; + +/* +** A phrase. One or more terms that must appear in a contiguous sequence +** within a document for it to match. +*/ +struct Fts5ExprPhrase { + Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */ + Fts5Buffer poslist; /* Current position list */ + int nTerm; /* Number of entries in aTerm[] */ + Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */ +}; + +/* +** One or more phrases that must appear within a certain token distance of +** each other within each matching document. +*/ +struct Fts5ExprNearset { + int nNear; /* NEAR parameter */ + Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */ + int nPhrase; /* Number of entries in aPhrase[] array */ + Fts5ExprPhrase *apPhrase[1]; /* Array of phrase pointers */ +}; + + +/* +** Parse context. +*/ +struct Fts5Parse { + Fts5Config *pConfig; + char *zErr; + int rc; + int nPhrase; /* Size of apPhrase array */ + Fts5ExprPhrase **apPhrase; /* Array of all phrases */ + Fts5ExprNode *pExpr; /* Result of a successful parse */ +}; + +void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){ + va_list ap; + va_start(ap, zFmt); + if( pParse->rc==SQLITE_OK ){ + pParse->zErr = sqlite3_vmprintf(zFmt, ap); + pParse->rc = SQLITE_ERROR; + } + va_end(ap); +} + +static int fts5ExprIsspace(char t){ + return t==' ' || t=='\t' || t=='\n' || t=='\r'; +} + +/* +** Read the first token from the nul-terminated string at *pz. +*/ +static int fts5ExprGetToken( + Fts5Parse *pParse, + const char **pz, /* IN/OUT: Pointer into buffer */ + Fts5Token *pToken +){ + const char *z = *pz; + int tok; + + /* Skip past any whitespace */ + while( fts5ExprIsspace(*z) ) z++; + + pToken->p = z; + pToken->n = 1; + switch( *z ){ + case '(': tok = FTS5_LP; break; + case ')': tok = FTS5_RP; break; + case '{': tok = FTS5_LCP; break; + case '}': tok = FTS5_RCP; break; + case ':': tok = FTS5_COLON; break; + case ',': tok = FTS5_COMMA; break; + case '+': tok = FTS5_PLUS; break; + case '*': tok = FTS5_STAR; break; + case '\0': tok = FTS5_EOF; break; + + case '"': { + const char *z2; + tok = FTS5_STRING; + + for(z2=&z[1]; 1; z2++){ + if( z2[0]=='"' ){ + z2++; + if( z2[0]!='"' ) break; + } + if( z2[0]=='\0' ){ + sqlite3Fts5ParseError(pParse, "unterminated string"); + return FTS5_EOF; + } + } + pToken->n = (z2 - z); + break; + } + + default: { + const char *z2; + if( sqlite3Fts5IsBareword(z[0])==0 ){ + sqlite3Fts5ParseError(pParse, "fts5: syntax error near \"%.1s\"", z); + return FTS5_EOF; + } + tok = FTS5_STRING; + for(z2=&z[1]; sqlite3Fts5IsBareword(*z2); z2++); + pToken->n = (z2 - z); + if( pToken->n==2 && memcmp(pToken->p, "OR", 2)==0 ) tok = FTS5_OR; + if( pToken->n==3 && memcmp(pToken->p, "NOT", 3)==0 ) tok = FTS5_NOT; + if( pToken->n==3 && memcmp(pToken->p, "AND", 3)==0 ) tok = FTS5_AND; + break; + } + } + + *pz = &pToken->p[pToken->n]; + return tok; +} + +static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); } +static void fts5ParseFree(void *p){ sqlite3_free(p); } + +int sqlite3Fts5ExprNew( + Fts5Config *pConfig, /* FTS5 Configuration */ + const char *zExpr, /* Expression text */ + Fts5Expr **ppNew, + char **pzErr +){ + Fts5Parse sParse; + Fts5Token token; + const char *z = zExpr; + int t; /* Next token type */ + void *pEngine; + Fts5Expr *pNew; + + *ppNew = 0; + *pzErr = 0; + memset(&sParse, 0, sizeof(sParse)); + pEngine = sqlite3Fts5ParserAlloc(fts5ParseAlloc); + if( pEngine==0 ){ return SQLITE_NOMEM; } + sParse.pConfig = pConfig; + + do { + t = fts5ExprGetToken(&sParse, &z, &token); + sqlite3Fts5Parser(pEngine, t, token, &sParse); + }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF ); + sqlite3Fts5ParserFree(pEngine, fts5ParseFree); + + assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 ); + if( sParse.rc==SQLITE_OK ){ + *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr)); + if( pNew==0 ){ + sParse.rc = SQLITE_NOMEM; + sqlite3Fts5ParseNodeFree(sParse.pExpr); + }else{ + if( !sParse.pExpr ){ + const int nByte = sizeof(Fts5ExprNode); + pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte); + if( pNew->pRoot ){ + pNew->pRoot->bEof = 1; + } + }else{ + pNew->pRoot = sParse.pExpr; + } + pNew->pIndex = 0; + pNew->pConfig = pConfig; + pNew->apExprPhrase = sParse.apPhrase; + pNew->nPhrase = sParse.nPhrase; + sParse.apPhrase = 0; + } + } + + sqlite3_free(sParse.apPhrase); + *pzErr = sParse.zErr; + return sParse.rc; +} + +/* +** Free the expression node object passed as the only argument. +*/ +void sqlite3Fts5ParseNodeFree(Fts5ExprNode *p){ + if( p ){ + int i; + for(i=0; inChild; i++){ + sqlite3Fts5ParseNodeFree(p->apChild[i]); + } + sqlite3Fts5ParseNearsetFree(p->pNear); + sqlite3_free(p); + } +} + +/* +** Free the expression object passed as the only argument. +*/ +void sqlite3Fts5ExprFree(Fts5Expr *p){ + if( p ){ + sqlite3Fts5ParseNodeFree(p->pRoot); + sqlite3_free(p->apExprPhrase); + sqlite3_free(p); + } +} + +/* +** Argument pTerm must be a synonym iterator. Return the current rowid +** that it points to. +*/ +static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){ + i64 iRet = 0; + int bRetValid = 0; + Fts5ExprTerm *p; + + assert( pTerm->pSynonym ); + assert( bDesc==0 || bDesc==1 ); + for(p=pTerm; p; p=p->pSynonym){ + if( 0==sqlite3Fts5IterEof(p->pIter) ){ + i64 iRowid = p->pIter->iRowid; + if( bRetValid==0 || (bDesc!=(iRowidpSynonym ); + for(p=pTerm; p; p=p->pSynonym){ + Fts5IndexIter *pIter = p->pIter; + if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){ + if( pIter->nData==0 ) continue; + if( nIter==nAlloc ){ + int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2; + Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte); + if( aNew==0 ){ + rc = SQLITE_NOMEM; + goto synonym_poslist_out; + } + memcpy(aNew, aIter, sizeof(Fts5PoslistReader) * nIter); + nAlloc = nAlloc*2; + if( aIter!=aStatic ) sqlite3_free(aIter); + aIter = aNew; + } + sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &aIter[nIter]); + assert( aIter[nIter].bEof==0 ); + nIter++; + } + } + + if( nIter==1 ){ + *pa = (u8*)aIter[0].a; + *pn = aIter[0].n; + }else{ + Fts5PoslistWriter writer = {0}; + i64 iPrev = -1; + fts5BufferZero(pBuf); + while( 1 ){ + int i; + i64 iMin = FTS5_LARGEST_INT64; + for(i=0; ip; + *pn = pBuf->n; + } + } + + synonym_poslist_out: + if( aIter!=aStatic ) sqlite3_free(aIter); + return rc; +} + + +/* +** All individual term iterators in pPhrase are guaranteed to be valid and +** pointing to the same rowid when this function is called. This function +** checks if the current rowid really is a match, and if so populates +** the pPhrase->poslist buffer accordingly. Output parameter *pbMatch +** is set to true if this is really a match, or false otherwise. +** +** SQLITE_OK is returned if an error occurs, or an SQLite error code +** otherwise. It is not considered an error code if the current rowid is +** not a match. +*/ +static int fts5ExprPhraseIsMatch( + Fts5ExprNode *pNode, /* Node pPhrase belongs to */ + Fts5ExprPhrase *pPhrase, /* Phrase object to initialize */ + int *pbMatch /* OUT: Set to true if really a match */ +){ + Fts5PoslistWriter writer = {0}; + Fts5PoslistReader aStatic[4]; + Fts5PoslistReader *aIter = aStatic; + int i; + int rc = SQLITE_OK; + + fts5BufferZero(&pPhrase->poslist); + + /* If the aStatic[] array is not large enough, allocate a large array + ** using sqlite3_malloc(). This approach could be improved upon. */ + if( pPhrase->nTerm>ArraySize(aStatic) ){ + int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm; + aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte); + if( !aIter ) return SQLITE_NOMEM; + } + memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm); + + /* Initialize a term iterator for each term in the phrase */ + for(i=0; inTerm; i++){ + Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; + int n = 0; + int bFlag = 0; + u8 *a = 0; + if( pTerm->pSynonym ){ + Fts5Buffer buf = {0, 0, 0}; + rc = fts5ExprSynonymList(pTerm, pNode->iRowid, &buf, &a, &n); + if( rc ){ + sqlite3_free(a); + goto ismatch_out; + } + if( a==buf.p ) bFlag = 1; + }else{ + a = (u8*)pTerm->pIter->pData; + n = pTerm->pIter->nData; + } + sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]); + aIter[i].bFlag = (u8)bFlag; + if( aIter[i].bEof ) goto ismatch_out; + } + + while( 1 ){ + int bMatch; + i64 iPos = aIter[0].iPos; + do { + bMatch = 1; + for(i=0; inTerm; i++){ + Fts5PoslistReader *pPos = &aIter[i]; + i64 iAdj = iPos + i; + if( pPos->iPos!=iAdj ){ + bMatch = 0; + while( pPos->iPosiPos>iAdj ) iPos = pPos->iPos-i; + } + } + }while( bMatch==0 ); + + /* Append position iPos to the output */ + rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos); + if( rc!=SQLITE_OK ) goto ismatch_out; + + for(i=0; inTerm; i++){ + if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out; + } + } + + ismatch_out: + *pbMatch = (pPhrase->poslist.n>0); + for(i=0; inTerm; i++){ + if( aIter[i].bFlag ) sqlite3_free((u8*)aIter[i].a); + } + if( aIter!=aStatic ) sqlite3_free(aIter); + return rc; +} + +typedef struct Fts5LookaheadReader Fts5LookaheadReader; +struct Fts5LookaheadReader { + const u8 *a; /* Buffer containing position list */ + int n; /* Size of buffer a[] in bytes */ + int i; /* Current offset in position list */ + i64 iPos; /* Current position */ + i64 iLookahead; /* Next position */ +}; + +#define FTS5_LOOKAHEAD_EOF (((i64)1) << 62) + +static int fts5LookaheadReaderNext(Fts5LookaheadReader *p){ + p->iPos = p->iLookahead; + if( sqlite3Fts5PoslistNext64(p->a, p->n, &p->i, &p->iLookahead) ){ + p->iLookahead = FTS5_LOOKAHEAD_EOF; + } + return (p->iPos==FTS5_LOOKAHEAD_EOF); +} + +static int fts5LookaheadReaderInit( + const u8 *a, int n, /* Buffer to read position list from */ + Fts5LookaheadReader *p /* Iterator object to initialize */ +){ + memset(p, 0, sizeof(Fts5LookaheadReader)); + p->a = a; + p->n = n; + fts5LookaheadReaderNext(p); + return fts5LookaheadReaderNext(p); +} + +typedef struct Fts5NearTrimmer Fts5NearTrimmer; +struct Fts5NearTrimmer { + Fts5LookaheadReader reader; /* Input iterator */ + Fts5PoslistWriter writer; /* Writer context */ + Fts5Buffer *pOut; /* Output poslist */ +}; + +/* +** The near-set object passed as the first argument contains more than +** one phrase. All phrases currently point to the same row. The +** Fts5ExprPhrase.poslist buffers are populated accordingly. This function +** tests if the current row contains instances of each phrase sufficiently +** close together to meet the NEAR constraint. Non-zero is returned if it +** does, or zero otherwise. +** +** If in/out parameter (*pRc) is set to other than SQLITE_OK when this +** function is called, it is a no-op. Or, if an error (e.g. SQLITE_NOMEM) +** occurs within this function (*pRc) is set accordingly before returning. +** The return value is undefined in both these cases. +** +** If no error occurs and non-zero (a match) is returned, the position-list +** of each phrase object is edited to contain only those entries that +** meet the constraint before returning. +*/ +static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){ + Fts5NearTrimmer aStatic[4]; + Fts5NearTrimmer *a = aStatic; + Fts5ExprPhrase **apPhrase = pNear->apPhrase; + + int i; + int rc = *pRc; + int bMatch; + + assert( pNear->nPhrase>1 ); + + /* If the aStatic[] array is not large enough, allocate a large array + ** using sqlite3_malloc(). This approach could be improved upon. */ + if( pNear->nPhrase>ArraySize(aStatic) ){ + int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase; + a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte); + }else{ + memset(aStatic, 0, sizeof(aStatic)); + } + if( rc!=SQLITE_OK ){ + *pRc = rc; + return 0; + } + + /* Initialize a lookahead iterator for each phrase. After passing the + ** buffer and buffer size to the lookaside-reader init function, zero + ** the phrase poslist buffer. The new poslist for the phrase (containing + ** the same entries as the original with some entries removed on account + ** of the NEAR constraint) is written over the original even as it is + ** being read. This is safe as the entries for the new poslist are a + ** subset of the old, so it is not possible for data yet to be read to + ** be overwritten. */ + for(i=0; inPhrase; i++){ + Fts5Buffer *pPoslist = &apPhrase[i]->poslist; + fts5LookaheadReaderInit(pPoslist->p, pPoslist->n, &a[i].reader); + pPoslist->n = 0; + a[i].pOut = pPoslist; + } + + while( 1 ){ + int iAdv; + i64 iMin; + i64 iMax; + + /* This block advances the phrase iterators until they point to a set of + ** entries that together comprise a match. */ + iMax = a[0].reader.iPos; + do { + bMatch = 1; + for(i=0; inPhrase; i++){ + Fts5LookaheadReader *pPos = &a[i].reader; + iMin = iMax - pNear->apPhrase[i]->nTerm - pNear->nNear; + if( pPos->iPosiPos>iMax ){ + bMatch = 0; + while( pPos->iPosiPos>iMax ) iMax = pPos->iPos; + } + } + }while( bMatch==0 ); + + /* Add an entry to each output position list */ + for(i=0; inPhrase; i++){ + i64 iPos = a[i].reader.iPos; + Fts5PoslistWriter *pWriter = &a[i].writer; + if( a[i].pOut->n==0 || iPos!=pWriter->iPrev ){ + sqlite3Fts5PoslistWriterAppend(a[i].pOut, pWriter, iPos); + } + } + + iAdv = 0; + iMin = a[0].reader.iLookahead; + for(i=0; inPhrase; i++){ + if( a[i].reader.iLookahead < iMin ){ + iMin = a[i].reader.iLookahead; + iAdv = i; + } + } + if( fts5LookaheadReaderNext(&a[iAdv].reader) ) goto ismatch_out; + } + + ismatch_out: { + int bRet = a[0].pOut->n>0; + *pRc = rc; + if( a!=aStatic ) sqlite3_free(a); + return bRet; + } +} + +/* +** Advance iterator pIter until it points to a value equal to or laster +** than the initial value of *piLast. If this means the iterator points +** to a value laster than *piLast, update *piLast to the new lastest value. +** +** If the iterator reaches EOF, set *pbEof to true before returning. If +** an error occurs, set *pRc to an error code. If either *pbEof or *pRc +** are set, return a non-zero value. Otherwise, return zero. +*/ +static int fts5ExprAdvanceto( + Fts5IndexIter *pIter, /* Iterator to advance */ + int bDesc, /* True if iterator is "rowid DESC" */ + i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ + int *pRc, /* OUT: Error code */ + int *pbEof /* OUT: Set to true if EOF */ +){ + i64 iLast = *piLast; + i64 iRowid; + + iRowid = pIter->iRowid; + if( (bDesc==0 && iLast>iRowid) || (bDesc && iLastiRowid; + assert( (bDesc==0 && iRowid>=iLast) || (bDesc==1 && iRowid<=iLast) ); + } + *piLast = iRowid; + + return 0; +} + +static int fts5ExprSynonymAdvanceto( + Fts5ExprTerm *pTerm, /* Term iterator to advance */ + int bDesc, /* True if iterator is "rowid DESC" */ + i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ + int *pRc /* OUT: Error code */ +){ + int rc = SQLITE_OK; + i64 iLast = *piLast; + Fts5ExprTerm *p; + int bEof = 0; + + for(p=pTerm; rc==SQLITE_OK && p; p=p->pSynonym){ + if( sqlite3Fts5IterEof(p->pIter)==0 ){ + i64 iRowid = p->pIter->iRowid; + if( (bDesc==0 && iLast>iRowid) || (bDesc && iLastpIter, iLast); + } + } + } + + if( rc!=SQLITE_OK ){ + *pRc = rc; + bEof = 1; + }else{ + *piLast = fts5ExprSynonymRowid(pTerm, bDesc, &bEof); + } + return bEof; +} + + +static int fts5ExprNearTest( + int *pRc, + Fts5Expr *pExpr, /* Expression that pNear is a part of */ + Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */ +){ + Fts5ExprNearset *pNear = pNode->pNear; + int rc = *pRc; + + if( pExpr->pConfig->eDetail!=FTS5_DETAIL_FULL ){ + Fts5ExprTerm *pTerm; + Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; + pPhrase->poslist.n = 0; + for(pTerm=&pPhrase->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ + Fts5IndexIter *pIter = pTerm->pIter; + if( sqlite3Fts5IterEof(pIter)==0 ){ + if( pIter->iRowid==pNode->iRowid && pIter->nData>0 ){ + pPhrase->poslist.n = 1; + } + } + } + return pPhrase->poslist.n; + }else{ + int i; + + /* Check that each phrase in the nearset matches the current row. + ** Populate the pPhrase->poslist buffers at the same time. If any + ** phrase is not a match, break out of the loop early. */ + for(i=0; rc==SQLITE_OK && inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){ + int bMatch = 0; + rc = fts5ExprPhraseIsMatch(pNode, pPhrase, &bMatch); + if( bMatch==0 ) break; + }else{ + Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; + fts5BufferSet(&rc, &pPhrase->poslist, pIter->nData, pIter->pData); + } + } + + *pRc = rc; + if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){ + return 1; + } + return 0; + } +} + + +/* +** Initialize all term iterators in the pNear object. If any term is found +** to match no documents at all, return immediately without initializing any +** further iterators. +*/ +static int fts5ExprNearInitAll( + Fts5Expr *pExpr, + Fts5ExprNode *pNode +){ + Fts5ExprNearset *pNear = pNode->pNear; + int i, j; + int rc = SQLITE_OK; + + assert( pNode->bNomatch==0 ); + for(i=0; rc==SQLITE_OK && inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + for(j=0; jnTerm; j++){ + Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; + Fts5ExprTerm *p; + int bEof = 1; + + for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){ + if( p->pIter ){ + sqlite3Fts5IterClose(p->pIter); + p->pIter = 0; + } + rc = sqlite3Fts5IndexQuery( + pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm), + (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | + (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), + pNear->pColset, + &p->pIter + ); + assert( rc==SQLITE_OK || p->pIter==0 ); + if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){ + bEof = 0; + } + } + + if( bEof ){ + pNode->bEof = 1; + return rc; + } + } + } + + return rc; +} + +/* +** If pExpr is an ASC iterator, this function returns a value with the +** same sign as: +** +** (iLhs - iRhs) +** +** Otherwise, if this is a DESC iterator, the opposite is returned: +** +** (iRhs - iLhs) +*/ +static int fts5RowidCmp( + Fts5Expr *pExpr, + i64 iLhs, + i64 iRhs +){ + assert( pExpr->bDesc==0 || pExpr->bDesc==1 ); + if( pExpr->bDesc==0 ){ + if( iLhs iRhs); + }else{ + if( iLhs>iRhs ) return -1; + return (iLhs < iRhs); + } +} + +static void fts5ExprSetEof(Fts5ExprNode *pNode){ + int i; + pNode->bEof = 1; + pNode->bNomatch = 0; + for(i=0; inChild; i++){ + fts5ExprSetEof(pNode->apChild[i]); + } +} + +static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){ + if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){ + Fts5ExprNearset *pNear = pNode->pNear; + int i; + for(i=0; inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + pPhrase->poslist.n = 0; + } + }else{ + int i; + for(i=0; inChild; i++){ + fts5ExprNodeZeroPoslist(pNode->apChild[i]); + } + } +} + + + +/* +** Compare the values currently indicated by the two nodes as follows: +** +** res = (*p1) - (*p2) +** +** Nodes that point to values that come later in the iteration order are +** considered to be larger. Nodes at EOF are the largest of all. +** +** This means that if the iteration order is ASC, then numerically larger +** rowids are considered larger. Or if it is the default DESC, numerically +** smaller rowids are larger. +*/ +static int fts5NodeCompare( + Fts5Expr *pExpr, + Fts5ExprNode *p1, + Fts5ExprNode *p2 +){ + if( p2->bEof ) return -1; + if( p1->bEof ) return +1; + return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid); +} + +/* +** All individual term iterators in pNear are guaranteed to be valid when +** this function is called. This function checks if all term iterators +** point to the same rowid, and if not, advances them until they do. +** If an EOF is reached before this happens, *pbEof is set to true before +** returning. +** +** SQLITE_OK is returned if an error occurs, or an SQLite error code +** otherwise. It is not considered an error code if an iterator reaches +** EOF. +*/ +static int fts5ExprNodeTest_STRING( + Fts5Expr *pExpr, /* Expression pPhrase belongs to */ + Fts5ExprNode *pNode +){ + Fts5ExprNearset *pNear = pNode->pNear; + Fts5ExprPhrase *pLeft = pNear->apPhrase[0]; + int rc = SQLITE_OK; + i64 iLast; /* Lastest rowid any iterator points to */ + int i, j; /* Phrase and token index, respectively */ + int bMatch; /* True if all terms are at the same rowid */ + const int bDesc = pExpr->bDesc; + + /* Check that this node should not be FTS5_TERM */ + assert( pNear->nPhrase>1 + || pNear->apPhrase[0]->nTerm>1 + || pNear->apPhrase[0]->aTerm[0].pSynonym + ); + + /* Initialize iLast, the "lastest" rowid any iterator points to. If the + ** iterator skips through rowids in the default ascending order, this means + ** the maximum rowid. Or, if the iterator is "ORDER BY rowid DESC", then it + ** means the minimum rowid. */ + if( pLeft->aTerm[0].pSynonym ){ + iLast = fts5ExprSynonymRowid(&pLeft->aTerm[0], bDesc, 0); + }else{ + iLast = pLeft->aTerm[0].pIter->iRowid; + } + + do { + bMatch = 1; + for(i=0; inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + for(j=0; jnTerm; j++){ + Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; + if( pTerm->pSynonym ){ + i64 iRowid = fts5ExprSynonymRowid(pTerm, bDesc, 0); + if( iRowid==iLast ) continue; + bMatch = 0; + if( fts5ExprSynonymAdvanceto(pTerm, bDesc, &iLast, &rc) ){ + pNode->bNomatch = 0; + pNode->bEof = 1; + return rc; + } + }else{ + Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter; + if( pIter->iRowid==iLast ) continue; + bMatch = 0; + if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){ + return rc; + } + } + } + } + }while( bMatch==0 ); + + pNode->iRowid = iLast; + pNode->bNomatch = ((0==fts5ExprNearTest(&rc, pExpr, pNode)) && rc==SQLITE_OK); + assert( pNode->bEof==0 || pNode->bNomatch==0 ); + + return rc; +} + +/* +** Advance the first term iterator in the first phrase of pNear. Set output +** variable *pbEof to true if it reaches EOF or if an error occurs. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +static int fts5ExprNodeNext_STRING( + Fts5Expr *pExpr, /* Expression pPhrase belongs to */ + Fts5ExprNode *pNode, /* FTS5_STRING or FTS5_TERM node */ + int bFromValid, + i64 iFrom +){ + Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0]; + int rc = SQLITE_OK; + + pNode->bNomatch = 0; + if( pTerm->pSynonym ){ + int bEof = 1; + Fts5ExprTerm *p; + + /* Find the firstest rowid any synonym points to. */ + i64 iRowid = fts5ExprSynonymRowid(pTerm, pExpr->bDesc, 0); + + /* Advance each iterator that currently points to iRowid. Or, if iFrom + ** is valid - each iterator that points to a rowid before iFrom. */ + for(p=pTerm; p; p=p->pSynonym){ + if( sqlite3Fts5IterEof(p->pIter)==0 ){ + i64 ii = p->pIter->iRowid; + if( ii==iRowid + || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) + ){ + if( bFromValid ){ + rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom); + }else{ + rc = sqlite3Fts5IterNext(p->pIter); + } + if( rc!=SQLITE_OK ) break; + if( sqlite3Fts5IterEof(p->pIter)==0 ){ + bEof = 0; + } + }else{ + bEof = 0; + } + } + } + + /* Set the EOF flag if either all synonym iterators are at EOF or an + ** error has occurred. */ + pNode->bEof = (rc || bEof); + }else{ + Fts5IndexIter *pIter = pTerm->pIter; + + assert( Fts5NodeIsString(pNode) ); + if( bFromValid ){ + rc = sqlite3Fts5IterNextFrom(pIter, iFrom); + }else{ + rc = sqlite3Fts5IterNext(pIter); + } + + pNode->bEof = (rc || sqlite3Fts5IterEof(pIter)); + } + + if( pNode->bEof==0 ){ + assert( rc==SQLITE_OK ); + rc = fts5ExprNodeTest_STRING(pExpr, pNode); + } + + return rc; +} + + +static int fts5ExprNodeTest_TERM( + Fts5Expr *pExpr, /* Expression that pNear is a part of */ + Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */ +){ + /* As this "NEAR" object is actually a single phrase that consists + ** of a single term only, grab pointers into the poslist managed by the + ** fts5_index.c iterator object. This is much faster than synthesizing + ** a new poslist the way we have to for more complicated phrase or NEAR + ** expressions. */ + Fts5ExprPhrase *pPhrase = pNode->pNear->apPhrase[0]; + Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; + + assert( pNode->eType==FTS5_TERM ); + assert( pNode->pNear->nPhrase==1 && pPhrase->nTerm==1 ); + assert( pPhrase->aTerm[0].pSynonym==0 ); + + pPhrase->poslist.n = pIter->nData; + if( pExpr->pConfig->eDetail==FTS5_DETAIL_FULL ){ + pPhrase->poslist.p = (u8*)pIter->pData; + } + pNode->iRowid = pIter->iRowid; + pNode->bNomatch = (pPhrase->poslist.n==0); + return SQLITE_OK; +} + +/* +** xNext() method for a node of type FTS5_TERM. +*/ +static int fts5ExprNodeNext_TERM( + Fts5Expr *pExpr, + Fts5ExprNode *pNode, + int bFromValid, + i64 iFrom +){ + int rc; + Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter; + + assert( pNode->bEof==0 ); + if( bFromValid ){ + rc = sqlite3Fts5IterNextFrom(pIter, iFrom); + }else{ + rc = sqlite3Fts5IterNext(pIter); + } + if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){ + rc = fts5ExprNodeTest_TERM(pExpr, pNode); + }else{ + pNode->bEof = 1; + pNode->bNomatch = 0; + } + return rc; +} + +static void fts5ExprNodeTest_OR( + Fts5Expr *pExpr, /* Expression of which pNode is a part */ + Fts5ExprNode *pNode /* Expression node to test */ +){ + Fts5ExprNode *pNext = pNode->apChild[0]; + int i; + + for(i=1; inChild; i++){ + Fts5ExprNode *pChild = pNode->apChild[i]; + int cmp = fts5NodeCompare(pExpr, pNext, pChild); + if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){ + pNext = pChild; + } + } + pNode->iRowid = pNext->iRowid; + pNode->bEof = pNext->bEof; + pNode->bNomatch = pNext->bNomatch; +} + +static int fts5ExprNodeNext_OR( + Fts5Expr *pExpr, + Fts5ExprNode *pNode, + int bFromValid, + i64 iFrom +){ + int i; + i64 iLast = pNode->iRowid; + + for(i=0; inChild; i++){ + Fts5ExprNode *p1 = pNode->apChild[i]; + assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 ); + if( p1->bEof==0 ){ + if( (p1->iRowid==iLast) + || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0) + ){ + int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom); + if( rc!=SQLITE_OK ) return rc; + } + } + } + + fts5ExprNodeTest_OR(pExpr, pNode); + return SQLITE_OK; +} + +/* +** Argument pNode is an FTS5_AND node. +*/ +static int fts5ExprNodeTest_AND( + Fts5Expr *pExpr, /* Expression pPhrase belongs to */ + Fts5ExprNode *pAnd /* FTS5_AND node to advance */ +){ + int iChild; + i64 iLast = pAnd->iRowid; + int rc = SQLITE_OK; + int bMatch; + + assert( pAnd->bEof==0 ); + do { + pAnd->bNomatch = 0; + bMatch = 1; + for(iChild=0; iChildnChild; iChild++){ + Fts5ExprNode *pChild = pAnd->apChild[iChild]; + int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid); + if( cmp>0 ){ + /* Advance pChild until it points to iLast or laster */ + rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast); + if( rc!=SQLITE_OK ) return rc; + } + + /* If the child node is now at EOF, so is the parent AND node. Otherwise, + ** the child node is guaranteed to have advanced at least as far as + ** rowid iLast. So if it is not at exactly iLast, pChild->iRowid is the + ** new lastest rowid seen so far. */ + assert( pChild->bEof || fts5RowidCmp(pExpr, iLast, pChild->iRowid)<=0 ); + if( pChild->bEof ){ + fts5ExprSetEof(pAnd); + bMatch = 1; + break; + }else if( iLast!=pChild->iRowid ){ + bMatch = 0; + iLast = pChild->iRowid; + } + + if( pChild->bNomatch ){ + pAnd->bNomatch = 1; + } + } + }while( bMatch==0 ); + + if( pAnd->bNomatch && pAnd!=pExpr->pRoot ){ + fts5ExprNodeZeroPoslist(pAnd); + } + pAnd->iRowid = iLast; + return SQLITE_OK; +} + +static int fts5ExprNodeNext_AND( + Fts5Expr *pExpr, + Fts5ExprNode *pNode, + int bFromValid, + i64 iFrom +){ + int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom); + if( rc==SQLITE_OK ){ + rc = fts5ExprNodeTest_AND(pExpr, pNode); + } + return rc; +} + +static int fts5ExprNodeTest_NOT( + Fts5Expr *pExpr, /* Expression pPhrase belongs to */ + Fts5ExprNode *pNode /* FTS5_NOT node to advance */ +){ + int rc = SQLITE_OK; + Fts5ExprNode *p1 = pNode->apChild[0]; + Fts5ExprNode *p2 = pNode->apChild[1]; + assert( pNode->nChild==2 ); + + while( rc==SQLITE_OK && p1->bEof==0 ){ + int cmp = fts5NodeCompare(pExpr, p1, p2); + if( cmp>0 ){ + rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid); + cmp = fts5NodeCompare(pExpr, p1, p2); + } + assert( rc!=SQLITE_OK || cmp<=0 ); + if( cmp || p2->bNomatch ) break; + rc = fts5ExprNodeNext(pExpr, p1, 0, 0); + } + pNode->bEof = p1->bEof; + pNode->bNomatch = p1->bNomatch; + pNode->iRowid = p1->iRowid; + if( p1->bEof ){ + fts5ExprNodeZeroPoslist(p2); + } + return rc; +} + +static int fts5ExprNodeNext_NOT( + Fts5Expr *pExpr, + Fts5ExprNode *pNode, + int bFromValid, + i64 iFrom +){ + int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom); + if( rc==SQLITE_OK ){ + rc = fts5ExprNodeTest_NOT(pExpr, pNode); + } + return rc; +} + +/* +** If pNode currently points to a match, this function returns SQLITE_OK +** without modifying it. Otherwise, pNode is advanced until it does point +** to a match or EOF is reached. +*/ +static int fts5ExprNodeTest( + Fts5Expr *pExpr, /* Expression of which pNode is a part */ + Fts5ExprNode *pNode /* Expression node to test */ +){ + int rc = SQLITE_OK; + if( pNode->bEof==0 ){ + switch( pNode->eType ){ + + case FTS5_STRING: { + rc = fts5ExprNodeTest_STRING(pExpr, pNode); + break; + } + + case FTS5_TERM: { + rc = fts5ExprNodeTest_TERM(pExpr, pNode); + break; + } + + case FTS5_AND: { + rc = fts5ExprNodeTest_AND(pExpr, pNode); + break; + } + + case FTS5_OR: { + fts5ExprNodeTest_OR(pExpr, pNode); + break; + } + + default: assert( pNode->eType==FTS5_NOT ); { + rc = fts5ExprNodeTest_NOT(pExpr, pNode); + break; + } + } + } + return rc; +} + + +/* +** Set node pNode, which is part of expression pExpr, to point to the first +** match. If there are no matches, set the Node.bEof flag to indicate EOF. +** +** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise. +** It is not an error if there are no matches. +*/ +static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){ + int rc = SQLITE_OK; + pNode->bEof = 0; + pNode->bNomatch = 0; + + if( Fts5NodeIsString(pNode) ){ + /* Initialize all term iterators in the NEAR object. */ + rc = fts5ExprNearInitAll(pExpr, pNode); + }else{ + int i; + int nEof = 0; + for(i=0; inChild && rc==SQLITE_OK; i++){ + Fts5ExprNode *pChild = pNode->apChild[i]; + rc = fts5ExprNodeFirst(pExpr, pNode->apChild[i]); + assert( pChild->bEof==0 || pChild->bEof==1 ); + nEof += pChild->bEof; + } + pNode->iRowid = pNode->apChild[0]->iRowid; + + switch( pNode->eType ){ + case FTS5_AND: + if( nEof>0 ) fts5ExprSetEof(pNode); + break; + + case FTS5_OR: + if( pNode->nChild==nEof ) fts5ExprSetEof(pNode); + break; + + default: + assert( pNode->eType==FTS5_NOT ); + pNode->bEof = pNode->apChild[0]->bEof; + break; + } + } + + if( rc==SQLITE_OK ){ + rc = fts5ExprNodeTest(pExpr, pNode); + } + return rc; +} + + +/* +** Begin iterating through the set of documents in index pIdx matched by +** the MATCH expression passed as the first argument. If the "bDesc" +** parameter is passed a non-zero value, iteration is in descending rowid +** order. Or, if it is zero, in ascending order. +** +** If iterating in ascending rowid order (bDesc==0), the first document +** visited is that with the smallest rowid that is larger than or equal +** to parameter iFirst. Or, if iterating in ascending order (bDesc==1), +** then the first document visited must have a rowid smaller than or +** equal to iFirst. +** +** Return SQLITE_OK if successful, or an SQLite error code otherwise. It +** is not considered an error if the query does not match any documents. +*/ +int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){ + Fts5ExprNode *pRoot = p->pRoot; + int rc = SQLITE_OK; + if( pRoot->xNext ){ + p->pIndex = pIdx; + p->bDesc = bDesc; + rc = fts5ExprNodeFirst(p, pRoot); + + /* If not at EOF but the current rowid occurs earlier than iFirst in + ** the iteration order, move to document iFirst or later. */ + if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){ + rc = fts5ExprNodeNext(p, pRoot, 1, iFirst); + } + + /* If the iterator is not at a real match, skip forward until it is. */ + while( pRoot->bNomatch ){ + assert( pRoot->bEof==0 && rc==SQLITE_OK ); + rc = fts5ExprNodeNext(p, pRoot, 0, 0); + } + } + return rc; +} + +/* +** Move to the next document +** +** Return SQLITE_OK if successful, or an SQLite error code otherwise. It +** is not considered an error if the query does not match any documents. +*/ +int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){ + int rc; + Fts5ExprNode *pRoot = p->pRoot; + assert( pRoot->bEof==0 && pRoot->bNomatch==0 ); + do { + rc = fts5ExprNodeNext(p, pRoot, 0, 0); + assert( pRoot->bNomatch==0 || (rc==SQLITE_OK && pRoot->bEof==0) ); + }while( pRoot->bNomatch ); + if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){ + pRoot->bEof = 1; + } + return rc; +} + +int sqlite3Fts5ExprEof(Fts5Expr *p){ + return p->pRoot->bEof; +} + +i64 sqlite3Fts5ExprRowid(Fts5Expr *p){ + return p->pRoot->iRowid; +} + +static int fts5ParseStringFromToken(Fts5Token *pToken, char **pz){ + int rc = SQLITE_OK; + *pz = sqlite3Fts5Strndup(&rc, pToken->p, pToken->n); + return rc; +} + +/* +** Free the phrase object passed as the only argument. +*/ +static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){ + if( pPhrase ){ + int i; + for(i=0; inTerm; i++){ + Fts5ExprTerm *pSyn; + Fts5ExprTerm *pNext; + Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; + sqlite3_free(pTerm->zTerm); + sqlite3Fts5IterClose(pTerm->pIter); + for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){ + pNext = pSyn->pSynonym; + sqlite3Fts5IterClose(pSyn->pIter); + fts5BufferFree((Fts5Buffer*)&pSyn[1]); + sqlite3_free(pSyn); + } + } + if( pPhrase->poslist.nSpace>0 ) fts5BufferFree(&pPhrase->poslist); + sqlite3_free(pPhrase); + } +} + +/* +** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated +** and populated with pPhrase. Or, if pNear is not NULL, phrase pPhrase is +** appended to it and the results returned. +** +** If an OOM error occurs, both the pNear and pPhrase objects are freed and +** NULL returned. +*/ +Fts5ExprNearset *sqlite3Fts5ParseNearset( + Fts5Parse *pParse, /* Parse context */ + Fts5ExprNearset *pNear, /* Existing nearset, or NULL */ + Fts5ExprPhrase *pPhrase /* Recently parsed phrase */ +){ + const int SZALLOC = 8; + Fts5ExprNearset *pRet = 0; + + if( pParse->rc==SQLITE_OK ){ + if( pPhrase==0 ){ + return pNear; + } + if( pNear==0 ){ + int nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); + pRet = sqlite3_malloc(nByte); + if( pRet==0 ){ + pParse->rc = SQLITE_NOMEM; + }else{ + memset(pRet, 0, nByte); + } + }else if( (pNear->nPhrase % SZALLOC)==0 ){ + int nNew = pNear->nPhrase + SZALLOC; + int nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*); + + pRet = (Fts5ExprNearset*)sqlite3_realloc(pNear, nByte); + if( pRet==0 ){ + pParse->rc = SQLITE_NOMEM; + } + }else{ + pRet = pNear; + } + } + + if( pRet==0 ){ + assert( pParse->rc!=SQLITE_OK ); + sqlite3Fts5ParseNearsetFree(pNear); + sqlite3Fts5ParsePhraseFree(pPhrase); + }else{ + pRet->apPhrase[pRet->nPhrase++] = pPhrase; + } + return pRet; +} + +typedef struct TokenCtx TokenCtx; +struct TokenCtx { + Fts5ExprPhrase *pPhrase; + int rc; +}; + +/* +** Callback for tokenizing terms used by ParseTerm(). +*/ +static int fts5ParseTokenize( + void *pContext, /* Pointer to Fts5InsertCtx object */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Buffer containing token */ + int nToken, /* Size of token in bytes */ + int iUnused1, /* Start offset of token */ + int iUnused2 /* End offset of token */ +){ + int rc = SQLITE_OK; + const int SZALLOC = 8; + TokenCtx *pCtx = (TokenCtx*)pContext; + Fts5ExprPhrase *pPhrase = pCtx->pPhrase; + + UNUSED_PARAM2(iUnused1, iUnused2); + + /* If an error has already occurred, this is a no-op */ + if( pCtx->rc!=SQLITE_OK ) return pCtx->rc; + + assert( pPhrase==0 || pPhrase->nTerm>0 ); + if( pPhrase && (tflags & FTS5_TOKEN_COLOCATED) ){ + Fts5ExprTerm *pSyn; + int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1; + pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte); + if( pSyn==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(pSyn, 0, nByte); + pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); + memcpy(pSyn->zTerm, pToken, nToken); + pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; + pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; + } + }else{ + Fts5ExprTerm *pTerm; + if( pPhrase==0 || (pPhrase->nTerm % SZALLOC)==0 ){ + Fts5ExprPhrase *pNew; + int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0); + + pNew = (Fts5ExprPhrase*)sqlite3_realloc(pPhrase, + sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew + ); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + if( pPhrase==0 ) memset(pNew, 0, sizeof(Fts5ExprPhrase)); + pCtx->pPhrase = pPhrase = pNew; + pNew->nTerm = nNew - SZALLOC; + } + } + + if( rc==SQLITE_OK ){ + pTerm = &pPhrase->aTerm[pPhrase->nTerm++]; + memset(pTerm, 0, sizeof(Fts5ExprTerm)); + pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken); + } + } + + pCtx->rc = rc; + return rc; +} + + +/* +** Free the phrase object passed as the only argument. +*/ +void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase *pPhrase){ + fts5ExprPhraseFree(pPhrase); +} + +/* +** Free the phrase object passed as the second argument. +*/ +void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset *pNear){ + if( pNear ){ + int i; + for(i=0; inPhrase; i++){ + fts5ExprPhraseFree(pNear->apPhrase[i]); + } + sqlite3_free(pNear->pColset); + sqlite3_free(pNear); + } +} + +void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){ + assert( pParse->pExpr==0 ); + pParse->pExpr = p; +} + +/* +** This function is called by the parser to process a string token. The +** string may or may not be quoted. In any case it is tokenized and a +** phrase object consisting of all tokens returned. +*/ +Fts5ExprPhrase *sqlite3Fts5ParseTerm( + Fts5Parse *pParse, /* Parse context */ + Fts5ExprPhrase *pAppend, /* Phrase to append to */ + Fts5Token *pToken, /* String to tokenize */ + int bPrefix /* True if there is a trailing "*" */ +){ + Fts5Config *pConfig = pParse->pConfig; + TokenCtx sCtx; /* Context object passed to callback */ + int rc; /* Tokenize return code */ + char *z = 0; + + memset(&sCtx, 0, sizeof(TokenCtx)); + sCtx.pPhrase = pAppend; + + rc = fts5ParseStringFromToken(pToken, &z); + if( rc==SQLITE_OK ){ + int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_QUERY : 0); + int n; + sqlite3Fts5Dequote(z); + n = (int)strlen(z); + rc = sqlite3Fts5Tokenize(pConfig, flags, z, n, &sCtx, fts5ParseTokenize); + } + sqlite3_free(z); + if( rc || (rc = sCtx.rc) ){ + pParse->rc = rc; + fts5ExprPhraseFree(sCtx.pPhrase); + sCtx.pPhrase = 0; + }else if( sCtx.pPhrase ){ + + if( pAppend==0 ){ + if( (pParse->nPhrase % 8)==0 ){ + int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); + Fts5ExprPhrase **apNew; + apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte); + if( apNew==0 ){ + pParse->rc = SQLITE_NOMEM; + fts5ExprPhraseFree(sCtx.pPhrase); + return 0; + } + pParse->apPhrase = apNew; + } + pParse->nPhrase++; + } + + pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase; + assert( sCtx.pPhrase->nTerm>0 ); + sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix; + } + + return sCtx.pPhrase; +} + +/* +** Create a new FTS5 expression by cloning phrase iPhrase of the +** expression passed as the second argument. +*/ +int sqlite3Fts5ExprClonePhrase( + Fts5Expr *pExpr, + int iPhrase, + Fts5Expr **ppNew +){ + int rc = SQLITE_OK; /* Return code */ + Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */ + int i; /* Used to iterate through phrase terms */ + Fts5Expr *pNew = 0; /* Expression to return via *ppNew */ + TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */ + + pOrig = pExpr->apExprPhrase[iPhrase]; + pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); + if( rc==SQLITE_OK ){ + pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, + sizeof(Fts5ExprPhrase*)); + } + if( rc==SQLITE_OK ){ + pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, + sizeof(Fts5ExprNode)); + } + if( rc==SQLITE_OK ){ + pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, + sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); + } + + for(i=0; rc==SQLITE_OK && inTerm; i++){ + int tflags = 0; + Fts5ExprTerm *p; + for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ + const char *zTerm = p->zTerm; + rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm), + 0, 0); + tflags = FTS5_TOKEN_COLOCATED; + } + if( rc==SQLITE_OK ){ + sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; + } + } + + if( rc==SQLITE_OK ){ + /* All the allocations succeeded. Put the expression object together. */ + pNew->pIndex = pExpr->pIndex; + pNew->pConfig = pExpr->pConfig; + pNew->nPhrase = 1; + pNew->apExprPhrase[0] = sCtx.pPhrase; + pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase; + pNew->pRoot->pNear->nPhrase = 1; + sCtx.pPhrase->pNode = pNew->pRoot; + + if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){ + pNew->pRoot->eType = FTS5_TERM; + pNew->pRoot->xNext = fts5ExprNodeNext_TERM; + }else{ + pNew->pRoot->eType = FTS5_STRING; + pNew->pRoot->xNext = fts5ExprNodeNext_STRING; + } + }else{ + sqlite3Fts5ExprFree(pNew); + fts5ExprPhraseFree(sCtx.pPhrase); + pNew = 0; + } + + *ppNew = pNew; + return rc; +} + + +/* +** Token pTok has appeared in a MATCH expression where the NEAR operator +** is expected. If token pTok does not contain "NEAR", store an error +** in the pParse object. +*/ +void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token *pTok){ + if( pTok->n!=4 || memcmp("NEAR", pTok->p, 4) ){ + sqlite3Fts5ParseError( + pParse, "fts5: syntax error near \"%.*s\"", pTok->n, pTok->p + ); + } +} + +void sqlite3Fts5ParseSetDistance( + Fts5Parse *pParse, + Fts5ExprNearset *pNear, + Fts5Token *p +){ + int nNear = 0; + int i; + if( p->n ){ + for(i=0; in; i++){ + char c = (char)p->p[i]; + if( c<'0' || c>'9' ){ + sqlite3Fts5ParseError( + pParse, "expected integer, got \"%.*s\"", p->n, p->p + ); + return; + } + nNear = nNear * 10 + (p->p[i] - '0'); + } + }else{ + nNear = FTS5_DEFAULT_NEARDIST; + } + pNear->nNear = nNear; +} + +/* +** The second argument passed to this function may be NULL, or it may be +** an existing Fts5Colset object. This function returns a pointer to +** a new colset object containing the contents of (p) with new value column +** number iCol appended. +** +** If an OOM error occurs, store an error code in pParse and return NULL. +** The old colset object (if any) is not freed in this case. +*/ +static Fts5Colset *fts5ParseColset( + Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ + Fts5Colset *p, /* Existing colset object */ + int iCol /* New column to add to colset object */ +){ + int nCol = p ? p->nCol : 0; /* Num. columns already in colset object */ + Fts5Colset *pNew; /* New colset object to return */ + + assert( pParse->rc==SQLITE_OK ); + assert( iCol>=0 && iColpConfig->nCol ); + + pNew = sqlite3_realloc(p, sizeof(Fts5Colset) + sizeof(int)*nCol); + if( pNew==0 ){ + pParse->rc = SQLITE_NOMEM; + }else{ + int *aiCol = pNew->aiCol; + int i, j; + for(i=0; iiCol ) break; + } + for(j=nCol; j>i; j--){ + aiCol[j] = aiCol[j-1]; + } + aiCol[i] = iCol; + pNew->nCol = nCol+1; + +#ifndef NDEBUG + /* Check that the array is in order and contains no duplicate entries. */ + for(i=1; inCol; i++) assert( pNew->aiCol[i]>pNew->aiCol[i-1] ); +#endif + } + + return pNew; +} + +Fts5Colset *sqlite3Fts5ParseColset( + Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ + Fts5Colset *pColset, /* Existing colset object */ + Fts5Token *p +){ + Fts5Colset *pRet = 0; + int iCol; + char *z; /* Dequoted copy of token p */ + + z = sqlite3Fts5Strndup(&pParse->rc, p->p, p->n); + if( pParse->rc==SQLITE_OK ){ + Fts5Config *pConfig = pParse->pConfig; + sqlite3Fts5Dequote(z); + for(iCol=0; iColnCol; iCol++){ + if( 0==sqlite3_stricmp(pConfig->azCol[iCol], z) ) break; + } + if( iCol==pConfig->nCol ){ + sqlite3Fts5ParseError(pParse, "no such column: %s", z); + }else{ + pRet = fts5ParseColset(pParse, pColset, iCol); + } + sqlite3_free(z); + } + + if( pRet==0 ){ + assert( pParse->rc!=SQLITE_OK ); + sqlite3_free(pColset); + } + + return pRet; +} + +void sqlite3Fts5ParseSetColset( + Fts5Parse *pParse, + Fts5ExprNearset *pNear, + Fts5Colset *pColset +){ + if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ + pParse->rc = SQLITE_ERROR; + pParse->zErr = sqlite3_mprintf( + "fts5: column queries are not supported (detail=none)" + ); + sqlite3_free(pColset); + return; + } + + if( pNear ){ + pNear->pColset = pColset; + }else{ + sqlite3_free(pColset); + } +} + +static void fts5ExprAssignXNext(Fts5ExprNode *pNode){ + switch( pNode->eType ){ + case FTS5_STRING: { + Fts5ExprNearset *pNear = pNode->pNear; + if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 + && pNear->apPhrase[0]->aTerm[0].pSynonym==0 + ){ + pNode->eType = FTS5_TERM; + pNode->xNext = fts5ExprNodeNext_TERM; + }else{ + pNode->xNext = fts5ExprNodeNext_STRING; + } + break; + }; + + case FTS5_OR: { + pNode->xNext = fts5ExprNodeNext_OR; + break; + }; + + case FTS5_AND: { + pNode->xNext = fts5ExprNodeNext_AND; + break; + }; + + default: assert( pNode->eType==FTS5_NOT ); { + pNode->xNext = fts5ExprNodeNext_NOT; + break; + }; + } +} + +static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){ + if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){ + int nByte = sizeof(Fts5ExprNode*) * pSub->nChild; + memcpy(&p->apChild[p->nChild], pSub->apChild, nByte); + p->nChild += pSub->nChild; + sqlite3_free(pSub); + }else{ + p->apChild[p->nChild++] = pSub; + } +} + +/* +** Allocate and return a new expression object. If anything goes wrong (i.e. +** OOM error), leave an error code in pParse and return NULL. +*/ +Fts5ExprNode *sqlite3Fts5ParseNode( + Fts5Parse *pParse, /* Parse context */ + int eType, /* FTS5_STRING, AND, OR or NOT */ + Fts5ExprNode *pLeft, /* Left hand child expression */ + Fts5ExprNode *pRight, /* Right hand child expression */ + Fts5ExprNearset *pNear /* For STRING expressions, the near cluster */ +){ + Fts5ExprNode *pRet = 0; + + if( pParse->rc==SQLITE_OK ){ + int nChild = 0; /* Number of children of returned node */ + int nByte; /* Bytes of space to allocate for this node */ + + assert( (eType!=FTS5_STRING && !pNear) + || (eType==FTS5_STRING && !pLeft && !pRight) + ); + if( eType==FTS5_STRING && pNear==0 ) return 0; + if( eType!=FTS5_STRING && pLeft==0 ) return pRight; + if( eType!=FTS5_STRING && pRight==0 ) return pLeft; + + if( eType==FTS5_NOT ){ + nChild = 2; + }else if( eType==FTS5_AND || eType==FTS5_OR ){ + nChild = 2; + if( pLeft->eType==eType ) nChild += pLeft->nChild-1; + if( pRight->eType==eType ) nChild += pRight->nChild-1; + } + + nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); + pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); + + if( pRet ){ + pRet->eType = eType; + pRet->pNear = pNear; + fts5ExprAssignXNext(pRet); + if( eType==FTS5_STRING ){ + int iPhrase; + for(iPhrase=0; iPhrasenPhrase; iPhrase++){ + pNear->apPhrase[iPhrase]->pNode = pRet; + } + + if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL + && (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm!=1) + ){ + assert( pParse->rc==SQLITE_OK ); + pParse->rc = SQLITE_ERROR; + assert( pParse->zErr==0 ); + pParse->zErr = sqlite3_mprintf( + "fts5: %s queries are not supported (detail!=full)", + pNear->nPhrase==1 ? "phrase": "NEAR" + ); + sqlite3_free(pRet); + pRet = 0; + } + + }else{ + fts5ExprAddChildren(pRet, pLeft); + fts5ExprAddChildren(pRet, pRight); + } + } + } + + if( pRet==0 ){ + assert( pParse->rc!=SQLITE_OK ); + sqlite3Fts5ParseNodeFree(pLeft); + sqlite3Fts5ParseNodeFree(pRight); + sqlite3Fts5ParseNearsetFree(pNear); + } + return pRet; +} + +static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ + int nByte = 0; + Fts5ExprTerm *p; + char *zQuoted; + + /* Determine the maximum amount of space required. */ + for(p=pTerm; p; p=p->pSynonym){ + nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2; + } + zQuoted = sqlite3_malloc(nByte); + + if( zQuoted ){ + int i = 0; + for(p=pTerm; p; p=p->pSynonym){ + char *zIn = p->zTerm; + zQuoted[i++] = '"'; + while( *zIn ){ + if( *zIn=='"' ) zQuoted[i++] = '"'; + zQuoted[i++] = *zIn++; + } + zQuoted[i++] = '"'; + if( p->pSynonym ) zQuoted[i++] = '|'; + } + if( pTerm->bPrefix ){ + zQuoted[i++] = ' '; + zQuoted[i++] = '*'; + } + zQuoted[i++] = '\0'; + } + return zQuoted; +} + +static char *fts5PrintfAppend(char *zApp, const char *zFmt, ...){ + char *zNew; + va_list ap; + va_start(ap, zFmt); + zNew = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + if( zApp && zNew ){ + char *zNew2 = sqlite3_mprintf("%s%s", zApp, zNew); + sqlite3_free(zNew); + zNew = zNew2; + } + sqlite3_free(zApp); + return zNew; +} + +/* +** Compose a tcl-readable representation of expression pExpr. Return a +** pointer to a buffer containing that representation. It is the +** responsibility of the caller to at some point free the buffer using +** sqlite3_free(). +*/ +static char *fts5ExprPrintTcl( + Fts5Config *pConfig, + const char *zNearsetCmd, + Fts5ExprNode *pExpr +){ + char *zRet = 0; + if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ + Fts5ExprNearset *pNear = pExpr->pNear; + int i; + int iTerm; + + zRet = fts5PrintfAppend(zRet, "%s ", zNearsetCmd); + if( zRet==0 ) return 0; + if( pNear->pColset ){ + int *aiCol = pNear->pColset->aiCol; + int nCol = pNear->pColset->nCol; + if( nCol==1 ){ + zRet = fts5PrintfAppend(zRet, "-col %d ", aiCol[0]); + }else{ + zRet = fts5PrintfAppend(zRet, "-col {%d", aiCol[0]); + for(i=1; ipColset->nCol; i++){ + zRet = fts5PrintfAppend(zRet, " %d", aiCol[i]); + } + zRet = fts5PrintfAppend(zRet, "} "); + } + if( zRet==0 ) return 0; + } + + if( pNear->nPhrase>1 ){ + zRet = fts5PrintfAppend(zRet, "-near %d ", pNear->nNear); + if( zRet==0 ) return 0; + } + + zRet = fts5PrintfAppend(zRet, "--"); + if( zRet==0 ) return 0; + + for(i=0; inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + + zRet = fts5PrintfAppend(zRet, " {"); + for(iTerm=0; zRet && iTermnTerm; iTerm++){ + char *zTerm = pPhrase->aTerm[iTerm].zTerm; + zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm); + if( pPhrase->aTerm[iTerm].bPrefix ){ + zRet = fts5PrintfAppend(zRet, "*"); + } + } + + if( zRet ) zRet = fts5PrintfAppend(zRet, "}"); + if( zRet==0 ) return 0; + } + + }else{ + char const *zOp = 0; + int i; + switch( pExpr->eType ){ + case FTS5_AND: zOp = "AND"; break; + case FTS5_NOT: zOp = "NOT"; break; + default: + assert( pExpr->eType==FTS5_OR ); + zOp = "OR"; + break; + } + + zRet = sqlite3_mprintf("%s", zOp); + for(i=0; zRet && inChild; i++){ + char *z = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->apChild[i]); + if( !z ){ + sqlite3_free(zRet); + zRet = 0; + }else{ + zRet = fts5PrintfAppend(zRet, " [%z]", z); + } + } + } + + return zRet; +} + +static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){ + char *zRet = 0; + if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ + Fts5ExprNearset *pNear = pExpr->pNear; + int i; + int iTerm; + + if( pNear->pColset ){ + int iCol = pNear->pColset->aiCol[0]; + zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]); + if( zRet==0 ) return 0; + } + + if( pNear->nPhrase>1 ){ + zRet = fts5PrintfAppend(zRet, "NEAR("); + if( zRet==0 ) return 0; + } + + for(i=0; inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + if( i!=0 ){ + zRet = fts5PrintfAppend(zRet, " "); + if( zRet==0 ) return 0; + } + for(iTerm=0; iTermnTerm; iTerm++){ + char *zTerm = fts5ExprTermPrint(&pPhrase->aTerm[iTerm]); + if( zTerm ){ + zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" + ", zTerm); + sqlite3_free(zTerm); + } + if( zTerm==0 || zRet==0 ){ + sqlite3_free(zRet); + return 0; + } + } + } + + if( pNear->nPhrase>1 ){ + zRet = fts5PrintfAppend(zRet, ", %d)", pNear->nNear); + if( zRet==0 ) return 0; + } + + }else{ + char const *zOp = 0; + int i; + + switch( pExpr->eType ){ + case FTS5_AND: zOp = " AND "; break; + case FTS5_NOT: zOp = " NOT "; break; + default: + assert( pExpr->eType==FTS5_OR ); + zOp = " OR "; + break; + } + + for(i=0; inChild; i++){ + char *z = fts5ExprPrint(pConfig, pExpr->apChild[i]); + if( z==0 ){ + sqlite3_free(zRet); + zRet = 0; + }else{ + int e = pExpr->apChild[i]->eType; + int b = (e!=FTS5_STRING && e!=FTS5_TERM); + zRet = fts5PrintfAppend(zRet, "%s%s%z%s", + (i==0 ? "" : zOp), + (b?"(":""), z, (b?")":"") + ); + } + if( zRet==0 ) break; + } + } + + return zRet; +} + +/* +** The implementation of user-defined scalar functions fts5_expr() (bTcl==0) +** and fts5_expr_tcl() (bTcl!=0). +*/ +static void fts5ExprFunction( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apVal, /* Function arguments */ + int bTcl +){ + Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx); + sqlite3 *db = sqlite3_context_db_handle(pCtx); + const char *zExpr = 0; + char *zErr = 0; + Fts5Expr *pExpr = 0; + int rc; + int i; + + const char **azConfig; /* Array of arguments for Fts5Config */ + const char *zNearsetCmd = "nearset"; + int nConfig; /* Size of azConfig[] */ + Fts5Config *pConfig = 0; + int iArg = 1; + + if( nArg<1 ){ + zErr = sqlite3_mprintf("wrong number of arguments to function %s", + bTcl ? "fts5_expr_tcl" : "fts5_expr" + ); + sqlite3_result_error(pCtx, zErr, -1); + sqlite3_free(zErr); + return; + } + + if( bTcl && nArg>1 ){ + zNearsetCmd = (const char*)sqlite3_value_text(apVal[1]); + iArg = 2; + } + + nConfig = 3 + (nArg-iArg); + azConfig = (const char**)sqlite3_malloc(sizeof(char*) * nConfig); + if( azConfig==0 ){ + sqlite3_result_error_nomem(pCtx); + return; + } + azConfig[0] = 0; + azConfig[1] = "main"; + azConfig[2] = "tbl"; + for(i=3; iArgpRoot->xNext==0 ){ + zText = sqlite3_mprintf(""); + }else if( bTcl ){ + zText = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRoot); + }else{ + zText = fts5ExprPrint(pConfig, pExpr->pRoot); + } + if( zText==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_result_text(pCtx, zText, -1, SQLITE_TRANSIENT); + sqlite3_free(zText); + } + } + + if( rc!=SQLITE_OK ){ + if( zErr ){ + sqlite3_result_error(pCtx, zErr, -1); + sqlite3_free(zErr); + }else{ + sqlite3_result_error_code(pCtx, rc); + } + } + sqlite3_free((void *)azConfig); + sqlite3Fts5ConfigFree(pConfig); + sqlite3Fts5ExprFree(pExpr); +} + +static void fts5ExprFunctionHr( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apVal /* Function arguments */ +){ + fts5ExprFunction(pCtx, nArg, apVal, 0); +} +static void fts5ExprFunctionTcl( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apVal /* Function arguments */ +){ + fts5ExprFunction(pCtx, nArg, apVal, 1); +} + +/* +** The implementation of an SQLite user-defined-function that accepts a +** single integer as an argument. If the integer is an alpha-numeric +** unicode code point, 1 is returned. Otherwise 0. +*/ +static void fts5ExprIsAlnum( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apVal /* Function arguments */ +){ + int iCode; + if( nArg!=1 ){ + sqlite3_result_error(pCtx, + "wrong number of arguments to function fts5_isalnum", -1 + ); + return; + } + iCode = sqlite3_value_int(apVal[0]); + sqlite3_result_int(pCtx, sqlite3Fts5UnicodeIsalnum(iCode)); +} + +static void fts5ExprFold( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apVal /* Function arguments */ +){ + if( nArg!=1 && nArg!=2 ){ + sqlite3_result_error(pCtx, + "wrong number of arguments to function fts5_fold", -1 + ); + }else{ + int iCode; + int bRemoveDiacritics = 0; + iCode = sqlite3_value_int(apVal[0]); + if( nArg==2 ) bRemoveDiacritics = sqlite3_value_int(apVal[1]); + sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics)); + } +} + +/* +** This is called during initialization to register the fts5_expr() scalar +** UDF with the SQLite handle passed as the only argument. +*/ +int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){ + struct Fts5ExprFunc { + const char *z; + void (*x)(sqlite3_context*,int,sqlite3_value**); + } aFunc[] = { + { "fts5_expr", fts5ExprFunctionHr }, + { "fts5_expr_tcl", fts5ExprFunctionTcl }, + { "fts5_isalnum", fts5ExprIsAlnum }, + { "fts5_fold", fts5ExprFold }, + }; + int i; + int rc = SQLITE_OK; + void *pCtx = (void*)pGlobal; + + for(i=0; rc==SQLITE_OK && iz, -1, SQLITE_UTF8, pCtx, p->x, 0, 0); + } + + /* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */ +#ifndef NDEBUG + (void)sqlite3Fts5ParserTrace; +#endif + + return rc; +} + +/* +** Return the number of phrases in expression pExpr. +*/ +int sqlite3Fts5ExprPhraseCount(Fts5Expr *pExpr){ + return (pExpr ? pExpr->nPhrase : 0); +} + +/* +** Return the number of terms in the iPhrase'th phrase in pExpr. +*/ +int sqlite3Fts5ExprPhraseSize(Fts5Expr *pExpr, int iPhrase){ + if( iPhrase<0 || iPhrase>=pExpr->nPhrase ) return 0; + return pExpr->apExprPhrase[iPhrase]->nTerm; +} + +/* +** This function is used to access the current position list for phrase +** iPhrase. +*/ +int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){ + int nRet; + Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase]; + Fts5ExprNode *pNode = pPhrase->pNode; + if( pNode->bEof==0 && pNode->iRowid==pExpr->pRoot->iRowid ){ + *pa = pPhrase->poslist.p; + nRet = pPhrase->poslist.n; + }else{ + *pa = 0; + nRet = 0; + } + return nRet; +} + +struct Fts5PoslistPopulator { + Fts5PoslistWriter writer; + int bOk; /* True if ok to populate */ + int bMiss; +}; + +Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){ + Fts5PoslistPopulator *pRet; + pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); + if( pRet ){ + int i; + memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); + for(i=0; inPhrase; i++){ + Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist; + Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; + assert( pExpr->apExprPhrase[i]->nTerm==1 ); + if( bLive && + (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof) + ){ + pRet[i].bMiss = 1; + }else{ + pBuf->n = 0; + } + } + } + return pRet; +} + +struct Fts5ExprCtx { + Fts5Expr *pExpr; + Fts5PoslistPopulator *aPopulator; + i64 iOff; +}; +typedef struct Fts5ExprCtx Fts5ExprCtx; + +/* +** TODO: Make this more efficient! +*/ +static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){ + int i; + for(i=0; inCol; i++){ + if( pColset->aiCol[i]==iCol ) return 1; + } + return 0; +} + +static int fts5ExprPopulatePoslistsCb( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iUnused1, /* Byte offset of token within input text */ + int iUnused2 /* Byte offset of end of token within input text */ +){ + Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx; + Fts5Expr *pExpr = p->pExpr; + int i; + + UNUSED_PARAM2(iUnused1, iUnused2); + + if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++; + for(i=0; inPhrase; i++){ + Fts5ExprTerm *pTerm; + if( p->aPopulator[i].bOk==0 ) continue; + for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ + int nTerm = strlen(pTerm->zTerm); + if( (nTerm==nToken || (nTermbPrefix)) + && memcmp(pTerm->zTerm, pToken, nTerm)==0 + ){ + int rc = sqlite3Fts5PoslistWriterAppend( + &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff + ); + if( rc ) return rc; + break; + } + } + } + return SQLITE_OK; +} + +int sqlite3Fts5ExprPopulatePoslists( + Fts5Config *pConfig, + Fts5Expr *pExpr, + Fts5PoslistPopulator *aPopulator, + int iCol, + const char *z, int n +){ + int i; + Fts5ExprCtx sCtx; + sCtx.pExpr = pExpr; + sCtx.aPopulator = aPopulator; + sCtx.iOff = (((i64)iCol) << 32) - 1; + + for(i=0; inPhrase; i++){ + Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; + Fts5Colset *pColset = pNode->pNear->pColset; + if( (pColset && 0==fts5ExprColsetTest(pColset, iCol)) + || aPopulator[i].bMiss + ){ + aPopulator[i].bOk = 0; + }else{ + aPopulator[i].bOk = 1; + } + } + + return sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb + ); +} + +static void fts5ExprClearPoslists(Fts5ExprNode *pNode){ + if( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING ){ + pNode->pNear->apPhrase[0]->poslist.n = 0; + }else{ + int i; + for(i=0; inChild; i++){ + fts5ExprClearPoslists(pNode->apChild[i]); + } + } +} + +static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){ + pNode->iRowid = iRowid; + pNode->bEof = 0; + switch( pNode->eType ){ + case FTS5_TERM: + case FTS5_STRING: + return (pNode->pNear->apPhrase[0]->poslist.n>0); + + case FTS5_AND: { + int i; + for(i=0; inChild; i++){ + if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid)==0 ){ + fts5ExprClearPoslists(pNode); + return 0; + } + } + break; + } + + case FTS5_OR: { + int i; + int bRet = 0; + for(i=0; inChild; i++){ + if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid) ){ + bRet = 1; + } + } + return bRet; + } + + default: { + assert( pNode->eType==FTS5_NOT ); + if( 0==fts5ExprCheckPoslists(pNode->apChild[0], iRowid) + || 0!=fts5ExprCheckPoslists(pNode->apChild[1], iRowid) + ){ + fts5ExprClearPoslists(pNode); + return 0; + } + break; + } + } + return 1; +} + +void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){ + fts5ExprCheckPoslists(pExpr->pRoot, iRowid); +} + +static void fts5ExprClearEof(Fts5ExprNode *pNode){ + int i; + for(i=0; inChild; i++){ + fts5ExprClearEof(pNode->apChild[i]); + } + pNode->bEof = 0; +} +void sqlite3Fts5ExprClearEof(Fts5Expr *pExpr){ + fts5ExprClearEof(pExpr->pRoot); +} + +/* +** This function is only called for detail=columns tables. +*/ +int sqlite3Fts5ExprPhraseCollist( + Fts5Expr *pExpr, + int iPhrase, + const u8 **ppCollist, + int *pnCollist +){ + Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase]; + Fts5ExprNode *pNode = pPhrase->pNode; + int rc = SQLITE_OK; + + assert( iPhrase>=0 && iPhrasenPhrase ); + assert( pExpr->pConfig->eDetail==FTS5_DETAIL_COLUMNS ); + + if( pNode->bEof==0 + && pNode->iRowid==pExpr->pRoot->iRowid + && pPhrase->poslist.n>0 + ){ + Fts5ExprTerm *pTerm = &pPhrase->aTerm[0]; + if( pTerm->pSynonym ){ + Fts5Buffer *pBuf = (Fts5Buffer*)&pTerm->pSynonym[1]; + rc = fts5ExprSynonymList( + pTerm, pNode->iRowid, pBuf, (u8**)ppCollist, pnCollist + ); + }else{ + *ppCollist = pPhrase->aTerm[0].pIter->pData; + *pnCollist = pPhrase->aTerm[0].pIter->nData; + } + }else{ + *ppCollist = 0; + *pnCollist = 0; + } + + return rc; +} + diff --git a/ext/fts5/fts5_hash.c b/ext/fts5/fts5_hash.c new file mode 100644 index 0000000..ada8bb1 --- /dev/null +++ b/ext/fts5/fts5_hash.c @@ -0,0 +1,527 @@ +/* +** 2014 August 11 +** +** 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. +** +****************************************************************************** +** +*/ + + + +#include "fts5Int.h" + +typedef struct Fts5HashEntry Fts5HashEntry; + +/* +** This file contains the implementation of an in-memory hash table used +** to accumuluate "term -> doclist" content before it is flused to a level-0 +** segment. +*/ + + +struct Fts5Hash { + int eDetail; /* Copy of Fts5Config.eDetail */ + int *pnByte; /* Pointer to bytes counter */ + int nEntry; /* Number of entries currently in hash */ + int nSlot; /* Size of aSlot[] array */ + Fts5HashEntry *pScan; /* Current ordered scan item */ + Fts5HashEntry **aSlot; /* Array of hash slots */ +}; + +/* +** Each entry in the hash table is represented by an object of the +** following type. Each object, its key (zKey[]) and its current data +** are stored in a single memory allocation. The position list data +** immediately follows the key data in memory. +** +** The data that follows the key is in a similar, but not identical format +** to the doclist data stored in the database. It is: +** +** * Rowid, as a varint +** * Position list, without 0x00 terminator. +** * Size of previous position list and rowid, as a 4 byte +** big-endian integer. +** +** iRowidOff: +** Offset of last rowid written to data area. Relative to first byte of +** structure. +** +** nData: +** Bytes of data written since iRowidOff. +*/ +struct Fts5HashEntry { + Fts5HashEntry *pHashNext; /* Next hash entry with same hash-key */ + Fts5HashEntry *pScanNext; /* Next entry in sorted order */ + + int nAlloc; /* Total size of allocation */ + int iSzPoslist; /* Offset of space for 4-byte poslist size */ + int nData; /* Total bytes of data (incl. structure) */ + int nKey; /* Length of zKey[] in bytes */ + u8 bDel; /* Set delete-flag @ iSzPoslist */ + u8 bContent; /* Set content-flag (detail=none mode) */ + i16 iCol; /* Column of last value written */ + int iPos; /* Position of last value written */ + i64 iRowid; /* Rowid of last value written */ + char zKey[8]; /* Nul-terminated entry key */ +}; + +/* +** Size of Fts5HashEntry without the zKey[] array. +*/ +#define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8) + + + +/* +** Allocate a new hash table. +*/ +int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){ + int rc = SQLITE_OK; + Fts5Hash *pNew; + + *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash)); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + int nByte; + memset(pNew, 0, sizeof(Fts5Hash)); + pNew->pnByte = pnByte; + pNew->eDetail = pConfig->eDetail; + + pNew->nSlot = 1024; + nByte = sizeof(Fts5HashEntry*) * pNew->nSlot; + pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte); + if( pNew->aSlot==0 ){ + sqlite3_free(pNew); + *ppNew = 0; + rc = SQLITE_NOMEM; + }else{ + memset(pNew->aSlot, 0, nByte); + } + } + return rc; +} + +/* +** Free a hash table object. +*/ +void sqlite3Fts5HashFree(Fts5Hash *pHash){ + if( pHash ){ + sqlite3Fts5HashClear(pHash); + sqlite3_free(pHash->aSlot); + sqlite3_free(pHash); + } +} + +/* +** Empty (but do not delete) a hash table. +*/ +void sqlite3Fts5HashClear(Fts5Hash *pHash){ + int i; + for(i=0; inSlot; i++){ + Fts5HashEntry *pNext; + Fts5HashEntry *pSlot; + for(pSlot=pHash->aSlot[i]; pSlot; pSlot=pNext){ + pNext = pSlot->pHashNext; + sqlite3_free(pSlot); + } + } + memset(pHash->aSlot, 0, pHash->nSlot * sizeof(Fts5HashEntry*)); + pHash->nEntry = 0; +} + +static unsigned int fts5HashKey(int nSlot, const u8 *p, int n){ + int i; + unsigned int h = 13; + for(i=n-1; i>=0; i--){ + h = (h << 3) ^ h ^ p[i]; + } + return (h % nSlot); +} + +static unsigned int fts5HashKey2(int nSlot, u8 b, const u8 *p, int n){ + int i; + unsigned int h = 13; + for(i=n-1; i>=0; i--){ + h = (h << 3) ^ h ^ p[i]; + } + h = (h << 3) ^ h ^ b; + return (h % nSlot); +} + +/* +** Resize the hash table by doubling the number of slots. +*/ +static int fts5HashResize(Fts5Hash *pHash){ + int nNew = pHash->nSlot*2; + int i; + Fts5HashEntry **apNew; + Fts5HashEntry **apOld = pHash->aSlot; + + apNew = (Fts5HashEntry**)sqlite3_malloc(nNew*sizeof(Fts5HashEntry*)); + if( !apNew ) return SQLITE_NOMEM; + memset(apNew, 0, nNew*sizeof(Fts5HashEntry*)); + + for(i=0; inSlot; i++){ + while( apOld[i] ){ + int iHash; + Fts5HashEntry *p = apOld[i]; + apOld[i] = p->pHashNext; + iHash = fts5HashKey(nNew, (u8*)p->zKey, (int)strlen(p->zKey)); + p->pHashNext = apNew[iHash]; + apNew[iHash] = p; + } + } + + sqlite3_free(apOld); + pHash->nSlot = nNew; + pHash->aSlot = apNew; + return SQLITE_OK; +} + +static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ + if( p->iSzPoslist ){ + u8 *pPtr = (u8*)p; + if( pHash->eDetail==FTS5_DETAIL_NONE ){ + assert( p->nData==p->iSzPoslist ); + if( p->bDel ){ + pPtr[p->nData++] = 0x00; + if( p->bContent ){ + pPtr[p->nData++] = 0x00; + } + } + }else{ + int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ + int nPos = nSz*2 + p->bDel; /* Value of nPos field */ + + assert( p->bDel==0 || p->bDel==1 ); + if( nPos<=127 ){ + pPtr[p->iSzPoslist] = (u8)nPos; + }else{ + int nByte = sqlite3Fts5GetVarintLen((u32)nPos); + memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); + sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); + p->nData += (nByte-1); + } + } + + p->iSzPoslist = 0; + p->bDel = 0; + p->bContent = 0; + } +} + +/* +** Add an entry to the in-memory hash table. The key is the concatenation +** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos). +** +** (bByte || pToken) -> (iRowid,iCol,iPos) +** +** Or, if iCol is negative, then the value is a delete marker. +*/ +int sqlite3Fts5HashWrite( + Fts5Hash *pHash, + i64 iRowid, /* Rowid for this entry */ + int iCol, /* Column token appears in (-ve -> delete) */ + int iPos, /* Position of token within column */ + char bByte, /* First byte of token */ + const char *pToken, int nToken /* Token to add or remove to or from index */ +){ + unsigned int iHash; + Fts5HashEntry *p; + u8 *pPtr; + int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */ + int bNew; /* If non-delete entry should be written */ + + bNew = (pHash->eDetail==FTS5_DETAIL_FULL); + + /* Attempt to locate an existing hash entry */ + iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); + for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ + if( p->zKey[0]==bByte + && p->nKey==nToken + && memcmp(&p->zKey[1], pToken, nToken)==0 + ){ + break; + } + } + + /* If an existing hash entry cannot be found, create a new one. */ + if( p==0 ){ + /* Figure out how much space to allocate */ + int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64; + if( nByte<128 ) nByte = 128; + + /* Grow the Fts5Hash.aSlot[] array if necessary. */ + if( (pHash->nEntry*2)>=pHash->nSlot ){ + int rc = fts5HashResize(pHash); + if( rc!=SQLITE_OK ) return rc; + iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); + } + + /* Allocate new Fts5HashEntry and add it to the hash table. */ + p = (Fts5HashEntry*)sqlite3_malloc(nByte); + if( !p ) return SQLITE_NOMEM; + memset(p, 0, FTS5_HASHENTRYSIZE); + p->nAlloc = nByte; + p->zKey[0] = bByte; + memcpy(&p->zKey[1], pToken, nToken); + assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) ); + p->nKey = nToken; + p->zKey[nToken+1] = '\0'; + p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE; + p->pHashNext = pHash->aSlot[iHash]; + pHash->aSlot[iHash] = p; + pHash->nEntry++; + + /* Add the first rowid field to the hash-entry */ + p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid); + p->iRowid = iRowid; + + p->iSzPoslist = p->nData; + if( pHash->eDetail!=FTS5_DETAIL_NONE ){ + p->nData += 1; + p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); + } + + nIncr += p->nData; + }else{ + + /* Appending to an existing hash-entry. Check that there is enough + ** space to append the largest possible new entry. Worst case scenario + ** is: + ** + ** + 9 bytes for a new rowid, + ** + 4 byte reserved for the "poslist size" varint. + ** + 1 byte for a "new column" byte, + ** + 3 bytes for a new column number (16-bit max) as a varint, + ** + 5 bytes for the new position offset (32-bit max). + */ + if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ + int nNew = p->nAlloc * 2; + Fts5HashEntry *pNew; + Fts5HashEntry **pp; + pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); + if( pNew==0 ) return SQLITE_NOMEM; + pNew->nAlloc = nNew; + for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); + *pp = pNew; + p = pNew; + } + nIncr -= p->nData; + } + assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) ); + + pPtr = (u8*)p; + + /* If this is a new rowid, append the 4-byte size field for the previous + ** entry, and the new rowid for this entry. */ + if( iRowid!=p->iRowid ){ + fts5HashAddPoslistSize(pHash, p); + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); + p->iRowid = iRowid; + bNew = 1; + p->iSzPoslist = p->nData; + if( pHash->eDetail!=FTS5_DETAIL_NONE ){ + p->nData += 1; + p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); + p->iPos = 0; + } + } + + if( iCol>=0 ){ + if( pHash->eDetail==FTS5_DETAIL_NONE ){ + p->bContent = 1; + }else{ + /* Append a new column value, if necessary */ + assert( iCol>=p->iCol ); + if( iCol!=p->iCol ){ + if( pHash->eDetail==FTS5_DETAIL_FULL ){ + pPtr[p->nData++] = 0x01; + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol); + p->iCol = iCol; + p->iPos = 0; + }else{ + bNew = 1; + p->iCol = iPos = iCol; + } + } + + /* Append the new position offset, if necessary */ + if( bNew ){ + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2); + p->iPos = iPos; + } + } + }else{ + /* This is a delete. Set the delete flag. */ + p->bDel = 1; + } + + nIncr += p->nData; + *pHash->pnByte += nIncr; + return SQLITE_OK; +} + + +/* +** Arguments pLeft and pRight point to linked-lists of hash-entry objects, +** each sorted in key order. This function merges the two lists into a +** single list and returns a pointer to its first element. +*/ +static Fts5HashEntry *fts5HashEntryMerge( + Fts5HashEntry *pLeft, + Fts5HashEntry *pRight +){ + Fts5HashEntry *p1 = pLeft; + Fts5HashEntry *p2 = pRight; + Fts5HashEntry *pRet = 0; + Fts5HashEntry **ppOut = &pRet; + + while( p1 || p2 ){ + if( p1==0 ){ + *ppOut = p2; + p2 = 0; + }else if( p2==0 ){ + *ppOut = p1; + p1 = 0; + }else{ + int i = 0; + while( p1->zKey[i]==p2->zKey[i] ) i++; + + if( ((u8)p1->zKey[i])>((u8)p2->zKey[i]) ){ + /* p2 is smaller */ + *ppOut = p2; + ppOut = &p2->pScanNext; + p2 = p2->pScanNext; + }else{ + /* p1 is smaller */ + *ppOut = p1; + ppOut = &p1->pScanNext; + p1 = p1->pScanNext; + } + *ppOut = 0; + } + } + + return pRet; +} + +/* +** Extract all tokens from hash table iHash and link them into a list +** in sorted order. The hash table is cleared before returning. It is +** the responsibility of the caller to free the elements of the returned +** list. +*/ +static int fts5HashEntrySort( + Fts5Hash *pHash, + const char *pTerm, int nTerm, /* Query prefix, if any */ + Fts5HashEntry **ppSorted +){ + const int nMergeSlot = 32; + Fts5HashEntry **ap; + Fts5HashEntry *pList; + int iSlot; + int i; + + *ppSorted = 0; + ap = sqlite3_malloc(sizeof(Fts5HashEntry*) * nMergeSlot); + if( !ap ) return SQLITE_NOMEM; + memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot); + + for(iSlot=0; iSlotnSlot; iSlot++){ + Fts5HashEntry *pIter; + for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){ + if( pTerm==0 || 0==memcmp(pIter->zKey, pTerm, nTerm) ){ + Fts5HashEntry *pEntry = pIter; + pEntry->pScanNext = 0; + for(i=0; ap[i]; i++){ + pEntry = fts5HashEntryMerge(pEntry, ap[i]); + ap[i] = 0; + } + ap[i] = pEntry; + } + } + } + + pList = 0; + for(i=0; inEntry = 0; + sqlite3_free(ap); + *ppSorted = pList; + return SQLITE_OK; +} + +/* +** Query the hash table for a doclist associated with term pTerm/nTerm. +*/ +int sqlite3Fts5HashQuery( + Fts5Hash *pHash, /* Hash table to query */ + const char *pTerm, int nTerm, /* Query term */ + const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */ + int *pnDoclist /* OUT: Size of doclist in bytes */ +){ + unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm); + Fts5HashEntry *p; + + for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ + if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break; + } + + if( p ){ + fts5HashAddPoslistSize(pHash, p); + *ppDoclist = (const u8*)&p->zKey[nTerm+1]; + *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); + }else{ + *ppDoclist = 0; + *pnDoclist = 0; + } + + return SQLITE_OK; +} + +int sqlite3Fts5HashScanInit( + Fts5Hash *p, /* Hash table to query */ + const char *pTerm, int nTerm /* Query prefix */ +){ + return fts5HashEntrySort(p, pTerm, nTerm, &p->pScan); +} + +void sqlite3Fts5HashScanNext(Fts5Hash *p){ + assert( !sqlite3Fts5HashScanEof(p) ); + p->pScan = p->pScan->pScanNext; +} + +int sqlite3Fts5HashScanEof(Fts5Hash *p){ + return (p->pScan==0); +} + +void sqlite3Fts5HashScanEntry( + Fts5Hash *pHash, + const char **pzTerm, /* OUT: term (nul-terminated) */ + const u8 **ppDoclist, /* OUT: pointer to doclist */ + int *pnDoclist /* OUT: size of doclist in bytes */ +){ + Fts5HashEntry *p; + if( (p = pHash->pScan) ){ + int nTerm = (int)strlen(p->zKey); + fts5HashAddPoslistSize(pHash, p); + *pzTerm = p->zKey; + *ppDoclist = (const u8*)&p->zKey[nTerm+1]; + *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); + }else{ + *pzTerm = 0; + *ppDoclist = 0; + *pnDoclist = 0; + } +} + diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c new file mode 100644 index 0000000..c40ffbc --- /dev/null +++ b/ext/fts5/fts5_index.c @@ -0,0 +1,6281 @@ +/* +** 2014 May 31 +** +** 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. +** +****************************************************************************** +** +** Low level access to the FTS index stored in the database file. The +** routines in this file file implement all read and write access to the +** %_data table. Other parts of the system access this functionality via +** the interface defined in fts5Int.h. +*/ + + +#include "fts5Int.h" + +/* +** Overview: +** +** The %_data table contains all the FTS indexes for an FTS5 virtual table. +** As well as the main term index, there may be up to 31 prefix indexes. +** The format is similar to FTS3/4, except that: +** +** * all segment b-tree leaf data is stored in fixed size page records +** (e.g. 1000 bytes). A single doclist may span multiple pages. Care is +** taken to ensure it is possible to iterate in either direction through +** the entries in a doclist, or to seek to a specific entry within a +** doclist, without loading it into memory. +** +** * large doclists that span many pages have associated "doclist index" +** records that contain a copy of the first rowid on each page spanned by +** the doclist. This is used to speed up seek operations, and merges of +** large doclists with very small doclists. +** +** * extra fields in the "structure record" record the state of ongoing +** incremental merge operations. +** +*/ + + +#define FTS5_OPT_WORK_UNIT 1000 /* Number of leaf pages per optimize step */ +#define FTS5_WORK_UNIT 64 /* Number of leaf pages in unit of work */ + +#define FTS5_MIN_DLIDX_SIZE 4 /* Add dlidx if this many empty pages */ + +#define FTS5_MAIN_PREFIX '0' + +#if FTS5_MAX_PREFIX_INDEXES > 31 +# error "FTS5_MAX_PREFIX_INDEXES is too large" +#endif + +/* +** Details: +** +** The %_data table managed by this module, +** +** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB); +** +** , contains the following 5 types of records. See the comments surrounding +** the FTS5_*_ROWID macros below for a description of how %_data rowids are +** assigned to each fo them. +** +** 1. Structure Records: +** +** The set of segments that make up an index - the index structure - are +** recorded in a single record within the %_data table. The record consists +** of a single 32-bit configuration cookie value followed by a list of +** SQLite varints. If the FTS table features more than one index (because +** there are one or more prefix indexes), it is guaranteed that all share +** the same cookie value. +** +** Immediately following the configuration cookie, the record begins with +** three varints: +** +** + number of levels, +** + total number of segments on all levels, +** + value of write counter. +** +** Then, for each level from 0 to nMax: +** +** + number of input segments in ongoing merge. +** + total number of segments in level. +** + for each segment from oldest to newest: +** + segment id (always > 0) +** + first leaf page number (often 1, always greater than 0) +** + final leaf page number +** +** 2. The Averages Record: +** +** A single record within the %_data table. The data is a list of varints. +** The first value is the number of rows in the index. Then, for each column +** from left to right, the total number of tokens in the column for all +** rows of the table. +** +** 3. Segment leaves: +** +** TERM/DOCLIST FORMAT: +** +** Most of each segment leaf is taken up by term/doclist data. The +** general format of term/doclist, starting with the first term +** on the leaf page, is: +** +** varint : size of first term +** blob: first term data +** doclist: first doclist +** zero-or-more { +** varint: number of bytes in common with previous term +** varint: number of bytes of new term data (nNew) +** blob: nNew bytes of new term data +** doclist: next doclist +** } +** +** doclist format: +** +** varint: first rowid +** poslist: first poslist +** zero-or-more { +** varint: rowid delta (always > 0) +** poslist: next poslist +** } +** +** poslist format: +** +** varint: size of poslist in bytes multiplied by 2, not including +** this field. Plus 1 if this entry carries the "delete" flag. +** collist: collist for column 0 +** zero-or-more { +** 0x01 byte +** varint: column number (I) +** collist: collist for column I +** } +** +** collist format: +** +** varint: first offset + 2 +** zero-or-more { +** varint: offset delta + 2 +** } +** +** PAGE FORMAT +** +** Each leaf page begins with a 4-byte header containing 2 16-bit +** unsigned integer fields in big-endian format. They are: +** +** * The byte offset of the first rowid on the page, if it exists +** and occurs before the first term (otherwise 0). +** +** * The byte offset of the start of the page footer. If the page +** footer is 0 bytes in size, then this field is the same as the +** size of the leaf page in bytes. +** +** The page footer consists of a single varint for each term located +** on the page. Each varint is the byte offset of the current term +** within the page, delta-compressed against the previous value. In +** other words, the first varint in the footer is the byte offset of +** the first term, the second is the byte offset of the second less that +** of the first, and so on. +** +** The term/doclist format described above is accurate if the entire +** term/doclist data fits on a single leaf page. If this is not the case, +** the format is changed in two ways: +** +** + if the first rowid on a page occurs before the first term, it +** is stored as a literal value: +** +** varint: first rowid +** +** + the first term on each page is stored in the same way as the +** very first term of the segment: +** +** varint : size of first term +** blob: first term data +** +** 5. Segment doclist indexes: +** +** Doclist indexes are themselves b-trees, however they usually consist of +** a single leaf record only. The format of each doclist index leaf page +** is: +** +** * Flags byte. Bits are: +** 0x01: Clear if leaf is also the root page, otherwise set. +** +** * Page number of fts index leaf page. As a varint. +** +** * First rowid on page indicated by previous field. As a varint. +** +** * A list of varints, one for each subsequent termless page. A +** positive delta if the termless page contains at least one rowid, +** or an 0x00 byte otherwise. +** +** Internal doclist index nodes are: +** +** * Flags byte. Bits are: +** 0x01: Clear for root page, otherwise set. +** +** * Page number of first child page. As a varint. +** +** * Copy of first rowid on page indicated by previous field. As a varint. +** +** * A list of delta-encoded varints - the first rowid on each subsequent +** child page. +** +*/ + +/* +** Rowids for the averages and structure records in the %_data table. +*/ +#define FTS5_AVERAGES_ROWID 1 /* Rowid used for the averages record */ +#define FTS5_STRUCTURE_ROWID 10 /* The structure record */ + +/* +** Macros determining the rowids used by segment leaves and dlidx leaves +** and nodes. All nodes and leaves are stored in the %_data table with large +** positive rowids. +** +** Each segment has a unique non-zero 16-bit id. +** +** The rowid for each segment leaf is found by passing the segment id and +** the leaf page number to the FTS5_SEGMENT_ROWID macro. Leaves are numbered +** sequentially starting from 1. +*/ +#define FTS5_DATA_ID_B 16 /* Max seg id number 65535 */ +#define FTS5_DATA_DLI_B 1 /* Doclist-index flag (1 bit) */ +#define FTS5_DATA_HEIGHT_B 5 /* Max dlidx tree height of 32 */ +#define FTS5_DATA_PAGE_B 31 /* Max page number of 2147483648 */ + +#define fts5_dri(segid, dlidx, height, pgno) ( \ + ((i64)(segid) << (FTS5_DATA_PAGE_B+FTS5_DATA_HEIGHT_B+FTS5_DATA_DLI_B)) + \ + ((i64)(dlidx) << (FTS5_DATA_PAGE_B + FTS5_DATA_HEIGHT_B)) + \ + ((i64)(height) << (FTS5_DATA_PAGE_B)) + \ + ((i64)(pgno)) \ +) + +#define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno) +#define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno) + +/* +** Maximum segments permitted in a single index +*/ +#define FTS5_MAX_SEGMENT 2000 + +#ifdef SQLITE_DEBUG +int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; } +#endif + + +/* +** Each time a blob is read from the %_data table, it is padded with this +** many zero bytes. This makes it easier to decode the various record formats +** without overreading if the records are corrupt. +*/ +#define FTS5_DATA_ZERO_PADDING 8 +#define FTS5_DATA_PADDING 20 + +typedef struct Fts5Data Fts5Data; +typedef struct Fts5DlidxIter Fts5DlidxIter; +typedef struct Fts5DlidxLvl Fts5DlidxLvl; +typedef struct Fts5DlidxWriter Fts5DlidxWriter; +typedef struct Fts5Iter Fts5Iter; +typedef struct Fts5PageWriter Fts5PageWriter; +typedef struct Fts5SegIter Fts5SegIter; +typedef struct Fts5DoclistIter Fts5DoclistIter; +typedef struct Fts5SegWriter Fts5SegWriter; +typedef struct Fts5Structure Fts5Structure; +typedef struct Fts5StructureLevel Fts5StructureLevel; +typedef struct Fts5StructureSegment Fts5StructureSegment; + +struct Fts5Data { + u8 *p; /* Pointer to buffer containing record */ + int nn; /* Size of record in bytes */ + int szLeaf; /* Size of leaf without page-index */ +}; + +/* +** One object per %_data table. +*/ +struct Fts5Index { + Fts5Config *pConfig; /* Virtual table configuration */ + char *zDataTbl; /* Name of %_data table */ + int nWorkUnit; /* Leaf pages in a "unit" of work */ + + /* + ** Variables related to the accumulation of tokens and doclists within the + ** in-memory hash tables before they are flushed to disk. + */ + Fts5Hash *pHash; /* Hash table for in-memory data */ + int nPendingData; /* Current bytes of pending data */ + i64 iWriteRowid; /* Rowid for current doc being written */ + int bDelete; /* Current write is a delete */ + + /* Error state. */ + int rc; /* Current error code */ + + /* State used by the fts5DataXXX() functions. */ + sqlite3_blob *pReader; /* RO incr-blob open on %_data table */ + sqlite3_stmt *pWriter; /* "INSERT ... %_data VALUES(?,?)" */ + sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */ + sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */ + sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=? */ + sqlite3_stmt *pIdxSelect; + int nRead; /* Total number of blocks read */ +}; + +struct Fts5DoclistIter { + u8 *aEof; /* Pointer to 1 byte past end of doclist */ + + /* Output variables. aPoslist==0 at EOF */ + i64 iRowid; + u8 *aPoslist; + int nPoslist; + int nSize; +}; + +/* +** The contents of the "structure" record for each index are represented +** using an Fts5Structure record in memory. Which uses instances of the +** other Fts5StructureXXX types as components. +*/ +struct Fts5StructureSegment { + int iSegid; /* Segment id */ + int pgnoFirst; /* First leaf page number in segment */ + int pgnoLast; /* Last leaf page number in segment */ +}; +struct Fts5StructureLevel { + int nMerge; /* Number of segments in incr-merge */ + int nSeg; /* Total number of segments on level */ + Fts5StructureSegment *aSeg; /* Array of segments. aSeg[0] is oldest. */ +}; +struct Fts5Structure { + int nRef; /* Object reference count */ + u64 nWriteCounter; /* Total leaves written to level 0 */ + int nSegment; /* Total segments in this structure */ + int nLevel; /* Number of levels in this index */ + Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */ +}; + +/* +** An object of type Fts5SegWriter is used to write to segments. +*/ +struct Fts5PageWriter { + int pgno; /* Page number for this page */ + int iPrevPgidx; /* Previous value written into pgidx */ + Fts5Buffer buf; /* Buffer containing leaf data */ + Fts5Buffer pgidx; /* Buffer containing page-index */ + Fts5Buffer term; /* Buffer containing previous term on page */ +}; +struct Fts5DlidxWriter { + int pgno; /* Page number for this page */ + int bPrevValid; /* True if iPrev is valid */ + i64 iPrev; /* Previous rowid value written to page */ + Fts5Buffer buf; /* Buffer containing page data */ +}; +struct Fts5SegWriter { + int iSegid; /* Segid to write to */ + Fts5PageWriter writer; /* PageWriter object */ + i64 iPrevRowid; /* Previous rowid written to current leaf */ + u8 bFirstRowidInDoclist; /* True if next rowid is first in doclist */ + u8 bFirstRowidInPage; /* True if next rowid is first in page */ + /* TODO1: Can use (writer.pgidx.n==0) instead of bFirstTermInPage */ + u8 bFirstTermInPage; /* True if next term will be first in leaf */ + int nLeafWritten; /* Number of leaf pages written */ + int nEmpty; /* Number of contiguous term-less nodes */ + + int nDlidx; /* Allocated size of aDlidx[] array */ + Fts5DlidxWriter *aDlidx; /* Array of Fts5DlidxWriter objects */ + + /* Values to insert into the %_idx table */ + Fts5Buffer btterm; /* Next term to insert into %_idx table */ + int iBtPage; /* Page number corresponding to btterm */ +}; + +typedef struct Fts5CResult Fts5CResult; +struct Fts5CResult { + u16 iFirst; /* aSeg[] index of firstest iterator */ + u8 bTermEq; /* True if the terms are equal */ +}; + +/* +** Object for iterating through a single segment, visiting each term/rowid +** pair in the segment. +** +** pSeg: +** The segment to iterate through. +** +** iLeafPgno: +** Current leaf page number within segment. +** +** iLeafOffset: +** Byte offset within the current leaf that is the first byte of the +** position list data (one byte passed the position-list size field). +** rowid field of the current entry. Usually this is the size field of the +** position list data. The exception is if the rowid for the current entry +** is the last thing on the leaf page. +** +** pLeaf: +** Buffer containing current leaf page data. Set to NULL at EOF. +** +** iTermLeafPgno, iTermLeafOffset: +** Leaf page number containing the last term read from the segment. And +** the offset immediately following the term data. +** +** flags: +** Mask of FTS5_SEGITER_XXX values. Interpreted as follows: +** +** FTS5_SEGITER_ONETERM: +** If set, set the iterator to point to EOF after the current doclist +** has been exhausted. Do not proceed to the next term in the segment. +** +** FTS5_SEGITER_REVERSE: +** This flag is only ever set if FTS5_SEGITER_ONETERM is also set. If +** it is set, iterate through rowid in descending order instead of the +** default ascending order. +** +** iRowidOffset/nRowidOffset/aRowidOffset: +** These are used if the FTS5_SEGITER_REVERSE flag is set. +** +** For each rowid on the page corresponding to the current term, the +** corresponding aRowidOffset[] entry is set to the byte offset of the +** start of the "position-list-size" field within the page. +** +** iTermIdx: +** Index of current term on iTermLeafPgno. +*/ +struct Fts5SegIter { + Fts5StructureSegment *pSeg; /* Segment to iterate through */ + int flags; /* Mask of configuration flags */ + int iLeafPgno; /* Current leaf page number */ + Fts5Data *pLeaf; /* Current leaf data */ + Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */ + int iLeafOffset; /* Byte offset within current leaf */ + + /* Next method */ + void (*xNext)(Fts5Index*, Fts5SegIter*, int*); + + /* The page and offset from which the current term was read. The offset + ** is the offset of the first rowid in the current doclist. */ + int iTermLeafPgno; + int iTermLeafOffset; + + int iPgidxOff; /* Next offset in pgidx */ + int iEndofDoclist; + + /* The following are only used if the FTS5_SEGITER_REVERSE flag is set. */ + int iRowidOffset; /* Current entry in aRowidOffset[] */ + int nRowidOffset; /* Allocated size of aRowidOffset[] array */ + int *aRowidOffset; /* Array of offset to rowid fields */ + + Fts5DlidxIter *pDlidx; /* If there is a doclist-index */ + + /* Variables populated based on current entry. */ + Fts5Buffer term; /* Current term */ + i64 iRowid; /* Current rowid */ + int nPos; /* Number of bytes in current position list */ + u8 bDel; /* True if the delete flag is set */ +}; + +/* +** Argument is a pointer to an Fts5Data structure that contains a +** leaf page. +*/ +#define ASSERT_SZLEAF_OK(x) assert( \ + (x)->szLeaf==(x)->nn || (x)->szLeaf==fts5GetU16(&(x)->p[2]) \ +) + +#define FTS5_SEGITER_ONETERM 0x01 +#define FTS5_SEGITER_REVERSE 0x02 + +/* +** Argument is a pointer to an Fts5Data structure that contains a leaf +** page. This macro evaluates to true if the leaf contains no terms, or +** false if it contains at least one term. +*/ +#define fts5LeafIsTermless(x) ((x)->szLeaf >= (x)->nn) + +#define fts5LeafTermOff(x, i) (fts5GetU16(&(x)->p[(x)->szLeaf + (i)*2])) + +#define fts5LeafFirstRowidOff(x) (fts5GetU16((x)->p)) + +/* +** Object for iterating through the merged results of one or more segments, +** visiting each term/rowid pair in the merged data. +** +** nSeg is always a power of two greater than or equal to the number of +** segments that this object is merging data from. Both the aSeg[] and +** aFirst[] arrays are sized at nSeg entries. The aSeg[] array is padded +** with zeroed objects - these are handled as if they were iterators opened +** on empty segments. +** +** The results of comparing segments aSeg[N] and aSeg[N+1], where N is an +** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the +** comparison in this context is the index of the iterator that currently +** points to the smaller term/rowid combination. Iterators at EOF are +** considered to be greater than all other iterators. +** +** aFirst[1] contains the index in aSeg[] of the iterator that points to +** the smallest key overall. aFirst[0] is unused. +** +** poslist: +** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered. +** There is no way to tell if this is populated or not. +*/ +struct Fts5Iter { + Fts5IndexIter base; /* Base class containing output vars */ + + Fts5Index *pIndex; /* Index that owns this iterator */ + Fts5Structure *pStruct; /* Database structure for this iterator */ + Fts5Buffer poslist; /* Buffer containing current poslist */ + Fts5Colset *pColset; /* Restrict matches to these columns */ + + /* Invoked to set output variables. */ + void (*xSetOutputs)(Fts5Iter*, Fts5SegIter*); + + int nSeg; /* Size of aSeg[] array */ + int bRev; /* True to iterate in reverse order */ + u8 bSkipEmpty; /* True to skip deleted entries */ + + i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */ + Fts5CResult *aFirst; /* Current merge state (see above) */ + Fts5SegIter aSeg[1]; /* Array of segment iterators */ +}; + + +/* +** An instance of the following type is used to iterate through the contents +** of a doclist-index record. +** +** pData: +** Record containing the doclist-index data. +** +** bEof: +** Set to true once iterator has reached EOF. +** +** iOff: +** Set to the current offset within record pData. +*/ +struct Fts5DlidxLvl { + Fts5Data *pData; /* Data for current page of this level */ + int iOff; /* Current offset into pData */ + int bEof; /* At EOF already */ + int iFirstOff; /* Used by reverse iterators */ + + /* Output variables */ + int iLeafPgno; /* Page number of current leaf page */ + i64 iRowid; /* First rowid on leaf iLeafPgno */ +}; +struct Fts5DlidxIter { + int nLvl; + int iSegid; + Fts5DlidxLvl aLvl[1]; +}; + +static void fts5PutU16(u8 *aOut, u16 iVal){ + aOut[0] = (iVal>>8); + aOut[1] = (iVal&0xFF); +} + +static u16 fts5GetU16(const u8 *aIn){ + return ((u16)aIn[0] << 8) + aIn[1]; +} + +/* +** Allocate and return a buffer at least nByte bytes in size. +** +** If an OOM error is encountered, return NULL and set the error code in +** the Fts5Index handle passed as the first argument. +*/ +static void *fts5IdxMalloc(Fts5Index *p, int nByte){ + return sqlite3Fts5MallocZero(&p->rc, nByte); +} + +/* +** Compare the contents of the pLeft buffer with the pRight/nRight blob. +** +** Return -ve if pLeft is smaller than pRight, 0 if they are equal or +** +ve if pRight is smaller than pLeft. In other words: +** +** res = *pLeft - *pRight +*/ +#ifdef SQLITE_DEBUG +static int fts5BufferCompareBlob( + Fts5Buffer *pLeft, /* Left hand side of comparison */ + const u8 *pRight, int nRight /* Right hand side of comparison */ +){ + int nCmp = MIN(pLeft->n, nRight); + int res = memcmp(pLeft->p, pRight, nCmp); + return (res==0 ? (pLeft->n - nRight) : res); +} +#endif + +/* +** Compare the contents of the two buffers using memcmp(). If one buffer +** is a prefix of the other, it is considered the lesser. +** +** Return -ve if pLeft is smaller than pRight, 0 if they are equal or +** +ve if pRight is smaller than pLeft. In other words: +** +** res = *pLeft - *pRight +*/ +static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){ + int nCmp = MIN(pLeft->n, pRight->n); + int res = memcmp(pLeft->p, pRight->p, nCmp); + return (res==0 ? (pLeft->n - pRight->n) : res); +} + +static int fts5LeafFirstTermOff(Fts5Data *pLeaf){ + int ret; + fts5GetVarint32(&pLeaf->p[pLeaf->szLeaf], ret); + return ret; +} + +/* +** Close the read-only blob handle, if it is open. +*/ +static void fts5CloseReader(Fts5Index *p){ + if( p->pReader ){ + sqlite3_blob *pReader = p->pReader; + p->pReader = 0; + sqlite3_blob_close(pReader); + } +} + + +/* +** Retrieve a record from the %_data table. +** +** If an error occurs, NULL is returned and an error left in the +** Fts5Index object. +*/ +static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ + Fts5Data *pRet = 0; + if( p->rc==SQLITE_OK ){ + int rc = SQLITE_OK; + + if( p->pReader ){ + /* This call may return SQLITE_ABORT if there has been a savepoint + ** rollback since it was last used. In this case a new blob handle + ** is required. */ + sqlite3_blob *pBlob = p->pReader; + p->pReader = 0; + rc = sqlite3_blob_reopen(pBlob, iRowid); + assert( p->pReader==0 ); + p->pReader = pBlob; + if( rc!=SQLITE_OK ){ + fts5CloseReader(p); + } + if( rc==SQLITE_ABORT ) rc = SQLITE_OK; + } + + /* If the blob handle is not open at this point, open it and seek + ** to the requested entry. */ + if( p->pReader==0 && rc==SQLITE_OK ){ + Fts5Config *pConfig = p->pConfig; + rc = sqlite3_blob_open(pConfig->db, + pConfig->zDb, p->zDataTbl, "block", iRowid, 0, &p->pReader + ); + } + + /* If either of the sqlite3_blob_open() or sqlite3_blob_reopen() calls + ** above returned SQLITE_ERROR, return SQLITE_CORRUPT_VTAB instead. + ** All the reasons those functions might return SQLITE_ERROR - missing + ** table, missing row, non-blob/text in block column - indicate + ** backing store corruption. */ + if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT; + + if( rc==SQLITE_OK ){ + u8 *aOut = 0; /* Read blob data into this buffer */ + int nByte = sqlite3_blob_bytes(p->pReader); + int nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING; + pRet = (Fts5Data*)sqlite3_malloc(nAlloc); + if( pRet ){ + pRet->nn = nByte; + aOut = pRet->p = (u8*)&pRet[1]; + }else{ + rc = SQLITE_NOMEM; + } + + if( rc==SQLITE_OK ){ + rc = sqlite3_blob_read(p->pReader, aOut, nByte, 0); + } + if( rc!=SQLITE_OK ){ + sqlite3_free(pRet); + pRet = 0; + }else{ + /* TODO1: Fix this */ + pRet->szLeaf = fts5GetU16(&pRet->p[2]); + } + } + p->rc = rc; + p->nRead++; + } + + assert( (pRet==0)==(p->rc!=SQLITE_OK) ); + return pRet; +} + +/* +** Release a reference to data record returned by an earlier call to +** fts5DataRead(). +*/ +static void fts5DataRelease(Fts5Data *pData){ + sqlite3_free(pData); +} + +static int fts5IndexPrepareStmt( + Fts5Index *p, + sqlite3_stmt **ppStmt, + char *zSql +){ + if( p->rc==SQLITE_OK ){ + if( zSql ){ + p->rc = sqlite3_prepare_v2(p->pConfig->db, zSql, -1, ppStmt, 0); + }else{ + p->rc = SQLITE_NOMEM; + } + } + sqlite3_free(zSql); + return p->rc; +} + + +/* +** INSERT OR REPLACE a record into the %_data table. +*/ +static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){ + if( p->rc!=SQLITE_OK ) return; + + if( p->pWriter==0 ){ + Fts5Config *pConfig = p->pConfig; + fts5IndexPrepareStmt(p, &p->pWriter, sqlite3_mprintf( + "REPLACE INTO '%q'.'%q_data'(id, block) VALUES(?,?)", + pConfig->zDb, pConfig->zName + )); + if( p->rc ) return; + } + + sqlite3_bind_int64(p->pWriter, 1, iRowid); + sqlite3_bind_blob(p->pWriter, 2, pData, nData, SQLITE_STATIC); + sqlite3_step(p->pWriter); + p->rc = sqlite3_reset(p->pWriter); +} + +/* +** Execute the following SQL: +** +** DELETE FROM %_data WHERE id BETWEEN $iFirst AND $iLast +*/ +static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){ + if( p->rc!=SQLITE_OK ) return; + + if( p->pDeleter==0 ){ + int rc; + Fts5Config *pConfig = p->pConfig; + char *zSql = sqlite3_mprintf( + "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?", + pConfig->zDb, pConfig->zName + ); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p->pDeleter, 0); + sqlite3_free(zSql); + } + if( rc!=SQLITE_OK ){ + p->rc = rc; + return; + } + } + + sqlite3_bind_int64(p->pDeleter, 1, iFirst); + sqlite3_bind_int64(p->pDeleter, 2, iLast); + sqlite3_step(p->pDeleter); + p->rc = sqlite3_reset(p->pDeleter); +} + +/* +** Remove all records associated with segment iSegid. +*/ +static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){ + i64 iFirst = FTS5_SEGMENT_ROWID(iSegid, 0); + i64 iLast = FTS5_SEGMENT_ROWID(iSegid+1, 0)-1; + fts5DataDelete(p, iFirst, iLast); + if( p->pIdxDeleter==0 ){ + Fts5Config *pConfig = p->pConfig; + fts5IndexPrepareStmt(p, &p->pIdxDeleter, sqlite3_mprintf( + "DELETE FROM '%q'.'%q_idx' WHERE segid=?", + pConfig->zDb, pConfig->zName + )); + } + if( p->rc==SQLITE_OK ){ + sqlite3_bind_int(p->pIdxDeleter, 1, iSegid); + sqlite3_step(p->pIdxDeleter); + p->rc = sqlite3_reset(p->pIdxDeleter); + } +} + +/* +** Release a reference to an Fts5Structure object returned by an earlier +** call to fts5StructureRead() or fts5StructureDecode(). +*/ +static void fts5StructureRelease(Fts5Structure *pStruct){ + if( pStruct && 0>=(--pStruct->nRef) ){ + int i; + assert( pStruct->nRef==0 ); + for(i=0; inLevel; i++){ + sqlite3_free(pStruct->aLevel[i].aSeg); + } + sqlite3_free(pStruct); + } +} + +static void fts5StructureRef(Fts5Structure *pStruct){ + pStruct->nRef++; +} + +/* +** Deserialize and return the structure record currently stored in serialized +** form within buffer pData/nData. +** +** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array +** are over-allocated by one slot. This allows the structure contents +** to be more easily edited. +** +** If an error occurs, *ppOut is set to NULL and an SQLite error code +** returned. Otherwise, *ppOut is set to point to the new object and +** SQLITE_OK returned. +*/ +static int fts5StructureDecode( + const u8 *pData, /* Buffer containing serialized structure */ + int nData, /* Size of buffer pData in bytes */ + int *piCookie, /* Configuration cookie value */ + Fts5Structure **ppOut /* OUT: Deserialized object */ +){ + int rc = SQLITE_OK; + int i = 0; + int iLvl; + int nLevel = 0; + int nSegment = 0; + int nByte; /* Bytes of space to allocate at pRet */ + Fts5Structure *pRet = 0; /* Structure object to return */ + + /* Grab the cookie value */ + if( piCookie ) *piCookie = sqlite3Fts5Get32(pData); + i = 4; + + /* Read the total number of levels and segments from the start of the + ** structure record. */ + i += fts5GetVarint32(&pData[i], nLevel); + i += fts5GetVarint32(&pData[i], nSegment); + nByte = ( + sizeof(Fts5Structure) + /* Main structure */ + sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */ + ); + pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte); + + if( pRet ){ + pRet->nRef = 1; + pRet->nLevel = nLevel; + pRet->nSegment = nSegment; + i += sqlite3Fts5GetVarint(&pData[i], &pRet->nWriteCounter); + + for(iLvl=0; rc==SQLITE_OK && iLvlaLevel[iLvl]; + int nTotal; + int iSeg; + + if( i>=nData ){ + rc = FTS5_CORRUPT; + }else{ + i += fts5GetVarint32(&pData[i], pLvl->nMerge); + i += fts5GetVarint32(&pData[i], nTotal); + assert( nTotal>=pLvl->nMerge ); + pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, + nTotal * sizeof(Fts5StructureSegment) + ); + } + + if( rc==SQLITE_OK ){ + pLvl->nSeg = nTotal; + for(iSeg=0; iSeg=nData ){ + rc = FTS5_CORRUPT; + break; + } + i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid); + i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst); + i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast); + } + } + } + if( rc!=SQLITE_OK ){ + fts5StructureRelease(pRet); + pRet = 0; + } + } + + *ppOut = pRet; + return rc; +} + +/* +** +*/ +static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){ + if( *pRc==SQLITE_OK ){ + Fts5Structure *pStruct = *ppStruct; + int nLevel = pStruct->nLevel; + int nByte = ( + sizeof(Fts5Structure) + /* Main structure */ + sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */ + ); + + pStruct = sqlite3_realloc(pStruct, nByte); + if( pStruct ){ + memset(&pStruct->aLevel[nLevel], 0, sizeof(Fts5StructureLevel)); + pStruct->nLevel++; + *ppStruct = pStruct; + }else{ + *pRc = SQLITE_NOMEM; + } + } +} + +/* +** Extend level iLvl so that there is room for at least nExtra more +** segments. +*/ +static void fts5StructureExtendLevel( + int *pRc, + Fts5Structure *pStruct, + int iLvl, + int nExtra, + int bInsert +){ + if( *pRc==SQLITE_OK ){ + Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; + Fts5StructureSegment *aNew; + int nByte; + + nByte = (pLvl->nSeg + nExtra) * sizeof(Fts5StructureSegment); + aNew = sqlite3_realloc(pLvl->aSeg, nByte); + if( aNew ){ + if( bInsert==0 ){ + memset(&aNew[pLvl->nSeg], 0, sizeof(Fts5StructureSegment) * nExtra); + }else{ + int nMove = pLvl->nSeg * sizeof(Fts5StructureSegment); + memmove(&aNew[nExtra], aNew, nMove); + memset(aNew, 0, sizeof(Fts5StructureSegment) * nExtra); + } + pLvl->aSeg = aNew; + }else{ + *pRc = SQLITE_NOMEM; + } + } +} + +/* +** Read, deserialize and return the structure record. +** +** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array +** are over-allocated as described for function fts5StructureDecode() +** above. +** +** If an error occurs, NULL is returned and an error code left in the +** Fts5Index handle. If an error has already occurred when this function +** is called, it is a no-op. +*/ +static Fts5Structure *fts5StructureRead(Fts5Index *p){ + Fts5Config *pConfig = p->pConfig; + Fts5Structure *pRet = 0; /* Object to return */ + int iCookie; /* Configuration cookie */ + Fts5Data *pData; + + pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID); + if( p->rc ) return 0; + /* TODO: Do we need this if the leaf-index is appended? Probably... */ + memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING); + p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet); + if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){ + p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); + } + + fts5DataRelease(pData); + if( p->rc!=SQLITE_OK ){ + fts5StructureRelease(pRet); + pRet = 0; + } + return pRet; +} + +/* +** Return the total number of segments in index structure pStruct. This +** function is only ever used as part of assert() conditions. +*/ +#ifdef SQLITE_DEBUG +static int fts5StructureCountSegments(Fts5Structure *pStruct){ + int nSegment = 0; /* Total number of segments */ + if( pStruct ){ + int iLvl; /* Used to iterate through levels */ + for(iLvl=0; iLvlnLevel; iLvl++){ + nSegment += pStruct->aLevel[iLvl].nSeg; + } + } + + return nSegment; +} +#endif + +#define fts5BufferSafeAppendBlob(pBuf, pBlob, nBlob) { \ + assert( (pBuf)->nSpace>=((pBuf)->n+nBlob) ); \ + memcpy(&(pBuf)->p[(pBuf)->n], pBlob, nBlob); \ + (pBuf)->n += nBlob; \ +} + +#define fts5BufferSafeAppendVarint(pBuf, iVal) { \ + (pBuf)->n += sqlite3Fts5PutVarint(&(pBuf)->p[(pBuf)->n], (iVal)); \ + assert( (pBuf)->nSpace>=(pBuf)->n ); \ +} + + +/* +** Serialize and store the "structure" record. +** +** If an error occurs, leave an error code in the Fts5Index object. If an +** error has already occurred, this function is a no-op. +*/ +static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){ + if( p->rc==SQLITE_OK ){ + Fts5Buffer buf; /* Buffer to serialize record into */ + int iLvl; /* Used to iterate through levels */ + int iCookie; /* Cookie value to store */ + + assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) ); + memset(&buf, 0, sizeof(Fts5Buffer)); + + /* Append the current configuration cookie */ + iCookie = p->pConfig->iCookie; + if( iCookie<0 ) iCookie = 0; + + if( 0==sqlite3Fts5BufferSize(&p->rc, &buf, 4+9+9+9) ){ + sqlite3Fts5Put32(buf.p, iCookie); + buf.n = 4; + fts5BufferSafeAppendVarint(&buf, pStruct->nLevel); + fts5BufferSafeAppendVarint(&buf, pStruct->nSegment); + fts5BufferSafeAppendVarint(&buf, (i64)pStruct->nWriteCounter); + } + + for(iLvl=0; iLvlnLevel; iLvl++){ + int iSeg; /* Used to iterate through segments */ + Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; + fts5BufferAppendVarint(&p->rc, &buf, pLvl->nMerge); + fts5BufferAppendVarint(&p->rc, &buf, pLvl->nSeg); + assert( pLvl->nMerge<=pLvl->nSeg ); + + for(iSeg=0; iSegnSeg; iSeg++){ + fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].iSegid); + fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoFirst); + fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoLast); + } + } + + fts5DataWrite(p, FTS5_STRUCTURE_ROWID, buf.p, buf.n); + fts5BufferFree(&buf); + } +} + +#if 0 +static void fts5DebugStructure(int*,Fts5Buffer*,Fts5Structure*); +static void fts5PrintStructure(const char *zCaption, Fts5Structure *pStruct){ + int rc = SQLITE_OK; + Fts5Buffer buf; + memset(&buf, 0, sizeof(buf)); + fts5DebugStructure(&rc, &buf, pStruct); + fprintf(stdout, "%s: %s\n", zCaption, buf.p); + fflush(stdout); + fts5BufferFree(&buf); +} +#else +# define fts5PrintStructure(x,y) +#endif + +static int fts5SegmentSize(Fts5StructureSegment *pSeg){ + return 1 + pSeg->pgnoLast - pSeg->pgnoFirst; +} + +/* +** Return a copy of index structure pStruct. Except, promote as many +** segments as possible to level iPromote. If an OOM occurs, NULL is +** returned. +*/ +static void fts5StructurePromoteTo( + Fts5Index *p, + int iPromote, + int szPromote, + Fts5Structure *pStruct +){ + int il, is; + Fts5StructureLevel *pOut = &pStruct->aLevel[iPromote]; + + if( pOut->nMerge==0 ){ + for(il=iPromote+1; ilnLevel; il++){ + Fts5StructureLevel *pLvl = &pStruct->aLevel[il]; + if( pLvl->nMerge ) return; + for(is=pLvl->nSeg-1; is>=0; is--){ + int sz = fts5SegmentSize(&pLvl->aSeg[is]); + if( sz>szPromote ) return; + fts5StructureExtendLevel(&p->rc, pStruct, iPromote, 1, 1); + if( p->rc ) return; + memcpy(pOut->aSeg, &pLvl->aSeg[is], sizeof(Fts5StructureSegment)); + pOut->nSeg++; + pLvl->nSeg--; + } + } + } +} + +/* +** A new segment has just been written to level iLvl of index structure +** pStruct. This function determines if any segments should be promoted +** as a result. Segments are promoted in two scenarios: +** +** a) If the segment just written is smaller than one or more segments +** within the previous populated level, it is promoted to the previous +** populated level. +** +** b) If the segment just written is larger than the newest segment on +** the next populated level, then that segment, and any other adjacent +** segments that are also smaller than the one just written, are +** promoted. +** +** If one or more segments are promoted, the structure object is updated +** to reflect this. +*/ +static void fts5StructurePromote( + Fts5Index *p, /* FTS5 backend object */ + int iLvl, /* Index level just updated */ + Fts5Structure *pStruct /* Index structure */ +){ + if( p->rc==SQLITE_OK ){ + int iTst; + int iPromote = -1; + int szPromote = 0; /* Promote anything this size or smaller */ + Fts5StructureSegment *pSeg; /* Segment just written */ + int szSeg; /* Size of segment just written */ + int nSeg = pStruct->aLevel[iLvl].nSeg; + + if( nSeg==0 ) return; + pSeg = &pStruct->aLevel[iLvl].aSeg[pStruct->aLevel[iLvl].nSeg-1]; + szSeg = (1 + pSeg->pgnoLast - pSeg->pgnoFirst); + + /* Check for condition (a) */ + for(iTst=iLvl-1; iTst>=0 && pStruct->aLevel[iTst].nSeg==0; iTst--); + if( iTst>=0 ){ + int i; + int szMax = 0; + Fts5StructureLevel *pTst = &pStruct->aLevel[iTst]; + assert( pTst->nMerge==0 ); + for(i=0; inSeg; i++){ + int sz = pTst->aSeg[i].pgnoLast - pTst->aSeg[i].pgnoFirst + 1; + if( sz>szMax ) szMax = sz; + } + if( szMax>=szSeg ){ + /* Condition (a) is true. Promote the newest segment on level + ** iLvl to level iTst. */ + iPromote = iTst; + szPromote = szMax; + } + } + + /* If condition (a) is not met, assume (b) is true. StructurePromoteTo() + ** is a no-op if it is not. */ + if( iPromote<0 ){ + iPromote = iLvl; + szPromote = szSeg; + } + fts5StructurePromoteTo(p, iPromote, szPromote, pStruct); + } +} + + +/* +** Advance the iterator passed as the only argument. If the end of the +** doclist-index page is reached, return non-zero. +*/ +static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){ + Fts5Data *pData = pLvl->pData; + + if( pLvl->iOff==0 ){ + assert( pLvl->bEof==0 ); + pLvl->iOff = 1; + pLvl->iOff += fts5GetVarint32(&pData->p[1], pLvl->iLeafPgno); + pLvl->iOff += fts5GetVarint(&pData->p[pLvl->iOff], (u64*)&pLvl->iRowid); + pLvl->iFirstOff = pLvl->iOff; + }else{ + int iOff; + for(iOff=pLvl->iOff; iOffnn; iOff++){ + if( pData->p[iOff] ) break; + } + + if( iOffnn ){ + i64 iVal; + pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1; + iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal); + pLvl->iRowid += iVal; + pLvl->iOff = iOff; + }else{ + pLvl->bEof = 1; + } + } + + return pLvl->bEof; +} + +/* +** Advance the iterator passed as the only argument. +*/ +static int fts5DlidxIterNextR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){ + Fts5DlidxLvl *pLvl = &pIter->aLvl[iLvl]; + + assert( iLvlnLvl ); + if( fts5DlidxLvlNext(pLvl) ){ + if( (iLvl+1) < pIter->nLvl ){ + fts5DlidxIterNextR(p, pIter, iLvl+1); + if( pLvl[1].bEof==0 ){ + fts5DataRelease(pLvl->pData); + memset(pLvl, 0, sizeof(Fts5DlidxLvl)); + pLvl->pData = fts5DataRead(p, + FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno) + ); + if( pLvl->pData ) fts5DlidxLvlNext(pLvl); + } + } + } + + return pIter->aLvl[0].bEof; +} +static int fts5DlidxIterNext(Fts5Index *p, Fts5DlidxIter *pIter){ + return fts5DlidxIterNextR(p, pIter, 0); +} + +/* +** The iterator passed as the first argument has the following fields set +** as follows. This function sets up the rest of the iterator so that it +** points to the first rowid in the doclist-index. +** +** pData: +** pointer to doclist-index record, +** +** When this function is called pIter->iLeafPgno is the page number the +** doclist is associated with (the one featuring the term). +*/ +static int fts5DlidxIterFirst(Fts5DlidxIter *pIter){ + int i; + for(i=0; inLvl; i++){ + fts5DlidxLvlNext(&pIter->aLvl[i]); + } + return pIter->aLvl[0].bEof; +} + + +static int fts5DlidxIterEof(Fts5Index *p, Fts5DlidxIter *pIter){ + return p->rc!=SQLITE_OK || pIter->aLvl[0].bEof; +} + +static void fts5DlidxIterLast(Fts5Index *p, Fts5DlidxIter *pIter){ + int i; + + /* Advance each level to the last entry on the last page */ + for(i=pIter->nLvl-1; p->rc==SQLITE_OK && i>=0; i--){ + Fts5DlidxLvl *pLvl = &pIter->aLvl[i]; + while( fts5DlidxLvlNext(pLvl)==0 ); + pLvl->bEof = 0; + + if( i>0 ){ + Fts5DlidxLvl *pChild = &pLvl[-1]; + fts5DataRelease(pChild->pData); + memset(pChild, 0, sizeof(Fts5DlidxLvl)); + pChild->pData = fts5DataRead(p, + FTS5_DLIDX_ROWID(pIter->iSegid, i-1, pLvl->iLeafPgno) + ); + } + } +} + +/* +** Move the iterator passed as the only argument to the previous entry. +*/ +static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){ + int iOff = pLvl->iOff; + + assert( pLvl->bEof==0 ); + if( iOff<=pLvl->iFirstOff ){ + pLvl->bEof = 1; + }else{ + u8 *a = pLvl->pData->p; + i64 iVal; + int iLimit; + int ii; + int nZero = 0; + + /* Currently iOff points to the first byte of a varint. This block + ** decrements iOff until it points to the first byte of the previous + ** varint. Taking care not to read any memory locations that occur + ** before the buffer in memory. */ + iLimit = (iOff>9 ? iOff-9 : 0); + for(iOff--; iOff>iLimit; iOff--){ + if( (a[iOff-1] & 0x80)==0 ) break; + } + + fts5GetVarint(&a[iOff], (u64*)&iVal); + pLvl->iRowid -= iVal; + pLvl->iLeafPgno--; + + /* Skip backwards past any 0x00 varints. */ + for(ii=iOff-1; ii>=pLvl->iFirstOff && a[ii]==0x00; ii--){ + nZero++; + } + if( ii>=pLvl->iFirstOff && (a[ii] & 0x80) ){ + /* The byte immediately before the last 0x00 byte has the 0x80 bit + ** set. So the last 0x00 is only a varint 0 if there are 8 more 0x80 + ** bytes before a[ii]. */ + int bZero = 0; /* True if last 0x00 counts */ + if( (ii-8)>=pLvl->iFirstOff ){ + int j; + for(j=1; j<=8 && (a[ii-j] & 0x80); j++); + bZero = (j>8); + } + if( bZero==0 ) nZero--; + } + pLvl->iLeafPgno -= nZero; + pLvl->iOff = iOff - nZero; + } + + return pLvl->bEof; +} + +static int fts5DlidxIterPrevR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){ + Fts5DlidxLvl *pLvl = &pIter->aLvl[iLvl]; + + assert( iLvlnLvl ); + if( fts5DlidxLvlPrev(pLvl) ){ + if( (iLvl+1) < pIter->nLvl ){ + fts5DlidxIterPrevR(p, pIter, iLvl+1); + if( pLvl[1].bEof==0 ){ + fts5DataRelease(pLvl->pData); + memset(pLvl, 0, sizeof(Fts5DlidxLvl)); + pLvl->pData = fts5DataRead(p, + FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno) + ); + if( pLvl->pData ){ + while( fts5DlidxLvlNext(pLvl)==0 ); + pLvl->bEof = 0; + } + } + } + } + + return pIter->aLvl[0].bEof; +} +static int fts5DlidxIterPrev(Fts5Index *p, Fts5DlidxIter *pIter){ + return fts5DlidxIterPrevR(p, pIter, 0); +} + +/* +** Free a doclist-index iterator object allocated by fts5DlidxIterInit(). +*/ +static void fts5DlidxIterFree(Fts5DlidxIter *pIter){ + if( pIter ){ + int i; + for(i=0; inLvl; i++){ + fts5DataRelease(pIter->aLvl[i].pData); + } + sqlite3_free(pIter); + } +} + +static Fts5DlidxIter *fts5DlidxIterInit( + Fts5Index *p, /* Fts5 Backend to iterate within */ + int bRev, /* True for ORDER BY ASC */ + int iSegid, /* Segment id */ + int iLeafPg /* Leaf page number to load dlidx for */ +){ + Fts5DlidxIter *pIter = 0; + int i; + int bDone = 0; + + for(i=0; p->rc==SQLITE_OK && bDone==0; i++){ + int nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl); + Fts5DlidxIter *pNew; + + pNew = (Fts5DlidxIter*)sqlite3_realloc(pIter, nByte); + if( pNew==0 ){ + p->rc = SQLITE_NOMEM; + }else{ + i64 iRowid = FTS5_DLIDX_ROWID(iSegid, i, iLeafPg); + Fts5DlidxLvl *pLvl = &pNew->aLvl[i]; + pIter = pNew; + memset(pLvl, 0, sizeof(Fts5DlidxLvl)); + pLvl->pData = fts5DataRead(p, iRowid); + if( pLvl->pData && (pLvl->pData->p[0] & 0x0001)==0 ){ + bDone = 1; + } + pIter->nLvl = i+1; + } + } + + if( p->rc==SQLITE_OK ){ + pIter->iSegid = iSegid; + if( bRev==0 ){ + fts5DlidxIterFirst(pIter); + }else{ + fts5DlidxIterLast(p, pIter); + } + } + + if( p->rc!=SQLITE_OK ){ + fts5DlidxIterFree(pIter); + pIter = 0; + } + + return pIter; +} + +static i64 fts5DlidxIterRowid(Fts5DlidxIter *pIter){ + return pIter->aLvl[0].iRowid; +} +static int fts5DlidxIterPgno(Fts5DlidxIter *pIter){ + return pIter->aLvl[0].iLeafPgno; +} + +/* +** Load the next leaf page into the segment iterator. +*/ +static void fts5SegIterNextPage( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter /* Iterator to advance to next page */ +){ + Fts5Data *pLeaf; + Fts5StructureSegment *pSeg = pIter->pSeg; + fts5DataRelease(pIter->pLeaf); + pIter->iLeafPgno++; + if( pIter->pNextLeaf ){ + pIter->pLeaf = pIter->pNextLeaf; + pIter->pNextLeaf = 0; + }else if( pIter->iLeafPgno<=pSeg->pgnoLast ){ + pIter->pLeaf = fts5DataRead(p, + FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno) + ); + }else{ + pIter->pLeaf = 0; + } + pLeaf = pIter->pLeaf; + + if( pLeaf ){ + pIter->iPgidxOff = pLeaf->szLeaf; + if( fts5LeafIsTermless(pLeaf) ){ + pIter->iEndofDoclist = pLeaf->nn+1; + }else{ + pIter->iPgidxOff += fts5GetVarint32(&pLeaf->p[pIter->iPgidxOff], + pIter->iEndofDoclist + ); + } + } +} + +/* +** Argument p points to a buffer containing a varint to be interpreted as a +** position list size field. Read the varint and return the number of bytes +** read. Before returning, set *pnSz to the number of bytes in the position +** list, and *pbDel to true if the delete flag is set, or false otherwise. +*/ +static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){ + int nSz; + int n = 0; + fts5FastGetVarint32(p, n, nSz); + assert_nc( nSz>=0 ); + *pnSz = nSz/2; + *pbDel = nSz & 0x0001; + return n; +} + +/* +** Fts5SegIter.iLeafOffset currently points to the first byte of a +** position-list size field. Read the value of the field and store it +** in the following variables: +** +** Fts5SegIter.nPos +** Fts5SegIter.bDel +** +** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the +** position list content (if any). +*/ +static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){ + if( p->rc==SQLITE_OK ){ + int iOff = pIter->iLeafOffset; /* Offset to read at */ + ASSERT_SZLEAF_OK(pIter->pLeaf); + if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ + int iEod = MIN(pIter->iEndofDoclist, pIter->pLeaf->szLeaf); + pIter->bDel = 0; + pIter->nPos = 1; + if( iOffpLeaf->p[iOff]==0 ){ + pIter->bDel = 1; + iOff++; + if( iOffpLeaf->p[iOff]==0 ){ + pIter->nPos = 1; + iOff++; + }else{ + pIter->nPos = 0; + } + } + }else{ + int nSz; + fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz); + pIter->bDel = (nSz & 0x0001); + pIter->nPos = nSz>>1; + assert_nc( pIter->nPos>=0 ); + } + pIter->iLeafOffset = iOff; + } +} + +static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ + u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ + int iOff = pIter->iLeafOffset; + + ASSERT_SZLEAF_OK(pIter->pLeaf); + if( iOff>=pIter->pLeaf->szLeaf ){ + fts5SegIterNextPage(p, pIter); + if( pIter->pLeaf==0 ){ + if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; + return; + } + iOff = 4; + a = pIter->pLeaf->p; + } + iOff += sqlite3Fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid); + pIter->iLeafOffset = iOff; +} + +/* +** Fts5SegIter.iLeafOffset currently points to the first byte of the +** "nSuffix" field of a term. Function parameter nKeep contains the value +** of the "nPrefix" field (if there was one - it is passed 0 if this is +** the first term in the segment). +** +** This function populates: +** +** Fts5SegIter.term +** Fts5SegIter.rowid +** +** accordingly and leaves (Fts5SegIter.iLeafOffset) set to the content of +** the first position list. The position list belonging to document +** (Fts5SegIter.iRowid). +*/ +static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){ + u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ + int iOff = pIter->iLeafOffset; /* Offset to read at */ + int nNew; /* Bytes of new data */ + + iOff += fts5GetVarint32(&a[iOff], nNew); + if( iOff+nNew>pIter->pLeaf->nn ){ + p->rc = FTS5_CORRUPT; + return; + } + pIter->term.n = nKeep; + fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]); + iOff += nNew; + pIter->iTermLeafOffset = iOff; + pIter->iTermLeafPgno = pIter->iLeafPgno; + pIter->iLeafOffset = iOff; + + if( pIter->iPgidxOff>=pIter->pLeaf->nn ){ + pIter->iEndofDoclist = pIter->pLeaf->nn+1; + }else{ + int nExtra; + pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], nExtra); + pIter->iEndofDoclist += nExtra; + } + + fts5SegIterLoadRowid(p, pIter); +} + +static void fts5SegIterNext(Fts5Index*, Fts5SegIter*, int*); +static void fts5SegIterNext_Reverse(Fts5Index*, Fts5SegIter*, int*); +static void fts5SegIterNext_None(Fts5Index*, Fts5SegIter*, int*); + +static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){ + if( pIter->flags & FTS5_SEGITER_REVERSE ){ + pIter->xNext = fts5SegIterNext_Reverse; + }else if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ + pIter->xNext = fts5SegIterNext_None; + }else{ + pIter->xNext = fts5SegIterNext; + } +} + +/* +** Initialize the iterator object pIter to iterate through the entries in +** segment pSeg. The iterator is left pointing to the first entry when +** this function returns. +** +** If an error occurs, Fts5Index.rc is set to an appropriate error code. If +** an error has already occurred when this function is called, it is a no-op. +*/ +static void fts5SegIterInit( + Fts5Index *p, /* FTS index object */ + Fts5StructureSegment *pSeg, /* Description of segment */ + Fts5SegIter *pIter /* Object to populate */ +){ + if( pSeg->pgnoFirst==0 ){ + /* This happens if the segment is being used as an input to an incremental + ** merge and all data has already been "trimmed". See function + ** fts5TrimSegments() for details. In this case leave the iterator empty. + ** The caller will see the (pIter->pLeaf==0) and assume the iterator is + ** at EOF already. */ + assert( pIter->pLeaf==0 ); + return; + } + + if( p->rc==SQLITE_OK ){ + memset(pIter, 0, sizeof(*pIter)); + fts5SegIterSetNext(p, pIter); + pIter->pSeg = pSeg; + pIter->iLeafPgno = pSeg->pgnoFirst-1; + fts5SegIterNextPage(p, pIter); + } + + if( p->rc==SQLITE_OK ){ + pIter->iLeafOffset = 4; + assert_nc( pIter->pLeaf->nn>4 ); + assert( fts5LeafFirstTermOff(pIter->pLeaf)==4 ); + pIter->iPgidxOff = pIter->pLeaf->szLeaf+1; + fts5SegIterLoadTerm(p, pIter, 0); + fts5SegIterLoadNPos(p, pIter); + } +} + +/* +** This function is only ever called on iterators created by calls to +** Fts5IndexQuery() with the FTS5INDEX_QUERY_DESC flag set. +** +** The iterator is in an unusual state when this function is called: the +** Fts5SegIter.iLeafOffset variable is set to the offset of the start of +** the position-list size field for the first relevant rowid on the page. +** Fts5SegIter.rowid is set, but nPos and bDel are not. +** +** This function advances the iterator so that it points to the last +** relevant rowid on the page and, if necessary, initializes the +** aRowidOffset[] and iRowidOffset variables. At this point the iterator +** is in its regular state - Fts5SegIter.iLeafOffset points to the first +** byte of the position list content associated with said rowid. +*/ +static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ + int eDetail = p->pConfig->eDetail; + int n = pIter->pLeaf->szLeaf; + int i = pIter->iLeafOffset; + u8 *a = pIter->pLeaf->p; + int iRowidOffset = 0; + + if( n>pIter->iEndofDoclist ){ + n = pIter->iEndofDoclist; + } + + ASSERT_SZLEAF_OK(pIter->pLeaf); + while( 1 ){ + i64 iDelta = 0; + + if( eDetail==FTS5_DETAIL_NONE ){ + /* todo */ + if( i=n ) break; + i += fts5GetVarint(&a[i], (u64*)&iDelta); + pIter->iRowid += iDelta; + + /* If necessary, grow the pIter->aRowidOffset[] array. */ + if( iRowidOffset>=pIter->nRowidOffset ){ + int nNew = pIter->nRowidOffset + 8; + int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int)); + if( aNew==0 ){ + p->rc = SQLITE_NOMEM; + break; + } + pIter->aRowidOffset = aNew; + pIter->nRowidOffset = nNew; + } + + pIter->aRowidOffset[iRowidOffset++] = pIter->iLeafOffset; + pIter->iLeafOffset = i; + } + pIter->iRowidOffset = iRowidOffset; + fts5SegIterLoadNPos(p, pIter); +} + +/* +** +*/ +static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){ + assert( pIter->flags & FTS5_SEGITER_REVERSE ); + assert( pIter->flags & FTS5_SEGITER_ONETERM ); + + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; + while( p->rc==SQLITE_OK && pIter->iLeafPgno>pIter->iTermLeafPgno ){ + Fts5Data *pNew; + pIter->iLeafPgno--; + pNew = fts5DataRead(p, FTS5_SEGMENT_ROWID( + pIter->pSeg->iSegid, pIter->iLeafPgno + )); + if( pNew ){ + /* iTermLeafOffset may be equal to szLeaf if the term is the last + ** thing on the page - i.e. the first rowid is on the following page. + ** In this case leave pIter->pLeaf==0, this iterator is at EOF. */ + if( pIter->iLeafPgno==pIter->iTermLeafPgno ){ + assert( pIter->pLeaf==0 ); + if( pIter->iTermLeafOffsetszLeaf ){ + pIter->pLeaf = pNew; + pIter->iLeafOffset = pIter->iTermLeafOffset; + } + }else{ + int iRowidOff; + iRowidOff = fts5LeafFirstRowidOff(pNew); + if( iRowidOff ){ + pIter->pLeaf = pNew; + pIter->iLeafOffset = iRowidOff; + } + } + + if( pIter->pLeaf ){ + u8 *a = &pIter->pLeaf->p[pIter->iLeafOffset]; + pIter->iLeafOffset += fts5GetVarint(a, (u64*)&pIter->iRowid); + break; + }else{ + fts5DataRelease(pNew); + } + } + } + + if( pIter->pLeaf ){ + pIter->iEndofDoclist = pIter->pLeaf->nn+1; + fts5SegIterReverseInitPage(p, pIter); + } +} + +/* +** Return true if the iterator passed as the second argument currently +** points to a delete marker. A delete marker is an entry with a 0 byte +** position-list. +*/ +static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5Iter *pIter){ + Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst]; + return (p->rc==SQLITE_OK && pSeg->pLeaf && pSeg->nPos==0); +} + +/* +** Advance iterator pIter to the next entry. +** +** This version of fts5SegIterNext() is only used by reverse iterators. +*/ +static void fts5SegIterNext_Reverse( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + int *pbUnused /* Unused */ +){ + assert( pIter->flags & FTS5_SEGITER_REVERSE ); + assert( pIter->pNextLeaf==0 ); + UNUSED_PARAM(pbUnused); + + if( pIter->iRowidOffset>0 ){ + u8 *a = pIter->pLeaf->p; + int iOff; + i64 iDelta; + + pIter->iRowidOffset--; + pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset]; + fts5SegIterLoadNPos(p, pIter); + iOff = pIter->iLeafOffset; + if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){ + iOff += pIter->nPos; + } + fts5GetVarint(&a[iOff], (u64*)&iDelta); + pIter->iRowid -= iDelta; + }else{ + fts5SegIterReverseNewPage(p, pIter); + } +} + +/* +** Advance iterator pIter to the next entry. +** +** This version of fts5SegIterNext() is only used if detail=none and the +** iterator is not a reverse direction iterator. +*/ +static void fts5SegIterNext_None( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + int *pbNewTerm /* OUT: Set for new term */ +){ + int iOff; + + assert( p->rc==SQLITE_OK ); + assert( (pIter->flags & FTS5_SEGITER_REVERSE)==0 ); + assert( p->pConfig->eDetail==FTS5_DETAIL_NONE ); + + ASSERT_SZLEAF_OK(pIter->pLeaf); + iOff = pIter->iLeafOffset; + + /* Next entry is on the next page */ + if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){ + fts5SegIterNextPage(p, pIter); + if( p->rc || pIter->pLeaf==0 ) return; + pIter->iRowid = 0; + iOff = 4; + } + + if( iOffiEndofDoclist ){ + /* Next entry is on the current page */ + i64 iDelta; + iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta); + pIter->iLeafOffset = iOff; + pIter->iRowid += iDelta; + }else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){ + if( pIter->pSeg ){ + int nKeep = 0; + if( iOff!=fts5LeafFirstTermOff(pIter->pLeaf) ){ + iOff += fts5GetVarint32(&pIter->pLeaf->p[iOff], nKeep); + } + pIter->iLeafOffset = iOff; + fts5SegIterLoadTerm(p, pIter, nKeep); + }else{ + const u8 *pList = 0; + const char *zTerm = 0; + int nList; + sqlite3Fts5HashScanNext(p->pHash); + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); + if( pList==0 ) goto next_none_eof; + pIter->pLeaf->p = (u8*)pList; + pIter->pLeaf->nn = nList; + pIter->pLeaf->szLeaf = nList; + pIter->iEndofDoclist = nList; + sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm); + pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); + } + + if( pbNewTerm ) *pbNewTerm = 1; + }else{ + goto next_none_eof; + } + + fts5SegIterLoadNPos(p, pIter); + + return; + next_none_eof: + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; +} + + +/* +** Advance iterator pIter to the next entry. +** +** If an error occurs, Fts5Index.rc is set to an appropriate error code. It +** is not considered an error if the iterator reaches EOF. If an error has +** already occurred when this function is called, it is a no-op. +*/ +static void fts5SegIterNext( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + int *pbNewTerm /* OUT: Set for new term */ +){ + Fts5Data *pLeaf = pIter->pLeaf; + int iOff; + int bNewTerm = 0; + int nKeep = 0; + u8 *a; + int n; + + assert( pbNewTerm==0 || *pbNewTerm==0 ); + assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE ); + + /* Search for the end of the position list within the current page. */ + a = pLeaf->p; + n = pLeaf->szLeaf; + + ASSERT_SZLEAF_OK(pLeaf); + iOff = pIter->iLeafOffset + pIter->nPos; + + if( iOffiEndofDoclist ); + if( iOff>=pIter->iEndofDoclist ){ + bNewTerm = 1; + if( iOff!=fts5LeafFirstTermOff(pLeaf) ){ + iOff += fts5GetVarint32(&a[iOff], nKeep); + } + }else{ + u64 iDelta; + iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta); + pIter->iRowid += iDelta; + assert_nc( iDelta>0 ); + } + pIter->iLeafOffset = iOff; + + }else if( pIter->pSeg==0 ){ + const u8 *pList = 0; + const char *zTerm = 0; + int nList = 0; + assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm ); + if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){ + sqlite3Fts5HashScanNext(p->pHash); + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); + } + if( pList==0 ){ + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; + }else{ + pIter->pLeaf->p = (u8*)pList; + pIter->pLeaf->nn = nList; + pIter->pLeaf->szLeaf = nList; + pIter->iEndofDoclist = nList+1; + sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm), + (u8*)zTerm); + pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); + *pbNewTerm = 1; + } + }else{ + iOff = 0; + /* Next entry is not on the current page */ + while( iOff==0 ){ + fts5SegIterNextPage(p, pIter); + pLeaf = pIter->pLeaf; + if( pLeaf==0 ) break; + ASSERT_SZLEAF_OK(pLeaf); + if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOffszLeaf ){ + iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid); + pIter->iLeafOffset = iOff; + + if( pLeaf->nn>pLeaf->szLeaf ){ + pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( + &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist + ); + } + + } + else if( pLeaf->nn>pLeaf->szLeaf ){ + pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( + &pLeaf->p[pLeaf->szLeaf], iOff + ); + pIter->iLeafOffset = iOff; + pIter->iEndofDoclist = iOff; + bNewTerm = 1; + } + assert_nc( iOffszLeaf ); + if( iOff>pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + return; + } + } + } + + /* Check if the iterator is now at EOF. If so, return early. */ + if( pIter->pLeaf ){ + if( bNewTerm ){ + if( pIter->flags & FTS5_SEGITER_ONETERM ){ + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; + }else{ + fts5SegIterLoadTerm(p, pIter, nKeep); + fts5SegIterLoadNPos(p, pIter); + if( pbNewTerm ) *pbNewTerm = 1; + } + }else{ + /* The following could be done by calling fts5SegIterLoadNPos(). But + ** this block is particularly performance critical, so equivalent + ** code is inlined. + ** + ** Later: Switched back to fts5SegIterLoadNPos() because it supports + ** detail=none mode. Not ideal. + */ + int nSz; + assert( p->rc==SQLITE_OK ); + fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz); + pIter->bDel = (nSz & 0x0001); + pIter->nPos = nSz>>1; + assert_nc( pIter->nPos>=0 ); + } + } +} + +#define SWAPVAL(T, a, b) { T tmp; tmp=a; a=b; b=tmp; } + +#define fts5IndexSkipVarint(a, iOff) { \ + int iEnd = iOff+9; \ + while( (a[iOff++] & 0x80) && iOffpDlidx; + Fts5Data *pLast = 0; + int pgnoLast = 0; + + if( pDlidx ){ + int iSegid = pIter->pSeg->iSegid; + pgnoLast = fts5DlidxIterPgno(pDlidx); + pLast = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast)); + }else{ + Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */ + + /* Currently, Fts5SegIter.iLeafOffset points to the first byte of + ** position-list content for the current rowid. Back it up so that it + ** points to the start of the position-list size field. */ + int iPoslist; + if( pIter->iTermLeafPgno==pIter->iLeafPgno ){ + iPoslist = pIter->iTermLeafOffset; + }else{ + iPoslist = 4; + } + fts5IndexSkipVarint(pLeaf->p, iPoslist); + pIter->iLeafOffset = iPoslist; + + /* If this condition is true then the largest rowid for the current + ** term may not be stored on the current page. So search forward to + ** see where said rowid really is. */ + if( pIter->iEndofDoclist>=pLeaf->szLeaf ){ + int pgno; + Fts5StructureSegment *pSeg = pIter->pSeg; + + /* The last rowid in the doclist may not be on the current page. Search + ** forward to find the page containing the last rowid. */ + for(pgno=pIter->iLeafPgno+1; !p->rc && pgno<=pSeg->pgnoLast; pgno++){ + i64 iAbs = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno); + Fts5Data *pNew = fts5DataRead(p, iAbs); + if( pNew ){ + int iRowid, bTermless; + iRowid = fts5LeafFirstRowidOff(pNew); + bTermless = fts5LeafIsTermless(pNew); + if( iRowid ){ + SWAPVAL(Fts5Data*, pNew, pLast); + pgnoLast = pgno; + } + fts5DataRelease(pNew); + if( bTermless==0 ) break; + } + } + } + } + + /* If pLast is NULL at this point, then the last rowid for this doclist + ** lies on the page currently indicated by the iterator. In this case + ** pIter->iLeafOffset is already set to point to the position-list size + ** field associated with the first relevant rowid on the page. + ** + ** Or, if pLast is non-NULL, then it is the page that contains the last + ** rowid. In this case configure the iterator so that it points to the + ** first rowid on this page. + */ + if( pLast ){ + int iOff; + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = pLast; + pIter->iLeafPgno = pgnoLast; + iOff = fts5LeafFirstRowidOff(pLast); + iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid); + pIter->iLeafOffset = iOff; + + if( fts5LeafIsTermless(pLast) ){ + pIter->iEndofDoclist = pLast->nn+1; + }else{ + pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast); + } + + } + + fts5SegIterReverseInitPage(p, pIter); +} + +/* +** Iterator pIter currently points to the first rowid of a doclist. +** There is a doclist-index associated with the final term on the current +** page. If the current term is the last term on the page, load the +** doclist-index from disk and initialize an iterator at (pIter->pDlidx). +*/ +static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){ + int iSeg = pIter->pSeg->iSegid; + int bRev = (pIter->flags & FTS5_SEGITER_REVERSE); + Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */ + + assert( pIter->flags & FTS5_SEGITER_ONETERM ); + assert( pIter->pDlidx==0 ); + + /* Check if the current doclist ends on this page. If it does, return + ** early without loading the doclist-index (as it belongs to a different + ** term. */ + if( pIter->iTermLeafPgno==pIter->iLeafPgno + && pIter->iEndofDoclistszLeaf + ){ + return; + } + + pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno); +} + +/* +** The iterator object passed as the second argument currently contains +** no valid values except for the Fts5SegIter.pLeaf member variable. This +** function searches the leaf page for a term matching (pTerm/nTerm). +** +** If the specified term is found on the page, then the iterator is left +** pointing to it. If argument bGe is zero and the term is not found, +** the iterator is left pointing at EOF. +** +** If bGe is non-zero and the specified term is not found, then the +** iterator is left pointing to the smallest term in the segment that +** is larger than the specified term, even if this term is not on the +** current page. +*/ +static void fts5LeafSeek( + Fts5Index *p, /* Leave any error code here */ + int bGe, /* True for a >= search */ + Fts5SegIter *pIter, /* Iterator to seek */ + const u8 *pTerm, int nTerm /* Term to search for */ +){ + int iOff; + const u8 *a = pIter->pLeaf->p; + int szLeaf = pIter->pLeaf->szLeaf; + int n = pIter->pLeaf->nn; + + int nMatch = 0; + int nKeep = 0; + int nNew = 0; + int iTermOff; + int iPgidx; /* Current offset in pgidx */ + int bEndOfPage = 0; + + assert( p->rc==SQLITE_OK ); + + iPgidx = szLeaf; + iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff); + iOff = iTermOff; + + while( 1 ){ + + /* Figure out how many new bytes are in this term */ + fts5FastGetVarint32(a, iOff, nNew); + if( nKeep=nMatch ); + if( nKeep==nMatch ){ + int nCmp; + int i; + nCmp = MIN(nNew, nTerm-nMatch); + for(i=0; ipTerm[nMatch] ){ + goto search_failed; + } + } + + if( iPgidx>=n ){ + bEndOfPage = 1; + break; + } + + iPgidx += fts5GetVarint32(&a[iPgidx], nKeep); + iTermOff += nKeep; + iOff = iTermOff; + + /* Read the nKeep field of the next term. */ + fts5FastGetVarint32(a, iOff, nKeep); + } + + search_failed: + if( bGe==0 ){ + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; + return; + }else if( bEndOfPage ){ + do { + fts5SegIterNextPage(p, pIter); + if( pIter->pLeaf==0 ) return; + a = pIter->pLeaf->p; + if( fts5LeafIsTermless(pIter->pLeaf)==0 ){ + iPgidx = pIter->pLeaf->szLeaf; + iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff); + if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + nKeep = 0; + iTermOff = iOff; + n = pIter->pLeaf->nn; + iOff += fts5GetVarint32(&a[iOff], nNew); + break; + } + } + }while( 1 ); + } + + search_success: + + pIter->iLeafOffset = iOff + nNew; + pIter->iTermLeafOffset = pIter->iLeafOffset; + pIter->iTermLeafPgno = pIter->iLeafPgno; + + fts5BufferSet(&p->rc, &pIter->term, nKeep, pTerm); + fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]); + + if( iPgidx>=n ){ + pIter->iEndofDoclist = pIter->pLeaf->nn+1; + }else{ + int nExtra; + iPgidx += fts5GetVarint32(&a[iPgidx], nExtra); + pIter->iEndofDoclist = iTermOff + nExtra; + } + pIter->iPgidxOff = iPgidx; + + fts5SegIterLoadRowid(p, pIter); + fts5SegIterLoadNPos(p, pIter); +} + +/* +** Initialize the object pIter to point to term pTerm/nTerm within segment +** pSeg. If there is no such term in the index, the iterator is set to EOF. +** +** If an error occurs, Fts5Index.rc is set to an appropriate error code. If +** an error has already occurred when this function is called, it is a no-op. +*/ +static void fts5SegIterSeekInit( + Fts5Index *p, /* FTS5 backend */ + const u8 *pTerm, int nTerm, /* Term to seek to */ + int flags, /* Mask of FTS5INDEX_XXX flags */ + Fts5StructureSegment *pSeg, /* Description of segment */ + Fts5SegIter *pIter /* Object to populate */ +){ + int iPg = 1; + int bGe = (flags & FTS5INDEX_QUERY_SCAN); + int bDlidx = 0; /* True if there is a doclist-index */ + + assert( bGe==0 || (flags & FTS5INDEX_QUERY_DESC)==0 ); + assert( pTerm && nTerm ); + memset(pIter, 0, sizeof(*pIter)); + pIter->pSeg = pSeg; + + /* This block sets stack variable iPg to the leaf page number that may + ** contain term (pTerm/nTerm), if it is present in the segment. */ + if( p->pIdxSelect==0 ){ + Fts5Config *pConfig = p->pConfig; + fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf( + "SELECT pgno FROM '%q'.'%q_idx' WHERE " + "segid=? AND term<=? ORDER BY term DESC LIMIT 1", + pConfig->zDb, pConfig->zName + )); + } + if( p->rc ) return; + sqlite3_bind_int(p->pIdxSelect, 1, pSeg->iSegid); + sqlite3_bind_blob(p->pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC); + if( SQLITE_ROW==sqlite3_step(p->pIdxSelect) ){ + i64 val = sqlite3_column_int(p->pIdxSelect, 0); + iPg = (int)(val>>1); + bDlidx = (val & 0x0001); + } + p->rc = sqlite3_reset(p->pIdxSelect); + + if( iPgpgnoFirst ){ + iPg = pSeg->pgnoFirst; + bDlidx = 0; + } + + pIter->iLeafPgno = iPg - 1; + fts5SegIterNextPage(p, pIter); + + if( pIter->pLeaf ){ + fts5LeafSeek(p, bGe, pIter, pTerm, nTerm); + } + + if( p->rc==SQLITE_OK && bGe==0 ){ + pIter->flags |= FTS5_SEGITER_ONETERM; + if( pIter->pLeaf ){ + if( flags & FTS5INDEX_QUERY_DESC ){ + pIter->flags |= FTS5_SEGITER_REVERSE; + } + if( bDlidx ){ + fts5SegIterLoadDlidx(p, pIter); + } + if( flags & FTS5INDEX_QUERY_DESC ){ + fts5SegIterReverse(p, pIter); + } + } + } + + fts5SegIterSetNext(p, pIter); + + /* Either: + ** + ** 1) an error has occurred, or + ** 2) the iterator points to EOF, or + ** 3) the iterator points to an entry with term (pTerm/nTerm), or + ** 4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points + ** to an entry with a term greater than or equal to (pTerm/nTerm). + */ + assert( p->rc!=SQLITE_OK /* 1 */ + || pIter->pLeaf==0 /* 2 */ + || fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */ + || (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */ + ); +} + +/* +** Initialize the object pIter to point to term pTerm/nTerm within the +** in-memory hash table. If there is no such term in the hash-table, the +** iterator is set to EOF. +** +** If an error occurs, Fts5Index.rc is set to an appropriate error code. If +** an error has already occurred when this function is called, it is a no-op. +*/ +static void fts5SegIterHashInit( + Fts5Index *p, /* FTS5 backend */ + const u8 *pTerm, int nTerm, /* Term to seek to */ + int flags, /* Mask of FTS5INDEX_XXX flags */ + Fts5SegIter *pIter /* Object to populate */ +){ + const u8 *pList = 0; + int nList = 0; + const u8 *z = 0; + int n = 0; + + assert( p->pHash ); + assert( p->rc==SQLITE_OK ); + + if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){ + p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm); + sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList); + n = (z ? (int)strlen((const char*)z) : 0); + }else{ + pIter->flags |= FTS5_SEGITER_ONETERM; + sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList); + z = pTerm; + n = nTerm; + } + + if( pList ){ + Fts5Data *pLeaf; + sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z); + pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); + if( pLeaf==0 ) return; + pLeaf->p = (u8*)pList; + pLeaf->nn = pLeaf->szLeaf = nList; + pIter->pLeaf = pLeaf; + pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid); + pIter->iEndofDoclist = pLeaf->nn; + + if( flags & FTS5INDEX_QUERY_DESC ){ + pIter->flags |= FTS5_SEGITER_REVERSE; + fts5SegIterReverseInitPage(p, pIter); + }else{ + fts5SegIterLoadNPos(p, pIter); + } + } + + fts5SegIterSetNext(p, pIter); +} + +/* +** Zero the iterator passed as the only argument. +*/ +static void fts5SegIterClear(Fts5SegIter *pIter){ + fts5BufferFree(&pIter->term); + fts5DataRelease(pIter->pLeaf); + fts5DataRelease(pIter->pNextLeaf); + fts5DlidxIterFree(pIter->pDlidx); + sqlite3_free(pIter->aRowidOffset); + memset(pIter, 0, sizeof(Fts5SegIter)); +} + +#ifdef SQLITE_DEBUG + +/* +** This function is used as part of the big assert() procedure implemented by +** fts5AssertMultiIterSetup(). It ensures that the result currently stored +** in *pRes is the correct result of comparing the current positions of the +** two iterators. +*/ +static void fts5AssertComparisonResult( + Fts5Iter *pIter, + Fts5SegIter *p1, + Fts5SegIter *p2, + Fts5CResult *pRes +){ + int i1 = p1 - pIter->aSeg; + int i2 = p2 - pIter->aSeg; + + if( p1->pLeaf || p2->pLeaf ){ + if( p1->pLeaf==0 ){ + assert( pRes->iFirst==i2 ); + }else if( p2->pLeaf==0 ){ + assert( pRes->iFirst==i1 ); + }else{ + int nMin = MIN(p1->term.n, p2->term.n); + int res = memcmp(p1->term.p, p2->term.p, nMin); + if( res==0 ) res = p1->term.n - p2->term.n; + + if( res==0 ){ + assert( pRes->bTermEq==1 ); + assert( p1->iRowid!=p2->iRowid ); + res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : 1; + }else{ + assert( pRes->bTermEq==0 ); + } + + if( res<0 ){ + assert( pRes->iFirst==i1 ); + }else{ + assert( pRes->iFirst==i2 ); + } + } + } +} + +/* +** This function is a no-op unless SQLITE_DEBUG is defined when this module +** is compiled. In that case, this function is essentially an assert() +** statement used to verify that the contents of the pIter->aFirst[] array +** are correct. +*/ +static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){ + if( p->rc==SQLITE_OK ){ + Fts5SegIter *pFirst = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; + int i; + + assert( (pFirst->pLeaf==0)==pIter->base.bEof ); + + /* Check that pIter->iSwitchRowid is set correctly. */ + for(i=0; inSeg; i++){ + Fts5SegIter *p1 = &pIter->aSeg[i]; + assert( p1==pFirst + || p1->pLeaf==0 + || fts5BufferCompare(&pFirst->term, &p1->term) + || p1->iRowid==pIter->iSwitchRowid + || (p1->iRowidiSwitchRowid)==pIter->bRev + ); + } + + for(i=0; inSeg; i+=2){ + Fts5SegIter *p1 = &pIter->aSeg[i]; + Fts5SegIter *p2 = &pIter->aSeg[i+1]; + Fts5CResult *pRes = &pIter->aFirst[(pIter->nSeg + i) / 2]; + fts5AssertComparisonResult(pIter, p1, p2, pRes); + } + + for(i=1; i<(pIter->nSeg / 2); i+=2){ + Fts5SegIter *p1 = &pIter->aSeg[ pIter->aFirst[i*2].iFirst ]; + Fts5SegIter *p2 = &pIter->aSeg[ pIter->aFirst[i*2+1].iFirst ]; + Fts5CResult *pRes = &pIter->aFirst[i]; + fts5AssertComparisonResult(pIter, p1, p2, pRes); + } + } +} +#else +# define fts5AssertMultiIterSetup(x,y) +#endif + +/* +** Do the comparison necessary to populate pIter->aFirst[iOut]. +** +** If the returned value is non-zero, then it is the index of an entry +** in the pIter->aSeg[] array that is (a) not at EOF, and (b) pointing +** to a key that is a duplicate of another, higher priority, +** segment-iterator in the pSeg->aSeg[] array. +*/ +static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){ + int i1; /* Index of left-hand Fts5SegIter */ + int i2; /* Index of right-hand Fts5SegIter */ + int iRes; + Fts5SegIter *p1; /* Left-hand Fts5SegIter */ + Fts5SegIter *p2; /* Right-hand Fts5SegIter */ + Fts5CResult *pRes = &pIter->aFirst[iOut]; + + assert( iOutnSeg && iOut>0 ); + assert( pIter->bRev==0 || pIter->bRev==1 ); + + if( iOut>=(pIter->nSeg/2) ){ + i1 = (iOut - pIter->nSeg/2) * 2; + i2 = i1 + 1; + }else{ + i1 = pIter->aFirst[iOut*2].iFirst; + i2 = pIter->aFirst[iOut*2+1].iFirst; + } + p1 = &pIter->aSeg[i1]; + p2 = &pIter->aSeg[i2]; + + pRes->bTermEq = 0; + if( p1->pLeaf==0 ){ /* If p1 is at EOF */ + iRes = i2; + }else if( p2->pLeaf==0 ){ /* If p2 is at EOF */ + iRes = i1; + }else{ + int res = fts5BufferCompare(&p1->term, &p2->term); + if( res==0 ){ + assert( i2>i1 ); + assert( i2!=0 ); + pRes->bTermEq = 1; + if( p1->iRowid==p2->iRowid ){ + p1->bDel = p2->bDel; + return i2; + } + res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1; + } + assert( res!=0 ); + if( res<0 ){ + iRes = i1; + }else{ + iRes = i2; + } + } + + pRes->iFirst = (u16)iRes; + return 0; +} + +/* +** Move the seg-iter so that it points to the first rowid on page iLeafPgno. +** It is an error if leaf iLeafPgno does not exist or contains no rowids. +*/ +static void fts5SegIterGotoPage( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + int iLeafPgno +){ + assert( iLeafPgno>pIter->iLeafPgno ); + + if( iLeafPgno>pIter->pSeg->pgnoLast ){ + p->rc = FTS5_CORRUPT; + }else{ + fts5DataRelease(pIter->pNextLeaf); + pIter->pNextLeaf = 0; + pIter->iLeafPgno = iLeafPgno-1; + fts5SegIterNextPage(p, pIter); + assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno ); + + if( p->rc==SQLITE_OK ){ + int iOff; + u8 *a = pIter->pLeaf->p; + int n = pIter->pLeaf->szLeaf; + + iOff = fts5LeafFirstRowidOff(pIter->pLeaf); + if( iOff<4 || iOff>=n ){ + p->rc = FTS5_CORRUPT; + }else{ + iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid); + pIter->iLeafOffset = iOff; + fts5SegIterLoadNPos(p, pIter); + } + } + } +} + +/* +** Advance the iterator passed as the second argument until it is at or +** past rowid iFrom. Regardless of the value of iFrom, the iterator is +** always advanced at least once. +*/ +static void fts5SegIterNextFrom( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + i64 iMatch /* Advance iterator at least this far */ +){ + int bRev = (pIter->flags & FTS5_SEGITER_REVERSE); + Fts5DlidxIter *pDlidx = pIter->pDlidx; + int iLeafPgno = pIter->iLeafPgno; + int bMove = 1; + + assert( pIter->flags & FTS5_SEGITER_ONETERM ); + assert( pIter->pDlidx ); + assert( pIter->pLeaf ); + + if( bRev==0 ){ + while( !fts5DlidxIterEof(p, pDlidx) && iMatch>fts5DlidxIterRowid(pDlidx) ){ + iLeafPgno = fts5DlidxIterPgno(pDlidx); + fts5DlidxIterNext(p, pDlidx); + } + assert_nc( iLeafPgno>=pIter->iLeafPgno || p->rc ); + if( iLeafPgno>pIter->iLeafPgno ){ + fts5SegIterGotoPage(p, pIter, iLeafPgno); + bMove = 0; + } + }else{ + assert( pIter->pNextLeaf==0 ); + assert( iMatchiRowid ); + while( !fts5DlidxIterEof(p, pDlidx) && iMatchiLeafPgno ); + + if( iLeafPgnoiLeafPgno ){ + pIter->iLeafPgno = iLeafPgno+1; + fts5SegIterReverseNewPage(p, pIter); + bMove = 0; + } + } + + do{ + if( bMove && p->rc==SQLITE_OK ) pIter->xNext(p, pIter, 0); + if( pIter->pLeaf==0 ) break; + if( bRev==0 && pIter->iRowid>=iMatch ) break; + if( bRev!=0 && pIter->iRowid<=iMatch ) break; + bMove = 1; + }while( p->rc==SQLITE_OK ); +} + + +/* +** Free the iterator object passed as the second argument. +*/ +static void fts5MultiIterFree(Fts5Iter *pIter){ + if( pIter ){ + int i; + for(i=0; inSeg; i++){ + fts5SegIterClear(&pIter->aSeg[i]); + } + fts5StructureRelease(pIter->pStruct); + fts5BufferFree(&pIter->poslist); + sqlite3_free(pIter); + } +} + +static void fts5MultiIterAdvanced( + Fts5Index *p, /* FTS5 backend to iterate within */ + Fts5Iter *pIter, /* Iterator to update aFirst[] array for */ + int iChanged, /* Index of sub-iterator just advanced */ + int iMinset /* Minimum entry in aFirst[] to set */ +){ + int i; + for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){ + int iEq; + if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){ + Fts5SegIter *pSeg = &pIter->aSeg[iEq]; + assert( p->rc==SQLITE_OK ); + pSeg->xNext(p, pSeg, 0); + i = pIter->nSeg + iEq; + } + } +} + +/* +** Sub-iterator iChanged of iterator pIter has just been advanced. It still +** points to the same term though - just a different rowid. This function +** attempts to update the contents of the pIter->aFirst[] accordingly. +** If it does so successfully, 0 is returned. Otherwise 1. +** +** If non-zero is returned, the caller should call fts5MultiIterAdvanced() +** on the iterator instead. That function does the same as this one, except +** that it deals with more complicated cases as well. +*/ +static int fts5MultiIterAdvanceRowid( + Fts5Iter *pIter, /* Iterator to update aFirst[] array for */ + int iChanged, /* Index of sub-iterator just advanced */ + Fts5SegIter **ppFirst +){ + Fts5SegIter *pNew = &pIter->aSeg[iChanged]; + + if( pNew->iRowid==pIter->iSwitchRowid + || (pNew->iRowidiSwitchRowid)==pIter->bRev + ){ + int i; + Fts5SegIter *pOther = &pIter->aSeg[iChanged ^ 0x0001]; + pIter->iSwitchRowid = pIter->bRev ? SMALLEST_INT64 : LARGEST_INT64; + for(i=(pIter->nSeg+iChanged)/2; 1; i=i/2){ + Fts5CResult *pRes = &pIter->aFirst[i]; + + assert( pNew->pLeaf ); + assert( pRes->bTermEq==0 || pOther->pLeaf ); + + if( pRes->bTermEq ){ + if( pNew->iRowid==pOther->iRowid ){ + return 1; + }else if( (pOther->iRowid>pNew->iRowid)==pIter->bRev ){ + pIter->iSwitchRowid = pOther->iRowid; + pNew = pOther; + }else if( (pOther->iRowid>pIter->iSwitchRowid)==pIter->bRev ){ + pIter->iSwitchRowid = pOther->iRowid; + } + } + pRes->iFirst = (u16)(pNew - pIter->aSeg); + if( i==1 ) break; + + pOther = &pIter->aSeg[ pIter->aFirst[i ^ 0x0001].iFirst ]; + } + } + + *ppFirst = pNew; + return 0; +} + +/* +** Set the pIter->bEof variable based on the state of the sub-iterators. +*/ +static void fts5MultiIterSetEof(Fts5Iter *pIter){ + Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; + pIter->base.bEof = pSeg->pLeaf==0; + pIter->iSwitchRowid = pSeg->iRowid; +} + +/* +** Move the iterator to the next entry. +** +** If an error occurs, an error code is left in Fts5Index.rc. It is not +** considered an error if the iterator reaches EOF, or if it is already at +** EOF when this function is called. +*/ +static void fts5MultiIterNext( + Fts5Index *p, + Fts5Iter *pIter, + int bFrom, /* True if argument iFrom is valid */ + i64 iFrom /* Advance at least as far as this */ +){ + int bUseFrom = bFrom; + while( p->rc==SQLITE_OK ){ + int iFirst = pIter->aFirst[1].iFirst; + int bNewTerm = 0; + Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; + assert( p->rc==SQLITE_OK ); + if( bUseFrom && pSeg->pDlidx ){ + fts5SegIterNextFrom(p, pSeg, iFrom); + }else{ + pSeg->xNext(p, pSeg, &bNewTerm); + } + + if( pSeg->pLeaf==0 || bNewTerm + || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg) + ){ + fts5MultiIterAdvanced(p, pIter, iFirst, 1); + fts5MultiIterSetEof(pIter); + pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst]; + if( pSeg->pLeaf==0 ) return; + } + + fts5AssertMultiIterSetup(p, pIter); + assert( pSeg==&pIter->aSeg[pIter->aFirst[1].iFirst] && pSeg->pLeaf ); + if( pIter->bSkipEmpty==0 || pSeg->nPos ){ + pIter->xSetOutputs(pIter, pSeg); + return; + } + bUseFrom = 0; + } +} + +static void fts5MultiIterNext2( + Fts5Index *p, + Fts5Iter *pIter, + int *pbNewTerm /* OUT: True if *might* be new term */ +){ + assert( pIter->bSkipEmpty ); + if( p->rc==SQLITE_OK ){ + do { + int iFirst = pIter->aFirst[1].iFirst; + Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; + int bNewTerm = 0; + + assert( p->rc==SQLITE_OK ); + pSeg->xNext(p, pSeg, &bNewTerm); + if( pSeg->pLeaf==0 || bNewTerm + || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg) + ){ + fts5MultiIterAdvanced(p, pIter, iFirst, 1); + fts5MultiIterSetEof(pIter); + *pbNewTerm = 1; + }else{ + *pbNewTerm = 0; + } + fts5AssertMultiIterSetup(p, pIter); + + }while( fts5MultiIterIsEmpty(p, pIter) ); + } +} + +static void fts5IterSetOutputs_Noop(Fts5Iter *pUnused1, Fts5SegIter *pUnused2){ + UNUSED_PARAM2(pUnused1, pUnused2); +} + +static Fts5Iter *fts5MultiIterAlloc( + Fts5Index *p, /* FTS5 backend to iterate within */ + int nSeg +){ + Fts5Iter *pNew; + int nSlot; /* Power of two >= nSeg */ + + for(nSlot=2; nSlotaSeg[] */ + sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */ + ); + if( pNew ){ + pNew->nSeg = nSlot; + pNew->aFirst = (Fts5CResult*)&pNew->aSeg[nSlot]; + pNew->pIndex = p; + pNew->xSetOutputs = fts5IterSetOutputs_Noop; + } + return pNew; +} + +static void fts5PoslistCallback( + Fts5Index *pUnused, + void *pContext, + const u8 *pChunk, int nChunk +){ + UNUSED_PARAM(pUnused); + assert_nc( nChunk>=0 ); + if( nChunk>0 ){ + fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk); + } +} + +typedef struct PoslistCallbackCtx PoslistCallbackCtx; +struct PoslistCallbackCtx { + Fts5Buffer *pBuf; /* Append to this buffer */ + Fts5Colset *pColset; /* Restrict matches to this column */ + int eState; /* See above */ +}; + +typedef struct PoslistOffsetsCtx PoslistOffsetsCtx; +struct PoslistOffsetsCtx { + Fts5Buffer *pBuf; /* Append to this buffer */ + Fts5Colset *pColset; /* Restrict matches to this column */ + int iRead; + int iWrite; +}; + +/* +** TODO: Make this more efficient! +*/ +static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){ + int i; + for(i=0; inCol; i++){ + if( pColset->aiCol[i]==iCol ) return 1; + } + return 0; +} + +static void fts5PoslistOffsetsCallback( + Fts5Index *pUnused, + void *pContext, + const u8 *pChunk, int nChunk +){ + PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext; + UNUSED_PARAM(pUnused); + assert_nc( nChunk>=0 ); + if( nChunk>0 ){ + int i = 0; + while( iiRead - 2; + pCtx->iRead = iVal; + if( fts5IndexColsetTest(pCtx->pColset, iVal) ){ + fts5BufferSafeAppendVarint(pCtx->pBuf, iVal + 2 - pCtx->iWrite); + pCtx->iWrite = iVal; + } + } + } +} + +static void fts5PoslistFilterCallback( + Fts5Index *pUnused, + void *pContext, + const u8 *pChunk, int nChunk +){ + PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext; + UNUSED_PARAM(pUnused); + assert_nc( nChunk>=0 ); + if( nChunk>0 ){ + /* Search through to find the first varint with value 1. This is the + ** start of the next columns hits. */ + int i = 0; + int iStart = 0; + + if( pCtx->eState==2 ){ + int iCol; + fts5FastGetVarint32(pChunk, i, iCol); + if( fts5IndexColsetTest(pCtx->pColset, iCol) ){ + pCtx->eState = 1; + fts5BufferSafeAppendVarint(pCtx->pBuf, 1); + }else{ + pCtx->eState = 0; + } + } + + do { + while( ieState ){ + fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart); + } + if( i=nChunk ){ + pCtx->eState = 2; + }else{ + fts5FastGetVarint32(pChunk, i, iCol); + pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol); + if( pCtx->eState ){ + fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart); + iStart = i; + } + } + } + }while( inPos; /* Number of bytes still to come */ + Fts5Data *pData = 0; + u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset]; + int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset); + int pgno = pSeg->iLeafPgno; + int pgnoSave = 0; + + /* This function does notmwork with detail=none databases. */ + assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE ); + + if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){ + pgnoSave = pgno+1; + } + + while( 1 ){ + xChunk(p, pCtx, pChunk, nChunk); + nRem -= nChunk; + fts5DataRelease(pData); + if( nRem<=0 ){ + break; + }else{ + pgno++; + pData = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno)); + if( pData==0 ) break; + pChunk = &pData->p[4]; + nChunk = MIN(nRem, pData->szLeaf - 4); + if( pgno==pgnoSave ){ + assert( pSeg->pNextLeaf==0 ); + pSeg->pNextLeaf = pData; + pData = 0; + } + } + } +} + +/* +** Iterator pIter currently points to a valid entry (not EOF). This +** function appends the position list data for the current entry to +** buffer pBuf. It does not make a copy of the position-list size +** field. +*/ +static void fts5SegiterPoslist( + Fts5Index *p, + Fts5SegIter *pSeg, + Fts5Colset *pColset, + Fts5Buffer *pBuf +){ + if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){ + if( pColset==0 ){ + fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback); + }else{ + if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){ + PoslistCallbackCtx sCtx; + sCtx.pBuf = pBuf; + sCtx.pColset = pColset; + sCtx.eState = fts5IndexColsetTest(pColset, 0); + assert( sCtx.eState==0 || sCtx.eState==1 ); + fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback); + }else{ + PoslistOffsetsCtx sCtx; + memset(&sCtx, 0, sizeof(sCtx)); + sCtx.pBuf = pBuf; + sCtx.pColset = pColset; + fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback); + } + } + } +} + +/* +** IN/OUT parameter (*pa) points to a position list n bytes in size. If +** the position list contains entries for column iCol, then (*pa) is set +** to point to the sub-position-list for that column and the number of +** bytes in it returned. Or, if the argument position list does not +** contain any entries for column iCol, return 0. +*/ +static int fts5IndexExtractCol( + const u8 **pa, /* IN/OUT: Pointer to poslist */ + int n, /* IN: Size of poslist in bytes */ + int iCol /* Column to extract from poslist */ +){ + int iCurrent = 0; /* Anything before the first 0x01 is col 0 */ + const u8 *p = *pa; + const u8 *pEnd = &p[n]; /* One byte past end of position list */ + + while( iCol>iCurrent ){ + /* Advance pointer p until it points to pEnd or an 0x01 byte that is + ** not part of a varint. Note that it is not possible for a negative + ** or extremely large varint to occur within an uncorrupted position + ** list. So the last byte of each varint may be assumed to have a clear + ** 0x80 bit. */ + while( *p!=0x01 ){ + while( *p++ & 0x80 ); + if( p>=pEnd ) return 0; + } + *pa = p++; + iCurrent = *p++; + if( iCurrent & 0x80 ){ + p--; + p += fts5GetVarint32(p, iCurrent); + } + } + if( iCol!=iCurrent ) return 0; + + /* Advance pointer p until it points to pEnd or an 0x01 byte that is + ** not part of a varint */ + while( pnCol; i++){ + const u8 *pSub = pPos; + int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]); + if( nSub ){ + fts5BufferAppendBlob(&rc, pBuf, nSub, pSub); + } + } + return rc; +} + +/* +** xSetOutputs callback used by detail=none tables. +*/ +static void fts5IterSetOutputs_None(Fts5Iter *pIter, Fts5SegIter *pSeg){ + assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_NONE ); + pIter->base.iRowid = pSeg->iRowid; + pIter->base.nData = pSeg->nPos; +} + +/* +** xSetOutputs callback used by detail=full and detail=col tables when no +** column filters are specified. +*/ +static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){ + pIter->base.iRowid = pSeg->iRowid; + pIter->base.nData = pSeg->nPos; + + assert( pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_NONE ); + assert( pIter->pColset==0 ); + + if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ + /* All data is stored on the current page. Populate the output + ** variables to point into the body of the page object. */ + pIter->base.pData = &pSeg->pLeaf->p[pSeg->iLeafOffset]; + }else{ + /* The data is distributed over two or more pages. Copy it into the + ** Fts5Iter.poslist buffer and then set the output pointer to point + ** to this buffer. */ + fts5BufferZero(&pIter->poslist); + fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist); + pIter->base.pData = pIter->poslist.p; + } +} + +/* +** xSetOutputs callback used by detail=col when there is a column filter +** and there are 100 or more columns. Also called as a fallback from +** fts5IterSetOutputs_Col100 if the column-list spans more than one page. +*/ +static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){ + fts5BufferZero(&pIter->poslist); + fts5SegiterPoslist(pIter->pIndex, pSeg, pIter->pColset, &pIter->poslist); + pIter->base.iRowid = pSeg->iRowid; + pIter->base.pData = pIter->poslist.p; + pIter->base.nData = pIter->poslist.n; +} + +/* +** xSetOutputs callback used when: +** +** * detail=col, +** * there is a column filter, and +** * the table contains 100 or fewer columns. +** +** The last point is to ensure all column numbers are stored as +** single-byte varints. +*/ +static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){ + + assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS ); + assert( pIter->pColset ); + + if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf ){ + fts5IterSetOutputs_Col(pIter, pSeg); + }else{ + u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset]; + u8 *pEnd = (u8*)&a[pSeg->nPos]; + int iPrev = 0; + int *aiCol = pIter->pColset->aiCol; + int *aiColEnd = &aiCol[pIter->pColset->nCol]; + + u8 *aOut = pIter->poslist.p; + int iPrevOut = 0; + + pIter->base.iRowid = pSeg->iRowid; + + while( abase.pData = pIter->poslist.p; + pIter->base.nData = aOut - pIter->poslist.p; + } +} + +/* +** xSetOutputs callback used by detail=full when there is a column filter. +*/ +static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){ + Fts5Colset *pColset = pIter->pColset; + pIter->base.iRowid = pSeg->iRowid; + + assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_FULL ); + assert( pColset ); + + if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ + /* All data is stored on the current page. Populate the output + ** variables to point into the body of the page object. */ + const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset]; + if( pColset->nCol==1 ){ + pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]); + pIter->base.pData = a; + }else{ + fts5BufferZero(&pIter->poslist); + fts5IndexExtractColset(pColset, a, pSeg->nPos, &pIter->poslist); + pIter->base.pData = pIter->poslist.p; + pIter->base.nData = pIter->poslist.n; + } + }else{ + /* The data is distributed over two or more pages. Copy it into the + ** Fts5Iter.poslist buffer and then set the output pointer to point + ** to this buffer. */ + fts5BufferZero(&pIter->poslist); + fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist); + pIter->base.pData = pIter->poslist.p; + pIter->base.nData = pIter->poslist.n; + } +} + +static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){ + if( *pRc==SQLITE_OK ){ + Fts5Config *pConfig = pIter->pIndex->pConfig; + if( pConfig->eDetail==FTS5_DETAIL_NONE ){ + pIter->xSetOutputs = fts5IterSetOutputs_None; + } + + else if( pIter->pColset==0 ){ + pIter->xSetOutputs = fts5IterSetOutputs_Nocolset; + } + + else if( pConfig->eDetail==FTS5_DETAIL_FULL ){ + pIter->xSetOutputs = fts5IterSetOutputs_Full; + } + + else{ + assert( pConfig->eDetail==FTS5_DETAIL_COLUMNS ); + if( pConfig->nCol<=100 ){ + pIter->xSetOutputs = fts5IterSetOutputs_Col100; + sqlite3Fts5BufferSize(pRc, &pIter->poslist, pConfig->nCol); + }else{ + pIter->xSetOutputs = fts5IterSetOutputs_Col; + } + } + } +} + + +/* +** Allocate a new Fts5Iter object. +** +** The new object will be used to iterate through data in structure pStruct. +** If iLevel is -ve, then all data in all segments is merged. Or, if iLevel +** is zero or greater, data from the first nSegment segments on level iLevel +** is merged. +** +** The iterator initially points to the first term/rowid entry in the +** iterated data. +*/ +static void fts5MultiIterNew( + Fts5Index *p, /* FTS5 backend to iterate within */ + Fts5Structure *pStruct, /* Structure of specific index */ + int flags, /* FTS5INDEX_QUERY_XXX flags */ + Fts5Colset *pColset, /* Colset to filter on (or NULL) */ + const u8 *pTerm, int nTerm, /* Term to seek to (or NULL/0) */ + int iLevel, /* Level to iterate (-1 for all) */ + int nSegment, /* Number of segments to merge (iLevel>=0) */ + Fts5Iter **ppOut /* New object */ +){ + int nSeg = 0; /* Number of segment-iters in use */ + int iIter = 0; /* */ + int iSeg; /* Used to iterate through segments */ + Fts5StructureLevel *pLvl; + Fts5Iter *pNew; + + assert( (pTerm==0 && nTerm==0) || iLevel<0 ); + + /* Allocate space for the new multi-seg-iterator. */ + if( p->rc==SQLITE_OK ){ + if( iLevel<0 ){ + assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) ); + nSeg = pStruct->nSegment; + nSeg += (p->pHash ? 1 : 0); + }else{ + nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment); + } + } + *ppOut = pNew = fts5MultiIterAlloc(p, nSeg); + if( pNew==0 ) return; + pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC)); + pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY)); + pNew->pStruct = pStruct; + pNew->pColset = pColset; + fts5StructureRef(pStruct); + if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){ + fts5IterSetOutputCb(&p->rc, pNew); + } + + /* Initialize each of the component segment iterators. */ + if( p->rc==SQLITE_OK ){ + if( iLevel<0 ){ + Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel]; + if( p->pHash ){ + /* Add a segment iterator for the current contents of the hash table. */ + Fts5SegIter *pIter = &pNew->aSeg[iIter++]; + fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter); + } + for(pLvl=&pStruct->aLevel[0]; pLvlnSeg-1; iSeg>=0; iSeg--){ + Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg]; + Fts5SegIter *pIter = &pNew->aSeg[iIter++]; + if( pTerm==0 ){ + fts5SegIterInit(p, pSeg, pIter); + }else{ + fts5SegIterSeekInit(p, pTerm, nTerm, flags, pSeg, pIter); + } + } + } + }else{ + pLvl = &pStruct->aLevel[iLevel]; + for(iSeg=nSeg-1; iSeg>=0; iSeg--){ + fts5SegIterInit(p, &pLvl->aSeg[iSeg], &pNew->aSeg[iIter++]); + } + } + assert( iIter==nSeg ); + } + + /* If the above was successful, each component iterators now points + ** to the first entry in its segment. In this case initialize the + ** aFirst[] array. Or, if an error has occurred, free the iterator + ** object and set the output variable to NULL. */ + if( p->rc==SQLITE_OK ){ + for(iIter=pNew->nSeg-1; iIter>0; iIter--){ + int iEq; + if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){ + Fts5SegIter *pSeg = &pNew->aSeg[iEq]; + if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0); + fts5MultiIterAdvanced(p, pNew, iEq, iIter); + } + } + fts5MultiIterSetEof(pNew); + fts5AssertMultiIterSetup(p, pNew); + + if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){ + fts5MultiIterNext(p, pNew, 0, 0); + }else if( pNew->base.bEof==0 ){ + Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst]; + pNew->xSetOutputs(pNew, pSeg); + } + + }else{ + fts5MultiIterFree(pNew); + *ppOut = 0; + } +} + +/* +** Create an Fts5Iter that iterates through the doclist provided +** as the second argument. +*/ +static void fts5MultiIterNew2( + Fts5Index *p, /* FTS5 backend to iterate within */ + Fts5Data *pData, /* Doclist to iterate through */ + int bDesc, /* True for descending rowid order */ + Fts5Iter **ppOut /* New object */ +){ + Fts5Iter *pNew; + pNew = fts5MultiIterAlloc(p, 2); + if( pNew ){ + Fts5SegIter *pIter = &pNew->aSeg[1]; + + pIter->flags = FTS5_SEGITER_ONETERM; + if( pData->szLeaf>0 ){ + pIter->pLeaf = pData; + pIter->iLeafOffset = fts5GetVarint(pData->p, (u64*)&pIter->iRowid); + pIter->iEndofDoclist = pData->nn; + pNew->aFirst[1].iFirst = 1; + if( bDesc ){ + pNew->bRev = 1; + pIter->flags |= FTS5_SEGITER_REVERSE; + fts5SegIterReverseInitPage(p, pIter); + }else{ + fts5SegIterLoadNPos(p, pIter); + } + pData = 0; + }else{ + pNew->base.bEof = 1; + } + fts5SegIterSetNext(p, pIter); + + *ppOut = pNew; + } + + fts5DataRelease(pData); +} + +/* +** Return true if the iterator is at EOF or if an error has occurred. +** False otherwise. +*/ +static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){ + assert( p->rc + || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof + ); + return (p->rc || pIter->base.bEof); +} + +/* +** Return the rowid of the entry that the iterator currently points +** to. If the iterator points to EOF when this function is called the +** results are undefined. +*/ +static i64 fts5MultiIterRowid(Fts5Iter *pIter){ + assert( pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf ); + return pIter->aSeg[ pIter->aFirst[1].iFirst ].iRowid; +} + +/* +** Move the iterator to the next entry at or following iMatch. +*/ +static void fts5MultiIterNextFrom( + Fts5Index *p, + Fts5Iter *pIter, + i64 iMatch +){ + while( 1 ){ + i64 iRowid; + fts5MultiIterNext(p, pIter, 1, iMatch); + if( fts5MultiIterEof(p, pIter) ) break; + iRowid = fts5MultiIterRowid(pIter); + if( pIter->bRev==0 && iRowid>=iMatch ) break; + if( pIter->bRev!=0 && iRowid<=iMatch ) break; + } +} + +/* +** Return a pointer to a buffer containing the term associated with the +** entry that the iterator currently points to. +*/ +static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){ + Fts5SegIter *p = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; + *pn = p->term.n; + return p->term.p; +} + +/* +** Allocate a new segment-id for the structure pStruct. The new segment +** id must be between 1 and 65335 inclusive, and must not be used by +** any currently existing segment. If a free segment id cannot be found, +** SQLITE_FULL is returned. +** +** If an error has already occurred, this function is a no-op. 0 is +** returned in this case. +*/ +static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){ + int iSegid = 0; + + if( p->rc==SQLITE_OK ){ + if( pStruct->nSegment>=FTS5_MAX_SEGMENT ){ + p->rc = SQLITE_FULL; + }else{ + while( iSegid==0 ){ + int iLvl, iSeg; + sqlite3_randomness(sizeof(u32), (void*)&iSegid); + iSegid = iSegid & ((1 << FTS5_DATA_ID_B)-1); + for(iLvl=0; iLvlnLevel; iLvl++){ + for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ + if( iSegid==pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ){ + iSegid = 0; + } + } + } + } + } + } + + return iSegid; +} + +/* +** Discard all data currently cached in the hash-tables. +*/ +static void fts5IndexDiscardData(Fts5Index *p){ + assert( p->pHash || p->nPendingData==0 ); + if( p->pHash ){ + sqlite3Fts5HashClear(p->pHash); + p->nPendingData = 0; + } +} + +/* +** Return the size of the prefix, in bytes, that buffer +** (pNew/) shares with buffer (pOld/nOld). +** +** Buffer (pNew/) is guaranteed to be greater +** than buffer (pOld/nOld). +*/ +static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){ + int i; + for(i=0; inDlidx>0 && pWriter->aDlidx[0].buf.n>0) ); + for(i=0; inDlidx; i++){ + Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[i]; + if( pDlidx->buf.n==0 ) break; + if( bFlush ){ + assert( pDlidx->pgno!=0 ); + fts5DataWrite(p, + FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno), + pDlidx->buf.p, pDlidx->buf.n + ); + } + sqlite3Fts5BufferZero(&pDlidx->buf); + pDlidx->bPrevValid = 0; + } +} + +/* +** Grow the pWriter->aDlidx[] array to at least nLvl elements in size. +** Any new array elements are zeroed before returning. +*/ +static int fts5WriteDlidxGrow( + Fts5Index *p, + Fts5SegWriter *pWriter, + int nLvl +){ + if( p->rc==SQLITE_OK && nLvl>=pWriter->nDlidx ){ + Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc( + pWriter->aDlidx, sizeof(Fts5DlidxWriter) * nLvl + ); + if( aDlidx==0 ){ + p->rc = SQLITE_NOMEM; + }else{ + int nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx); + memset(&aDlidx[pWriter->nDlidx], 0, nByte); + pWriter->aDlidx = aDlidx; + pWriter->nDlidx = nLvl; + } + } + return p->rc; +} + +/* +** If the current doclist-index accumulating in pWriter->aDlidx[] is large +** enough, flush it to disk and return 1. Otherwise discard it and return +** zero. +*/ +static int fts5WriteFlushDlidx(Fts5Index *p, Fts5SegWriter *pWriter){ + int bFlag = 0; + + /* If there were FTS5_MIN_DLIDX_SIZE or more empty leaf pages written + ** to the database, also write the doclist-index to disk. */ + if( pWriter->aDlidx[0].buf.n>0 && pWriter->nEmpty>=FTS5_MIN_DLIDX_SIZE ){ + bFlag = 1; + } + fts5WriteDlidxClear(p, pWriter, bFlag); + pWriter->nEmpty = 0; + return bFlag; +} + +/* +** This function is called whenever processing of the doclist for the +** last term on leaf page (pWriter->iBtPage) is completed. +** +** The doclist-index for that term is currently stored in-memory within the +** Fts5SegWriter.aDlidx[] array. If it is large enough, this function +** writes it out to disk. Or, if it is too small to bother with, discards +** it. +** +** Fts5SegWriter.btterm currently contains the first term on page iBtPage. +*/ +static void fts5WriteFlushBtree(Fts5Index *p, Fts5SegWriter *pWriter){ + int bFlag; + + assert( pWriter->iBtPage || pWriter->nEmpty==0 ); + if( pWriter->iBtPage==0 ) return; + bFlag = fts5WriteFlushDlidx(p, pWriter); + + if( p->rc==SQLITE_OK ){ + const char *z = (pWriter->btterm.n>0?(const char*)pWriter->btterm.p:""); + /* The following was already done in fts5WriteInit(): */ + /* sqlite3_bind_int(p->pIdxWriter, 1, pWriter->iSegid); */ + sqlite3_bind_blob(p->pIdxWriter, 2, z, pWriter->btterm.n, SQLITE_STATIC); + sqlite3_bind_int64(p->pIdxWriter, 3, bFlag + ((i64)pWriter->iBtPage<<1)); + sqlite3_step(p->pIdxWriter); + p->rc = sqlite3_reset(p->pIdxWriter); + } + pWriter->iBtPage = 0; +} + +/* +** This is called once for each leaf page except the first that contains +** at least one term. Argument (nTerm/pTerm) is the split-key - a term that +** is larger than all terms written to earlier leaves, and equal to or +** smaller than the first term on the new leaf. +** +** If an error occurs, an error code is left in Fts5Index.rc. If an error +** has already occurred when this function is called, it is a no-op. +*/ +static void fts5WriteBtreeTerm( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegWriter *pWriter, /* Writer object */ + int nTerm, const u8 *pTerm /* First term on new page */ +){ + fts5WriteFlushBtree(p, pWriter); + fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm); + pWriter->iBtPage = pWriter->writer.pgno; +} + +/* +** This function is called when flushing a leaf page that contains no +** terms at all to disk. +*/ +static void fts5WriteBtreeNoTerm( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegWriter *pWriter /* Writer object */ +){ + /* If there were no rowids on the leaf page either and the doclist-index + ** has already been started, append an 0x00 byte to it. */ + if( pWriter->bFirstRowidInPage && pWriter->aDlidx[0].buf.n>0 ){ + Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[0]; + assert( pDlidx->bPrevValid ); + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, 0); + } + + /* Increment the "number of sequential leaves without a term" counter. */ + pWriter->nEmpty++; +} + +static i64 fts5DlidxExtractFirstRowid(Fts5Buffer *pBuf){ + i64 iRowid; + int iOff; + + iOff = 1 + fts5GetVarint(&pBuf->p[1], (u64*)&iRowid); + fts5GetVarint(&pBuf->p[iOff], (u64*)&iRowid); + return iRowid; +} + +/* +** Rowid iRowid has just been appended to the current leaf page. It is the +** first on the page. This function appends an appropriate entry to the current +** doclist-index. +*/ +static void fts5WriteDlidxAppend( + Fts5Index *p, + Fts5SegWriter *pWriter, + i64 iRowid +){ + int i; + int bDone = 0; + + for(i=0; p->rc==SQLITE_OK && bDone==0; i++){ + i64 iVal; + Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[i]; + + if( pDlidx->buf.n>=p->pConfig->pgsz ){ + /* The current doclist-index page is full. Write it to disk and push + ** a copy of iRowid (which will become the first rowid on the next + ** doclist-index leaf page) up into the next level of the b-tree + ** hierarchy. If the node being flushed is currently the root node, + ** also push its first rowid upwards. */ + pDlidx->buf.p[0] = 0x01; /* Not the root node */ + fts5DataWrite(p, + FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno), + pDlidx->buf.p, pDlidx->buf.n + ); + fts5WriteDlidxGrow(p, pWriter, i+2); + pDlidx = &pWriter->aDlidx[i]; + if( p->rc==SQLITE_OK && pDlidx[1].buf.n==0 ){ + i64 iFirst = fts5DlidxExtractFirstRowid(&pDlidx->buf); + + /* This was the root node. Push its first rowid up to the new root. */ + pDlidx[1].pgno = pDlidx->pgno; + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, 0); + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, pDlidx->pgno); + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, iFirst); + pDlidx[1].bPrevValid = 1; + pDlidx[1].iPrev = iFirst; + } + + sqlite3Fts5BufferZero(&pDlidx->buf); + pDlidx->bPrevValid = 0; + pDlidx->pgno++; + }else{ + bDone = 1; + } + + if( pDlidx->bPrevValid ){ + iVal = iRowid - pDlidx->iPrev; + }else{ + i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno); + assert( pDlidx->buf.n==0 ); + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, !bDone); + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, iPgno); + iVal = iRowid; + } + + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, iVal); + pDlidx->bPrevValid = 1; + pDlidx->iPrev = iRowid; + } +} + +static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){ + static const u8 zero[] = { 0x00, 0x00, 0x00, 0x00 }; + Fts5PageWriter *pPage = &pWriter->writer; + i64 iRowid; + + assert( (pPage->pgidx.n==0)==(pWriter->bFirstTermInPage) ); + + /* Set the szLeaf header field. */ + assert( 0==fts5GetU16(&pPage->buf.p[2]) ); + fts5PutU16(&pPage->buf.p[2], (u16)pPage->buf.n); + + if( pWriter->bFirstTermInPage ){ + /* No term was written to this page. */ + assert( pPage->pgidx.n==0 ); + fts5WriteBtreeNoTerm(p, pWriter); + }else{ + /* Append the pgidx to the page buffer. Set the szLeaf header field. */ + fts5BufferAppendBlob(&p->rc, &pPage->buf, pPage->pgidx.n, pPage->pgidx.p); + } + + /* Write the page out to disk */ + iRowid = FTS5_SEGMENT_ROWID(pWriter->iSegid, pPage->pgno); + fts5DataWrite(p, iRowid, pPage->buf.p, pPage->buf.n); + + /* Initialize the next page. */ + fts5BufferZero(&pPage->buf); + fts5BufferZero(&pPage->pgidx); + fts5BufferAppendBlob(&p->rc, &pPage->buf, 4, zero); + pPage->iPrevPgidx = 0; + pPage->pgno++; + + /* Increase the leaves written counter */ + pWriter->nLeafWritten++; + + /* The new leaf holds no terms or rowids */ + pWriter->bFirstTermInPage = 1; + pWriter->bFirstRowidInPage = 1; +} + +/* +** Append term pTerm/nTerm to the segment being written by the writer passed +** as the second argument. +** +** If an error occurs, set the Fts5Index.rc error code. If an error has +** already occurred, this function is a no-op. +*/ +static void fts5WriteAppendTerm( + Fts5Index *p, + Fts5SegWriter *pWriter, + int nTerm, const u8 *pTerm +){ + int nPrefix; /* Bytes of prefix compression for term */ + Fts5PageWriter *pPage = &pWriter->writer; + Fts5Buffer *pPgidx = &pWriter->writer.pgidx; + + assert( p->rc==SQLITE_OK ); + assert( pPage->buf.n>=4 ); + assert( pPage->buf.n>4 || pWriter->bFirstTermInPage ); + + /* If the current leaf page is full, flush it to disk. */ + if( (pPage->buf.n + pPgidx->n + nTerm + 2)>=p->pConfig->pgsz ){ + if( pPage->buf.n>4 ){ + fts5WriteFlushLeaf(p, pWriter); + } + fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING); + } + + /* TODO1: Updating pgidx here. */ + pPgidx->n += sqlite3Fts5PutVarint( + &pPgidx->p[pPgidx->n], pPage->buf.n - pPage->iPrevPgidx + ); + pPage->iPrevPgidx = pPage->buf.n; +#if 0 + fts5PutU16(&pPgidx->p[pPgidx->n], pPage->buf.n); + pPgidx->n += 2; +#endif + + if( pWriter->bFirstTermInPage ){ + nPrefix = 0; + if( pPage->pgno!=1 ){ + /* This is the first term on a leaf that is not the leftmost leaf in + ** the segment b-tree. In this case it is necessary to add a term to + ** the b-tree hierarchy that is (a) larger than the largest term + ** already written to the segment and (b) smaller than or equal to + ** this term. In other words, a prefix of (pTerm/nTerm) that is one + ** byte longer than the longest prefix (pTerm/nTerm) shares with the + ** previous term. + ** + ** Usually, the previous term is available in pPage->term. The exception + ** is if this is the first term written in an incremental-merge step. + ** In this case the previous term is not available, so just write a + ** copy of (pTerm/nTerm) into the parent node. This is slightly + ** inefficient, but still correct. */ + int n = nTerm; + if( pPage->term.n ){ + n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm); + } + fts5WriteBtreeTerm(p, pWriter, n, pTerm); + pPage = &pWriter->writer; + } + }else{ + nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm); + fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix); + } + + /* Append the number of bytes of new data, then the term data itself + ** to the page. */ + fts5BufferAppendVarint(&p->rc, &pPage->buf, nTerm - nPrefix); + fts5BufferAppendBlob(&p->rc, &pPage->buf, nTerm - nPrefix, &pTerm[nPrefix]); + + /* Update the Fts5PageWriter.term field. */ + fts5BufferSet(&p->rc, &pPage->term, nTerm, pTerm); + pWriter->bFirstTermInPage = 0; + + pWriter->bFirstRowidInPage = 0; + pWriter->bFirstRowidInDoclist = 1; + + assert( p->rc || (pWriter->nDlidx>0 && pWriter->aDlidx[0].buf.n==0) ); + pWriter->aDlidx[0].pgno = pPage->pgno; +} + +/* +** Append a rowid and position-list size field to the writers output. +*/ +static void fts5WriteAppendRowid( + Fts5Index *p, + Fts5SegWriter *pWriter, + i64 iRowid +){ + if( p->rc==SQLITE_OK ){ + Fts5PageWriter *pPage = &pWriter->writer; + + if( (pPage->buf.n + pPage->pgidx.n)>=p->pConfig->pgsz ){ + fts5WriteFlushLeaf(p, pWriter); + } + + /* If this is to be the first rowid written to the page, set the + ** rowid-pointer in the page-header. Also append a value to the dlidx + ** buffer, in case a doclist-index is required. */ + if( pWriter->bFirstRowidInPage ){ + fts5PutU16(pPage->buf.p, (u16)pPage->buf.n); + fts5WriteDlidxAppend(p, pWriter, iRowid); + } + + /* Write the rowid. */ + if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){ + fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid); + }else{ + assert( p->rc || iRowid>pWriter->iPrevRowid ); + fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid); + } + pWriter->iPrevRowid = iRowid; + pWriter->bFirstRowidInDoclist = 0; + pWriter->bFirstRowidInPage = 0; + } +} + +static void fts5WriteAppendPoslistData( + Fts5Index *p, + Fts5SegWriter *pWriter, + const u8 *aData, + int nData +){ + Fts5PageWriter *pPage = &pWriter->writer; + const u8 *a = aData; + int n = nData; + + assert( p->pConfig->pgsz>0 ); + while( p->rc==SQLITE_OK + && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz + ){ + int nReq = p->pConfig->pgsz - pPage->buf.n - pPage->pgidx.n; + int nCopy = 0; + while( nCopyrc, &pPage->buf, nCopy, a); + a += nCopy; + n -= nCopy; + fts5WriteFlushLeaf(p, pWriter); + } + if( n>0 ){ + fts5BufferAppendBlob(&p->rc, &pPage->buf, n, a); + } +} + +/* +** Flush any data cached by the writer object to the database. Free any +** allocations associated with the writer. +*/ +static void fts5WriteFinish( + Fts5Index *p, + Fts5SegWriter *pWriter, /* Writer object */ + int *pnLeaf /* OUT: Number of leaf pages in b-tree */ +){ + int i; + Fts5PageWriter *pLeaf = &pWriter->writer; + if( p->rc==SQLITE_OK ){ + assert( pLeaf->pgno>=1 ); + if( pLeaf->buf.n>4 ){ + fts5WriteFlushLeaf(p, pWriter); + } + *pnLeaf = pLeaf->pgno-1; + fts5WriteFlushBtree(p, pWriter); + } + fts5BufferFree(&pLeaf->term); + fts5BufferFree(&pLeaf->buf); + fts5BufferFree(&pLeaf->pgidx); + fts5BufferFree(&pWriter->btterm); + + for(i=0; inDlidx; i++){ + sqlite3Fts5BufferFree(&pWriter->aDlidx[i].buf); + } + sqlite3_free(pWriter->aDlidx); +} + +static void fts5WriteInit( + Fts5Index *p, + Fts5SegWriter *pWriter, + int iSegid +){ + const int nBuffer = p->pConfig->pgsz + FTS5_DATA_PADDING; + + memset(pWriter, 0, sizeof(Fts5SegWriter)); + pWriter->iSegid = iSegid; + + fts5WriteDlidxGrow(p, pWriter, 1); + pWriter->writer.pgno = 1; + pWriter->bFirstTermInPage = 1; + pWriter->iBtPage = 1; + + assert( pWriter->writer.buf.n==0 ); + assert( pWriter->writer.pgidx.n==0 ); + + /* Grow the two buffers to pgsz + padding bytes in size. */ + sqlite3Fts5BufferSize(&p->rc, &pWriter->writer.pgidx, nBuffer); + sqlite3Fts5BufferSize(&p->rc, &pWriter->writer.buf, nBuffer); + + if( p->pIdxWriter==0 ){ + Fts5Config *pConfig = p->pConfig; + fts5IndexPrepareStmt(p, &p->pIdxWriter, sqlite3_mprintf( + "INSERT INTO '%q'.'%q_idx'(segid,term,pgno) VALUES(?,?,?)", + pConfig->zDb, pConfig->zName + )); + } + + if( p->rc==SQLITE_OK ){ + /* Initialize the 4-byte leaf-page header to 0x00. */ + memset(pWriter->writer.buf.p, 0, 4); + pWriter->writer.buf.n = 4; + + /* Bind the current output segment id to the index-writer. This is an + ** optimization over binding the same value over and over as rows are + ** inserted into %_idx by the current writer. */ + sqlite3_bind_int(p->pIdxWriter, 1, pWriter->iSegid); + } +} + +/* +** Iterator pIter was used to iterate through the input segments of on an +** incremental merge operation. This function is called if the incremental +** merge step has finished but the input has not been completely exhausted. +*/ +static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ + int i; + Fts5Buffer buf; + memset(&buf, 0, sizeof(Fts5Buffer)); + for(i=0; inSeg; i++){ + Fts5SegIter *pSeg = &pIter->aSeg[i]; + if( pSeg->pSeg==0 ){ + /* no-op */ + }else if( pSeg->pLeaf==0 ){ + /* All keys from this input segment have been transfered to the output. + ** Set both the first and last page-numbers to 0 to indicate that the + ** segment is now empty. */ + pSeg->pSeg->pgnoLast = 0; + pSeg->pSeg->pgnoFirst = 0; + }else{ + int iOff = pSeg->iTermLeafOffset; /* Offset on new first leaf page */ + i64 iLeafRowid; + Fts5Data *pData; + int iId = pSeg->pSeg->iSegid; + u8 aHdr[4] = {0x00, 0x00, 0x00, 0x00}; + + iLeafRowid = FTS5_SEGMENT_ROWID(iId, pSeg->iTermLeafPgno); + pData = fts5DataRead(p, iLeafRowid); + if( pData ){ + fts5BufferZero(&buf); + fts5BufferGrow(&p->rc, &buf, pData->nn); + fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr); + fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n); + fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p); + fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff, &pData->p[iOff]); + if( p->rc==SQLITE_OK ){ + /* Set the szLeaf field */ + fts5PutU16(&buf.p[2], (u16)buf.n); + } + + /* Set up the new page-index array */ + fts5BufferAppendVarint(&p->rc, &buf, 4); + if( pSeg->iLeafPgno==pSeg->iTermLeafPgno + && pSeg->iEndofDoclistszLeaf + ){ + int nDiff = pData->szLeaf - pSeg->iEndofDoclist; + fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4); + fts5BufferAppendBlob(&p->rc, &buf, + pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff] + ); + } + + fts5DataRelease(pData); + pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno; + fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid); + fts5DataWrite(p, iLeafRowid, buf.p, buf.n); + } + } + } + fts5BufferFree(&buf); +} + +static void fts5MergeChunkCallback( + Fts5Index *p, + void *pCtx, + const u8 *pChunk, int nChunk +){ + Fts5SegWriter *pWriter = (Fts5SegWriter*)pCtx; + fts5WriteAppendPoslistData(p, pWriter, pChunk, nChunk); +} + +/* +** +*/ +static void fts5IndexMergeLevel( + Fts5Index *p, /* FTS5 backend object */ + Fts5Structure **ppStruct, /* IN/OUT: Stucture of index */ + int iLvl, /* Level to read input from */ + int *pnRem /* Write up to this many output leaves */ +){ + Fts5Structure *pStruct = *ppStruct; + Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; + Fts5StructureLevel *pLvlOut; + Fts5Iter *pIter = 0; /* Iterator to read input data */ + int nRem = pnRem ? *pnRem : 0; /* Output leaf pages left to write */ + int nInput; /* Number of input segments */ + Fts5SegWriter writer; /* Writer object */ + Fts5StructureSegment *pSeg; /* Output segment */ + Fts5Buffer term; + int bOldest; /* True if the output segment is the oldest */ + int eDetail = p->pConfig->eDetail; + const int flags = FTS5INDEX_QUERY_NOOUTPUT; + + assert( iLvlnLevel ); + assert( pLvl->nMerge<=pLvl->nSeg ); + + memset(&writer, 0, sizeof(Fts5SegWriter)); + memset(&term, 0, sizeof(Fts5Buffer)); + if( pLvl->nMerge ){ + pLvlOut = &pStruct->aLevel[iLvl+1]; + assert( pLvlOut->nSeg>0 ); + nInput = pLvl->nMerge; + pSeg = &pLvlOut->aSeg[pLvlOut->nSeg-1]; + + fts5WriteInit(p, &writer, pSeg->iSegid); + writer.writer.pgno = pSeg->pgnoLast+1; + writer.iBtPage = 0; + }else{ + int iSegid = fts5AllocateSegid(p, pStruct); + + /* Extend the Fts5Structure object as required to ensure the output + ** segment exists. */ + if( iLvl==pStruct->nLevel-1 ){ + fts5StructureAddLevel(&p->rc, ppStruct); + pStruct = *ppStruct; + } + fts5StructureExtendLevel(&p->rc, pStruct, iLvl+1, 1, 0); + if( p->rc ) return; + pLvl = &pStruct->aLevel[iLvl]; + pLvlOut = &pStruct->aLevel[iLvl+1]; + + fts5WriteInit(p, &writer, iSegid); + + /* Add the new segment to the output level */ + pSeg = &pLvlOut->aSeg[pLvlOut->nSeg]; + pLvlOut->nSeg++; + pSeg->pgnoFirst = 1; + pSeg->iSegid = iSegid; + pStruct->nSegment++; + + /* Read input from all segments in the input level */ + nInput = pLvl->nSeg; + } + bOldest = (pLvlOut->nSeg==1 && pStruct->nLevel==iLvl+2); + + assert( iLvl>=0 ); + for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, iLvl, nInput, &pIter); + fts5MultiIterEof(p, pIter)==0; + fts5MultiIterNext(p, pIter, 0, 0) + ){ + Fts5SegIter *pSegIter = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; + int nPos; /* position-list size field value */ + int nTerm; + const u8 *pTerm; + + /* Check for key annihilation. */ + if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue; + + pTerm = fts5MultiIterTerm(pIter, &nTerm); + if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){ + if( pnRem && writer.nLeafWritten>nRem ){ + break; + } + + /* This is a new term. Append a term to the output segment. */ + fts5WriteAppendTerm(p, &writer, nTerm, pTerm); + fts5BufferSet(&p->rc, &term, nTerm, pTerm); + } + + /* Append the rowid to the output */ + /* WRITEPOSLISTSIZE */ + fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter)); + + if( eDetail==FTS5_DETAIL_NONE ){ + if( pSegIter->bDel ){ + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0); + if( pSegIter->nPos>0 ){ + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0); + } + } + }else{ + /* Append the position-list data to the output */ + nPos = pSegIter->nPos*2 + pSegIter->bDel; + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, nPos); + fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback); + } + } + + /* Flush the last leaf page to disk. Set the output segment b-tree height + ** and last leaf page number at the same time. */ + fts5WriteFinish(p, &writer, &pSeg->pgnoLast); + + if( fts5MultiIterEof(p, pIter) ){ + int i; + + /* Remove the redundant segments from the %_data table */ + for(i=0; iaSeg[i].iSegid); + } + + /* Remove the redundant segments from the input level */ + if( pLvl->nSeg!=nInput ){ + int nMove = (pLvl->nSeg - nInput) * sizeof(Fts5StructureSegment); + memmove(pLvl->aSeg, &pLvl->aSeg[nInput], nMove); + } + pStruct->nSegment -= nInput; + pLvl->nSeg -= nInput; + pLvl->nMerge = 0; + if( pSeg->pgnoLast==0 ){ + pLvlOut->nSeg--; + pStruct->nSegment--; + } + }else{ + assert( pSeg->pgnoLast>0 ); + fts5TrimSegments(p, pIter); + pLvl->nMerge = nInput; + } + + fts5MultiIterFree(pIter); + fts5BufferFree(&term); + if( pnRem ) *pnRem -= writer.nLeafWritten; +} + +/* +** Do up to nPg pages of automerge work on the index. +*/ +static void fts5IndexMerge( + Fts5Index *p, /* FTS5 backend object */ + Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */ + int nPg /* Pages of work to do */ +){ + int nRem = nPg; + Fts5Structure *pStruct = *ppStruct; + while( nRem>0 && p->rc==SQLITE_OK ){ + int iLvl; /* To iterate through levels */ + int iBestLvl = 0; /* Level offering the most input segments */ + int nBest = 0; /* Number of input segments on best level */ + + /* Set iBestLvl to the level to read input segments from. */ + assert( pStruct->nLevel>0 ); + for(iLvl=0; iLvlnLevel; iLvl++){ + Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; + if( pLvl->nMerge ){ + if( pLvl->nMerge>nBest ){ + iBestLvl = iLvl; + nBest = pLvl->nMerge; + } + break; + } + if( pLvl->nSeg>nBest ){ + nBest = pLvl->nSeg; + iBestLvl = iLvl; + } + } + + /* If nBest is still 0, then the index must be empty. */ +#ifdef SQLITE_DEBUG + for(iLvl=0; nBest==0 && iLvlnLevel; iLvl++){ + assert( pStruct->aLevel[iLvl].nSeg==0 ); + } +#endif + + if( nBestpConfig->nAutomerge + && pStruct->aLevel[iBestLvl].nMerge==0 + ){ + break; + } + fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem); + if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){ + fts5StructurePromote(p, iBestLvl+1, pStruct); + } + } + *ppStruct = pStruct; +} + +/* +** A total of nLeaf leaf pages of data has just been flushed to a level-0 +** segment. This function updates the write-counter accordingly and, if +** necessary, performs incremental merge work. +** +** If an error occurs, set the Fts5Index.rc error code. If an error has +** already occurred, this function is a no-op. +*/ +static void fts5IndexAutomerge( + Fts5Index *p, /* FTS5 backend object */ + Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */ + int nLeaf /* Number of output leaves just written */ +){ + if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 ){ + Fts5Structure *pStruct = *ppStruct; + u64 nWrite; /* Initial value of write-counter */ + int nWork; /* Number of work-quanta to perform */ + int nRem; /* Number of leaf pages left to write */ + + /* Update the write-counter. While doing so, set nWork. */ + nWrite = pStruct->nWriteCounter; + nWork = (int)(((nWrite + nLeaf) / p->nWorkUnit) - (nWrite / p->nWorkUnit)); + pStruct->nWriteCounter += nLeaf; + nRem = (int)(p->nWorkUnit * nWork * pStruct->nLevel); + + fts5IndexMerge(p, ppStruct, nRem); + } +} + +static void fts5IndexCrisismerge( + Fts5Index *p, /* FTS5 backend object */ + Fts5Structure **ppStruct /* IN/OUT: Current structure of index */ +){ + const int nCrisis = p->pConfig->nCrisisMerge; + Fts5Structure *pStruct = *ppStruct; + int iLvl = 0; + + assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 ); + while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){ + fts5IndexMergeLevel(p, &pStruct, iLvl, 0); + assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) ); + fts5StructurePromote(p, iLvl+1, pStruct); + iLvl++; + } + *ppStruct = pStruct; +} + +static int fts5IndexReturn(Fts5Index *p){ + int rc = p->rc; + p->rc = SQLITE_OK; + return rc; +} + +typedef struct Fts5FlushCtx Fts5FlushCtx; +struct Fts5FlushCtx { + Fts5Index *pIdx; + Fts5SegWriter writer; +}; + +/* +** Buffer aBuf[] contains a list of varints, all small enough to fit +** in a 32-bit integer. Return the size of the largest prefix of this +** list nMax bytes or less in size. +*/ +static int fts5PoslistPrefix(const u8 *aBuf, int nMax){ + int ret; + u32 dummy; + ret = fts5GetVarint32(aBuf, dummy); + if( ret nMax ) break; + ret += i; + } + } + return ret; +} + +/* +** Flush the contents of in-memory hash table iHash to a new level-0 +** segment on disk. Also update the corresponding structure record. +** +** If an error occurs, set the Fts5Index.rc error code. If an error has +** already occurred, this function is a no-op. +*/ +static void fts5FlushOneHash(Fts5Index *p){ + Fts5Hash *pHash = p->pHash; + Fts5Structure *pStruct; + int iSegid; + int pgnoLast = 0; /* Last leaf page number in segment */ + + /* Obtain a reference to the index structure and allocate a new segment-id + ** for the new level-0 segment. */ + pStruct = fts5StructureRead(p); + iSegid = fts5AllocateSegid(p, pStruct); + + if( iSegid ){ + const int pgsz = p->pConfig->pgsz; + int eDetail = p->pConfig->eDetail; + Fts5StructureSegment *pSeg; /* New segment within pStruct */ + Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */ + Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */ + + Fts5SegWriter writer; + fts5WriteInit(p, &writer, iSegid); + + pBuf = &writer.writer.buf; + pPgidx = &writer.writer.pgidx; + + /* fts5WriteInit() should have initialized the buffers to (most likely) + ** the maximum space required. */ + assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) ); + assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) ); + + /* Begin scanning through hash table entries. This loop runs once for each + ** term/doclist currently stored within the hash table. */ + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3Fts5HashScanInit(pHash, 0, 0); + } + while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){ + const char *zTerm; /* Buffer containing term */ + const u8 *pDoclist; /* Pointer to doclist for this term */ + int nDoclist; /* Size of doclist in bytes */ + + /* Write the term for this entry to disk. */ + sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist); + fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm); + + assert( writer.bFirstRowidInPage==0 ); + if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){ + /* The entire doclist will fit on the current leaf. */ + fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist); + }else{ + i64 iRowid = 0; + i64 iDelta = 0; + int iOff = 0; + + /* The entire doclist will not fit on this leaf. The following + ** loop iterates through the poslists that make up the current + ** doclist. */ + while( p->rc==SQLITE_OK && iOffp[0], (u16)pBuf->n); /* first rowid on page */ + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid); + writer.bFirstRowidInPage = 0; + fts5WriteDlidxAppend(p, &writer, iRowid); + }else{ + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta); + } + assert( pBuf->n<=pBuf->nSpace ); + + if( eDetail==FTS5_DETAIL_NONE ){ + if( iOffp[pBuf->n++] = 0; + iOff++; + if( iOffp[pBuf->n++] = 0; + iOff++; + } + } + if( (pBuf->n + pPgidx->n)>=pgsz ){ + fts5WriteFlushLeaf(p, &writer); + } + }else{ + int bDummy; + int nPos; + int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy); + nCopy += nPos; + if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){ + /* The entire poslist will fit on the current leaf. So copy + ** it in one go. */ + fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy); + }else{ + /* The entire poslist will not fit on this leaf. So it needs + ** to be broken into sections. The only qualification being + ** that each varint must be stored contiguously. */ + const u8 *pPoslist = &pDoclist[iOff]; + int iPos = 0; + while( p->rc==SQLITE_OK ){ + int nSpace = pgsz - pBuf->n - pPgidx->n; + int n = 0; + if( (nCopy - iPos)<=nSpace ){ + n = nCopy - iPos; + }else{ + n = fts5PoslistPrefix(&pPoslist[iPos], nSpace); + } + assert( n>0 ); + fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n); + iPos += n; + if( (pBuf->n + pPgidx->n)>=pgsz ){ + fts5WriteFlushLeaf(p, &writer); + } + if( iPos>=nCopy ) break; + } + } + iOff += nCopy; + } + } + } + + /* TODO2: Doclist terminator written here. */ + /* pBuf->p[pBuf->n++] = '\0'; */ + assert( pBuf->n<=pBuf->nSpace ); + sqlite3Fts5HashScanNext(pHash); + } + sqlite3Fts5HashClear(pHash); + fts5WriteFinish(p, &writer, &pgnoLast); + + /* Update the Fts5Structure. It is written back to the database by the + ** fts5StructureRelease() call below. */ + if( pStruct->nLevel==0 ){ + fts5StructureAddLevel(&p->rc, &pStruct); + } + fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0); + if( p->rc==SQLITE_OK ){ + pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ]; + pSeg->iSegid = iSegid; + pSeg->pgnoFirst = 1; + pSeg->pgnoLast = pgnoLast; + pStruct->nSegment++; + } + fts5StructurePromote(p, 0, pStruct); + } + + fts5IndexAutomerge(p, &pStruct, pgnoLast); + fts5IndexCrisismerge(p, &pStruct); + fts5StructureWrite(p, pStruct); + fts5StructureRelease(pStruct); +} + +/* +** Flush any data stored in the in-memory hash tables to the database. +*/ +static void fts5IndexFlush(Fts5Index *p){ + /* Unless it is empty, flush the hash table to disk */ + if( p->nPendingData ){ + assert( p->pHash ); + p->nPendingData = 0; + fts5FlushOneHash(p); + } +} + + +int sqlite3Fts5IndexOptimize(Fts5Index *p){ + Fts5Structure *pStruct; + Fts5Structure *pNew = 0; + int nSeg = 0; + + assert( p->rc==SQLITE_OK ); + fts5IndexFlush(p); + pStruct = fts5StructureRead(p); + + if( pStruct ){ + assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) ); + nSeg = pStruct->nSegment; + if( nSeg>1 ){ + int nByte = sizeof(Fts5Structure); + nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel); + pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte); + } + } + if( pNew ){ + Fts5StructureLevel *pLvl; + int nByte = nSeg * sizeof(Fts5StructureSegment); + pNew->nLevel = pStruct->nLevel+1; + pNew->nRef = 1; + pNew->nWriteCounter = pStruct->nWriteCounter; + pLvl = &pNew->aLevel[pStruct->nLevel]; + pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&p->rc, nByte); + if( pLvl->aSeg ){ + int iLvl, iSeg; + int iSegOut = 0; + for(iLvl=0; iLvlnLevel; iLvl++){ + for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ + pLvl->aSeg[iSegOut] = pStruct->aLevel[iLvl].aSeg[iSeg]; + iSegOut++; + } + } + pNew->nSegment = pLvl->nSeg = nSeg; + }else{ + sqlite3_free(pNew); + pNew = 0; + } + } + + if( pNew ){ + int iLvl = pNew->nLevel-1; + while( p->rc==SQLITE_OK && pNew->aLevel[iLvl].nSeg>0 ){ + int nRem = FTS5_OPT_WORK_UNIT; + fts5IndexMergeLevel(p, &pNew, iLvl, &nRem); + } + + fts5StructureWrite(p, pNew); + fts5StructureRelease(pNew); + } + + fts5StructureRelease(pStruct); + return fts5IndexReturn(p); +} + +int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){ + Fts5Structure *pStruct; + + pStruct = fts5StructureRead(p); + if( pStruct && pStruct->nLevel ){ + fts5IndexMerge(p, &pStruct, nMerge); + fts5StructureWrite(p, pStruct); + } + fts5StructureRelease(pStruct); + + return fts5IndexReturn(p); +} + +static void fts5AppendRowid( + Fts5Index *p, + i64 iDelta, + Fts5Iter *pUnused, + Fts5Buffer *pBuf +){ + UNUSED_PARAM(pUnused); + fts5BufferAppendVarint(&p->rc, pBuf, iDelta); +} + +static void fts5AppendPoslist( + Fts5Index *p, + i64 iDelta, + Fts5Iter *pMulti, + Fts5Buffer *pBuf +){ + int nData = pMulti->base.nData; + assert( nData>0 ); + if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nData+9+9) ){ + fts5BufferSafeAppendVarint(pBuf, iDelta); + fts5BufferSafeAppendVarint(pBuf, nData*2); + fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData); + } +} + + +static void fts5DoclistIterNext(Fts5DoclistIter *pIter){ + u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist; + + assert( pIter->aPoslist ); + if( p>=pIter->aEof ){ + pIter->aPoslist = 0; + }else{ + i64 iDelta; + + p += fts5GetVarint(p, (u64*)&iDelta); + pIter->iRowid += iDelta; + + /* Read position list size */ + if( p[0] & 0x80 ){ + int nPos; + pIter->nSize = fts5GetVarint32(p, nPos); + pIter->nPoslist = (nPos>>1); + }else{ + pIter->nPoslist = ((int)(p[0])) >> 1; + pIter->nSize = 1; + } + + pIter->aPoslist = p; + } +} + +static void fts5DoclistIterInit( + Fts5Buffer *pBuf, + Fts5DoclistIter *pIter +){ + memset(pIter, 0, sizeof(*pIter)); + pIter->aPoslist = pBuf->p; + pIter->aEof = &pBuf->p[pBuf->n]; + fts5DoclistIterNext(pIter); +} + +#if 0 +/* +** Append a doclist to buffer pBuf. +** +** This function assumes that space within the buffer has already been +** allocated. +*/ +static void fts5MergeAppendDocid( + Fts5Buffer *pBuf, /* Buffer to write to */ + i64 *piLastRowid, /* IN/OUT: Previous rowid written (if any) */ + i64 iRowid /* Rowid to append */ +){ + assert( pBuf->n!=0 || (*piLastRowid)==0 ); + fts5BufferSafeAppendVarint(pBuf, iRowid - *piLastRowid); + *piLastRowid = iRowid; +} +#endif + +#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \ + assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \ + fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \ + (iLastRowid) = (iRowid); \ +} + +/* +** Swap the contents of buffer *p1 with that of *p2. +*/ +static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){ + Fts5Buffer tmp = *p1; + *p1 = *p2; + *p2 = tmp; +} + +static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){ + int i = *piOff; + if( i>=pBuf->n ){ + *piOff = -1; + }else{ + u64 iVal; + *piOff = i + sqlite3Fts5GetVarint(&pBuf->p[i], &iVal); + *piRowid += iVal; + } +} + +/* +** This is the equivalent of fts5MergePrefixLists() for detail=none mode. +** In this case the buffers consist of a delta-encoded list of rowids only. +*/ +static void fts5MergeRowidLists( + Fts5Index *p, /* FTS5 backend object */ + Fts5Buffer *p1, /* First list to merge */ + Fts5Buffer *p2 /* Second list to merge */ +){ + int i1 = 0; + int i2 = 0; + i64 iRowid1 = 0; + i64 iRowid2 = 0; + i64 iOut = 0; + + Fts5Buffer out; + memset(&out, 0, sizeof(out)); + sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n); + if( p->rc ) return; + + fts5NextRowid(p1, &i1, &iRowid1); + fts5NextRowid(p2, &i2, &iRowid2); + while( i1>=0 || i2>=0 ){ + if( i1>=0 && (i2<0 || iRowid1iOut ); + fts5BufferSafeAppendVarint(&out, iRowid1 - iOut); + iOut = iRowid1; + fts5NextRowid(p1, &i1, &iRowid1); + }else{ + assert( iOut==0 || iRowid2>iOut ); + fts5BufferSafeAppendVarint(&out, iRowid2 - iOut); + iOut = iRowid2; + if( i1>=0 && iRowid1==iRowid2 ){ + fts5NextRowid(p1, &i1, &iRowid1); + } + fts5NextRowid(p2, &i2, &iRowid2); + } + } + + fts5BufferSwap(&out, p1); + fts5BufferFree(&out); +} + +/* +** Buffers p1 and p2 contain doclists. This function merges the content +** of the two doclists together and sets buffer p1 to the result before +** returning. +** +** If an error occurs, an error code is left in p->rc. If an error has +** already occurred, this function is a no-op. +*/ +static void fts5MergePrefixLists( + Fts5Index *p, /* FTS5 backend object */ + Fts5Buffer *p1, /* First list to merge */ + Fts5Buffer *p2 /* Second list to merge */ +){ + if( p2->n ){ + i64 iLastRowid = 0; + Fts5DoclistIter i1; + Fts5DoclistIter i2; + Fts5Buffer out = {0, 0, 0}; + Fts5Buffer tmp = {0, 0, 0}; + + if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n) ) return; + fts5DoclistIterInit(p1, &i1); + fts5DoclistIterInit(p2, &i2); + + while( 1 ){ + if( i1.iRowidrc, &tmp, i1.nPoslist + i2.nPoslist); + if( p->rc ) break; + + sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); + sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); + assert( iPos1>=0 && iPos2>=0 ); + + if( iPos1=0 && iPos2>=0 ){ + while( 1 ){ + if( iPos1=0 ){ + if( iPos1!=iPrev ){ + sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1); + } + fts5BufferSafeAppendBlob(&tmp, &a1[iOff1], i1.nPoslist-iOff1); + }else{ + assert( iPos2>=0 && iPos2!=iPrev ); + sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2); + fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2); + } + + /* WRITEPOSLISTSIZE */ + fts5BufferSafeAppendVarint(&out, tmp.n * 2); + fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); + fts5DoclistIterNext(&i1); + fts5DoclistIterNext(&i2); + if( i1.aPoslist==0 || i2.aPoslist==0 ) break; + } + } + + if( i1.aPoslist ){ + fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid); + fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist); + } + else if( i2.aPoslist ){ + fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); + fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist); + } + + fts5BufferSet(&p->rc, p1, out.n, out.p); + fts5BufferFree(&tmp); + fts5BufferFree(&out); + } +} + +static void fts5SetupPrefixIter( + Fts5Index *p, /* Index to read from */ + int bDesc, /* True for "ORDER BY rowid DESC" */ + const u8 *pToken, /* Buffer containing prefix to match */ + int nToken, /* Size of buffer pToken in bytes */ + Fts5Colset *pColset, /* Restrict matches to these columns */ + Fts5Iter **ppIter /* OUT: New iterator */ +){ + Fts5Structure *pStruct; + Fts5Buffer *aBuf; + const int nBuf = 32; + + void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*); + void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*); + if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ + xMerge = fts5MergeRowidLists; + xAppend = fts5AppendRowid; + }else{ + xMerge = fts5MergePrefixLists; + xAppend = fts5AppendPoslist; + } + + aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf); + pStruct = fts5StructureRead(p); + + if( aBuf && pStruct ){ + const int flags = FTS5INDEX_QUERY_SCAN + | FTS5INDEX_QUERY_SKIPEMPTY + | FTS5INDEX_QUERY_NOOUTPUT; + int i; + i64 iLastRowid = 0; + Fts5Iter *p1 = 0; /* Iterator used to gather data from index */ + Fts5Data *pData; + Fts5Buffer doclist; + int bNewTerm = 1; + + memset(&doclist, 0, sizeof(doclist)); + fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1); + fts5IterSetOutputCb(&p->rc, p1); + for( /* no-op */ ; + fts5MultiIterEof(p, p1)==0; + fts5MultiIterNext2(p, p1, &bNewTerm) + ){ + Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ]; + int nTerm = pSeg->term.n; + const u8 *pTerm = pSeg->term.p; + p1->xSetOutputs(p1, pSeg); + + assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 ); + if( bNewTerm ){ + if( nTermbase.nData==0 ) continue; + + if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){ + for(i=0; p->rc==SQLITE_OK && doclist.n; i++){ + assert( ibase.iRowid-iLastRowid, p1, &doclist); + iLastRowid = p1->base.iRowid; + } + + for(i=0; irc==SQLITE_OK ){ + xMerge(p, &doclist, &aBuf[i]); + } + fts5BufferFree(&aBuf[i]); + } + fts5MultiIterFree(p1); + + pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n); + if( pData ){ + pData->p = (u8*)&pData[1]; + pData->nn = pData->szLeaf = doclist.n; + memcpy(pData->p, doclist.p, doclist.n); + fts5MultiIterNew2(p, pData, bDesc, ppIter); + } + fts5BufferFree(&doclist); + } + + fts5StructureRelease(pStruct); + sqlite3_free(aBuf); +} + + +/* +** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain +** to the document with rowid iRowid. +*/ +int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ + assert( p->rc==SQLITE_OK ); + + /* Allocate the hash table if it has not already been allocated */ + if( p->pHash==0 ){ + p->rc = sqlite3Fts5HashNew(p->pConfig, &p->pHash, &p->nPendingData); + } + + /* Flush the hash table to disk if required */ + if( iRowidiWriteRowid + || (iRowid==p->iWriteRowid && p->bDelete==0) + || (p->nPendingData > p->pConfig->nHashSize) + ){ + fts5IndexFlush(p); + } + + p->iWriteRowid = iRowid; + p->bDelete = bDelete; + return fts5IndexReturn(p); +} + +/* +** Commit data to disk. +*/ +int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){ + assert( p->rc==SQLITE_OK ); + fts5IndexFlush(p); + if( bCommit ) fts5CloseReader(p); + return fts5IndexReturn(p); +} + +/* +** Discard any data stored in the in-memory hash tables. Do not write it +** to the database. Additionally, assume that the contents of the %_data +** table may have changed on disk. So any in-memory caches of %_data +** records must be invalidated. +*/ +int sqlite3Fts5IndexRollback(Fts5Index *p){ + fts5CloseReader(p); + fts5IndexDiscardData(p); + /* assert( p->rc==SQLITE_OK ); */ + return SQLITE_OK; +} + +/* +** The %_data table is completely empty when this function is called. This +** function populates it with the initial structure objects for each index, +** and the initial version of the "averages" record (a zero-byte blob). +*/ +int sqlite3Fts5IndexReinit(Fts5Index *p){ + Fts5Structure s; + memset(&s, 0, sizeof(Fts5Structure)); + fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); + fts5StructureWrite(p, &s); + return fts5IndexReturn(p); +} + +/* +** Open a new Fts5Index handle. If the bCreate argument is true, create +** and initialize the underlying %_data table. +** +** If successful, set *pp to point to the new object and return SQLITE_OK. +** Otherwise, set *pp to NULL and return an SQLite error code. +*/ +int sqlite3Fts5IndexOpen( + Fts5Config *pConfig, + int bCreate, + Fts5Index **pp, + char **pzErr +){ + int rc = SQLITE_OK; + Fts5Index *p; /* New object */ + + *pp = p = (Fts5Index*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Index)); + if( rc==SQLITE_OK ){ + p->pConfig = pConfig; + p->nWorkUnit = FTS5_WORK_UNIT; + p->zDataTbl = sqlite3Fts5Mprintf(&rc, "%s_data", pConfig->zName); + if( p->zDataTbl && bCreate ){ + rc = sqlite3Fts5CreateTable( + pConfig, "data", "id INTEGER PRIMARY KEY, block BLOB", 0, pzErr + ); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5CreateTable(pConfig, "idx", + "segid, term, pgno, PRIMARY KEY(segid, term)", + 1, pzErr + ); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexReinit(p); + } + } + } + + assert( rc!=SQLITE_OK || p->rc==SQLITE_OK ); + if( rc ){ + sqlite3Fts5IndexClose(p); + *pp = 0; + } + return rc; +} + +/* +** Close a handle opened by an earlier call to sqlite3Fts5IndexOpen(). +*/ +int sqlite3Fts5IndexClose(Fts5Index *p){ + int rc = SQLITE_OK; + if( p ){ + assert( p->pReader==0 ); + sqlite3_finalize(p->pWriter); + sqlite3_finalize(p->pDeleter); + sqlite3_finalize(p->pIdxWriter); + sqlite3_finalize(p->pIdxDeleter); + sqlite3_finalize(p->pIdxSelect); + sqlite3Fts5HashFree(p->pHash); + sqlite3_free(p->zDataTbl); + sqlite3_free(p); + } + return rc; +} + +/* +** Argument p points to a buffer containing utf-8 text that is n bytes in +** size. Return the number of bytes in the nChar character prefix of the +** buffer, or 0 if there are less than nChar characters in total. +*/ +int sqlite3Fts5IndexCharlenToBytelen( + const char *p, + int nByte, + int nChar +){ + int n = 0; + int i; + for(i=0; i=nByte ) return 0; /* Input contains fewer than nChar chars */ + if( (unsigned char)p[n++]>=0xc0 ){ + while( (p[n] & 0xc0)==0x80 ) n++; + } + } + return n; +} + +/* +** pIn is a UTF-8 encoded string, nIn bytes in size. Return the number of +** unicode characters in the string. +*/ +static int fts5IndexCharlen(const char *pIn, int nIn){ + int nChar = 0; + int i = 0; + while( i=0xc0 ){ + while( i delete) */ + int iPos, /* Position of token within column */ + const char *pToken, int nToken /* Token to add or remove to or from index */ +){ + int i; /* Used to iterate through indexes */ + int rc = SQLITE_OK; /* Return code */ + Fts5Config *pConfig = p->pConfig; + + assert( p->rc==SQLITE_OK ); + assert( (iCol<0)==p->bDelete ); + + /* Add the entry to the main terms index. */ + rc = sqlite3Fts5HashWrite( + p->pHash, p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX, pToken, nToken + ); + + for(i=0; inPrefix && rc==SQLITE_OK; i++){ + const int nChar = pConfig->aPrefix[i]; + int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar); + if( nByte ){ + rc = sqlite3Fts5HashWrite(p->pHash, + p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken, + nByte + ); + } + } + + return rc; +} + +/* +** Open a new iterator to iterate though all rowid that match the +** specified token or token prefix. +*/ +int sqlite3Fts5IndexQuery( + Fts5Index *p, /* FTS index to query */ + const char *pToken, int nToken, /* Token (or prefix) to query for */ + int flags, /* Mask of FTS5INDEX_QUERY_X flags */ + Fts5Colset *pColset, /* Match these columns only */ + Fts5IndexIter **ppIter /* OUT: New iterator object */ +){ + Fts5Config *pConfig = p->pConfig; + Fts5Iter *pRet = 0; + Fts5Buffer buf = {0, 0, 0}; + + /* If the QUERY_SCAN flag is set, all other flags must be clear. */ + assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN ); + + if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){ + int iIdx = 0; /* Index to search */ + memcpy(&buf.p[1], pToken, nToken); + + /* Figure out which index to search and set iIdx accordingly. If this + ** is a prefix query for which there is no prefix index, set iIdx to + ** greater than pConfig->nPrefix to indicate that the query will be + ** satisfied by scanning multiple terms in the main index. + ** + ** If the QUERY_TEST_NOIDX flag was specified, then this must be a + ** prefix-query. Instead of using a prefix-index (if one exists), + ** evaluate the prefix query using the main FTS index. This is used + ** for internal sanity checking by the integrity-check in debug + ** mode only. */ +#ifdef SQLITE_DEBUG + if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){ + assert( flags & FTS5INDEX_QUERY_PREFIX ); + iIdx = 1+pConfig->nPrefix; + }else +#endif + if( flags & FTS5INDEX_QUERY_PREFIX ){ + int nChar = fts5IndexCharlen(pToken, nToken); + for(iIdx=1; iIdx<=pConfig->nPrefix; iIdx++){ + if( pConfig->aPrefix[iIdx-1]==nChar ) break; + } + } + + if( iIdx<=pConfig->nPrefix ){ + /* Straight index lookup */ + Fts5Structure *pStruct = fts5StructureRead(p); + buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx); + if( pStruct ){ + fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY, + pColset, buf.p, nToken+1, -1, 0, &pRet + ); + fts5StructureRelease(pStruct); + } + }else{ + /* Scan multiple terms in the main index */ + int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0; + buf.p[0] = FTS5_MAIN_PREFIX; + fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet); + assert( p->rc!=SQLITE_OK || pRet->pColset==0 ); + fts5IterSetOutputCb(&p->rc, pRet); + if( p->rc==SQLITE_OK ){ + Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst]; + if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg); + } + } + + if( p->rc ){ + sqlite3Fts5IterClose(&pRet->base); + pRet = 0; + fts5CloseReader(p); + } + + *ppIter = &pRet->base; + sqlite3Fts5BufferFree(&buf); + } + return fts5IndexReturn(p); +} + +/* +** Return true if the iterator passed as the only argument is at EOF. +*/ +/* +** Move to the next matching rowid. +*/ +int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; + assert( pIter->pIndex->rc==SQLITE_OK ); + fts5MultiIterNext(pIter->pIndex, pIter, 0, 0); + return fts5IndexReturn(pIter->pIndex); +} + +/* +** Move to the next matching term/rowid. Used by the fts5vocab module. +*/ +int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; + Fts5Index *p = pIter->pIndex; + + assert( pIter->pIndex->rc==SQLITE_OK ); + + fts5MultiIterNext(p, pIter, 0, 0); + if( p->rc==SQLITE_OK ){ + Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; + if( pSeg->pLeaf && pSeg->term.p[0]!=FTS5_MAIN_PREFIX ){ + fts5DataRelease(pSeg->pLeaf); + pSeg->pLeaf = 0; + pIter->base.bEof = 1; + } + } + + return fts5IndexReturn(pIter->pIndex); +} + +/* +** Move to the next matching rowid that occurs at or after iMatch. The +** definition of "at or after" depends on whether this iterator iterates +** in ascending or descending rowid order. +*/ +int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; + fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch); + return fts5IndexReturn(pIter->pIndex); +} + +/* +** Return the current term. +*/ +const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){ + int n; + const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n); + *pn = n-1; + return &z[1]; +} + +/* +** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery(). +*/ +void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){ + if( pIndexIter ){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; + Fts5Index *pIndex = pIter->pIndex; + fts5MultiIterFree(pIter); + fts5CloseReader(pIndex); + } +} + +/* +** Read and decode the "averages" record from the database. +** +** Parameter anSize must point to an array of size nCol, where nCol is +** the number of user defined columns in the FTS table. +*/ +int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize){ + int nCol = p->pConfig->nCol; + Fts5Data *pData; + + *pnRow = 0; + memset(anSize, 0, sizeof(i64) * nCol); + pData = fts5DataRead(p, FTS5_AVERAGES_ROWID); + if( p->rc==SQLITE_OK && pData->nn ){ + int i = 0; + int iCol; + i += fts5GetVarint(&pData->p[i], (u64*)pnRow); + for(iCol=0; inn && iColp[i], (u64*)&anSize[iCol]); + } + } + + fts5DataRelease(pData); + return fts5IndexReturn(p); +} + +/* +** Replace the current "averages" record with the contents of the buffer +** supplied as the second argument. +*/ +int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8 *pData, int nData){ + assert( p->rc==SQLITE_OK ); + fts5DataWrite(p, FTS5_AVERAGES_ROWID, pData, nData); + return fts5IndexReturn(p); +} + +/* +** Return the total number of blocks this module has read from the %_data +** table since it was created. +*/ +int sqlite3Fts5IndexReads(Fts5Index *p){ + return p->nRead; +} + +/* +** Set the 32-bit cookie value stored at the start of all structure +** records to the value passed as the second argument. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +int sqlite3Fts5IndexSetCookie(Fts5Index *p, int iNew){ + int rc; /* Return code */ + Fts5Config *pConfig = p->pConfig; /* Configuration object */ + u8 aCookie[4]; /* Binary representation of iNew */ + sqlite3_blob *pBlob = 0; + + assert( p->rc==SQLITE_OK ); + sqlite3Fts5Put32(aCookie, iNew); + + rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl, + "block", FTS5_STRUCTURE_ROWID, 1, &pBlob + ); + if( rc==SQLITE_OK ){ + sqlite3_blob_write(pBlob, aCookie, 4, 0); + rc = sqlite3_blob_close(pBlob); + } + + return rc; +} + +int sqlite3Fts5IndexLoadConfig(Fts5Index *p){ + Fts5Structure *pStruct; + pStruct = fts5StructureRead(p); + fts5StructureRelease(pStruct); + return fts5IndexReturn(p); +} + + +/************************************************************************* +************************************************************************** +** Below this point is the implementation of the integrity-check +** functionality. +*/ + +/* +** Return a simple checksum value based on the arguments. +*/ +u64 sqlite3Fts5IndexEntryCksum( + i64 iRowid, + int iCol, + int iPos, + int iIdx, + const char *pTerm, + int nTerm +){ + int i; + u64 ret = iRowid; + ret += (ret<<3) + iCol; + ret += (ret<<3) + iPos; + if( iIdx>=0 ) ret += (ret<<3) + (FTS5_MAIN_PREFIX + iIdx); + for(i=0; iiLeaf ); + cksum1 += iRowid + ((i64)pgno<<32); + } + fts5DlidxIterFree(pDlidx); + pDlidx = 0; + + for(pDlidx=fts5DlidxIterInit(p, 1, iSegid, iLeaf); + fts5DlidxIterEof(p, pDlidx)==0; + fts5DlidxIterPrev(p, pDlidx) + ){ + i64 iRowid = fts5DlidxIterRowid(pDlidx); + int pgno = fts5DlidxIterPgno(pDlidx); + assert( fts5DlidxIterPgno(pDlidx)>iLeaf ); + cksum2 += iRowid + ((i64)pgno<<32); + } + fts5DlidxIterFree(pDlidx); + pDlidx = 0; + + if( p->rc==SQLITE_OK && cksum1!=cksum2 ) p->rc = FTS5_CORRUPT; +} + +static int fts5QueryCksum( + Fts5Index *p, /* Fts5 index object */ + int iIdx, + const char *z, /* Index key to query for */ + int n, /* Size of index key in bytes */ + int flags, /* Flags for Fts5IndexQuery */ + u64 *pCksum /* IN/OUT: Checksum value */ +){ + int eDetail = p->pConfig->eDetail; + u64 cksum = *pCksum; + Fts5IndexIter *pIter = 0; + int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter); + + while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIter) ){ + i64 rowid = pIter->iRowid; + + if( eDetail==FTS5_DETAIL_NONE ){ + cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n); + }else{ + Fts5PoslistReader sReader; + for(sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &sReader); + sReader.bEof==0; + sqlite3Fts5PoslistReaderNext(&sReader) + ){ + int iCol = FTS5_POS2COLUMN(sReader.iPos); + int iOff = FTS5_POS2OFFSET(sReader.iPos); + cksum ^= sqlite3Fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n); + } + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IterNext(pIter); + } + } + sqlite3Fts5IterClose(pIter); + + *pCksum = cksum; + return rc; +} + + +/* +** This function is also purely an internal test. It does not contribute to +** FTS functionality, or even the integrity-check, in any way. +*/ +static void fts5TestTerm( + Fts5Index *p, + Fts5Buffer *pPrev, /* Previous term */ + const char *z, int n, /* Possibly new term to test */ + u64 expected, + u64 *pCksum +){ + int rc = p->rc; + if( pPrev->n==0 ){ + fts5BufferSet(&rc, pPrev, n, (const u8*)z); + }else + if( rc==SQLITE_OK && (pPrev->n!=n || memcmp(pPrev->p, z, n)) ){ + u64 cksum3 = *pCksum; + const char *zTerm = (const char*)&pPrev->p[1]; /* term sans prefix-byte */ + int nTerm = pPrev->n-1; /* Size of zTerm in bytes */ + int iIdx = (pPrev->p[0] - FTS5_MAIN_PREFIX); + int flags = (iIdx==0 ? 0 : FTS5INDEX_QUERY_PREFIX); + u64 ck1 = 0; + u64 ck2 = 0; + + /* Check that the results returned for ASC and DESC queries are + ** the same. If not, call this corruption. */ + rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, flags, &ck1); + if( rc==SQLITE_OK ){ + int f = flags|FTS5INDEX_QUERY_DESC; + rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2); + } + if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT; + + /* If this is a prefix query, check that the results returned if the + ** the index is disabled are the same. In both ASC and DESC order. + ** + ** This check may only be performed if the hash table is empty. This + ** is because the hash table only supports a single scan query at + ** a time, and the multi-iter loop from which this function is called + ** is already performing such a scan. */ + if( p->nPendingData==0 ){ + if( iIdx>0 && rc==SQLITE_OK ){ + int f = flags|FTS5INDEX_QUERY_TEST_NOIDX; + ck2 = 0; + rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2); + if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT; + } + if( iIdx>0 && rc==SQLITE_OK ){ + int f = flags|FTS5INDEX_QUERY_TEST_NOIDX|FTS5INDEX_QUERY_DESC; + ck2 = 0; + rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2); + if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT; + } + } + + cksum3 ^= ck1; + fts5BufferSet(&rc, pPrev, n, (const u8*)z); + + if( rc==SQLITE_OK && cksum3!=expected ){ + rc = FTS5_CORRUPT; + } + *pCksum = cksum3; + } + p->rc = rc; +} + +#else +# define fts5TestDlidxReverse(x,y,z) +# define fts5TestTerm(u,v,w,x,y,z) +#endif + +/* +** Check that: +** +** 1) All leaves of pSeg between iFirst and iLast (inclusive) exist and +** contain zero terms. +** 2) All leaves of pSeg between iNoRowid and iLast (inclusive) exist and +** contain zero rowids. +*/ +static void fts5IndexIntegrityCheckEmpty( + Fts5Index *p, + Fts5StructureSegment *pSeg, /* Segment to check internal consistency */ + int iFirst, + int iNoRowid, + int iLast +){ + int i; + + /* Now check that the iter.nEmpty leaves following the current leaf + ** (a) exist and (b) contain no terms. */ + for(i=iFirst; p->rc==SQLITE_OK && i<=iLast; i++){ + Fts5Data *pLeaf = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i)); + if( pLeaf ){ + if( !fts5LeafIsTermless(pLeaf) ) p->rc = FTS5_CORRUPT; + if( i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf) ) p->rc = FTS5_CORRUPT; + } + fts5DataRelease(pLeaf); + } +} + +static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){ + int iTermOff = 0; + int ii; + + Fts5Buffer buf1 = {0,0,0}; + Fts5Buffer buf2 = {0,0,0}; + + ii = pLeaf->szLeaf; + while( iinn && p->rc==SQLITE_OK ){ + int res; + int iOff; + int nIncr; + + ii += fts5GetVarint32(&pLeaf->p[ii], nIncr); + iTermOff += nIncr; + iOff = iTermOff; + + if( iOff>=pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else if( iTermOff==nIncr ){ + int nByte; + iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte); + if( (iOff+nByte)>pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + fts5BufferSet(&p->rc, &buf1, nByte, &pLeaf->p[iOff]); + } + }else{ + int nKeep, nByte; + iOff += fts5GetVarint32(&pLeaf->p[iOff], nKeep); + iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte); + if( nKeep>buf1.n || (iOff+nByte)>pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + buf1.n = nKeep; + fts5BufferAppendBlob(&p->rc, &buf1, nByte, &pLeaf->p[iOff]); + } + + if( p->rc==SQLITE_OK ){ + res = fts5BufferCompare(&buf1, &buf2); + if( res<=0 ) p->rc = FTS5_CORRUPT; + } + } + fts5BufferSet(&p->rc, &buf2, buf1.n, buf1.p); + } + + fts5BufferFree(&buf1); + fts5BufferFree(&buf2); +} + +static void fts5IndexIntegrityCheckSegment( + Fts5Index *p, /* FTS5 backend object */ + Fts5StructureSegment *pSeg /* Segment to check internal consistency */ +){ + Fts5Config *pConfig = p->pConfig; + sqlite3_stmt *pStmt = 0; + int rc2; + int iIdxPrevLeaf = pSeg->pgnoFirst-1; + int iDlidxPrevLeaf = pSeg->pgnoLast; + + if( pSeg->pgnoFirst==0 ) return; + + fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf( + "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d", + pConfig->zDb, pConfig->zName, pSeg->iSegid + )); + + /* Iterate through the b-tree hierarchy. */ + while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + i64 iRow; /* Rowid for this leaf */ + Fts5Data *pLeaf; /* Data for this leaf */ + + int nIdxTerm = sqlite3_column_bytes(pStmt, 1); + const char *zIdxTerm = (const char*)sqlite3_column_text(pStmt, 1); + int iIdxLeaf = sqlite3_column_int(pStmt, 2); + int bIdxDlidx = sqlite3_column_int(pStmt, 3); + + /* If the leaf in question has already been trimmed from the segment, + ** ignore this b-tree entry. Otherwise, load it into memory. */ + if( iIdxLeafpgnoFirst ) continue; + iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf); + pLeaf = fts5DataRead(p, iRow); + if( pLeaf==0 ) break; + + /* Check that the leaf contains at least one term, and that it is equal + ** to or larger than the split-key in zIdxTerm. Also check that if there + ** is also a rowid pointer within the leaf page header, it points to a + ** location before the term. */ + if( pLeaf->nn<=pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + int iOff; /* Offset of first term on leaf */ + int iRowidOff; /* Offset of first rowid on leaf */ + int nTerm; /* Size of term on leaf in bytes */ + int res; /* Comparison of term and split-key */ + + iOff = fts5LeafFirstTermOff(pLeaf); + iRowidOff = fts5LeafFirstRowidOff(pLeaf); + if( iRowidOff>=iOff ){ + p->rc = FTS5_CORRUPT; + }else{ + iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm); + res = memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); + if( res==0 ) res = nTerm - nIdxTerm; + if( res<0 ) p->rc = FTS5_CORRUPT; + } + + fts5IntegrityCheckPgidx(p, pLeaf); + } + fts5DataRelease(pLeaf); + if( p->rc ) break; + + /* Now check that the iter.nEmpty leaves following the current leaf + ** (a) exist and (b) contain no terms. */ + fts5IndexIntegrityCheckEmpty( + p, pSeg, iIdxPrevLeaf+1, iDlidxPrevLeaf+1, iIdxLeaf-1 + ); + if( p->rc ) break; + + /* If there is a doclist-index, check that it looks right. */ + if( bIdxDlidx ){ + Fts5DlidxIter *pDlidx = 0; /* For iterating through doclist index */ + int iPrevLeaf = iIdxLeaf; + int iSegid = pSeg->iSegid; + int iPg = 0; + i64 iKey; + + for(pDlidx=fts5DlidxIterInit(p, 0, iSegid, iIdxLeaf); + fts5DlidxIterEof(p, pDlidx)==0; + fts5DlidxIterNext(p, pDlidx) + ){ + + /* Check any rowid-less pages that occur before the current leaf. */ + for(iPg=iPrevLeaf+1; iPgrc = FTS5_CORRUPT; + fts5DataRelease(pLeaf); + } + } + iPrevLeaf = fts5DlidxIterPgno(pDlidx); + + /* Check that the leaf page indicated by the iterator really does + ** contain the rowid suggested by the same. */ + iKey = FTS5_SEGMENT_ROWID(iSegid, iPrevLeaf); + pLeaf = fts5DataRead(p, iKey); + if( pLeaf ){ + i64 iRowid; + int iRowidOff = fts5LeafFirstRowidOff(pLeaf); + ASSERT_SZLEAF_OK(pLeaf); + if( iRowidOff>=pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid); + if( iRowid!=fts5DlidxIterRowid(pDlidx) ) p->rc = FTS5_CORRUPT; + } + fts5DataRelease(pLeaf); + } + } + + iDlidxPrevLeaf = iPg; + fts5DlidxIterFree(pDlidx); + fts5TestDlidxReverse(p, iSegid, iIdxLeaf); + }else{ + iDlidxPrevLeaf = pSeg->pgnoLast; + /* TODO: Check there is no doclist index */ + } + + iIdxPrevLeaf = iIdxLeaf; + } + + rc2 = sqlite3_finalize(pStmt); + if( p->rc==SQLITE_OK ) p->rc = rc2; + + /* Page iter.iLeaf must now be the rightmost leaf-page in the segment */ +#if 0 + if( p->rc==SQLITE_OK && iter.iLeaf!=pSeg->pgnoLast ){ + p->rc = FTS5_CORRUPT; + } +#endif +} + + +/* +** Run internal checks to ensure that the FTS index (a) is internally +** consistent and (b) contains entries for which the XOR of the checksums +** as calculated by sqlite3Fts5IndexEntryCksum() is cksum. +** +** Return SQLITE_CORRUPT if any of the internal checks fail, or if the +** checksum does not match. Return SQLITE_OK if all checks pass without +** error, or some other SQLite error code if another error (e.g. OOM) +** occurs. +*/ +int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ + int eDetail = p->pConfig->eDetail; + u64 cksum2 = 0; /* Checksum based on contents of indexes */ + Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */ + Fts5Iter *pIter; /* Used to iterate through entire index */ + Fts5Structure *pStruct; /* Index structure */ + +#ifdef SQLITE_DEBUG + /* Used by extra internal tests only run if NDEBUG is not defined */ + u64 cksum3 = 0; /* Checksum based on contents of indexes */ + Fts5Buffer term = {0,0,0}; /* Buffer used to hold most recent term */ +#endif + const int flags = FTS5INDEX_QUERY_NOOUTPUT; + + /* Load the FTS index structure */ + pStruct = fts5StructureRead(p); + + /* Check that the internal nodes of each segment match the leaves */ + if( pStruct ){ + int iLvl, iSeg; + for(iLvl=0; iLvlnLevel; iLvl++){ + for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ + Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg]; + fts5IndexIntegrityCheckSegment(p, pSeg); + } + } + } + + /* The cksum argument passed to this function is a checksum calculated + ** based on all expected entries in the FTS index (including prefix index + ** entries). This block checks that a checksum calculated based on the + ** actual contents of FTS index is identical. + ** + ** Two versions of the same checksum are calculated. The first (stack + ** variable cksum2) based on entries extracted from the full-text index + ** while doing a linear scan of each individual index in turn. + ** + ** As each term visited by the linear scans, a separate query for the + ** same term is performed. cksum3 is calculated based on the entries + ** extracted by these queries. + */ + for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, -1, 0, &pIter); + fts5MultiIterEof(p, pIter)==0; + fts5MultiIterNext(p, pIter, 0, 0) + ){ + int n; /* Size of term in bytes */ + i64 iPos = 0; /* Position read from poslist */ + int iOff = 0; /* Offset within poslist */ + i64 iRowid = fts5MultiIterRowid(pIter); + char *z = (char*)fts5MultiIterTerm(pIter, &n); + + /* If this is a new term, query for it. Update cksum3 with the results. */ + fts5TestTerm(p, &term, z, n, cksum2, &cksum3); + + if( eDetail==FTS5_DETAIL_NONE ){ + if( 0==fts5MultiIterIsEmpty(p, pIter) ){ + cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n); + } + }else{ + poslist.n = 0; + fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist); + while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){ + int iCol = FTS5_POS2COLUMN(iPos); + int iTokOff = FTS5_POS2OFFSET(iPos); + cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n); + } + } + } + fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3); + + fts5MultiIterFree(pIter); + if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT; + + fts5StructureRelease(pStruct); +#ifdef SQLITE_DEBUG + fts5BufferFree(&term); +#endif + fts5BufferFree(&poslist); + return fts5IndexReturn(p); +} + +/************************************************************************* +************************************************************************** +** Below this point is the implementation of the fts5_decode() scalar +** function only. +*/ + +/* +** Decode a segment-data rowid from the %_data table. This function is +** the opposite of macro FTS5_SEGMENT_ROWID(). +*/ +static void fts5DecodeRowid( + i64 iRowid, /* Rowid from %_data table */ + int *piSegid, /* OUT: Segment id */ + int *pbDlidx, /* OUT: Dlidx flag */ + int *piHeight, /* OUT: Height */ + int *piPgno /* OUT: Page number */ +){ + *piPgno = (int)(iRowid & (((i64)1 << FTS5_DATA_PAGE_B) - 1)); + iRowid >>= FTS5_DATA_PAGE_B; + + *piHeight = (int)(iRowid & (((i64)1 << FTS5_DATA_HEIGHT_B) - 1)); + iRowid >>= FTS5_DATA_HEIGHT_B; + + *pbDlidx = (int)(iRowid & 0x0001); + iRowid >>= FTS5_DATA_DLI_B; + + *piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1)); +} + +static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ + int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */ + fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno); + + if( iSegid==0 ){ + if( iKey==FTS5_AVERAGES_ROWID ){ + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{averages} "); + }else{ + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{structure}"); + } + } + else{ + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%ssegid=%d h=%d pgno=%d}", + bDlidx ? "dlidx " : "", iSegid, iHeight, iPgno + ); + } +} + +static void fts5DebugStructure( + int *pRc, /* IN/OUT: error code */ + Fts5Buffer *pBuf, + Fts5Structure *p +){ + int iLvl, iSeg; /* Iterate through levels, segments */ + + for(iLvl=0; iLvlnLevel; iLvl++){ + Fts5StructureLevel *pLvl = &p->aLevel[iLvl]; + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, + " {lvl=%d nMerge=%d nSeg=%d", iLvl, pLvl->nMerge, pLvl->nSeg + ); + for(iSeg=0; iSegnSeg; iSeg++){ + Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg]; + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}", + pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast + ); + } + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}"); + } +} + +/* +** This is part of the fts5_decode() debugging aid. +** +** Arguments pBlob/nBlob contain a serialized Fts5Structure object. This +** function appends a human-readable representation of the same object +** to the buffer passed as the second argument. +*/ +static void fts5DecodeStructure( + int *pRc, /* IN/OUT: error code */ + Fts5Buffer *pBuf, + const u8 *pBlob, int nBlob +){ + int rc; /* Return code */ + Fts5Structure *p = 0; /* Decoded structure object */ + + rc = fts5StructureDecode(pBlob, nBlob, 0, &p); + if( rc!=SQLITE_OK ){ + *pRc = rc; + return; + } + + fts5DebugStructure(pRc, pBuf, p); + fts5StructureRelease(p); +} + +/* +** This is part of the fts5_decode() debugging aid. +** +** Arguments pBlob/nBlob contain an "averages" record. This function +** appends a human-readable representation of record to the buffer passed +** as the second argument. +*/ +static void fts5DecodeAverages( + int *pRc, /* IN/OUT: error code */ + Fts5Buffer *pBuf, + const u8 *pBlob, int nBlob +){ + int i = 0; + const char *zSpace = ""; + + while( i0 ){ + iOff = sqlite3Fts5GetVarint(a, (u64*)&iDocid); + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " id=%lld", iDocid); + } + while( iOff none) */ +}; + +/* +** A single object of this type is allocated when the FTS5 module is +** registered with a database handle. It is used to store pointers to +** all registered FTS5 extensions - tokenizers and auxiliary functions. +*/ +struct Fts5Global { + fts5_api api; /* User visible part of object (see fts5.h) */ + sqlite3 *db; /* Associated database connection */ + i64 iNextId; /* Used to allocate unique cursor ids */ + Fts5Auxiliary *pAux; /* First in list of all aux. functions */ + Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */ + Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */ + Fts5Cursor *pCsr; /* First in list of all open cursors */ +}; + +/* +** Each auxiliary function registered with the FTS5 module is represented +** by an object of the following type. All such objects are stored as part +** of the Fts5Global.pAux list. +*/ +struct Fts5Auxiliary { + Fts5Global *pGlobal; /* Global context for this function */ + char *zFunc; /* Function name (nul-terminated) */ + void *pUserData; /* User-data pointer */ + fts5_extension_function xFunc; /* Callback function */ + void (*xDestroy)(void*); /* Destructor function */ + Fts5Auxiliary *pNext; /* Next registered auxiliary function */ +}; + +/* +** Each tokenizer module registered with the FTS5 module is represented +** by an object of the following type. All such objects are stored as part +** of the Fts5Global.pTok list. +*/ +struct Fts5TokenizerModule { + char *zName; /* Name of tokenizer */ + void *pUserData; /* User pointer passed to xCreate() */ + fts5_tokenizer x; /* Tokenizer functions */ + void (*xDestroy)(void*); /* Destructor function */ + Fts5TokenizerModule *pNext; /* Next registered tokenizer module */ +}; + +/* +** Virtual-table object. +*/ +struct Fts5Table { + sqlite3_vtab base; /* Base class used by SQLite core */ + Fts5Config *pConfig; /* Virtual table configuration */ + Fts5Index *pIndex; /* Full-text index */ + Fts5Storage *pStorage; /* Document store */ + Fts5Global *pGlobal; /* Global (connection wide) data */ + Fts5Cursor *pSortCsr; /* Sort data from this cursor */ +#ifdef SQLITE_DEBUG + struct Fts5TransactionState ts; +#endif +}; + +struct Fts5MatchPhrase { + Fts5Buffer *pPoslist; /* Pointer to current poslist */ + int nTerm; /* Size of phrase in terms */ +}; + +/* +** pStmt: +** SELECT rowid, FROM ORDER BY +rank; +** +** aIdx[]: +** There is one entry in the aIdx[] array for each phrase in the query, +** the value of which is the offset within aPoslist[] following the last +** byte of the position list for the corresponding phrase. +*/ +struct Fts5Sorter { + sqlite3_stmt *pStmt; + i64 iRowid; /* Current rowid */ + const u8 *aPoslist; /* Position lists for current row */ + int nIdx; /* Number of entries in aIdx[] */ + int aIdx[1]; /* Offsets into aPoslist for current row */ +}; + + +/* +** Virtual-table cursor object. +** +** iSpecial: +** If this is a 'special' query (refer to function fts5SpecialMatch()), +** then this variable contains the result of the query. +** +** iFirstRowid, iLastRowid: +** These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the +** cursor iterates in ascending order of rowids, iFirstRowid is the lower +** limit of rowids to return, and iLastRowid the upper. In other words, the +** WHERE clause in the user's query might have been: +** +** MATCH AND rowid BETWEEN $iFirstRowid AND $iLastRowid +** +** If the cursor iterates in descending order of rowid, iFirstRowid +** is the upper limit (i.e. the "first" rowid visited) and iLastRowid +** the lower. +*/ +struct Fts5Cursor { + sqlite3_vtab_cursor base; /* Base class used by SQLite core */ + Fts5Cursor *pNext; /* Next cursor in Fts5Cursor.pCsr list */ + int *aColumnSize; /* Values for xColumnSize() */ + i64 iCsrId; /* Cursor id */ + + /* Zero from this point onwards on cursor reset */ + int ePlan; /* FTS5_PLAN_XXX value */ + int bDesc; /* True for "ORDER BY rowid DESC" queries */ + i64 iFirstRowid; /* Return no rowids earlier than this */ + i64 iLastRowid; /* Return no rowids later than this */ + sqlite3_stmt *pStmt; /* Statement used to read %_content */ + Fts5Expr *pExpr; /* Expression for MATCH queries */ + Fts5Sorter *pSorter; /* Sorter for "ORDER BY rank" queries */ + int csrflags; /* Mask of cursor flags (see below) */ + i64 iSpecial; /* Result of special query */ + + /* "rank" function. Populated on demand from vtab.xColumn(). */ + char *zRank; /* Custom rank function */ + char *zRankArgs; /* Custom rank function args */ + Fts5Auxiliary *pRank; /* Rank callback (or NULL) */ + int nRankArg; /* Number of trailing arguments for rank() */ + sqlite3_value **apRankArg; /* Array of trailing arguments */ + sqlite3_stmt *pRankArgStmt; /* Origin of objects in apRankArg[] */ + + /* Auxiliary data storage */ + Fts5Auxiliary *pAux; /* Currently executing extension function */ + Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */ + + /* Cache used by auxiliary functions xInst() and xInstCount() */ + Fts5PoslistReader *aInstIter; /* One for each phrase */ + int nInstAlloc; /* Size of aInst[] array (entries / 3) */ + int nInstCount; /* Number of phrase instances */ + int *aInst; /* 3 integers per phrase instance */ +}; + +/* +** Bits that make up the "idxNum" parameter passed indirectly by +** xBestIndex() to xFilter(). +*/ +#define FTS5_BI_MATCH 0x0001 /* MATCH ? */ +#define FTS5_BI_RANK 0x0002 /* rank MATCH ? */ +#define FTS5_BI_ROWID_EQ 0x0004 /* rowid == ? */ +#define FTS5_BI_ROWID_LE 0x0008 /* rowid <= ? */ +#define FTS5_BI_ROWID_GE 0x0010 /* rowid >= ? */ + +#define FTS5_BI_ORDER_RANK 0x0020 +#define FTS5_BI_ORDER_ROWID 0x0040 +#define FTS5_BI_ORDER_DESC 0x0080 + +/* +** Values for Fts5Cursor.csrflags +*/ +#define FTS5CSR_EOF 0x01 +#define FTS5CSR_REQUIRE_CONTENT 0x02 +#define FTS5CSR_REQUIRE_DOCSIZE 0x04 +#define FTS5CSR_REQUIRE_INST 0x08 +#define FTS5CSR_FREE_ZRANK 0x10 +#define FTS5CSR_REQUIRE_RESEEK 0x20 +#define FTS5CSR_REQUIRE_POSLIST 0x40 + +#define BitFlagAllTest(x,y) (((x) & (y))==(y)) +#define BitFlagTest(x,y) (((x) & (y))!=0) + + +/* +** Macros to Set(), Clear() and Test() cursor flags. +*/ +#define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag)) +#define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag)) +#define CsrFlagTest(pCsr, flag) ((pCsr)->csrflags & (flag)) + +struct Fts5Auxdata { + Fts5Auxiliary *pAux; /* Extension to which this belongs */ + void *pPtr; /* Pointer value */ + void(*xDelete)(void*); /* Destructor */ + Fts5Auxdata *pNext; /* Next object in linked list */ +}; + +#ifdef SQLITE_DEBUG +#define FTS5_BEGIN 1 +#define FTS5_SYNC 2 +#define FTS5_COMMIT 3 +#define FTS5_ROLLBACK 4 +#define FTS5_SAVEPOINT 5 +#define FTS5_RELEASE 6 +#define FTS5_ROLLBACKTO 7 +static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){ + switch( op ){ + case FTS5_BEGIN: + assert( p->ts.eState==0 ); + p->ts.eState = 1; + p->ts.iSavepoint = -1; + break; + + case FTS5_SYNC: + assert( p->ts.eState==1 ); + p->ts.eState = 2; + break; + + case FTS5_COMMIT: + assert( p->ts.eState==2 ); + p->ts.eState = 0; + break; + + case FTS5_ROLLBACK: + assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 ); + p->ts.eState = 0; + break; + + case FTS5_SAVEPOINT: + assert( p->ts.eState==1 ); + assert( iSavepoint>=0 ); + assert( iSavepoint>p->ts.iSavepoint ); + p->ts.iSavepoint = iSavepoint; + break; + + case FTS5_RELEASE: + assert( p->ts.eState==1 ); + assert( iSavepoint>=0 ); + assert( iSavepoint<=p->ts.iSavepoint ); + p->ts.iSavepoint = iSavepoint-1; + break; + + case FTS5_ROLLBACKTO: + assert( p->ts.eState==1 ); + assert( iSavepoint>=0 ); + assert( iSavepoint<=p->ts.iSavepoint ); + p->ts.iSavepoint = iSavepoint; + break; + } +} +#else +# define fts5CheckTransactionState(x,y,z) +#endif + +/* +** Return true if pTab is a contentless table. +*/ +static int fts5IsContentless(Fts5Table *pTab){ + return pTab->pConfig->eContent==FTS5_CONTENT_NONE; +} + +/* +** Delete a virtual table handle allocated by fts5InitVtab(). +*/ +static void fts5FreeVtab(Fts5Table *pTab){ + if( pTab ){ + sqlite3Fts5IndexClose(pTab->pIndex); + sqlite3Fts5StorageClose(pTab->pStorage); + sqlite3Fts5ConfigFree(pTab->pConfig); + sqlite3_free(pTab); + } +} + +/* +** The xDisconnect() virtual table method. +*/ +static int fts5DisconnectMethod(sqlite3_vtab *pVtab){ + fts5FreeVtab((Fts5Table*)pVtab); + return SQLITE_OK; +} + +/* +** The xDestroy() virtual table method. +*/ +static int fts5DestroyMethod(sqlite3_vtab *pVtab){ + Fts5Table *pTab = (Fts5Table*)pVtab; + int rc = sqlite3Fts5DropAll(pTab->pConfig); + if( rc==SQLITE_OK ){ + fts5FreeVtab((Fts5Table*)pVtab); + } + return rc; +} + +/* +** This function is the implementation of both the xConnect and xCreate +** methods of the FTS3 virtual table. +** +** The argv[] array contains the following: +** +** argv[0] -> module name ("fts5") +** argv[1] -> database name +** argv[2] -> table name +** argv[...] -> "column name" and other module argument fields. +*/ +static int fts5InitVtab( + int bCreate, /* True for xCreate, false for xConnect */ + sqlite3 *db, /* The SQLite database connection */ + void *pAux, /* Hash table containing tokenizers */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ + char **pzErr /* Write any error message here */ +){ + Fts5Global *pGlobal = (Fts5Global*)pAux; + const char **azConfig = (const char**)argv; + int rc = SQLITE_OK; /* Return code */ + Fts5Config *pConfig = 0; /* Results of parsing argc/argv */ + Fts5Table *pTab = 0; /* New virtual table object */ + + /* Allocate the new vtab object and parse the configuration */ + pTab = (Fts5Table*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Table)); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr); + assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 ); + } + if( rc==SQLITE_OK ){ + pTab->pConfig = pConfig; + pTab->pGlobal = pGlobal; + } + + /* Open the index sub-system */ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->pIndex, pzErr); + } + + /* Open the storage sub-system */ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageOpen( + pConfig, pTab->pIndex, bCreate, &pTab->pStorage, pzErr + ); + } + + /* Call sqlite3_declare_vtab() */ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ConfigDeclareVtab(pConfig); + } + + /* Load the initial configuration */ + if( rc==SQLITE_OK ){ + assert( pConfig->pzErrmsg==0 ); + pConfig->pzErrmsg = pzErr; + rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex); + sqlite3Fts5IndexRollback(pTab->pIndex); + pConfig->pzErrmsg = 0; + } + + if( rc!=SQLITE_OK ){ + fts5FreeVtab(pTab); + pTab = 0; + }else if( bCreate ){ + fts5CheckTransactionState(pTab, FTS5_BEGIN, 0); + } + *ppVTab = (sqlite3_vtab*)pTab; + return rc; +} + +/* +** The xConnect() and xCreate() methods for the virtual table. All the +** work is done in function fts5InitVtab(). +*/ +static int fts5ConnectMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + 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 */ +){ + return fts5InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr); +} +static int fts5CreateMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + 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 */ +){ + return fts5InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr); +} + +/* +** The different query plans. +*/ +#define FTS5_PLAN_MATCH 1 /* ( MATCH ?) */ +#define FTS5_PLAN_SOURCE 2 /* A source cursor for SORTED_MATCH */ +#define FTS5_PLAN_SPECIAL 3 /* An internal query */ +#define FTS5_PLAN_SORTED_MATCH 4 /* ( MATCH ? ORDER BY rank) */ +#define FTS5_PLAN_SCAN 5 /* No usable constraint */ +#define FTS5_PLAN_ROWID 6 /* (rowid = ?) */ + +/* +** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this +** extension is currently being used by a version of SQLite too old to +** support index-info flags. In that case this function is a no-op. +*/ +static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){ +#if SQLITE_VERSION_NUMBER>=3008012 +#ifndef SQLITE_CORE + if( sqlite3_libversion_number()>=3008012 ) +#endif + { + pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; + } +#endif +} + +/* +** Implementation of the xBestIndex method for FTS5 tables. Within the +** WHERE constraint, it searches for the following: +** +** 1. A MATCH constraint against the special column. +** 2. A MATCH constraint against the "rank" column. +** 3. An == constraint against the rowid column. +** 4. A < or <= constraint against the rowid column. +** 5. A > or >= constraint against the rowid column. +** +** Within the ORDER BY, either: +** +** 5. ORDER BY rank [ASC|DESC] +** 6. ORDER BY rowid [ASC|DESC] +** +** Costs are assigned as follows: +** +** a) If an unusable MATCH operator is present in the WHERE clause, the +** cost is unconditionally set to 1e50 (a really big number). +** +** a) If a MATCH operator is present, the cost depends on the other +** constraints also present. As follows: +** +** * No other constraints: cost=1000.0 +** * One rowid range constraint: cost=750.0 +** * Both rowid range constraints: cost=500.0 +** * An == rowid constraint: cost=100.0 +** +** b) Otherwise, if there is no MATCH: +** +** * No other constraints: cost=1000000.0 +** * One rowid range constraint: cost=750000.0 +** * Both rowid range constraints: cost=250000.0 +** * An == rowid constraint: cost=10.0 +** +** Costs are not modified by the ORDER BY clause. +*/ +static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ + Fts5Table *pTab = (Fts5Table*)pVTab; + Fts5Config *pConfig = pTab->pConfig; + int idxFlags = 0; /* Parameter passed through to xFilter() */ + int bHasMatch; + int iNext; + int i; + + struct Constraint { + int op; /* Mask against sqlite3_index_constraint.op */ + int fts5op; /* FTS5 mask for idxFlags */ + int iCol; /* 0==rowid, 1==tbl, 2==rank */ + int omit; /* True to omit this if found */ + int iConsIndex; /* Index in pInfo->aConstraint[] */ + } aConstraint[] = { + {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, + FTS5_BI_MATCH, 1, 1, -1}, + {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, + FTS5_BI_RANK, 2, 1, -1}, + {SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_ROWID_EQ, 0, 0, -1}, + {SQLITE_INDEX_CONSTRAINT_LT|SQLITE_INDEX_CONSTRAINT_LE, + FTS5_BI_ROWID_LE, 0, 0, -1}, + {SQLITE_INDEX_CONSTRAINT_GT|SQLITE_INDEX_CONSTRAINT_GE, + FTS5_BI_ROWID_GE, 0, 0, -1}, + }; + + int aColMap[3]; + aColMap[0] = -1; + aColMap[1] = pConfig->nCol; + aColMap[2] = pConfig->nCol+1; + + /* Set idxFlags flags for all WHERE clause terms that will be used. */ + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; + int j; + for(j=0; jiColumn==aColMap[pC->iCol] && p->op & pC->op ){ + if( p->usable ){ + pC->iConsIndex = i; + idxFlags |= pC->fts5op; + }else if( j==0 ){ + /* As there exists an unusable MATCH constraint this is an + ** unusable plan. Set a prohibitively high cost. */ + pInfo->estimatedCost = 1e50; + return SQLITE_OK; + } + } + } + } + + /* Set idxFlags flags for the ORDER BY clause */ + if( pInfo->nOrderBy==1 ){ + int iSort = pInfo->aOrderBy[0].iColumn; + if( iSort==(pConfig->nCol+1) && BitFlagTest(idxFlags, FTS5_BI_MATCH) ){ + idxFlags |= FTS5_BI_ORDER_RANK; + }else if( iSort==-1 ){ + idxFlags |= FTS5_BI_ORDER_ROWID; + } + if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){ + pInfo->orderByConsumed = 1; + if( pInfo->aOrderBy[0].desc ){ + idxFlags |= FTS5_BI_ORDER_DESC; + } + } + } + + /* Calculate the estimated cost based on the flags set in idxFlags. */ + bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH); + if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){ + pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0; + if( bHasMatch==0 ) fts5SetUniqueFlag(pInfo); + }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ + pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0; + }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ + pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0; + }else{ + pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0; + } + + /* Assign argvIndex values to each constraint in use. */ + iNext = 1; + for(i=0; iiConsIndex>=0 ){ + pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++; + pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit; + } + } + + pInfo->idxNum = idxFlags; + return SQLITE_OK; +} + +/* +** Implementation of xOpen method. +*/ +static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ + Fts5Table *pTab = (Fts5Table*)pVTab; + Fts5Config *pConfig = pTab->pConfig; + Fts5Cursor *pCsr; /* New cursor object */ + int nByte; /* Bytes of space to allocate */ + int rc = SQLITE_OK; /* Return code */ + + nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int); + pCsr = (Fts5Cursor*)sqlite3_malloc(nByte); + if( pCsr ){ + Fts5Global *pGlobal = pTab->pGlobal; + memset(pCsr, 0, nByte); + pCsr->aColumnSize = (int*)&pCsr[1]; + pCsr->pNext = pGlobal->pCsr; + pGlobal->pCsr = pCsr; + pCsr->iCsrId = ++pGlobal->iNextId; + }else{ + rc = SQLITE_NOMEM; + } + *ppCsr = (sqlite3_vtab_cursor*)pCsr; + return rc; +} + +static int fts5StmtType(Fts5Cursor *pCsr){ + if( pCsr->ePlan==FTS5_PLAN_SCAN ){ + return (pCsr->bDesc) ? FTS5_STMT_SCAN_DESC : FTS5_STMT_SCAN_ASC; + } + return FTS5_STMT_LOOKUP; +} + +/* +** This function is called after the cursor passed as the only argument +** is moved to point at a different row. It clears all cached data +** specific to the previous row stored by the cursor object. +*/ +static void fts5CsrNewrow(Fts5Cursor *pCsr){ + CsrFlagSet(pCsr, + FTS5CSR_REQUIRE_CONTENT + | FTS5CSR_REQUIRE_DOCSIZE + | FTS5CSR_REQUIRE_INST + | FTS5CSR_REQUIRE_POSLIST + ); +} + +static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5Auxdata *pData; + Fts5Auxdata *pNext; + + sqlite3_free(pCsr->aInstIter); + sqlite3_free(pCsr->aInst); + if( pCsr->pStmt ){ + int eStmt = fts5StmtType(pCsr); + sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt); + } + if( pCsr->pSorter ){ + Fts5Sorter *pSorter = pCsr->pSorter; + sqlite3_finalize(pSorter->pStmt); + sqlite3_free(pSorter); + } + + if( pCsr->ePlan!=FTS5_PLAN_SOURCE ){ + sqlite3Fts5ExprFree(pCsr->pExpr); + } + + for(pData=pCsr->pAuxdata; pData; pData=pNext){ + pNext = pData->pNext; + if( pData->xDelete ) pData->xDelete(pData->pPtr); + sqlite3_free(pData); + } + + sqlite3_finalize(pCsr->pRankArgStmt); + sqlite3_free(pCsr->apRankArg); + + if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){ + sqlite3_free(pCsr->zRank); + sqlite3_free(pCsr->zRankArgs); + } + + memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr)); +} + + +/* +** Close the cursor. For additional information see the documentation +** on the xClose method of the virtual table interface. +*/ +static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){ + if( pCursor ){ + Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + Fts5Cursor **pp; + + fts5FreeCursorComponents(pCsr); + /* Remove the cursor from the Fts5Global.pCsr list */ + for(pp=&pTab->pGlobal->pCsr; (*pp)!=pCsr; pp=&(*pp)->pNext); + *pp = pCsr->pNext; + + sqlite3_free(pCsr); + } + return SQLITE_OK; +} + +static int fts5SorterNext(Fts5Cursor *pCsr){ + Fts5Sorter *pSorter = pCsr->pSorter; + int rc; + + rc = sqlite3_step(pSorter->pStmt); + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + CsrFlagSet(pCsr, FTS5CSR_EOF); + }else if( rc==SQLITE_ROW ){ + const u8 *a; + const u8 *aBlob; + int nBlob; + int i; + int iOff = 0; + rc = SQLITE_OK; + + pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0); + nBlob = sqlite3_column_bytes(pSorter->pStmt, 1); + aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1); + + /* nBlob==0 in detail=none mode. */ + if( nBlob>0 ){ + for(i=0; i<(pSorter->nIdx-1); i++){ + int iVal; + a += fts5GetVarint32(a, iVal); + iOff += iVal; + pSorter->aIdx[i] = iOff; + } + pSorter->aIdx[i] = &aBlob[nBlob] - a; + pSorter->aPoslist = a; + } + + fts5CsrNewrow(pCsr); + } + + return rc; +} + + +/* +** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors +** open on table pTab. +*/ +static void fts5TripCursors(Fts5Table *pTab){ + Fts5Cursor *pCsr; + for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ + if( pCsr->ePlan==FTS5_PLAN_MATCH + && pCsr->base.pVtab==(sqlite3_vtab*)pTab + ){ + CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK); + } + } +} + +/* +** If the REQUIRE_RESEEK flag is set on the cursor passed as the first +** argument, close and reopen all Fts5IndexIter iterators that the cursor +** is using. Then attempt to move the cursor to a rowid equal to or laster +** (in the cursors sort order - ASC or DESC) than the current rowid. +** +** If the new rowid is not equal to the old, set output parameter *pbSkip +** to 1 before returning. Otherwise, leave it unchanged. +** +** Return SQLITE_OK if successful or if no reseek was required, or an +** error code if an error occurred. +*/ +static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ + int rc = SQLITE_OK; + assert( *pbSkip==0 ); + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){ + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + int bDesc = pCsr->bDesc; + i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr); + + rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc); + if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){ + *pbSkip = 1; + } + + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK); + fts5CsrNewrow(pCsr); + if( sqlite3Fts5ExprEof(pCsr->pExpr) ){ + CsrFlagSet(pCsr, FTS5CSR_EOF); + *pbSkip = 1; + } + } + return rc; +} + + +/* +** Advance the cursor to the next row in the table that matches the +** search criteria. +** +** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned +** even if we reach end-of-file. The fts5EofMethod() will be called +** subsequently to determine whether or not an EOF was hit. +*/ +static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + int rc; + + assert( (pCsr->ePlan<3)== + (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) + ); + assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) ); + + if( pCsr->ePlan<3 ){ + int bSkip = 0; + if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc; + rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid); + CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr)); + fts5CsrNewrow(pCsr); + }else{ + switch( pCsr->ePlan ){ + case FTS5_PLAN_SPECIAL: { + CsrFlagSet(pCsr, FTS5CSR_EOF); + rc = SQLITE_OK; + break; + } + + case FTS5_PLAN_SORTED_MATCH: { + rc = fts5SorterNext(pCsr); + break; + } + + default: + rc = sqlite3_step(pCsr->pStmt); + if( rc!=SQLITE_ROW ){ + CsrFlagSet(pCsr, FTS5CSR_EOF); + rc = sqlite3_reset(pCsr->pStmt); + }else{ + rc = SQLITE_OK; + } + break; + } + } + + return rc; +} + + +static int fts5PrepareStatement( + sqlite3_stmt **ppStmt, + Fts5Config *pConfig, + const char *zFmt, + ... +){ + sqlite3_stmt *pRet = 0; + int rc; + char *zSql; + va_list ap; + + va_start(ap, zFmt); + zSql = sqlite3_vmprintf(zFmt, ap); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0); + if( rc!=SQLITE_OK ){ + *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); + } + sqlite3_free(zSql); + } + + va_end(ap); + *ppStmt = pRet; + return rc; +} + +static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ + Fts5Config *pConfig = pTab->pConfig; + Fts5Sorter *pSorter; + int nPhrase; + int nByte; + int rc; + const char *zRank = pCsr->zRank; + const char *zRankArgs = pCsr->zRankArgs; + + nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); + nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); + pSorter = (Fts5Sorter*)sqlite3_malloc(nByte); + if( pSorter==0 ) return SQLITE_NOMEM; + memset(pSorter, 0, nByte); + pSorter->nIdx = nPhrase; + + /* TODO: It would be better to have some system for reusing statement + ** handles here, rather than preparing a new one for each query. But that + ** is not possible as SQLite reference counts the virtual table objects. + ** And since the statement required here reads from this very virtual + ** table, saving it creates a circular reference. + ** + ** If SQLite a built-in statement cache, this wouldn't be a problem. */ + rc = fts5PrepareStatement(&pSorter->pStmt, pConfig, + "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s", + pConfig->zDb, pConfig->zName, zRank, pConfig->zName, + (zRankArgs ? ", " : ""), + (zRankArgs ? zRankArgs : ""), + bDesc ? "DESC" : "ASC" + ); + + pCsr->pSorter = pSorter; + if( rc==SQLITE_OK ){ + assert( pTab->pSortCsr==0 ); + pTab->pSortCsr = pCsr; + rc = fts5SorterNext(pCsr); + pTab->pSortCsr = 0; + } + + if( rc!=SQLITE_OK ){ + sqlite3_finalize(pSorter->pStmt); + sqlite3_free(pSorter); + pCsr->pSorter = 0; + } + + return rc; +} + +static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ + int rc; + Fts5Expr *pExpr = pCsr->pExpr; + rc = sqlite3Fts5ExprFirst(pExpr, pTab->pIndex, pCsr->iFirstRowid, bDesc); + if( sqlite3Fts5ExprEof(pExpr) ){ + CsrFlagSet(pCsr, FTS5CSR_EOF); + } + fts5CsrNewrow(pCsr); + return rc; +} + +/* +** Process a "special" query. A special query is identified as one with a +** MATCH expression that begins with a '*' character. The remainder of +** the text passed to the MATCH operator are used as the special query +** parameters. +*/ +static int fts5SpecialMatch( + Fts5Table *pTab, + Fts5Cursor *pCsr, + const char *zQuery +){ + int rc = SQLITE_OK; /* Return code */ + const char *z = zQuery; /* Special query text */ + int n; /* Number of bytes in text at z */ + + while( z[0]==' ' ) z++; + for(n=0; z[n] && z[n]!=' '; n++); + + assert( pTab->base.zErrMsg==0 ); + pCsr->ePlan = FTS5_PLAN_SPECIAL; + + if( 0==sqlite3_strnicmp("reads", z, n) ){ + pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->pIndex); + } + else if( 0==sqlite3_strnicmp("id", z, n) ){ + pCsr->iSpecial = pCsr->iCsrId; + } + else{ + /* An unrecognized directive. Return an error message. */ + pTab->base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z); + rc = SQLITE_ERROR; + } + + return rc; +} + +/* +** Search for an auxiliary function named zName that can be used with table +** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary +** structure. Otherwise, if no such function exists, return NULL. +*/ +static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){ + Fts5Auxiliary *pAux; + + for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){ + if( sqlite3_stricmp(zName, pAux->zFunc)==0 ) return pAux; + } + + /* No function of the specified name was found. Return 0. */ + return 0; +} + + +static int fts5FindRankFunction(Fts5Cursor *pCsr){ + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5Config *pConfig = pTab->pConfig; + int rc = SQLITE_OK; + Fts5Auxiliary *pAux = 0; + const char *zRank = pCsr->zRank; + const char *zRankArgs = pCsr->zRankArgs; + + if( zRankArgs ){ + char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs); + if( zSql ){ + sqlite3_stmt *pStmt = 0; + rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 ); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + int nByte; + pCsr->nRankArg = sqlite3_column_count(pStmt); + nByte = sizeof(sqlite3_value*)*pCsr->nRankArg; + pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte); + if( rc==SQLITE_OK ){ + int i; + for(i=0; inRankArg; i++){ + pCsr->apRankArg[i] = sqlite3_column_value(pStmt, i); + } + } + pCsr->pRankArgStmt = pStmt; + }else{ + rc = sqlite3_finalize(pStmt); + assert( rc!=SQLITE_OK ); + } + } + } + } + + if( rc==SQLITE_OK ){ + pAux = fts5FindAuxiliary(pTab, zRank); + if( pAux==0 ){ + assert( pTab->base.zErrMsg==0 ); + pTab->base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank); + rc = SQLITE_ERROR; + } + } + + pCsr->pRank = pAux; + return rc; +} + + +static int fts5CursorParseRank( + Fts5Config *pConfig, + Fts5Cursor *pCsr, + sqlite3_value *pRank +){ + int rc = SQLITE_OK; + if( pRank ){ + const char *z = (const char*)sqlite3_value_text(pRank); + char *zRank = 0; + char *zRankArgs = 0; + + if( z==0 ){ + if( sqlite3_value_type(pRank)==SQLITE_NULL ) rc = SQLITE_ERROR; + }else{ + rc = sqlite3Fts5ConfigParseRank(z, &zRank, &zRankArgs); + } + if( rc==SQLITE_OK ){ + pCsr->zRank = zRank; + pCsr->zRankArgs = zRankArgs; + CsrFlagSet(pCsr, FTS5CSR_FREE_ZRANK); + }else if( rc==SQLITE_ERROR ){ + pCsr->base.pVtab->zErrMsg = sqlite3_mprintf( + "parse error in rank function: %s", z + ); + } + }else{ + if( pConfig->zRank ){ + pCsr->zRank = (char*)pConfig->zRank; + pCsr->zRankArgs = (char*)pConfig->zRankArgs; + }else{ + pCsr->zRank = (char*)FTS5_DEFAULT_RANK; + pCsr->zRankArgs = 0; + } + } + return rc; +} + +static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){ + if( pVal ){ + int eType = sqlite3_value_numeric_type(pVal); + if( eType==SQLITE_INTEGER ){ + return sqlite3_value_int64(pVal); + } + } + return iDefault; +} + +/* +** This is the xFilter interface for the virtual table. See +** the virtual table xFilter method documentation for additional +** information. +** +** There are three possible query strategies: +** +** 1. Full-text search using a MATCH operator. +** 2. A by-rowid lookup. +** 3. A full-table scan. +*/ +static int fts5FilterMethod( + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ + int idxNum, /* Strategy index */ + const char *zUnused, /* Unused */ + int nVal, /* Number of elements in apVal */ + sqlite3_value **apVal /* Arguments for the indexing scheme */ +){ + Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); + Fts5Config *pConfig = pTab->pConfig; + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + int rc = SQLITE_OK; /* Error code */ + int iVal = 0; /* Counter for apVal[] */ + int bDesc; /* True if ORDER BY [rank|rowid] DESC */ + int bOrderByRank; /* True if ORDER BY rank */ + sqlite3_value *pMatch = 0; /* MATCH ? expression (or NULL) */ + sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */ + sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */ + sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */ + sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */ + char **pzErrmsg = pConfig->pzErrmsg; + + UNUSED_PARAM(zUnused); + UNUSED_PARAM(nVal); + + if( pCsr->ePlan ){ + fts5FreeCursorComponents(pCsr); + memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr)); + } + + assert( pCsr->pStmt==0 ); + assert( pCsr->pExpr==0 ); + assert( pCsr->csrflags==0 ); + assert( pCsr->pRank==0 ); + assert( pCsr->zRank==0 ); + assert( pCsr->zRankArgs==0 ); + + assert( pzErrmsg==0 || pzErrmsg==&pTab->base.zErrMsg ); + pConfig->pzErrmsg = &pTab->base.zErrMsg; + + /* Decode the arguments passed through to this function. + ** + ** Note: The following set of if(...) statements must be in the same + ** order as the corresponding entries in the struct at the top of + ** fts5BestIndexMethod(). */ + if( BitFlagTest(idxNum, FTS5_BI_MATCH) ) pMatch = apVal[iVal++]; + if( BitFlagTest(idxNum, FTS5_BI_RANK) ) pRank = apVal[iVal++]; + if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++]; + if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++]; + if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++]; + assert( iVal==nVal ); + bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0); + pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0); + + /* Set the cursor upper and lower rowid limits. Only some strategies + ** actually use them. This is ok, as the xBestIndex() method leaves the + ** sqlite3_index_constraint.omit flag clear for range constraints + ** on the rowid field. */ + if( pRowidEq ){ + pRowidLe = pRowidGe = pRowidEq; + } + if( bDesc ){ + pCsr->iFirstRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64); + pCsr->iLastRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64); + }else{ + pCsr->iLastRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64); + pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64); + } + + if( pTab->pSortCsr ){ + /* If pSortCsr is non-NULL, then this call is being made as part of + ** processing for a "... MATCH ORDER BY rank" query (ePlan is + ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will + ** return results to the user for this query. The current cursor + ** (pCursor) is used to execute the query issued by function + ** fts5CursorFirstSorted() above. */ + assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 ); + assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 ); + assert( pCsr->iLastRowid==LARGEST_INT64 ); + assert( pCsr->iFirstRowid==SMALLEST_INT64 ); + pCsr->ePlan = FTS5_PLAN_SOURCE; + pCsr->pExpr = pTab->pSortCsr->pExpr; + rc = fts5CursorFirst(pTab, pCsr, bDesc); + sqlite3Fts5ExprClearEof(pCsr->pExpr); + }else if( pMatch ){ + const char *zExpr = (const char*)sqlite3_value_text(apVal[0]); + if( zExpr==0 ) zExpr = ""; + + rc = fts5CursorParseRank(pConfig, pCsr, pRank); + if( rc==SQLITE_OK ){ + if( zExpr[0]=='*' ){ + /* The user has issued a query of the form "MATCH '*...'". This + ** indicates that the MATCH expression is not a full text query, + ** but a request for an internal parameter. */ + rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]); + }else{ + char **pzErr = &pTab->base.zErrMsg; + rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr); + if( rc==SQLITE_OK ){ + if( bOrderByRank ){ + pCsr->ePlan = FTS5_PLAN_SORTED_MATCH; + rc = fts5CursorFirstSorted(pTab, pCsr, bDesc); + }else{ + pCsr->ePlan = FTS5_PLAN_MATCH; + rc = fts5CursorFirst(pTab, pCsr, bDesc); + } + } + } + } + }else if( pConfig->zContent==0 ){ + *pConfig->pzErrmsg = sqlite3_mprintf( + "%s: table does not support scanning", pConfig->zName + ); + rc = SQLITE_ERROR; + }else{ + /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup + ** by rowid (ePlan==FTS5_PLAN_ROWID). */ + pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN); + rc = sqlite3Fts5StorageStmt( + pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->base.zErrMsg + ); + if( rc==SQLITE_OK ){ + if( pCsr->ePlan==FTS5_PLAN_ROWID ){ + sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); + }else{ + sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid); + sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid); + } + rc = fts5NextMethod(pCursor); + } + } + + pConfig->pzErrmsg = pzErrmsg; + return rc; +} + +/* +** This is the xEof method of the virtual table. SQLite calls this +** routine to find out if it has reached the end of a result set. +*/ +static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + return (CsrFlagTest(pCsr, FTS5CSR_EOF) ? 1 : 0); +} + +/* +** Return the rowid that the cursor currently points to. +*/ +static i64 fts5CursorRowid(Fts5Cursor *pCsr){ + assert( pCsr->ePlan==FTS5_PLAN_MATCH + || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH + || pCsr->ePlan==FTS5_PLAN_SOURCE + ); + if( pCsr->pSorter ){ + return pCsr->pSorter->iRowid; + }else{ + return sqlite3Fts5ExprRowid(pCsr->pExpr); + } +} + +/* +** This is the xRowid method. The SQLite core calls this routine to +** retrieve the rowid for the current row of the result set. fts5 +** exposes %_content.rowid as the rowid for the virtual table. The +** rowid should be written to *pRowid. +*/ +static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + int ePlan = pCsr->ePlan; + + assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 ); + switch( ePlan ){ + case FTS5_PLAN_SPECIAL: + *pRowid = 0; + break; + + case FTS5_PLAN_SOURCE: + case FTS5_PLAN_MATCH: + case FTS5_PLAN_SORTED_MATCH: + *pRowid = fts5CursorRowid(pCsr); + break; + + default: + *pRowid = sqlite3_column_int64(pCsr->pStmt, 0); + break; + } + + return SQLITE_OK; +} + +/* +** If the cursor requires seeking (bSeekRequired flag is set), seek it. +** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise. +** +** If argument bErrormsg is true and an error occurs, an error message may +** be left in sqlite3_vtab.zErrMsg. +*/ +static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ + int rc = SQLITE_OK; + + /* If the cursor does not yet have a statement handle, obtain one now. */ + if( pCsr->pStmt==0 ){ + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + int eStmt = fts5StmtType(pCsr); + rc = sqlite3Fts5StorageStmt( + pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->base.zErrMsg:0) + ); + assert( rc!=SQLITE_OK || pTab->base.zErrMsg==0 ); + assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ); + } + + if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){ + assert( pCsr->pExpr ); + sqlite3_reset(pCsr->pStmt); + sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr)); + rc = sqlite3_step(pCsr->pStmt); + if( rc==SQLITE_ROW ){ + rc = SQLITE_OK; + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT); + }else{ + rc = sqlite3_reset(pCsr->pStmt); + if( rc==SQLITE_OK ){ + rc = FTS5_CORRUPT; + } + } + } + return rc; +} + +static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){ + va_list ap; /* ... printf arguments */ + va_start(ap, zFormat); + assert( p->base.zErrMsg==0 ); + p->base.zErrMsg = sqlite3_vmprintf(zFormat, ap); + va_end(ap); +} + +/* +** This function is called to handle an FTS INSERT command. In other words, +** an INSERT statement of the form: +** +** INSERT INTO fts(fts) VALUES($pCmd) +** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal) +** +** Argument pVal is the value assigned to column "fts" by the INSERT +** statement. This function returns SQLITE_OK if successful, or an SQLite +** error code if an error occurs. +** +** The commands implemented by this function are documented in the "Special +** INSERT Directives" section of the documentation. It should be updated if +** more commands are added to this function. +*/ +static int fts5SpecialInsert( + Fts5Table *pTab, /* Fts5 table object */ + const char *zCmd, /* Text inserted into table-name column */ + sqlite3_value *pVal /* Value inserted into rank column */ +){ + Fts5Config *pConfig = pTab->pConfig; + int rc = SQLITE_OK; + int bError = 0; + + if( 0==sqlite3_stricmp("delete-all", zCmd) ){ + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + fts5SetVtabError(pTab, + "'delete-all' may only be used with a " + "contentless or external content fts5 table" + ); + rc = SQLITE_ERROR; + }else{ + rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage); + } + }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){ + if( pConfig->eContent==FTS5_CONTENT_NONE ){ + fts5SetVtabError(pTab, + "'rebuild' may not be used with a contentless fts5 table" + ); + rc = SQLITE_ERROR; + }else{ + rc = sqlite3Fts5StorageRebuild(pTab->pStorage); + } + }else if( 0==sqlite3_stricmp("optimize", zCmd) ){ + rc = sqlite3Fts5StorageOptimize(pTab->pStorage); + }else if( 0==sqlite3_stricmp("merge", zCmd) ){ + int nMerge = sqlite3_value_int(pVal); + rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge); + }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){ + rc = sqlite3Fts5StorageIntegrity(pTab->pStorage); +#ifdef SQLITE_DEBUG + }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){ + pConfig->bPrefixIndex = sqlite3_value_int(pVal); +#endif + }else{ + rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError); + } + if( rc==SQLITE_OK ){ + if( bError ){ + rc = SQLITE_ERROR; + }else{ + rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0); + } + } + } + return rc; +} + +static int fts5SpecialDelete( + Fts5Table *pTab, + sqlite3_value **apVal +){ + int rc = SQLITE_OK; + int eType1 = sqlite3_value_type(apVal[1]); + if( eType1==SQLITE_INTEGER ){ + sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]); + } + return rc; +} + +static void fts5StorageInsert( + int *pRc, + Fts5Table *pTab, + sqlite3_value **apVal, + i64 *piRowid +){ + int rc = *pRc; + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid); + } + *pRc = rc; +} + +/* +** This function is the implementation of the xUpdate callback used by +** FTS3 virtual tables. It is invoked by SQLite each time a row is to be +** inserted, updated or deleted. +** +** A delete specifies a single argument - the rowid of the row to remove. +** +** Update and insert operations pass: +** +** 1. The "old" rowid, or NULL. +** 2. The "new" rowid. +** 3. Values for each of the nCol matchable columns. +** 4. Values for the two hidden columns ( and "rank"). +*/ +static int fts5UpdateMethod( + sqlite3_vtab *pVtab, /* Virtual table handle */ + int nArg, /* Size of argument array */ + sqlite3_value **apVal, /* Array of arguments */ + sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ +){ + Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5Config *pConfig = pTab->pConfig; + int eType0; /* value_type() of apVal[0] */ + int rc = SQLITE_OK; /* Return code */ + + /* A transaction must be open when this is called. */ + assert( pTab->ts.eState==1 ); + + assert( pVtab->zErrMsg==0 ); + assert( nArg==1 || nArg==(2+pConfig->nCol+2) ); + assert( nArg==1 + || sqlite3_value_type(apVal[1])==SQLITE_INTEGER + || sqlite3_value_type(apVal[1])==SQLITE_NULL + ); + assert( pTab->pConfig->pzErrmsg==0 ); + pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; + + /* Put any active cursors into REQUIRE_SEEK state. */ + fts5TripCursors(pTab); + + eType0 = sqlite3_value_type(apVal[0]); + if( eType0==SQLITE_NULL + && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL + ){ + /* A "special" INSERT op. These are handled separately. */ + const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]); + if( pConfig->eContent!=FTS5_CONTENT_NORMAL + && 0==sqlite3_stricmp("delete", z) + ){ + rc = fts5SpecialDelete(pTab, apVal); + }else{ + rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]); + } + }else{ + /* A regular INSERT, UPDATE or DELETE statement. The trick here is that + ** any conflict on the rowid value must be detected before any + ** modifications are made to the database file. There are 4 cases: + ** + ** 1) DELETE + ** 2) UPDATE (rowid not modified) + ** 3) UPDATE (rowid modified) + ** 4) INSERT + ** + ** Cases 3 and 4 may violate the rowid constraint. + */ + int eConflict = SQLITE_ABORT; + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + eConflict = sqlite3_vtab_on_conflict(pConfig->db); + } + + assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL ); + assert( nArg!=1 || eType0==SQLITE_INTEGER ); + + /* Filter out attempts to run UPDATE or DELETE on contentless tables. + ** This is not suported. */ + if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){ + pTab->base.zErrMsg = sqlite3_mprintf( + "cannot %s contentless fts5 table: %s", + (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName + ); + rc = SQLITE_ERROR; + } + + /* Case 1: DELETE */ + else if( nArg==1 ){ + i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); + } + + /* Case 2: INSERT */ + else if( eType0!=SQLITE_INTEGER ){ + /* If this is a REPLACE, first remove the current entry (if any) */ + if( eConflict==SQLITE_REPLACE + && sqlite3_value_type(apVal[1])==SQLITE_INTEGER + ){ + i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + } + fts5StorageInsert(&rc, pTab, apVal, pRowid); + } + + /* Case 2: UPDATE */ + else{ + i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ + i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ + if( iOld!=iNew ){ + if( eConflict==SQLITE_REPLACE ){ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + } + fts5StorageInsert(&rc, pTab, apVal, pRowid); + }else{ + rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid); + } + } + }else{ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + fts5StorageInsert(&rc, pTab, apVal, pRowid); + } + } + } + + pTab->pConfig->pzErrmsg = 0; + return rc; +} + +/* +** Implementation of xSync() method. +*/ +static int fts5SyncMethod(sqlite3_vtab *pVtab){ + int rc; + Fts5Table *pTab = (Fts5Table*)pVtab; + fts5CheckTransactionState(pTab, FTS5_SYNC, 0); + pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; + fts5TripCursors(pTab); + rc = sqlite3Fts5StorageSync(pTab->pStorage, 1); + pTab->pConfig->pzErrmsg = 0; + return rc; +} + +/* +** Implementation of xBegin() method. +*/ +static int fts5BeginMethod(sqlite3_vtab *pVtab){ + UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */ + fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0); + return SQLITE_OK; +} + +/* +** Implementation of xCommit() method. This is a no-op. The contents of +** the pending-terms hash-table have already been flushed into the database +** by fts5SyncMethod(). +*/ +static int fts5CommitMethod(sqlite3_vtab *pVtab){ + UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */ + fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0); + return SQLITE_OK; +} + +/* +** Implementation of xRollback(). Discard the contents of the pending-terms +** hash-table. Any changes made to the database are reverted by SQLite. +*/ +static int fts5RollbackMethod(sqlite3_vtab *pVtab){ + int rc; + Fts5Table *pTab = (Fts5Table*)pVtab; + fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0); + rc = sqlite3Fts5StorageRollback(pTab->pStorage); + return rc; +} + +static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*); + +static void *fts5ApiUserData(Fts5Context *pCtx){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + return pCsr->pAux->pUserData; +} + +static int fts5ApiColumnCount(Fts5Context *pCtx){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + return ((Fts5Table*)(pCsr->base.pVtab))->pConfig->nCol; +} + +static int fts5ApiColumnTotalSize( + Fts5Context *pCtx, + int iCol, + sqlite3_int64 *pnToken +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken); +} + +static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow); +} + +static int fts5ApiTokenize( + Fts5Context *pCtx, + const char *pText, int nText, + void *pUserData, + int (*xToken)(void*, int, const char*, int, int, int) +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + return sqlite3Fts5Tokenize( + pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken + ); +} + +static int fts5ApiPhraseCount(Fts5Context *pCtx){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + return sqlite3Fts5ExprPhraseCount(pCsr->pExpr); +} + +static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase); +} + +static int fts5ApiColumnText( + Fts5Context *pCtx, + int iCol, + const char **pz, + int *pn +){ + int rc = SQLITE_OK; + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ + *pz = 0; + *pn = 0; + }else{ + rc = fts5SeekCursor(pCsr, 0); + if( rc==SQLITE_OK ){ + *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); + *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); + } + } + return rc; +} + +static int fts5CsrPoslist( + Fts5Cursor *pCsr, + int iPhrase, + const u8 **pa, + int *pn +){ + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; + int rc = SQLITE_OK; + int bLive = (pCsr->pSorter==0); + + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ + + if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ + Fts5PoslistPopulator *aPopulator; + int i; + aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive); + if( aPopulator==0 ) rc = SQLITE_NOMEM; + for(i=0; inCol && rc==SQLITE_OK; i++){ + int n; const char *z; + rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ExprPopulatePoslists( + pConfig, pCsr->pExpr, aPopulator, i, z, n + ); + } + } + sqlite3_free(aPopulator); + + if( pCsr->pSorter ){ + sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid); + } + } + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST); + } + + if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){ + Fts5Sorter *pSorter = pCsr->pSorter; + int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); + *pn = pSorter->aIdx[iPhrase] - i1; + *pa = &pSorter->aPoslist[i1]; + }else{ + *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); + } + + return rc; +} + +/* +** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated +** correctly for the current view. Return SQLITE_OK if successful, or an +** SQLite error code otherwise. +*/ +static int fts5CacheInstArray(Fts5Cursor *pCsr){ + int rc = SQLITE_OK; + Fts5PoslistReader *aIter; /* One iterator for each phrase */ + int nIter; /* Number of iterators/phrases */ + + nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); + if( pCsr->aInstIter==0 ){ + int nByte = sizeof(Fts5PoslistReader) * nIter; + pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte); + } + aIter = pCsr->aInstIter; + + if( aIter ){ + int nInst = 0; /* Number instances seen so far */ + int i; + + /* Initialize all iterators */ + for(i=0; i=pCsr->nInstAlloc ){ + pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; + aInst = (int*)sqlite3_realloc( + pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3 + ); + if( aInst ){ + pCsr->aInst = aInst; + }else{ + rc = SQLITE_NOMEM; + break; + } + } + + aInst = &pCsr->aInst[3 * (nInst-1)]; + aInst[0] = iBest; + aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); + aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); + sqlite3Fts5PoslistReaderNext(&aIter[iBest]); + } + } + + pCsr->nInstCount = nInst; + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST); + } + return rc; +} + +static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + int rc = SQLITE_OK; + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 + || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){ + *pnInst = pCsr->nInstCount; + } + return rc; +} + +static int fts5ApiInst( + Fts5Context *pCtx, + int iIdx, + int *piPhrase, + int *piCol, + int *piOff +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + int rc = SQLITE_OK; + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 + || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) + ){ + if( iIdx<0 || iIdx>=pCsr->nInstCount ){ + rc = SQLITE_RANGE; +#if 0 + }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){ + *piPhrase = pCsr->aInst[iIdx*3]; + *piCol = pCsr->aInst[iIdx*3 + 2]; + *piOff = -1; +#endif + }else{ + *piPhrase = pCsr->aInst[iIdx*3]; + *piCol = pCsr->aInst[iIdx*3 + 1]; + *piOff = pCsr->aInst[iIdx*3 + 2]; + } + } + return rc; +} + +static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){ + return fts5CursorRowid((Fts5Cursor*)pCtx); +} + +static int fts5ColumnSizeCb( + void *pContext, /* Pointer to int */ + int tflags, + const char *pUnused, /* Buffer containing token */ + int nUnused, /* Size of token in bytes */ + int iUnused1, /* Start offset of token */ + int iUnused2 /* End offset of token */ +){ + int *pCnt = (int*)pContext; + UNUSED_PARAM2(pUnused, nUnused); + UNUSED_PARAM2(iUnused1, iUnused2); + if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){ + (*pCnt)++; + } + return SQLITE_OK; +} + +static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5Config *pConfig = pTab->pConfig; + int rc = SQLITE_OK; + + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){ + if( pConfig->bColumnsize ){ + i64 iRowid = fts5CursorRowid(pCsr); + rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize); + }else if( pConfig->zContent==0 ){ + int i; + for(i=0; inCol; i++){ + if( pConfig->abUnindexed[i]==0 ){ + pCsr->aColumnSize[i] = -1; + } + } + }else{ + int i; + for(i=0; rc==SQLITE_OK && inCol; i++){ + if( pConfig->abUnindexed[i]==0 ){ + const char *z; int n; + void *p = (void*)(&pCsr->aColumnSize[i]); + pCsr->aColumnSize[i] = 0; + rc = fts5ApiColumnText(pCtx, i, &z, &n); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5Tokenize( + pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb + ); + } + } + } + } + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE); + } + if( iCol<0 ){ + int i; + *pnToken = 0; + for(i=0; inCol; i++){ + *pnToken += pCsr->aColumnSize[i]; + } + }else if( iColnCol ){ + *pnToken = pCsr->aColumnSize[iCol]; + }else{ + *pnToken = 0; + rc = SQLITE_RANGE; + } + return rc; +} + +/* +** Implementation of the xSetAuxdata() method. +*/ +static int fts5ApiSetAuxdata( + Fts5Context *pCtx, /* Fts5 context */ + void *pPtr, /* Pointer to save as auxdata */ + void(*xDelete)(void*) /* Destructor for pPtr (or NULL) */ +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Auxdata *pData; + + /* Search through the cursors list of Fts5Auxdata objects for one that + ** corresponds to the currently executing auxiliary function. */ + for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){ + if( pData->pAux==pCsr->pAux ) break; + } + + if( pData ){ + if( pData->xDelete ){ + pData->xDelete(pData->pPtr); + } + }else{ + int rc = SQLITE_OK; + pData = (Fts5Auxdata*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Auxdata)); + if( pData==0 ){ + if( xDelete ) xDelete(pPtr); + return rc; + } + pData->pAux = pCsr->pAux; + pData->pNext = pCsr->pAuxdata; + pCsr->pAuxdata = pData; + } + + pData->xDelete = xDelete; + pData->pPtr = pPtr; + return SQLITE_OK; +} + +static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Auxdata *pData; + void *pRet = 0; + + for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){ + if( pData->pAux==pCsr->pAux ) break; + } + + if( pData ){ + pRet = pData->pPtr; + if( bClear ){ + pData->pPtr = 0; + pData->xDelete = 0; + } + } + + return pRet; +} + +static void fts5ApiPhraseNext( + Fts5Context *pUnused, + Fts5PhraseIter *pIter, + int *piCol, int *piOff +){ + UNUSED_PARAM(pUnused); + if( pIter->a>=pIter->b ){ + *piCol = -1; + *piOff = -1; + }else{ + int iVal; + pIter->a += fts5GetVarint32(pIter->a, iVal); + if( iVal==1 ){ + pIter->a += fts5GetVarint32(pIter->a, iVal); + *piCol = iVal; + *piOff = 0; + pIter->a += fts5GetVarint32(pIter->a, iVal); + } + *piOff += (iVal-2); + } +} + +static int fts5ApiPhraseFirst( + Fts5Context *pCtx, + int iPhrase, + Fts5PhraseIter *pIter, + int *piCol, int *piOff +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + int n; + int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); + if( rc==SQLITE_OK ){ + pIter->b = &pIter->a[n]; + *piCol = 0; + *piOff = 0; + fts5ApiPhraseNext(pCtx, pIter, piCol, piOff); + } + return rc; +} + +static void fts5ApiPhraseNextColumn( + Fts5Context *pCtx, + Fts5PhraseIter *pIter, + int *piCol +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; + + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + if( pIter->a>=pIter->b ){ + *piCol = -1; + }else{ + int iIncr; + pIter->a += fts5GetVarint32(&pIter->a[0], iIncr); + *piCol += (iIncr-2); + } + }else{ + while( 1 ){ + int dummy; + if( pIter->a>=pIter->b ){ + *piCol = -1; + return; + } + if( pIter->a[0]==0x01 ) break; + pIter->a += fts5GetVarint32(pIter->a, dummy); + } + pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); + } +} + +static int fts5ApiPhraseFirstColumn( + Fts5Context *pCtx, + int iPhrase, + Fts5PhraseIter *pIter, + int *piCol +){ + int rc = SQLITE_OK; + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; + + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + Fts5Sorter *pSorter = pCsr->pSorter; + int n; + if( pSorter ){ + int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); + n = pSorter->aIdx[iPhrase] - i1; + pIter->a = &pSorter->aPoslist[i1]; + }else{ + rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); + } + if( rc==SQLITE_OK ){ + pIter->b = &pIter->a[n]; + *piCol = 0; + fts5ApiPhraseNextColumn(pCtx, pIter, piCol); + } + }else{ + int n; + rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); + if( rc==SQLITE_OK ){ + pIter->b = &pIter->a[n]; + if( n<=0 ){ + *piCol = -1; + }else if( pIter->a[0]==0x01 ){ + pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); + }else{ + *piCol = 0; + } + } + } + + return rc; +} + + +static int fts5ApiQueryPhrase(Fts5Context*, int, void*, + int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) +); + +static const Fts5ExtensionApi sFts5Api = { + 2, /* iVersion */ + fts5ApiUserData, + fts5ApiColumnCount, + fts5ApiRowCount, + fts5ApiColumnTotalSize, + fts5ApiTokenize, + fts5ApiPhraseCount, + fts5ApiPhraseSize, + fts5ApiInstCount, + fts5ApiInst, + fts5ApiRowid, + fts5ApiColumnText, + fts5ApiColumnSize, + fts5ApiQueryPhrase, + fts5ApiSetAuxdata, + fts5ApiGetAuxdata, + fts5ApiPhraseFirst, + fts5ApiPhraseNext, + fts5ApiPhraseFirstColumn, + fts5ApiPhraseNextColumn, +}; + +/* +** Implementation of API function xQueryPhrase(). +*/ +static int fts5ApiQueryPhrase( + Fts5Context *pCtx, + int iPhrase, + void *pUserData, + int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*) +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + int rc; + Fts5Cursor *pNew = 0; + + rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew); + if( rc==SQLITE_OK ){ + pNew->ePlan = FTS5_PLAN_MATCH; + pNew->iFirstRowid = SMALLEST_INT64; + pNew->iLastRowid = LARGEST_INT64; + pNew->base.pVtab = (sqlite3_vtab*)pTab; + rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr); + } + + if( rc==SQLITE_OK ){ + for(rc = fts5CursorFirst(pTab, pNew, 0); + rc==SQLITE_OK && CsrFlagTest(pNew, FTS5CSR_EOF)==0; + rc = fts5NextMethod((sqlite3_vtab_cursor*)pNew) + ){ + rc = xCallback(&sFts5Api, (Fts5Context*)pNew, pUserData); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + break; + } + } + } + + fts5CloseMethod((sqlite3_vtab_cursor*)pNew); + return rc; +} + +static void fts5ApiInvoke( + Fts5Auxiliary *pAux, + Fts5Cursor *pCsr, + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + assert( pCsr->pAux==0 ); + pCsr->pAux = pAux; + pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv); + pCsr->pAux = 0; +} + +static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){ + Fts5Cursor *pCsr; + for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ + if( pCsr->iCsrId==iCsrId ) break; + } + return pCsr; +} + +static void fts5ApiCallback( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + + Fts5Auxiliary *pAux; + Fts5Cursor *pCsr; + i64 iCsrId; + + assert( argc>=1 ); + pAux = (Fts5Auxiliary*)sqlite3_user_data(context); + iCsrId = sqlite3_value_int64(argv[0]); + + pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId); + if( pCsr==0 ){ + char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId); + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + }else{ + fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]); + } +} + + +/* +** Given cursor id iId, return a pointer to the corresponding Fts5Index +** object. Or NULL If the cursor id does not exist. +** +** If successful, set *ppConfig to point to the associated config object +** before returning. +*/ +Fts5Index *sqlite3Fts5IndexFromCsrid( + Fts5Global *pGlobal, /* FTS5 global context for db handle */ + i64 iCsrId, /* Id of cursor to find */ + Fts5Config **ppConfig /* OUT: Configuration object */ +){ + Fts5Cursor *pCsr; + Fts5Table *pTab; + + pCsr = fts5CursorFromCsrid(pGlobal, iCsrId); + pTab = (Fts5Table*)pCsr->base.pVtab; + *ppConfig = pTab->pConfig; + + return pTab->pIndex; +} + +/* +** Return a "position-list blob" corresponding to the current position of +** cursor pCsr via sqlite3_result_blob(). A position-list blob contains +** the current position-list for each phrase in the query associated with +** cursor pCsr. +** +** A position-list blob begins with (nPhrase-1) varints, where nPhrase is +** the number of phrases in the query. Following the varints are the +** concatenated position lists for each phrase, in order. +** +** The first varint (if it exists) contains the size of the position list +** for phrase 0. The second (same disclaimer) contains the size of position +** list 1. And so on. There is no size field for the final position list, +** as it can be derived from the total size of the blob. +*/ +static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){ + int i; + int rc = SQLITE_OK; + int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); + Fts5Buffer val; + + memset(&val, 0, sizeof(Fts5Buffer)); + switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){ + case FTS5_DETAIL_FULL: + + /* Append the varints */ + for(i=0; i<(nPhrase-1); i++){ + const u8 *dummy; + int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy); + sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); + } + + /* Append the position lists */ + for(i=0; ipExpr, i, &pPoslist); + sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); + } + break; + + case FTS5_DETAIL_COLUMNS: + + /* Append the varints */ + for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){ + const u8 *dummy; + int nByte; + rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte); + sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); + } + + /* Append the position lists */ + for(i=0; rc==SQLITE_OK && ipExpr, i, &pPoslist, &nPoslist); + sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); + } + break; + + default: + break; + } + + sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free); + return rc; +} + +/* +** This is the xColumn method, called by SQLite to request a value from +** the row that the supplied cursor currently points to. +*/ +static int fts5ColumnMethod( + 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 */ +){ + Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); + Fts5Config *pConfig = pTab->pConfig; + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + int rc = SQLITE_OK; + + assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 ); + + if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){ + if( iCol==pConfig->nCol ){ + sqlite3_result_int64(pCtx, pCsr->iSpecial); + } + }else + + if( iCol==pConfig->nCol ){ + /* User is requesting the value of the special column with the same name + ** as the table. Return the cursor integer id number. This value is only + ** useful in that it may be passed as the first argument to an FTS5 + ** auxiliary function. */ + sqlite3_result_int64(pCtx, pCsr->iCsrId); + }else if( iCol==pConfig->nCol+1 ){ + + /* The value of the "rank" column. */ + if( pCsr->ePlan==FTS5_PLAN_SOURCE ){ + fts5PoslistBlob(pCtx, pCsr); + }else if( + pCsr->ePlan==FTS5_PLAN_MATCH + || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH + ){ + if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){ + fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg); + } + } + }else if( !fts5IsContentless(pTab) ){ + rc = fts5SeekCursor(pCsr, 1); + if( rc==SQLITE_OK ){ + sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); + } + } + return rc; +} + + +/* +** This routine implements the xFindFunction method for the FTS3 +** virtual table. +*/ +static int fts5FindFunctionMethod( + sqlite3_vtab *pVtab, /* Virtual table handle */ + int nUnused, /* Number of SQL function arguments */ + const char *zName, /* Name of SQL function */ + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ + void **ppArg /* OUT: User data for *pxFunc */ +){ + Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5Auxiliary *pAux; + + UNUSED_PARAM(nUnused); + pAux = fts5FindAuxiliary(pTab, zName); + if( pAux ){ + *pxFunc = fts5ApiCallback; + *ppArg = (void*)pAux; + return 1; + } + + /* No function of the specified name was found. Return 0. */ + return 0; +} + +/* +** Implementation of FTS5 xRename method. Rename an fts5 table. +*/ +static int fts5RenameMethod( + sqlite3_vtab *pVtab, /* Virtual table handle */ + const char *zName /* New name of table */ +){ + Fts5Table *pTab = (Fts5Table*)pVtab; + return sqlite3Fts5StorageRename(pTab->pStorage, zName); +} + +/* +** The xSavepoint() method. +** +** Flush the contents of the pending-terms table to disk. +*/ +static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ + Fts5Table *pTab = (Fts5Table*)pVtab; + UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ + fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); + fts5TripCursors(pTab); + return sqlite3Fts5StorageSync(pTab->pStorage, 0); +} + +/* +** The xRelease() method. +** +** This is a no-op. +*/ +static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ + Fts5Table *pTab = (Fts5Table*)pVtab; + UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ + fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint); + fts5TripCursors(pTab); + return sqlite3Fts5StorageSync(pTab->pStorage, 0); +} + +/* +** The xRollbackTo() method. +** +** Discard the contents of the pending terms table. +*/ +static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ + Fts5Table *pTab = (Fts5Table*)pVtab; + UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ + fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); + fts5TripCursors(pTab); + return sqlite3Fts5StorageRollback(pTab->pStorage); +} + +/* +** Register a new auxiliary function with global context pGlobal. +*/ +static int fts5CreateAux( + fts5_api *pApi, /* Global context (one per db handle) */ + const char *zName, /* Name of new function */ + void *pUserData, /* User data for aux. function */ + fts5_extension_function xFunc, /* Aux. function implementation */ + void(*xDestroy)(void*) /* Destructor for pUserData */ +){ + Fts5Global *pGlobal = (Fts5Global*)pApi; + int rc = sqlite3_overload_function(pGlobal->db, zName, -1); + if( rc==SQLITE_OK ){ + Fts5Auxiliary *pAux; + int nName; /* Size of zName in bytes, including \0 */ + int nByte; /* Bytes of space to allocate */ + + nName = (int)strlen(zName) + 1; + nByte = sizeof(Fts5Auxiliary) + nName; + pAux = (Fts5Auxiliary*)sqlite3_malloc(nByte); + if( pAux ){ + memset(pAux, 0, nByte); + pAux->zFunc = (char*)&pAux[1]; + memcpy(pAux->zFunc, zName, nName); + pAux->pGlobal = pGlobal; + pAux->pUserData = pUserData; + pAux->xFunc = xFunc; + pAux->xDestroy = xDestroy; + pAux->pNext = pGlobal->pAux; + pGlobal->pAux = pAux; + }else{ + rc = SQLITE_NOMEM; + } + } + + return rc; +} + +/* +** Register a new tokenizer. This is the implementation of the +** fts5_api.xCreateTokenizer() method. +*/ +static int fts5CreateTokenizer( + fts5_api *pApi, /* Global context (one per db handle) */ + const char *zName, /* Name of new function */ + void *pUserData, /* User data for aux. function */ + fts5_tokenizer *pTokenizer, /* Tokenizer implementation */ + void(*xDestroy)(void*) /* Destructor for pUserData */ +){ + Fts5Global *pGlobal = (Fts5Global*)pApi; + Fts5TokenizerModule *pNew; + int nName; /* Size of zName and its \0 terminator */ + int nByte; /* Bytes of space to allocate */ + int rc = SQLITE_OK; + + nName = (int)strlen(zName) + 1; + nByte = sizeof(Fts5TokenizerModule) + nName; + pNew = (Fts5TokenizerModule*)sqlite3_malloc(nByte); + if( pNew ){ + memset(pNew, 0, nByte); + pNew->zName = (char*)&pNew[1]; + memcpy(pNew->zName, zName, nName); + pNew->pUserData = pUserData; + pNew->x = *pTokenizer; + pNew->xDestroy = xDestroy; + pNew->pNext = pGlobal->pTok; + pGlobal->pTok = pNew; + if( pNew->pNext==0 ){ + pGlobal->pDfltTok = pNew; + } + }else{ + rc = SQLITE_NOMEM; + } + + return rc; +} + +static Fts5TokenizerModule *fts5LocateTokenizer( + Fts5Global *pGlobal, + const char *zName +){ + Fts5TokenizerModule *pMod = 0; + + if( zName==0 ){ + pMod = pGlobal->pDfltTok; + }else{ + for(pMod=pGlobal->pTok; pMod; pMod=pMod->pNext){ + if( sqlite3_stricmp(zName, pMod->zName)==0 ) break; + } + } + + return pMod; +} + +/* +** Find a tokenizer. This is the implementation of the +** fts5_api.xFindTokenizer() method. +*/ +static int fts5FindTokenizer( + fts5_api *pApi, /* Global context (one per db handle) */ + const char *zName, /* Name of new function */ + void **ppUserData, + fts5_tokenizer *pTokenizer /* Populate this object */ +){ + int rc = SQLITE_OK; + Fts5TokenizerModule *pMod; + + pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName); + if( pMod ){ + *pTokenizer = pMod->x; + *ppUserData = pMod->pUserData; + }else{ + memset(pTokenizer, 0, sizeof(fts5_tokenizer)); + rc = SQLITE_ERROR; + } + + return rc; +} + +int sqlite3Fts5GetTokenizer( + Fts5Global *pGlobal, + const char **azArg, + int nArg, + Fts5Tokenizer **ppTok, + fts5_tokenizer **ppTokApi, + char **pzErr +){ + Fts5TokenizerModule *pMod; + int rc = SQLITE_OK; + + pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]); + if( pMod==0 ){ + assert( nArg>0 ); + rc = SQLITE_ERROR; + *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]); + }else{ + rc = pMod->x.xCreate(pMod->pUserData, &azArg[1], (nArg?nArg-1:0), ppTok); + *ppTokApi = &pMod->x; + if( rc!=SQLITE_OK && pzErr ){ + *pzErr = sqlite3_mprintf("error in tokenizer constructor"); + } + } + + if( rc!=SQLITE_OK ){ + *ppTokApi = 0; + *ppTok = 0; + } + + return rc; +} + +static void fts5ModuleDestroy(void *pCtx){ + Fts5TokenizerModule *pTok, *pNextTok; + Fts5Auxiliary *pAux, *pNextAux; + Fts5Global *pGlobal = (Fts5Global*)pCtx; + + for(pAux=pGlobal->pAux; pAux; pAux=pNextAux){ + pNextAux = pAux->pNext; + if( pAux->xDestroy ) pAux->xDestroy(pAux->pUserData); + sqlite3_free(pAux); + } + + for(pTok=pGlobal->pTok; pTok; pTok=pNextTok){ + pNextTok = pTok->pNext; + if( pTok->xDestroy ) pTok->xDestroy(pTok->pUserData); + sqlite3_free(pTok); + } + + sqlite3_free(pGlobal); +} + +static void fts5Fts5Func( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apUnused /* Function arguments */ +){ + Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx); + char buf[8]; + UNUSED_PARAM2(nArg, apUnused); + assert( nArg==0 ); + assert( sizeof(buf)>=sizeof(pGlobal) ); + memcpy(buf, (void*)&pGlobal, sizeof(pGlobal)); + sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT); +} + +/* +** Implementation of fts5_source_id() function. +*/ +static void fts5SourceIdFunc( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apUnused /* Function arguments */ +){ + assert( nArg==0 ); + UNUSED_PARAM2(nArg, apUnused); + sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT); +} + +static int fts5Init(sqlite3 *db){ + static const sqlite3_module fts5Mod = { + /* iVersion */ 2, + /* xCreate */ fts5CreateMethod, + /* xConnect */ fts5ConnectMethod, + /* xBestIndex */ fts5BestIndexMethod, + /* xDisconnect */ fts5DisconnectMethod, + /* xDestroy */ fts5DestroyMethod, + /* xOpen */ fts5OpenMethod, + /* xClose */ fts5CloseMethod, + /* xFilter */ fts5FilterMethod, + /* xNext */ fts5NextMethod, + /* xEof */ fts5EofMethod, + /* xColumn */ fts5ColumnMethod, + /* xRowid */ fts5RowidMethod, + /* xUpdate */ fts5UpdateMethod, + /* xBegin */ fts5BeginMethod, + /* xSync */ fts5SyncMethod, + /* xCommit */ fts5CommitMethod, + /* xRollback */ fts5RollbackMethod, + /* xFindFunction */ fts5FindFunctionMethod, + /* xRename */ fts5RenameMethod, + /* xSavepoint */ fts5SavepointMethod, + /* xRelease */ fts5ReleaseMethod, + /* xRollbackTo */ fts5RollbackToMethod, + }; + + int rc; + Fts5Global *pGlobal = 0; + + pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global)); + if( pGlobal==0 ){ + rc = SQLITE_NOMEM; + }else{ + void *p = (void*)pGlobal; + memset(pGlobal, 0, sizeof(Fts5Global)); + pGlobal->db = db; + pGlobal->api.iVersion = 2; + pGlobal->api.xCreateFunction = fts5CreateAux; + pGlobal->api.xCreateTokenizer = fts5CreateTokenizer; + pGlobal->api.xFindTokenizer = fts5FindTokenizer; + rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy); + if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db); + if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db); + if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api); + if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api); + if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function( + db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0 + ); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function( + db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0 + ); + } + } + return rc; +} + +/* +** The following functions are used to register the module with SQLite. If +** this module is being built as part of the SQLite core (SQLITE_CORE is +** defined), then sqlite3_open() will call sqlite3Fts5Init() directly. +** +** Or, if this module is being built as a loadable extension, +** sqlite3Fts5Init() is omitted and the two standard entry points +** sqlite3_fts_init() and sqlite3_fts5_init() defined instead. +*/ +#ifndef SQLITE_CORE +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_fts_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + return fts5Init(db); +} + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_fts5_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + return fts5Init(db); +} +#else +int sqlite3Fts5Init(sqlite3 *db){ + return fts5Init(db); +} +#endif diff --git a/ext/fts5/fts5_storage.c b/ext/fts5/fts5_storage.c new file mode 100644 index 0000000..e4f5dd8 --- /dev/null +++ b/ext/fts5/fts5_storage.c @@ -0,0 +1,1125 @@ +/* +** 2014 May 31 +** +** 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. +** +****************************************************************************** +** +*/ + + + +#include "fts5Int.h" + +struct Fts5Storage { + Fts5Config *pConfig; + Fts5Index *pIndex; + int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */ + i64 nTotalRow; /* Total number of rows in FTS table */ + i64 *aTotalSize; /* Total sizes of each column */ + sqlite3_stmt *aStmt[11]; +}; + + +#if FTS5_STMT_SCAN_ASC!=0 +# error "FTS5_STMT_SCAN_ASC mismatch" +#endif +#if FTS5_STMT_SCAN_DESC!=1 +# error "FTS5_STMT_SCAN_DESC mismatch" +#endif +#if FTS5_STMT_LOOKUP!=2 +# error "FTS5_STMT_LOOKUP mismatch" +#endif + +#define FTS5_STMT_INSERT_CONTENT 3 +#define FTS5_STMT_REPLACE_CONTENT 4 +#define FTS5_STMT_DELETE_CONTENT 5 +#define FTS5_STMT_REPLACE_DOCSIZE 6 +#define FTS5_STMT_DELETE_DOCSIZE 7 +#define FTS5_STMT_LOOKUP_DOCSIZE 8 +#define FTS5_STMT_REPLACE_CONFIG 9 +#define FTS5_STMT_SCAN 10 + +/* +** Prepare the two insert statements - Fts5Storage.pInsertContent and +** Fts5Storage.pInsertDocsize - if they have not already been prepared. +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +static int fts5StorageGetStmt( + Fts5Storage *p, /* Storage handle */ + int eStmt, /* FTS5_STMT_XXX constant */ + sqlite3_stmt **ppStmt, /* OUT: Prepared statement handle */ + char **pzErrMsg /* OUT: Error message (if any) */ +){ + int rc = SQLITE_OK; + + /* If there is no %_docsize table, there should be no requests for + ** statements to operate on it. */ + assert( p->pConfig->bColumnsize || ( + eStmt!=FTS5_STMT_REPLACE_DOCSIZE + && eStmt!=FTS5_STMT_DELETE_DOCSIZE + && eStmt!=FTS5_STMT_LOOKUP_DOCSIZE + )); + + assert( eStmt>=0 && eStmtaStmt) ); + if( p->aStmt[eStmt]==0 ){ + const char *azStmt[] = { + "SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC", + "SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC", + "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */ + + "INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */ + "REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */ + "DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */ + "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", /* REPLACE_DOCSIZE */ + "DELETE FROM %Q.'%q_docsize' WHERE id=?", /* DELETE_DOCSIZE */ + + "SELECT sz FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */ + + "REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */ + "SELECT %s FROM %s AS T", /* SCAN */ + }; + Fts5Config *pC = p->pConfig; + char *zSql = 0; + + switch( eStmt ){ + case FTS5_STMT_SCAN: + zSql = sqlite3_mprintf(azStmt[eStmt], + pC->zContentExprlist, pC->zContent + ); + break; + + case FTS5_STMT_SCAN_ASC: + case FTS5_STMT_SCAN_DESC: + zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist, + pC->zContent, pC->zContentRowid, pC->zContentRowid, + pC->zContentRowid + ); + break; + + case FTS5_STMT_LOOKUP: + zSql = sqlite3_mprintf(azStmt[eStmt], + pC->zContentExprlist, pC->zContent, pC->zContentRowid + ); + break; + + case FTS5_STMT_INSERT_CONTENT: + case FTS5_STMT_REPLACE_CONTENT: { + int nCol = pC->nCol + 1; + char *zBind; + int i; + + zBind = sqlite3_malloc(1 + nCol*2); + if( zBind ){ + for(i=0; izDb, pC->zName, zBind); + sqlite3_free(zBind); + } + break; + } + + default: + zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName); + break; + } + + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0); + sqlite3_free(zSql); + if( rc!=SQLITE_OK && pzErrMsg ){ + *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); + } + } + } + + *ppStmt = p->aStmt[eStmt]; + return rc; +} + + +static int fts5ExecPrintf( + sqlite3 *db, + char **pzErr, + const char *zFormat, + ... +){ + int rc; + va_list ap; /* ... printf arguments */ + char *zSql; + + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_exec(db, zSql, 0, 0, pzErr); + sqlite3_free(zSql); + } + + va_end(ap); + return rc; +} + +/* +** Drop all shadow tables. Return SQLITE_OK if successful or an SQLite error +** code otherwise. +*/ +int sqlite3Fts5DropAll(Fts5Config *pConfig){ + int rc = fts5ExecPrintf(pConfig->db, 0, + "DROP TABLE IF EXISTS %Q.'%q_data';" + "DROP TABLE IF EXISTS %Q.'%q_idx';" + "DROP TABLE IF EXISTS %Q.'%q_config';", + pConfig->zDb, pConfig->zName, + pConfig->zDb, pConfig->zName, + pConfig->zDb, pConfig->zName + ); + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + rc = fts5ExecPrintf(pConfig->db, 0, + "DROP TABLE IF EXISTS %Q.'%q_docsize';", + pConfig->zDb, pConfig->zName + ); + } + if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ + rc = fts5ExecPrintf(pConfig->db, 0, + "DROP TABLE IF EXISTS %Q.'%q_content';", + pConfig->zDb, pConfig->zName + ); + } + return rc; +} + +static void fts5StorageRenameOne( + Fts5Config *pConfig, /* Current FTS5 configuration */ + int *pRc, /* IN/OUT: Error code */ + const char *zTail, /* Tail of table name e.g. "data", "config" */ + const char *zName /* New name of FTS5 table */ +){ + if( *pRc==SQLITE_OK ){ + *pRc = fts5ExecPrintf(pConfig->db, 0, + "ALTER TABLE %Q.'%q_%s' RENAME TO '%q_%s';", + pConfig->zDb, pConfig->zName, zTail, zName, zTail + ); + } +} + +int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){ + Fts5Config *pConfig = pStorage->pConfig; + int rc = sqlite3Fts5StorageSync(pStorage, 1); + + fts5StorageRenameOne(pConfig, &rc, "data", zName); + fts5StorageRenameOne(pConfig, &rc, "idx", zName); + fts5StorageRenameOne(pConfig, &rc, "config", zName); + if( pConfig->bColumnsize ){ + fts5StorageRenameOne(pConfig, &rc, "docsize", zName); + } + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + fts5StorageRenameOne(pConfig, &rc, "content", zName); + } + return rc; +} + +/* +** Create the shadow table named zPost, with definition zDefn. Return +** SQLITE_OK if successful, or an SQLite error code otherwise. +*/ +int sqlite3Fts5CreateTable( + Fts5Config *pConfig, /* FTS5 configuration */ + const char *zPost, /* Shadow table to create (e.g. "content") */ + const char *zDefn, /* Columns etc. for shadow table */ + int bWithout, /* True for without rowid */ + char **pzErr /* OUT: Error message */ +){ + int rc; + char *zErr = 0; + + rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s", + pConfig->zDb, pConfig->zName, zPost, zDefn, bWithout?" WITHOUT ROWID":"" + ); + if( zErr ){ + *pzErr = sqlite3_mprintf( + "fts5: error creating shadow table %q_%s: %s", + pConfig->zName, zPost, zErr + ); + sqlite3_free(zErr); + } + + return rc; +} + +/* +** Open a new Fts5Index handle. If the bCreate argument is true, create +** and initialize the underlying tables +** +** If successful, set *pp to point to the new object and return SQLITE_OK. +** Otherwise, set *pp to NULL and return an SQLite error code. +*/ +int sqlite3Fts5StorageOpen( + Fts5Config *pConfig, + Fts5Index *pIndex, + int bCreate, + Fts5Storage **pp, + char **pzErr /* OUT: Error message */ +){ + int rc = SQLITE_OK; + Fts5Storage *p; /* New object */ + int nByte; /* Bytes of space to allocate */ + + nByte = sizeof(Fts5Storage) /* Fts5Storage object */ + + pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */ + *pp = p = (Fts5Storage*)sqlite3_malloc(nByte); + if( !p ) return SQLITE_NOMEM; + + memset(p, 0, nByte); + p->aTotalSize = (i64*)&p[1]; + p->pConfig = pConfig; + p->pIndex = pIndex; + + if( bCreate ){ + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + int nDefn = 32 + pConfig->nCol*10; + char *zDefn = sqlite3_malloc(32 + pConfig->nCol * 10); + if( zDefn==0 ){ + rc = SQLITE_NOMEM; + }else{ + int i; + int iOff; + sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY"); + iOff = (int)strlen(zDefn); + for(i=0; inCol; i++){ + sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i); + iOff += (int)strlen(&zDefn[iOff]); + } + rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr); + } + sqlite3_free(zDefn); + } + + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + rc = sqlite3Fts5CreateTable( + pConfig, "docsize", "id INTEGER PRIMARY KEY, sz BLOB", 0, pzErr + ); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5CreateTable( + pConfig, "config", "k PRIMARY KEY, v", 1, pzErr + ); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageConfigValue(p, "version", 0, FTS5_CURRENT_VERSION); + } + } + + if( rc ){ + sqlite3Fts5StorageClose(p); + *pp = 0; + } + return rc; +} + +/* +** Close a handle opened by an earlier call to sqlite3Fts5StorageOpen(). +*/ +int sqlite3Fts5StorageClose(Fts5Storage *p){ + int rc = SQLITE_OK; + if( p ){ + int i; + + /* Finalize all SQL statements */ + for(i=0; iaStmt); i++){ + sqlite3_finalize(p->aStmt[i]); + } + + sqlite3_free(p); + } + return rc; +} + +typedef struct Fts5InsertCtx Fts5InsertCtx; +struct Fts5InsertCtx { + Fts5Storage *pStorage; + int iCol; + int szCol; /* Size of column value in tokens */ +}; + +/* +** Tokenization callback used when inserting tokens into the FTS index. +*/ +static int fts5StorageInsertCallback( + void *pContext, /* Pointer to Fts5InsertCtx object */ + int tflags, + const char *pToken, /* Buffer containing token */ + int nToken, /* Size of token in bytes */ + int iUnused1, /* Start offset of token */ + int iUnused2 /* End offset of token */ +){ + Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext; + Fts5Index *pIdx = pCtx->pStorage->pIndex; + UNUSED_PARAM2(iUnused1, iUnused2); + if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ + pCtx->szCol++; + } + return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken); +} + +/* +** If a row with rowid iDel is present in the %_content table, add the +** delete-markers to the FTS index necessary to delete it. Do not actually +** remove the %_content row at this time though. +*/ +static int fts5StorageDeleteFromIndex( + Fts5Storage *p, + i64 iDel, + sqlite3_value **apVal +){ + Fts5Config *pConfig = p->pConfig; + sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */ + int rc; /* Return code */ + int rc2; /* sqlite3_reset() return code */ + int iCol; + Fts5InsertCtx ctx; + + if( apVal==0 ){ + rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0); + if( rc!=SQLITE_OK ) return rc; + sqlite3_bind_int64(pSeek, 1, iDel); + if( sqlite3_step(pSeek)!=SQLITE_ROW ){ + return sqlite3_reset(pSeek); + } + } + + ctx.pStorage = p; + ctx.iCol = -1; + rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); + for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ + if( pConfig->abUnindexed[iCol-1]==0 ){ + const char *zText; + int nText; + if( pSeek ){ + zText = (const char*)sqlite3_column_text(pSeek, iCol); + nText = sqlite3_column_bytes(pSeek, iCol); + }else{ + zText = (const char*)sqlite3_value_text(apVal[iCol-1]); + nText = sqlite3_value_bytes(apVal[iCol-1]); + } + ctx.szCol = 0; + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, + zText, nText, (void*)&ctx, fts5StorageInsertCallback + ); + p->aTotalSize[iCol-1] -= (i64)ctx.szCol; + } + } + p->nTotalRow--; + + rc2 = sqlite3_reset(pSeek); + if( rc==SQLITE_OK ) rc = rc2; + return rc; +} + + +/* +** Insert a record into the %_docsize table. Specifically, do: +** +** INSERT OR REPLACE INTO %_docsize(id, sz) VALUES(iRowid, pBuf); +** +** If there is no %_docsize table (as happens if the columnsize=0 option +** is specified when the FTS5 table is created), this function is a no-op. +*/ +static int fts5StorageInsertDocsize( + Fts5Storage *p, /* Storage module to write to */ + i64 iRowid, /* id value */ + Fts5Buffer *pBuf /* sz value */ +){ + int rc = SQLITE_OK; + if( p->pConfig->bColumnsize ){ + sqlite3_stmt *pReplace = 0; + rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pReplace, 1, iRowid); + sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); + sqlite3_step(pReplace); + rc = sqlite3_reset(pReplace); + } + } + return rc; +} + +/* +** Load the contents of the "averages" record from disk into the +** p->nTotalRow and p->aTotalSize[] variables. If successful, and if +** argument bCache is true, set the p->bTotalsValid flag to indicate +** that the contents of aTotalSize[] and nTotalRow are valid until +** further notice. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +static int fts5StorageLoadTotals(Fts5Storage *p, int bCache){ + int rc = SQLITE_OK; + if( p->bTotalsValid==0 ){ + rc = sqlite3Fts5IndexGetAverages(p->pIndex, &p->nTotalRow, p->aTotalSize); + p->bTotalsValid = bCache; + } + return rc; +} + +/* +** Store the current contents of the p->nTotalRow and p->aTotalSize[] +** variables in the "averages" record on disk. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +static int fts5StorageSaveTotals(Fts5Storage *p){ + int nCol = p->pConfig->nCol; + int i; + Fts5Buffer buf; + int rc = SQLITE_OK; + memset(&buf, 0, sizeof(buf)); + + sqlite3Fts5BufferAppendVarint(&rc, &buf, p->nTotalRow); + for(i=0; iaTotalSize[i]); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexSetAverages(p->pIndex, buf.p, buf.n); + } + sqlite3_free(buf.p); + + return rc; +} + +/* +** Remove a row from the FTS table. +*/ +int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){ + Fts5Config *pConfig = p->pConfig; + int rc; + sqlite3_stmt *pDel = 0; + + assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 ); + rc = fts5StorageLoadTotals(p, 1); + + /* Delete the index records */ + if( rc==SQLITE_OK ){ + rc = fts5StorageDeleteFromIndex(p, iDel, apVal); + } + + /* Delete the %_docsize record */ + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDel, 1, iDel); + sqlite3_step(pDel); + rc = sqlite3_reset(pDel); + } + } + + /* Delete the %_content record */ + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + if( rc==SQLITE_OK ){ + rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0); + } + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDel, 1, iDel); + sqlite3_step(pDel); + rc = sqlite3_reset(pDel); + } + } + + /* Write the averages record */ + if( rc==SQLITE_OK ){ + rc = fts5StorageSaveTotals(p); + } + + return rc; +} + +/* +** Delete all entries in the FTS5 index. +*/ +int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){ + Fts5Config *pConfig = p->pConfig; + int rc; + + /* Delete the contents of the %_data and %_docsize tables. */ + rc = fts5ExecPrintf(pConfig->db, 0, + "DELETE FROM %Q.'%q_data';" + "DELETE FROM %Q.'%q_idx';", + pConfig->zDb, pConfig->zName, + pConfig->zDb, pConfig->zName + ); + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + rc = fts5ExecPrintf(pConfig->db, 0, + "DELETE FROM %Q.'%q_docsize';", + pConfig->zDb, pConfig->zName + ); + } + + /* Reinitialize the %_data table. This call creates the initial structure + ** and averages records. */ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexReinit(p->pIndex); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageConfigValue(p, "version", 0, FTS5_CURRENT_VERSION); + } + return rc; +} + +int sqlite3Fts5StorageRebuild(Fts5Storage *p){ + Fts5Buffer buf = {0,0,0}; + Fts5Config *pConfig = p->pConfig; + sqlite3_stmt *pScan = 0; + Fts5InsertCtx ctx; + int rc; + + memset(&ctx, 0, sizeof(Fts5InsertCtx)); + ctx.pStorage = p; + rc = sqlite3Fts5StorageDeleteAll(p); + if( rc==SQLITE_OK ){ + rc = fts5StorageLoadTotals(p, 1); + } + + if( rc==SQLITE_OK ){ + rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); + } + + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){ + i64 iRowid = sqlite3_column_int64(pScan, 0); + + sqlite3Fts5BufferZero(&buf); + rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); + for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ + ctx.szCol = 0; + if( pConfig->abUnindexed[ctx.iCol]==0 ){ + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + (const char*)sqlite3_column_text(pScan, ctx.iCol+1), + sqlite3_column_bytes(pScan, ctx.iCol+1), + (void*)&ctx, + fts5StorageInsertCallback + ); + } + sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); + p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; + } + p->nTotalRow++; + + if( rc==SQLITE_OK ){ + rc = fts5StorageInsertDocsize(p, iRowid, &buf); + } + } + sqlite3_free(buf.p); + + /* Write the averages record */ + if( rc==SQLITE_OK ){ + rc = fts5StorageSaveTotals(p); + } + return rc; +} + +int sqlite3Fts5StorageOptimize(Fts5Storage *p){ + return sqlite3Fts5IndexOptimize(p->pIndex); +} + +int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){ + return sqlite3Fts5IndexMerge(p->pIndex, nMerge); +} + +/* +** Allocate a new rowid. This is used for "external content" tables when +** a NULL value is inserted into the rowid column. The new rowid is allocated +** by inserting a dummy row into the %_docsize table. The dummy will be +** overwritten later. +** +** If the %_docsize table does not exist, SQLITE_MISMATCH is returned. In +** this case the user is required to provide a rowid explicitly. +*/ +static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){ + int rc = SQLITE_MISMATCH; + if( p->pConfig->bColumnsize ){ + sqlite3_stmt *pReplace = 0; + rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_null(pReplace, 1); + sqlite3_bind_null(pReplace, 2); + sqlite3_step(pReplace); + rc = sqlite3_reset(pReplace); + } + if( rc==SQLITE_OK ){ + *piRowid = sqlite3_last_insert_rowid(p->pConfig->db); + } + } + return rc; +} + +/* +** Insert a new row into the FTS content table. +*/ +int sqlite3Fts5StorageContentInsert( + Fts5Storage *p, + sqlite3_value **apVal, + i64 *piRowid +){ + Fts5Config *pConfig = p->pConfig; + int rc = SQLITE_OK; + + /* Insert the new row into the %_content table. */ + if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){ + if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){ + *piRowid = sqlite3_value_int64(apVal[1]); + }else{ + rc = fts5StorageNewRowid(p, piRowid); + } + }else{ + sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */ + int i; /* Counter variable */ + rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0); + for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){ + rc = sqlite3_bind_value(pInsert, i, apVal[i]); + } + if( rc==SQLITE_OK ){ + sqlite3_step(pInsert); + rc = sqlite3_reset(pInsert); + } + *piRowid = sqlite3_last_insert_rowid(pConfig->db); + } + + return rc; +} + +/* +** Insert new entries into the FTS index and %_docsize table. +*/ +int sqlite3Fts5StorageIndexInsert( + Fts5Storage *p, + sqlite3_value **apVal, + i64 iRowid +){ + Fts5Config *pConfig = p->pConfig; + int rc = SQLITE_OK; /* Return code */ + Fts5InsertCtx ctx; /* Tokenization callback context object */ + Fts5Buffer buf; /* Buffer used to build up %_docsize blob */ + + memset(&buf, 0, sizeof(Fts5Buffer)); + ctx.pStorage = p; + rc = fts5StorageLoadTotals(p, 1); + + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); + } + for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ + ctx.szCol = 0; + if( pConfig->abUnindexed[ctx.iCol]==0 ){ + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + (const char*)sqlite3_value_text(apVal[ctx.iCol+2]), + sqlite3_value_bytes(apVal[ctx.iCol+2]), + (void*)&ctx, + fts5StorageInsertCallback + ); + } + sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); + p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; + } + p->nTotalRow++; + + /* Write the %_docsize record */ + if( rc==SQLITE_OK ){ + rc = fts5StorageInsertDocsize(p, iRowid, &buf); + } + sqlite3_free(buf.p); + + /* Write the averages record */ + if( rc==SQLITE_OK ){ + rc = fts5StorageSaveTotals(p); + } + + return rc; +} + +static int fts5StorageCount(Fts5Storage *p, const char *zSuffix, i64 *pnRow){ + Fts5Config *pConfig = p->pConfig; + char *zSql; + int rc; + + zSql = sqlite3_mprintf("SELECT count(*) FROM %Q.'%q_%s'", + pConfig->zDb, pConfig->zName, zSuffix + ); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_stmt *pCnt = 0; + rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pCnt, 0); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pCnt) ){ + *pnRow = sqlite3_column_int64(pCnt, 0); + } + rc = sqlite3_finalize(pCnt); + } + } + + sqlite3_free(zSql); + return rc; +} + +/* +** Context object used by sqlite3Fts5StorageIntegrity(). +*/ +typedef struct Fts5IntegrityCtx Fts5IntegrityCtx; +struct Fts5IntegrityCtx { + i64 iRowid; + int iCol; + int szCol; + u64 cksum; + Fts5Termset *pTermset; + Fts5Config *pConfig; +}; + + +/* +** Tokenization callback used by integrity check. +*/ +static int fts5StorageIntegrityCallback( + void *pContext, /* Pointer to Fts5IntegrityCtx object */ + int tflags, + const char *pToken, /* Buffer containing token */ + int nToken, /* Size of token in bytes */ + int iUnused1, /* Start offset of token */ + int iUnused2 /* End offset of token */ +){ + Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext; + Fts5Termset *pTermset = pCtx->pTermset; + int bPresent; + int ii; + int rc = SQLITE_OK; + int iPos; + int iCol; + + UNUSED_PARAM2(iUnused1, iUnused2); + + if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ + pCtx->szCol++; + } + + switch( pCtx->pConfig->eDetail ){ + case FTS5_DETAIL_FULL: + iPos = pCtx->szCol-1; + iCol = pCtx->iCol; + break; + + case FTS5_DETAIL_COLUMNS: + iPos = pCtx->iCol; + iCol = 0; + break; + + default: + assert( pCtx->pConfig->eDetail==FTS5_DETAIL_NONE ); + iPos = 0; + iCol = 0; + break; + } + + rc = sqlite3Fts5TermsetAdd(pTermset, 0, pToken, nToken, &bPresent); + if( rc==SQLITE_OK && bPresent==0 ){ + pCtx->cksum ^= sqlite3Fts5IndexEntryCksum( + pCtx->iRowid, iCol, iPos, 0, pToken, nToken + ); + } + + for(ii=0; rc==SQLITE_OK && iipConfig->nPrefix; ii++){ + const int nChar = pCtx->pConfig->aPrefix[ii]; + int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar); + if( nByte ){ + rc = sqlite3Fts5TermsetAdd(pTermset, ii+1, pToken, nByte, &bPresent); + if( bPresent==0 ){ + pCtx->cksum ^= sqlite3Fts5IndexEntryCksum( + pCtx->iRowid, iCol, iPos, ii+1, pToken, nByte + ); + } + } + } + + return rc; +} + +/* +** Check that the contents of the FTS index match that of the %_content +** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return +** some other SQLite error code if an error occurs while attempting to +** determine this. +*/ +int sqlite3Fts5StorageIntegrity(Fts5Storage *p){ + Fts5Config *pConfig = p->pConfig; + int rc; /* Return code */ + int *aColSize; /* Array of size pConfig->nCol */ + i64 *aTotalSize; /* Array of size pConfig->nCol */ + Fts5IntegrityCtx ctx; + sqlite3_stmt *pScan; + + memset(&ctx, 0, sizeof(Fts5IntegrityCtx)); + ctx.pConfig = p->pConfig; + aTotalSize = (i64*)sqlite3_malloc(pConfig->nCol * (sizeof(int)+sizeof(i64))); + if( !aTotalSize ) return SQLITE_NOMEM; + aColSize = (int*)&aTotalSize[pConfig->nCol]; + memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol); + + /* Generate the expected index checksum based on the contents of the + ** %_content table. This block stores the checksum in ctx.cksum. */ + rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); + if( rc==SQLITE_OK ){ + int rc2; + while( SQLITE_ROW==sqlite3_step(pScan) ){ + int i; + ctx.iRowid = sqlite3_column_int64(pScan, 0); + ctx.szCol = 0; + if( pConfig->bColumnsize ){ + rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize); + } + if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + } + for(i=0; rc==SQLITE_OK && inCol; i++){ + if( pConfig->abUnindexed[i] ) continue; + ctx.iCol = i; + ctx.szCol = 0; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + (const char*)sqlite3_column_text(pScan, i+1), + sqlite3_column_bytes(pScan, i+1), + (void*)&ctx, + fts5StorageIntegrityCallback + ); + } + if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ + rc = FTS5_CORRUPT; + } + aTotalSize[i] += ctx.szCol; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; + } + } + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; + + if( rc!=SQLITE_OK ) break; + } + rc2 = sqlite3_reset(pScan); + if( rc==SQLITE_OK ) rc = rc2; + } + + /* Test that the "totals" (sometimes called "averages") record looks Ok */ + if( rc==SQLITE_OK ){ + int i; + rc = fts5StorageLoadTotals(p, 0); + for(i=0; rc==SQLITE_OK && inCol; i++){ + if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT; + } + } + + /* Check that the %_docsize and %_content tables contain the expected + ** number of rows. */ + if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ + i64 nRow = 0; + rc = fts5StorageCount(p, "content", &nRow); + if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; + } + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + i64 nRow = 0; + rc = fts5StorageCount(p, "docsize", &nRow); + if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; + } + + /* Pass the expected checksum down to the FTS index module. It will + ** verify, amongst other things, that it matches the checksum generated by + ** inspecting the index itself. */ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum); + } + + sqlite3_free(aTotalSize); + return rc; +} + +/* +** Obtain an SQLite statement handle that may be used to read data from the +** %_content table. +*/ +int sqlite3Fts5StorageStmt( + Fts5Storage *p, + int eStmt, + sqlite3_stmt **pp, + char **pzErrMsg +){ + int rc; + assert( eStmt==FTS5_STMT_SCAN_ASC + || eStmt==FTS5_STMT_SCAN_DESC + || eStmt==FTS5_STMT_LOOKUP + ); + rc = fts5StorageGetStmt(p, eStmt, pp, pzErrMsg); + if( rc==SQLITE_OK ){ + assert( p->aStmt[eStmt]==*pp ); + p->aStmt[eStmt] = 0; + } + return rc; +} + +/* +** Release an SQLite statement handle obtained via an earlier call to +** sqlite3Fts5StorageStmt(). The eStmt parameter passed to this function +** must match that passed to the sqlite3Fts5StorageStmt() call. +*/ +void sqlite3Fts5StorageStmtRelease( + Fts5Storage *p, + int eStmt, + sqlite3_stmt *pStmt +){ + assert( eStmt==FTS5_STMT_SCAN_ASC + || eStmt==FTS5_STMT_SCAN_DESC + || eStmt==FTS5_STMT_LOOKUP + ); + if( p->aStmt[eStmt]==0 ){ + sqlite3_reset(pStmt); + p->aStmt[eStmt] = pStmt; + }else{ + sqlite3_finalize(pStmt); + } +} + +static int fts5StorageDecodeSizeArray( + int *aCol, int nCol, /* Array to populate */ + const u8 *aBlob, int nBlob /* Record to read varints from */ +){ + int i; + int iOff = 0; + for(i=0; i=nBlob ) return 1; + iOff += fts5GetVarint32(&aBlob[iOff], aCol[i]); + } + return (iOff!=nBlob); +} + +/* +** Argument aCol points to an array of integers containing one entry for +** each table column. This function reads the %_docsize record for the +** specified rowid and populates aCol[] with the results. +** +** An SQLite error code is returned if an error occurs, or SQLITE_OK +** otherwise. +*/ +int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){ + int nCol = p->pConfig->nCol; /* Number of user columns in table */ + sqlite3_stmt *pLookup = 0; /* Statement to query %_docsize */ + int rc; /* Return Code */ + + assert( p->pConfig->bColumnsize ); + rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0); + if( rc==SQLITE_OK ){ + int bCorrupt = 1; + sqlite3_bind_int64(pLookup, 1, iRowid); + if( SQLITE_ROW==sqlite3_step(pLookup) ){ + const u8 *aBlob = sqlite3_column_blob(pLookup, 0); + int nBlob = sqlite3_column_bytes(pLookup, 0); + if( 0==fts5StorageDecodeSizeArray(aCol, nCol, aBlob, nBlob) ){ + bCorrupt = 0; + } + } + rc = sqlite3_reset(pLookup); + if( bCorrupt && rc==SQLITE_OK ){ + rc = FTS5_CORRUPT; + } + } + + return rc; +} + +int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){ + int rc = fts5StorageLoadTotals(p, 0); + if( rc==SQLITE_OK ){ + *pnToken = 0; + if( iCol<0 ){ + int i; + for(i=0; ipConfig->nCol; i++){ + *pnToken += p->aTotalSize[i]; + } + }else if( iColpConfig->nCol ){ + *pnToken = p->aTotalSize[iCol]; + }else{ + rc = SQLITE_RANGE; + } + } + return rc; +} + +int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){ + int rc = fts5StorageLoadTotals(p, 0); + if( rc==SQLITE_OK ){ + *pnRow = p->nTotalRow; + } + return rc; +} + +/* +** Flush any data currently held in-memory to disk. +*/ +int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){ + if( bCommit && p->bTotalsValid ){ + int rc = fts5StorageSaveTotals(p); + p->bTotalsValid = 0; + if( rc!=SQLITE_OK ) return rc; + } + return sqlite3Fts5IndexSync(p->pIndex, bCommit); +} + +int sqlite3Fts5StorageRollback(Fts5Storage *p){ + p->bTotalsValid = 0; + return sqlite3Fts5IndexRollback(p->pIndex); +} + +int sqlite3Fts5StorageConfigValue( + Fts5Storage *p, + const char *z, + sqlite3_value *pVal, + int iVal +){ + sqlite3_stmt *pReplace = 0; + int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_CONFIG, &pReplace, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_text(pReplace, 1, z, -1, SQLITE_STATIC); + if( pVal ){ + sqlite3_bind_value(pReplace, 2, pVal); + }else{ + sqlite3_bind_int(pReplace, 2, iVal); + } + sqlite3_step(pReplace); + rc = sqlite3_reset(pReplace); + } + if( rc==SQLITE_OK && pVal ){ + int iNew = p->pConfig->iCookie + 1; + rc = sqlite3Fts5IndexSetCookie(p->pIndex, iNew); + if( rc==SQLITE_OK ){ + p->pConfig->iCookie = iNew; + } + } + return rc; +} + + diff --git a/ext/fts5/fts5_tcl.c b/ext/fts5/fts5_tcl.c new file mode 100644 index 0000000..72db657 --- /dev/null +++ b/ext/fts5/fts5_tcl.c @@ -0,0 +1,1150 @@ +/* +** 2014 Dec 01 +** +** 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. +** +****************************************************************************** +** +*/ + + +#ifdef SQLITE_TEST +#include + +#ifdef SQLITE_ENABLE_FTS5 + +#include "fts5.h" +#include +#include + +extern int sqlite3_fts5_may_be_corrupt; +extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*); +extern int sqlite3Fts5TestRegisterTok(sqlite3*, fts5_api*); + +/************************************************************************* +** This is a copy of the first part of the SqliteDb structure in +** tclsqlite.c. We need it here so that the get_sqlite_pointer routine +** can extract the sqlite3* pointer from an existing Tcl SQLite +** connection. +*/ + +extern const char *sqlite3ErrName(int); + +struct SqliteDb { + sqlite3 *db; +}; + +/* +** Decode a pointer to an sqlite3 object. +*/ +static int f5tDbPointer(Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3 **ppDb){ + struct SqliteDb *p; + Tcl_CmdInfo cmdInfo; + char *z = Tcl_GetString(pObj); + if( Tcl_GetCommandInfo(interp, z, &cmdInfo) ){ + p = (struct SqliteDb*)cmdInfo.objClientData; + *ppDb = p->db; + return TCL_OK; + } + return TCL_ERROR; +} + +/* End of code that accesses the SqliteDb struct. +**************************************************************************/ + +static int f5tResultToErrorCode(const char *zRes){ + struct ErrorCode { + int rc; + const char *zError; + } aErr[] = { + { SQLITE_DONE, "SQLITE_DONE" }, + { SQLITE_ERROR, "SQLITE_ERROR" }, + { SQLITE_OK, "SQLITE_OK" }, + { SQLITE_OK, "" }, + }; + int i; + + for(i=0; ipScript); + int rc; + + Tcl_IncrRefCount(pEval); + Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zToken, nToken)); + Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewIntObj(iStart)); + Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewIntObj(iEnd)); + + rc = Tcl_EvalObjEx(p->interp, pEval, 0); + Tcl_DecrRefCount(pEval); + if( rc==TCL_OK ){ + rc = f5tResultToErrorCode(Tcl_GetStringResult(p->interp)); + } + + return rc; +} + +static int xF5tApi(void*, Tcl_Interp*, int, Tcl_Obj *CONST []); + +static int xQueryPhraseCb( + const Fts5ExtensionApi *pApi, + Fts5Context *pFts, + void *pCtx +){ + F5tFunction *p = (F5tFunction*)pCtx; + static sqlite3_int64 iCmd = 0; + Tcl_Obj *pEval; + int rc; + + char zCmd[64]; + F5tApi sApi; + + sApi.pApi = pApi; + sApi.pFts = pFts; + sprintf(zCmd, "f5t_2_%lld", iCmd++); + Tcl_CreateObjCommand(p->interp, zCmd, xF5tApi, &sApi, 0); + + pEval = Tcl_DuplicateObj(p->pScript); + Tcl_IncrRefCount(pEval); + Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zCmd, -1)); + rc = Tcl_EvalObjEx(p->interp, pEval, 0); + Tcl_DecrRefCount(pEval); + Tcl_DeleteCommand(p->interp, zCmd); + + if( rc==TCL_OK ){ + rc = f5tResultToErrorCode(Tcl_GetStringResult(p->interp)); + } + + return rc; +} + +static void xSetAuxdataDestructor(void *p){ + F5tAuxData *pData = (F5tAuxData*)p; + Tcl_DecrRefCount(pData->pObj); + sqlite3_free(pData); +} + +/* +** api sub-command... +** +** Description... +*/ +static int xF5tApi( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + struct Sub { + const char *zName; + int nArg; + const char *zMsg; + } aSub[] = { + { "xColumnCount", 0, "" }, /* 0 */ + { "xRowCount", 0, "" }, /* 1 */ + { "xColumnTotalSize", 1, "COL" }, /* 2 */ + { "xTokenize", 2, "TEXT SCRIPT" }, /* 3 */ + { "xPhraseCount", 0, "" }, /* 4 */ + { "xPhraseSize", 1, "PHRASE" }, /* 5 */ + { "xInstCount", 0, "" }, /* 6 */ + { "xInst", 1, "IDX" }, /* 7 */ + { "xRowid", 0, "" }, /* 8 */ + { "xColumnText", 1, "COL" }, /* 9 */ + { "xColumnSize", 1, "COL" }, /* 10 */ + { "xQueryPhrase", 2, "PHRASE SCRIPT" }, /* 11 */ + { "xSetAuxdata", 1, "VALUE" }, /* 12 */ + { "xGetAuxdata", 1, "CLEAR" }, /* 13 */ + { "xSetAuxdataInt", 1, "INTEGER" }, /* 14 */ + { "xGetAuxdataInt", 1, "CLEAR" }, /* 15 */ + { "xPhraseForeach", 4, "IPHRASE COLVAR OFFVAR SCRIPT" }, /* 16 */ + { "xPhraseColumnForeach", 3, "IPHRASE COLVAR SCRIPT" }, /* 17 */ + { 0, 0, 0} + }; + + int rc; + int iSub = 0; + F5tApi *p = (F5tApi*)clientData; + + if( objc<2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND"); + return TCL_ERROR; + } + + rc = Tcl_GetIndexFromObjStruct( + interp, objv[1], aSub, sizeof(aSub[0]), "SUB-COMMAND", 0, &iSub + ); + if( rc!=TCL_OK ) return rc; + if( aSub[iSub].nArg!=objc-2 ){ + Tcl_WrongNumArgs(interp, 1, objv, aSub[iSub].zMsg); + return TCL_ERROR; + } + +#define CASE(i,str) case i: assert( strcmp(aSub[i].zName, str)==0 ); + switch( iSub ){ + CASE(0, "xColumnCount") { + int nCol; + nCol = p->pApi->xColumnCount(p->pFts); + if( rc==SQLITE_OK ){ + Tcl_SetObjResult(interp, Tcl_NewIntObj(nCol)); + } + break; + } + CASE(1, "xRowCount") { + sqlite3_int64 nRow; + rc = p->pApi->xRowCount(p->pFts, &nRow); + if( rc==SQLITE_OK ){ + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nRow)); + } + break; + } + CASE(2, "xColumnTotalSize") { + int iCol; + sqlite3_int64 nSize; + if( Tcl_GetIntFromObj(interp, objv[2], &iCol) ) return TCL_ERROR; + rc = p->pApi->xColumnTotalSize(p->pFts, iCol, &nSize); + if( rc==SQLITE_OK ){ + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nSize)); + } + break; + } + CASE(3, "xTokenize") { + int nText; + char *zText = Tcl_GetStringFromObj(objv[2], &nText); + F5tFunction ctx; + ctx.interp = interp; + ctx.pScript = objv[3]; + rc = p->pApi->xTokenize(p->pFts, zText, nText, &ctx, xTokenizeCb); + if( rc==SQLITE_OK ){ + Tcl_ResetResult(interp); + } + return rc; + } + CASE(4, "xPhraseCount") { + int nPhrase; + nPhrase = p->pApi->xPhraseCount(p->pFts); + if( rc==SQLITE_OK ){ + Tcl_SetObjResult(interp, Tcl_NewIntObj(nPhrase)); + } + break; + } + CASE(5, "xPhraseSize") { + int iPhrase; + int sz; + if( Tcl_GetIntFromObj(interp, objv[2], &iPhrase) ){ + return TCL_ERROR; + } + sz = p->pApi->xPhraseSize(p->pFts, iPhrase); + if( rc==SQLITE_OK ){ + Tcl_SetObjResult(interp, Tcl_NewIntObj(sz)); + } + break; + } + CASE(6, "xInstCount") { + int nInst; + rc = p->pApi->xInstCount(p->pFts, &nInst); + if( rc==SQLITE_OK ){ + Tcl_SetObjResult(interp, Tcl_NewIntObj(nInst)); + } + break; + } + CASE(7, "xInst") { + int iIdx, ip, ic, io; + if( Tcl_GetIntFromObj(interp, objv[2], &iIdx) ){ + return TCL_ERROR; + } + rc = p->pApi->xInst(p->pFts, iIdx, &ip, &ic, &io); + if( rc==SQLITE_OK ){ + Tcl_Obj *pList = Tcl_NewObj(); + Tcl_ListObjAppendElement(interp, pList, Tcl_NewIntObj(ip)); + Tcl_ListObjAppendElement(interp, pList, Tcl_NewIntObj(ic)); + Tcl_ListObjAppendElement(interp, pList, Tcl_NewIntObj(io)); + Tcl_SetObjResult(interp, pList); + } + break; + } + CASE(8, "xRowid") { + sqlite3_int64 iRowid = p->pApi->xRowid(p->pFts); + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iRowid)); + break; + } + CASE(9, "xColumnText") { + const char *z = 0; + int n = 0; + int iCol; + if( Tcl_GetIntFromObj(interp, objv[2], &iCol) ){ + return TCL_ERROR; + } + rc = p->pApi->xColumnText(p->pFts, iCol, &z, &n); + if( rc==SQLITE_OK ){ + Tcl_SetObjResult(interp, Tcl_NewStringObj(z, n)); + } + break; + } + CASE(10, "xColumnSize") { + int n = 0; + int iCol; + if( Tcl_GetIntFromObj(interp, objv[2], &iCol) ){ + return TCL_ERROR; + } + rc = p->pApi->xColumnSize(p->pFts, iCol, &n); + if( rc==SQLITE_OK ){ + Tcl_SetObjResult(interp, Tcl_NewIntObj(n)); + } + break; + } + CASE(11, "xQueryPhrase") { + int iPhrase; + F5tFunction ctx; + if( Tcl_GetIntFromObj(interp, objv[2], &iPhrase) ){ + return TCL_ERROR; + } + ctx.interp = interp; + ctx.pScript = objv[3]; + rc = p->pApi->xQueryPhrase(p->pFts, iPhrase, &ctx, xQueryPhraseCb); + if( rc==SQLITE_OK ){ + Tcl_ResetResult(interp); + } + break; + } + CASE(12, "xSetAuxdata") { + F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc(sizeof(F5tAuxData)); + if( pData==0 ){ + Tcl_AppendResult(interp, "out of memory", 0); + return TCL_ERROR; + } + pData->pObj = objv[2]; + Tcl_IncrRefCount(pData->pObj); + rc = p->pApi->xSetAuxdata(p->pFts, pData, xSetAuxdataDestructor); + break; + } + CASE(13, "xGetAuxdata") { + F5tAuxData *pData; + int bClear; + if( Tcl_GetBooleanFromObj(interp, objv[2], &bClear) ){ + return TCL_ERROR; + } + pData = (F5tAuxData*)p->pApi->xGetAuxdata(p->pFts, bClear); + if( pData==0 ){ + Tcl_ResetResult(interp); + }else{ + Tcl_SetObjResult(interp, pData->pObj); + if( bClear ){ + xSetAuxdataDestructor((void*)pData); + } + } + break; + } + + /* These two - xSetAuxdataInt and xGetAuxdataInt - are similar to the + ** xSetAuxdata and xGetAuxdata methods implemented above. The difference + ** is that they may only save an integer value as auxiliary data, and + ** do not specify a destructor function. */ + CASE(14, "xSetAuxdataInt") { + int iVal; + if( Tcl_GetIntFromObj(interp, objv[2], &iVal) ) return TCL_ERROR; + rc = p->pApi->xSetAuxdata(p->pFts, (void*)((char*)0 + iVal), 0); + break; + } + CASE(15, "xGetAuxdataInt") { + int iVal; + int bClear; + if( Tcl_GetBooleanFromObj(interp, objv[2], &bClear) ) return TCL_ERROR; + iVal = ((char*)p->pApi->xGetAuxdata(p->pFts, bClear) - (char*)0); + Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal)); + break; + } + + CASE(16, "xPhraseForeach") { + int iPhrase; + int iCol; + int iOff; + const char *zColvar; + const char *zOffvar; + Tcl_Obj *pScript = objv[5]; + Fts5PhraseIter iter; + + if( Tcl_GetIntFromObj(interp, objv[2], &iPhrase) ) return TCL_ERROR; + zColvar = Tcl_GetString(objv[3]); + zOffvar = Tcl_GetString(objv[4]); + + rc = p->pApi->xPhraseFirst(p->pFts, iPhrase, &iter, &iCol, &iOff); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); + return TCL_ERROR; + } + for( ;iCol>=0; p->pApi->xPhraseNext(p->pFts, &iter, &iCol, &iOff) ){ + Tcl_SetVar2Ex(interp, zColvar, 0, Tcl_NewIntObj(iCol), 0); + Tcl_SetVar2Ex(interp, zOffvar, 0, Tcl_NewIntObj(iOff), 0); + rc = Tcl_EvalObjEx(interp, pScript, 0); + if( rc==TCL_CONTINUE ) rc = TCL_OK; + if( rc!=TCL_OK ){ + if( rc==TCL_BREAK ) rc = TCL_OK; + break; + } + } + + break; + } + + CASE(17, "xPhraseColumnForeach") { + int iPhrase; + int iCol; + const char *zColvar; + Tcl_Obj *pScript = objv[4]; + Fts5PhraseIter iter; + + if( Tcl_GetIntFromObj(interp, objv[2], &iPhrase) ) return TCL_ERROR; + zColvar = Tcl_GetString(objv[3]); + + rc = p->pApi->xPhraseFirstColumn(p->pFts, iPhrase, &iter, &iCol); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); + return TCL_ERROR; + } + for( ; iCol>=0; p->pApi->xPhraseNextColumn(p->pFts, &iter, &iCol)){ + Tcl_SetVar2Ex(interp, zColvar, 0, Tcl_NewIntObj(iCol), 0); + rc = Tcl_EvalObjEx(interp, pScript, 0); + if( rc==TCL_CONTINUE ) rc = TCL_OK; + if( rc!=TCL_OK ){ + if( rc==TCL_BREAK ) rc = TCL_OK; + break; + } + } + + break; + } + + default: + assert( 0 ); + break; + } +#undef CASE + + if( rc!=SQLITE_OK ){ + Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); + return TCL_ERROR; + } + + return TCL_OK; +} + +static void xF5tFunction( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +){ + F5tFunction *p = (F5tFunction*)pApi->xUserData(pFts); + Tcl_Obj *pEval; /* Script to evaluate */ + int i; + int rc; + + static sqlite3_int64 iCmd = 0; + char zCmd[64]; + F5tApi sApi; + sApi.pApi = pApi; + sApi.pFts = pFts; + + sprintf(zCmd, "f5t_%lld", iCmd++); + Tcl_CreateObjCommand(p->interp, zCmd, xF5tApi, &sApi, 0); + pEval = Tcl_DuplicateObj(p->pScript); + Tcl_IncrRefCount(pEval); + Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zCmd, -1)); + + for(i=0; iinterp, pEval, pObj); + } + + rc = Tcl_EvalObjEx(p->interp, pEval, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(pEval); + Tcl_DeleteCommand(p->interp, zCmd); + + if( rc!=TCL_OK ){ + sqlite3_result_error(pCtx, Tcl_GetStringResult(p->interp), -1); + }else{ + Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); + int n; + const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); + char c = zType[0]; + if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ + /* Only return a BLOB type if the Tcl variable is a bytearray and + ** has no string representation. */ + unsigned char *data = Tcl_GetByteArrayFromObj(pVar, &n); + sqlite3_result_blob(pCtx, data, n, SQLITE_TRANSIENT); + }else if( c=='b' && strcmp(zType,"boolean")==0 ){ + Tcl_GetIntFromObj(0, pVar, &n); + sqlite3_result_int(pCtx, n); + }else if( c=='d' && strcmp(zType,"double")==0 ){ + double r; + Tcl_GetDoubleFromObj(0, pVar, &r); + sqlite3_result_double(pCtx, r); + }else if( (c=='w' && strcmp(zType,"wideInt")==0) || + (c=='i' && strcmp(zType,"int")==0) ){ + Tcl_WideInt v; + Tcl_GetWideIntFromObj(0, pVar, &v); + sqlite3_result_int64(pCtx, v); + }else{ + unsigned char *data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); + sqlite3_result_text(pCtx, (char *)data, n, SQLITE_TRANSIENT); + } + } +} + +static void xF5tDestroy(void *pCtx){ + F5tFunction *p = (F5tFunction*)pCtx; + Tcl_DecrRefCount(p->pScript); + ckfree((char *)p); +} + +/* +** sqlite3_fts5_create_function DB NAME SCRIPT +** +** Description... +*/ +static int f5tCreateFunction( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + char *zName; + Tcl_Obj *pScript; + sqlite3 *db = 0; + fts5_api *pApi = 0; + F5tFunction *pCtx = 0; + int rc; + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB NAME SCRIPT"); + return TCL_ERROR; + } + if( f5tDbAndApi(interp, objv[1], &db, &pApi) ) return TCL_ERROR; + + zName = Tcl_GetString(objv[2]); + pScript = objv[3]; + pCtx = (F5tFunction*)ckalloc(sizeof(F5tFunction)); + pCtx->interp = interp; + pCtx->pScript = pScript; + Tcl_IncrRefCount(pScript); + + rc = pApi->xCreateFunction( + pApi, zName, (void*)pCtx, xF5tFunction, xF5tDestroy + ); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0); + return TCL_ERROR; + } + + return TCL_OK; +} + +typedef struct F5tTokenizeCtx F5tTokenizeCtx; +struct F5tTokenizeCtx { + Tcl_Obj *pRet; + int bSubst; + const char *zInput; +}; + +static int xTokenizeCb2( + void *pCtx, + int tflags, + const char *zToken, int nToken, + int iStart, int iEnd +){ + F5tTokenizeCtx *p = (F5tTokenizeCtx*)pCtx; + if( p->bSubst ){ + Tcl_ListObjAppendElement(0, p->pRet, Tcl_NewStringObj(zToken, nToken)); + Tcl_ListObjAppendElement( + 0, p->pRet, Tcl_NewStringObj(&p->zInput[iStart], iEnd-iStart) + ); + }else{ + Tcl_ListObjAppendElement(0, p->pRet, Tcl_NewStringObj(zToken, nToken)); + Tcl_ListObjAppendElement(0, p->pRet, Tcl_NewIntObj(iStart)); + Tcl_ListObjAppendElement(0, p->pRet, Tcl_NewIntObj(iEnd)); + } + return SQLITE_OK; +} + + +/* +** sqlite3_fts5_tokenize DB TOKENIZER TEXT +** +** Description... +*/ +static int f5tTokenize( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + char *zText; + int nText; + sqlite3 *db = 0; + fts5_api *pApi = 0; + Fts5Tokenizer *pTok = 0; + fts5_tokenizer tokenizer; + Tcl_Obj *pRet = 0; + void *pUserdata; + int rc; + + int nArg; + const char **azArg; + F5tTokenizeCtx ctx; + + if( objc!=4 && objc!=5 ){ + Tcl_WrongNumArgs(interp, 1, objv, "?-subst? DB NAME TEXT"); + return TCL_ERROR; + } + if( objc==5 ){ + char *zOpt = Tcl_GetString(objv[1]); + if( strcmp("-subst", zOpt) ){ + Tcl_AppendResult(interp, "unrecognized option: ", zOpt, 0); + return TCL_ERROR; + } + } + if( f5tDbAndApi(interp, objv[objc-3], &db, &pApi) ) return TCL_ERROR; + if( Tcl_SplitList(interp, Tcl_GetString(objv[objc-2]), &nArg, &azArg) ){ + return TCL_ERROR; + } + if( nArg==0 ){ + Tcl_AppendResult(interp, "no such tokenizer: ", 0); + Tcl_Free((void*)azArg); + return TCL_ERROR; + } + zText = Tcl_GetStringFromObj(objv[objc-1], &nText); + + rc = pApi->xFindTokenizer(pApi, azArg[0], &pUserdata, &tokenizer); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, "no such tokenizer: ", azArg[0], 0); + return TCL_ERROR; + } + + rc = tokenizer.xCreate(pUserdata, &azArg[1], nArg-1, &pTok); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, "error in tokenizer.xCreate()", 0); + return TCL_ERROR; + } + + pRet = Tcl_NewObj(); + Tcl_IncrRefCount(pRet); + ctx.bSubst = (objc==5); + ctx.pRet = pRet; + ctx.zInput = zText; + rc = tokenizer.xTokenize( + pTok, (void*)&ctx, FTS5_TOKENIZE_DOCUMENT, zText, nText, xTokenizeCb2 + ); + tokenizer.xDelete(pTok); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", 0); + Tcl_DecrRefCount(pRet); + return TCL_ERROR; + } + + + Tcl_Free((void*)azArg); + Tcl_SetObjResult(interp, pRet); + Tcl_DecrRefCount(pRet); + return TCL_OK; +} + +/************************************************************************* +** Start of tokenizer wrapper. +*/ + +typedef struct F5tTokenizerContext F5tTokenizerContext; +typedef struct F5tTokenizerCb F5tTokenizerCb; +typedef struct F5tTokenizerModule F5tTokenizerModule; +typedef struct F5tTokenizerInstance F5tTokenizerInstance; + +struct F5tTokenizerContext { + void *pCtx; + int (*xToken)(void*, int, const char*, int, int, int); +}; + +struct F5tTokenizerModule { + Tcl_Interp *interp; + Tcl_Obj *pScript; + F5tTokenizerContext *pContext; +}; + +struct F5tTokenizerInstance { + Tcl_Interp *interp; + Tcl_Obj *pScript; + F5tTokenizerContext *pContext; +}; + +static int f5tTokenizerCreate( + void *pCtx, + const char **azArg, + int nArg, + Fts5Tokenizer **ppOut +){ + F5tTokenizerModule *pMod = (F5tTokenizerModule*)pCtx; + Tcl_Obj *pEval; + int rc = TCL_OK; + int i; + + pEval = Tcl_DuplicateObj(pMod->pScript); + Tcl_IncrRefCount(pEval); + for(i=0; rc==TCL_OK && iinterp, pEval, pObj); + } + + if( rc==TCL_OK ){ + rc = Tcl_EvalObjEx(pMod->interp, pEval, TCL_GLOBAL_ONLY); + } + Tcl_DecrRefCount(pEval); + + if( rc==TCL_OK ){ + F5tTokenizerInstance *pInst; + pInst = (F5tTokenizerInstance*)ckalloc(sizeof(F5tTokenizerInstance)); + memset(pInst, 0, sizeof(F5tTokenizerInstance)); + pInst->interp = pMod->interp; + pInst->pScript = Tcl_GetObjResult(pMod->interp); + pInst->pContext = pMod->pContext; + Tcl_IncrRefCount(pInst->pScript); + *ppOut = (Fts5Tokenizer*)pInst; + } + + return rc; +} + + +static void f5tTokenizerDelete(Fts5Tokenizer *p){ + F5tTokenizerInstance *pInst = (F5tTokenizerInstance*)p; + Tcl_DecrRefCount(pInst->pScript); + ckfree((char *)pInst); +} + +static int f5tTokenizerTokenize( + Fts5Tokenizer *p, + void *pCtx, + int flags, + const char *pText, int nText, + int (*xToken)(void*, int, const char*, int, int, int) +){ + F5tTokenizerInstance *pInst = (F5tTokenizerInstance*)p; + void *pOldCtx; + int (*xOldToken)(void*, int, const char*, int, int, int); + Tcl_Obj *pEval; + int rc; + const char *zFlags; + + pOldCtx = pInst->pContext->pCtx; + xOldToken = pInst->pContext->xToken; + + pInst->pContext->pCtx = pCtx; + pInst->pContext->xToken = xToken; + + assert( + flags==FTS5_TOKENIZE_DOCUMENT + || flags==FTS5_TOKENIZE_AUX + || flags==FTS5_TOKENIZE_QUERY + || flags==(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) + ); + pEval = Tcl_DuplicateObj(pInst->pScript); + Tcl_IncrRefCount(pEval); + switch( flags ){ + case FTS5_TOKENIZE_DOCUMENT: + zFlags = "document"; + break; + case FTS5_TOKENIZE_AUX: + zFlags = "aux"; + break; + case FTS5_TOKENIZE_QUERY: + zFlags = "query"; + break; + case (FTS5_TOKENIZE_PREFIX | FTS5_TOKENIZE_QUERY): + zFlags = "prefixquery"; + break; + default: + assert( 0 ); + zFlags = "invalid"; + break; + } + + Tcl_ListObjAppendElement(pInst->interp, pEval, Tcl_NewStringObj(zFlags, -1)); + Tcl_ListObjAppendElement(pInst->interp, pEval, Tcl_NewStringObj(pText,nText)); + rc = Tcl_EvalObjEx(pInst->interp, pEval, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(pEval); + + pInst->pContext->pCtx = pOldCtx; + pInst->pContext->xToken = xOldToken; + return rc; +} + +/* +** sqlite3_fts5_token ?-colocated? TEXT START END +*/ +static int f5tTokenizerReturn( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + F5tTokenizerContext *p = (F5tTokenizerContext*)clientData; + int iStart; + int iEnd; + int nToken; + int tflags = 0; + char *zToken; + int rc; + + if( objc==5 ){ + int nArg; + char *zArg = Tcl_GetStringFromObj(objv[1], &nArg); + if( nArg<=10 && nArg>=2 && memcmp("-colocated", zArg, nArg)==0 ){ + tflags |= FTS5_TOKEN_COLOCATED; + }else{ + goto usage; + } + }else if( objc!=4 ){ + goto usage; + } + + zToken = Tcl_GetStringFromObj(objv[objc-3], &nToken); + if( Tcl_GetIntFromObj(interp, objv[objc-2], &iStart) + || Tcl_GetIntFromObj(interp, objv[objc-1], &iEnd) + ){ + return TCL_ERROR; + } + + if( p->xToken==0 ){ + Tcl_AppendResult(interp, + "sqlite3_fts5_token may only be used by tokenizer callback", 0 + ); + return TCL_ERROR; + } + + rc = p->xToken(p->pCtx, tflags, zToken, nToken, iStart, iEnd); + Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); + return TCL_OK; + + usage: + Tcl_WrongNumArgs(interp, 1, objv, "?-colocated? TEXT START END"); + return TCL_ERROR; +} + +static void f5tDelTokenizer(void *pCtx){ + F5tTokenizerModule *pMod = (F5tTokenizerModule*)pCtx; + Tcl_DecrRefCount(pMod->pScript); + ckfree((char *)pMod); +} + +/* +** sqlite3_fts5_create_tokenizer DB NAME SCRIPT +** +** Register a tokenizer named NAME implemented by script SCRIPT. When +** a tokenizer instance is created (fts5_tokenizer.xCreate), any tokenizer +** arguments are appended to SCRIPT and the result executed. +** +** The value returned by (SCRIPT + args) is itself a tcl script. This +** script - call it SCRIPT2 - is executed to tokenize text using the +** tokenizer instance "returned" by SCRIPT. Specifically, to tokenize +** text SCRIPT2 is invoked with a single argument appended to it - the +** text to tokenize. +** +** SCRIPT2 should invoke the [sqlite3_fts5_token] command once for each +** token within the tokenized text. +*/ +static int f5tCreateTokenizer( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + F5tTokenizerContext *pContext = (F5tTokenizerContext*)clientData; + sqlite3 *db; + fts5_api *pApi; + char *zName; + Tcl_Obj *pScript; + fts5_tokenizer t; + F5tTokenizerModule *pMod; + int rc; + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB NAME SCRIPT"); + return TCL_ERROR; + } + if( f5tDbAndApi(interp, objv[1], &db, &pApi) ){ + return TCL_ERROR; + } + zName = Tcl_GetString(objv[2]); + pScript = objv[3]; + + t.xCreate = f5tTokenizerCreate; + t.xTokenize = f5tTokenizerTokenize; + t.xDelete = f5tTokenizerDelete; + + pMod = (F5tTokenizerModule*)ckalloc(sizeof(F5tTokenizerModule)); + pMod->interp = interp; + pMod->pScript = pScript; + pMod->pContext = pContext; + Tcl_IncrRefCount(pScript); + rc = pApi->xCreateTokenizer(pApi, zName, (void*)pMod, &t, f5tDelTokenizer); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, "error in fts5_api.xCreateTokenizer()", 0); + return TCL_ERROR; + } + + return TCL_OK; +} + +static void xF5tFree(ClientData clientData){ + ckfree(clientData); +} + +/* +** sqlite3_fts5_may_be_corrupt BOOLEAN +** +** Set or clear the global "may-be-corrupt" flag. Return the old value. +*/ +static int f5tMayBeCorrupt( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int bOld = sqlite3_fts5_may_be_corrupt; + + if( objc!=2 && objc!=1 ){ + Tcl_WrongNumArgs(interp, 1, objv, "?BOOLEAN?"); + return TCL_ERROR; + } + if( objc==2 ){ + int bNew; + if( Tcl_GetBooleanFromObj(interp, objv[1], &bNew) ) return TCL_ERROR; + sqlite3_fts5_may_be_corrupt = bNew; + } + + Tcl_SetObjResult(interp, Tcl_NewIntObj(bOld)); + return TCL_OK; +} + + +static unsigned int f5t_fts5HashKey(int nSlot, const char *p, int n){ + int i; + unsigned int h = 13; + for(i=n-1; i>=0; i--){ + h = (h << 3) ^ h ^ p[i]; + } + return (h % nSlot); +} + +static int f5tTokenHash( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + char *z; + int n; + unsigned int iVal; + int nSlot; + + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "NSLOT TOKEN"); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[1], &nSlot) ){ + return TCL_ERROR; + } + z = Tcl_GetStringFromObj(objv[2], &n); + + iVal = f5t_fts5HashKey(nSlot, z, n); + Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal)); + return TCL_OK; +} + +static int f5tRegisterMatchinfo( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int rc; + sqlite3 *db = 0; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB"); + return TCL_ERROR; + } + if( f5tDbPointer(interp, objv[1], &db) ){ + return TCL_ERROR; + } + + rc = sqlite3Fts5TestRegisterMatchinfo(db); + if( rc!=SQLITE_OK ){ + Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); + return TCL_ERROR; + } + return TCL_OK; +} + +static int f5tRegisterTok( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int rc; + sqlite3 *db = 0; + fts5_api *pApi = 0; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB"); + return TCL_ERROR; + } + if( f5tDbAndApi(interp, objv[1], &db, &pApi) ){ + return TCL_ERROR; + } + + rc = sqlite3Fts5TestRegisterTok(db, pApi); + if( rc!=SQLITE_OK ){ + Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Entry point. +*/ +int Fts5tcl_Init(Tcl_Interp *interp){ + static struct Cmd { + char *zName; + Tcl_ObjCmdProc *xProc; + int bTokenizeCtx; + } aCmd[] = { + { "sqlite3_fts5_create_tokenizer", f5tCreateTokenizer, 1 }, + { "sqlite3_fts5_token", f5tTokenizerReturn, 1 }, + { "sqlite3_fts5_tokenize", f5tTokenize, 0 }, + { "sqlite3_fts5_create_function", f5tCreateFunction, 0 }, + { "sqlite3_fts5_may_be_corrupt", f5tMayBeCorrupt, 0 }, + { "sqlite3_fts5_token_hash", f5tTokenHash, 0 }, + { "sqlite3_fts5_register_matchinfo", f5tRegisterMatchinfo, 0 }, + { "sqlite3_fts5_register_fts5tokenize", f5tRegisterTok, 0 } + }; + int i; + F5tTokenizerContext *pContext; + + pContext = (F5tTokenizerContext*)ckalloc(sizeof(F5tTokenizerContext)); + memset(pContext, 0, sizeof(*pContext)); + + for(i=0; ibTokenizeCtx ) pCtx = (void*)pContext; + Tcl_CreateObjCommand(interp, p->zName, p->xProc, pCtx, (i ? 0 : xF5tFree)); + } + + return TCL_OK; +} +#else /* SQLITE_ENABLE_FTS5 */ +int Fts5tcl_Init(Tcl_Interp *interp){ + return TCL_OK; +} +#endif /* SQLITE_ENABLE_FTS5 */ +#endif /* SQLITE_TEST */ diff --git a/ext/fts5/fts5_test_mi.c b/ext/fts5/fts5_test_mi.c new file mode 100644 index 0000000..2833177 --- /dev/null +++ b/ext/fts5/fts5_test_mi.c @@ -0,0 +1,424 @@ +/* +** 2015 Aug 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 contains test code only, it is not included in release +** versions of FTS5. It contains the implementation of an FTS5 auxiliary +** function very similar to the FTS4 function matchinfo(): +** +** https://www.sqlite.org/fts3.html#matchinfo +** +** Known differences are that: +** +** 1) this function uses the FTS5 definition of "matchable phrase", which +** excludes any phrases that are part of an expression sub-tree that +** does not match the current row. This comes up for MATCH queries +** such as: +** +** "a OR (b AND c)" +** +** In FTS4, if a single row contains instances of tokens "a" and "c", +** but not "b", all instances of "c" are considered matches. In FTS5, +** they are not (as the "b AND c" sub-tree does not match the current +** row. +** +** 2) For the values returned by 'x' that apply to all rows of the table, +** NEAR constraints are not considered. But for the number of hits in +** the current row, they are. +** +** This file exports a single function that may be called to register the +** matchinfo() implementation with a database handle: +** +** int sqlite3Fts5TestRegisterMatchinfo(sqlite3 *db); +*/ + + +#ifdef SQLITE_TEST +#ifdef SQLITE_ENABLE_FTS5 + +#include "fts5.h" +#include +#include +#include + +typedef struct Fts5MatchinfoCtx Fts5MatchinfoCtx; +typedef unsigned int u32; + +struct Fts5MatchinfoCtx { + int nCol; /* Number of cols in FTS5 table */ + int nPhrase; /* Number of phrases in FTS5 query */ + char *zArg; /* nul-term'd copy of 2nd arg */ + int nRet; /* Number of elements in aRet[] */ + u32 *aRet; /* Array of 32-bit unsigned ints to return */ +}; + + + +/* +** Return a pointer to the fts5_api pointer for database connection db. +** If an error occurs, return NULL and leave an error in the database +** handle (accessible using sqlite3_errcode()/errmsg()). +*/ +static fts5_api *fts5_api_from_db(sqlite3 *db){ + fts5_api *pRet = 0; + sqlite3_stmt *pStmt = 0; + + if( SQLITE_OK==sqlite3_prepare(db, "SELECT fts5()", -1, &pStmt, 0) + && SQLITE_ROW==sqlite3_step(pStmt) + && sizeof(pRet)==sqlite3_column_bytes(pStmt, 0) + ){ + memcpy(&pRet, sqlite3_column_blob(pStmt, 0), sizeof(pRet)); + } + sqlite3_finalize(pStmt); + return pRet; +} + + +/* +** Argument f should be a flag accepted by matchinfo() (a valid character +** in the string passed as the second argument). If it is not, -1 is +** returned. Otherwise, if f is a valid matchinfo flag, the value returned +** is the number of 32-bit integers added to the output array if the +** table has nCol columns and the query nPhrase phrases. +*/ +static int fts5MatchinfoFlagsize(int nCol, int nPhrase, char f){ + int ret = -1; + switch( f ){ + case 'p': ret = 1; break; + case 'c': ret = 1; break; + case 'x': ret = 3 * nCol * nPhrase; break; + case 'y': ret = nCol * nPhrase; break; + case 'b': ret = ((nCol + 31) / 32) * nPhrase; break; + case 'n': ret = 1; break; + case 'a': ret = nCol; break; + case 'l': ret = nCol; break; + case 's': ret = nCol; break; + } + return ret; +} + +static int fts5MatchinfoIter( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + Fts5MatchinfoCtx *p, + int(*x)(const Fts5ExtensionApi*,Fts5Context*,Fts5MatchinfoCtx*,char,u32*) +){ + int i; + int n = 0; + int rc = SQLITE_OK; + char f; + for(i=0; (f = p->zArg[i]); i++){ + rc = x(pApi, pFts, p, f, &p->aRet[n]); + if( rc!=SQLITE_OK ) break; + n += fts5MatchinfoFlagsize(p->nCol, p->nPhrase, f); + } + return rc; +} + +static int fts5MatchinfoXCb( + const Fts5ExtensionApi *pApi, + Fts5Context *pFts, + void *pUserData +){ + Fts5PhraseIter iter; + int iCol, iOff; + u32 *aOut = (u32*)pUserData; + int iPrev = -1; + + for(pApi->xPhraseFirst(pFts, 0, &iter, &iCol, &iOff); + iCol>=0; + pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) + ){ + aOut[iCol*3+1]++; + if( iCol!=iPrev ) aOut[iCol*3 + 2]++; + iPrev = iCol; + } + + return SQLITE_OK; +} + +static int fts5MatchinfoGlobalCb( + const Fts5ExtensionApi *pApi, + Fts5Context *pFts, + Fts5MatchinfoCtx *p, + char f, + u32 *aOut +){ + int rc = SQLITE_OK; + switch( f ){ + case 'p': + aOut[0] = p->nPhrase; + break; + + case 'c': + aOut[0] = p->nCol; + break; + + case 'x': { + int i; + for(i=0; inPhrase && rc==SQLITE_OK; i++){ + void *pPtr = (void*)&aOut[i * p->nCol * 3]; + rc = pApi->xQueryPhrase(pFts, i, pPtr, fts5MatchinfoXCb); + } + break; + } + + case 'n': { + sqlite3_int64 nRow; + rc = pApi->xRowCount(pFts, &nRow); + aOut[0] = (u32)nRow; + break; + } + + case 'a': { + sqlite3_int64 nRow = 0; + rc = pApi->xRowCount(pFts, &nRow); + if( nRow==0 ){ + memset(aOut, 0, sizeof(u32) * p->nCol); + }else{ + int i; + for(i=0; rc==SQLITE_OK && inCol; i++){ + sqlite3_int64 nToken; + rc = pApi->xColumnTotalSize(pFts, i, &nToken); + if( rc==SQLITE_OK){ + aOut[i] = (u32)((2*nToken + nRow) / (2*nRow)); + } + } + } + break; + } + + } + return rc; +} + +static int fts5MatchinfoLocalCb( + const Fts5ExtensionApi *pApi, + Fts5Context *pFts, + Fts5MatchinfoCtx *p, + char f, + u32 *aOut +){ + int i; + int rc = SQLITE_OK; + + switch( f ){ + case 'b': { + int iPhrase; + int nInt = ((p->nCol + 31) / 32) * p->nPhrase; + for(i=0; inPhrase; iPhrase++){ + Fts5PhraseIter iter; + int iCol; + for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); + iCol>=0; + pApi->xPhraseNextColumn(pFts, &iter, &iCol) + ){ + aOut[iPhrase * ((p->nCol+31)/32) + iCol/32] |= ((u32)1 << iCol%32); + } + } + + break; + } + + case 'x': + case 'y': { + int nMul = (f=='x' ? 3 : 1); + int iPhrase; + + for(i=0; i<(p->nCol*p->nPhrase); i++) aOut[i*nMul] = 0; + + for(iPhrase=0; iPhrasenPhrase; iPhrase++){ + Fts5PhraseIter iter; + int iOff, iCol; + for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); + iOff>=0; + pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) + ){ + if( f=='b' ){ + aOut[iPhrase * ((p->nCol+31)/32) + iCol/32] |= ((u32)1 << iCol%32); + }else{ + aOut[nMul * (iCol + iPhrase * p->nCol)]++; + } + } + } + + break; + } + + case 'l': { + for(i=0; rc==SQLITE_OK && inCol; i++){ + int nToken; + rc = pApi->xColumnSize(pFts, i, &nToken); + aOut[i] = (u32)nToken; + } + break; + } + + case 's': { + int nInst; + + memset(aOut, 0, sizeof(u32) * p->nCol); + + rc = pApi->xInstCount(pFts, &nInst); + for(i=0; rc==SQLITE_OK && ixInst(pFts, i, &iPhrase, &iCol, &iOff); + iNextPhrase = iPhrase+1; + iNextOff = iOff+pApi->xPhraseSize(pFts, 0); + for(j=i+1; rc==SQLITE_OK && jxInst(pFts, j, &ip, &ic, &io); + if( ic!=iCol || io>iNextOff ) break; + if( ip==iNextPhrase && io==iNextOff ){ + nSeq++; + iNextPhrase = ip+1; + iNextOff = io + pApi->xPhraseSize(pFts, ip); + } + } + + if( nSeq>aOut[iCol] ) aOut[iCol] = nSeq; + } + + break; + } + } + return rc; +} + +static Fts5MatchinfoCtx *fts5MatchinfoNew( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning error message */ + const char *zArg /* Matchinfo flag string */ +){ + Fts5MatchinfoCtx *p; + int nCol; + int nPhrase; + int i; + int nInt; + int nByte; + int rc; + + nCol = pApi->xColumnCount(pFts); + nPhrase = pApi->xPhraseCount(pFts); + + nInt = 0; + for(i=0; zArg[i]; i++){ + int n = fts5MatchinfoFlagsize(nCol, nPhrase, zArg[i]); + if( n<0 ){ + char *zErr = sqlite3_mprintf("unrecognized matchinfo flag: %c", zArg[i]); + sqlite3_result_error(pCtx, zErr, -1); + sqlite3_free(zErr); + return 0; + } + nInt += n; + } + + nByte = sizeof(Fts5MatchinfoCtx) /* The struct itself */ + + sizeof(u32) * nInt /* The p->aRet[] array */ + + (i+1); /* The p->zArg string */ + p = (Fts5MatchinfoCtx*)sqlite3_malloc(nByte); + if( p==0 ){ + sqlite3_result_error_nomem(pCtx); + return 0; + } + memset(p, 0, nByte); + + p->nCol = nCol; + p->nPhrase = nPhrase; + p->aRet = (u32*)&p[1]; + p->nRet = nInt; + p->zArg = (char*)&p->aRet[nInt]; + memcpy(p->zArg, zArg, i); + + rc = fts5MatchinfoIter(pApi, pFts, p, fts5MatchinfoGlobalCb); + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(pCtx, rc); + sqlite3_free(p); + p = 0; + } + + return p; +} + +static void fts5MatchinfoFunc( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +){ + const char *zArg; + Fts5MatchinfoCtx *p; + int rc = SQLITE_OK; + + if( nVal>0 ){ + zArg = (const char*)sqlite3_value_text(apVal[0]); + }else{ + zArg = "pcx"; + } + + p = (Fts5MatchinfoCtx*)pApi->xGetAuxdata(pFts, 0); + if( p==0 || sqlite3_stricmp(zArg, p->zArg) ){ + p = fts5MatchinfoNew(pApi, pFts, pCtx, zArg); + if( p==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = pApi->xSetAuxdata(pFts, p, sqlite3_free); + } + } + + if( rc==SQLITE_OK ){ + rc = fts5MatchinfoIter(pApi, pFts, p, fts5MatchinfoLocalCb); + } + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(pCtx, rc); + }else{ + /* No errors has occured, so return a copy of the array of integers. */ + int nByte = p->nRet * sizeof(u32); + sqlite3_result_blob(pCtx, (void*)p->aRet, nByte, SQLITE_TRANSIENT); + } +} + +int sqlite3Fts5TestRegisterMatchinfo(sqlite3 *db){ + int rc; /* Return code */ + fts5_api *pApi; /* FTS5 API functions */ + + /* Extract the FTS5 API pointer from the database handle. The + ** fts5_api_from_db() function above is copied verbatim from the + ** FTS5 documentation. Refer there for details. */ + pApi = fts5_api_from_db(db); + + /* If fts5_api_from_db() returns NULL, then either FTS5 is not registered + ** with this database handle, or an error (OOM perhaps?) has occurred. + ** + ** Also check that the fts5_api object is version 2 or newer. + */ + if( pApi==0 || pApi->iVersion<1 ){ + return SQLITE_ERROR; + } + + /* Register the implementation of matchinfo() */ + rc = pApi->xCreateFunction(pApi, "matchinfo", 0, fts5MatchinfoFunc, 0); + + return rc; +} + +#endif /* SQLITE_ENABLE_FTS5 */ +#endif /* SQLITE_TEST */ + diff --git a/ext/fts5/fts5_test_tok.c b/ext/fts5/fts5_test_tok.c new file mode 100644 index 0000000..10af126 --- /dev/null +++ b/ext/fts5/fts5_test_tok.c @@ -0,0 +1,482 @@ +/* +** 2013 Apr 22 +** +** 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 contains code for the "fts5tokenize" virtual table module. +** An fts5tokenize virtual table is created as follows: +** +** CREATE VIRTUAL TABLE USING fts5tokenize( +** , , ... +** ); +** +** The table created has the following schema: +** +** CREATE TABLE (input HIDDEN, token, start, end, position) +** +** When queried, the query must include a WHERE clause of type: +** +** input = +** +** The virtual table module tokenizes this , using the FTS3 +** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE +** statement and returns one row for each token in the result. With +** fields set as follows: +** +** input: Always set to a copy of +** token: A token from the input. +** start: Byte offset of the token within the input . +** end: Byte offset of the byte immediately following the end of the +** token within the input string. +** pos: Token offset of token within input. +** +*/ +#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_FTS5) + +#include +#include +#include + +typedef struct Fts5tokTable Fts5tokTable; +typedef struct Fts5tokCursor Fts5tokCursor; +typedef struct Fts5tokRow Fts5tokRow; + +/* +** Virtual table structure. +*/ +struct Fts5tokTable { + sqlite3_vtab base; /* Base class used by SQLite core */ + fts5_tokenizer tok; /* Tokenizer functions */ + Fts5Tokenizer *pTok; /* Tokenizer instance */ +}; + +/* +** A container for a rows values. +*/ +struct Fts5tokRow { + char *zToken; + int iStart; + int iEnd; + int iPos; +}; + +/* +** Virtual table cursor structure. +*/ +struct Fts5tokCursor { + sqlite3_vtab_cursor base; /* Base class used by SQLite core */ + int iRowid; /* Current 'rowid' value */ + char *zInput; /* Input string */ + int nRow; /* Number of entries in aRow[] */ + Fts5tokRow *aRow; /* Array of rows to return */ +}; + +static void fts5tokDequote(char *z){ + char q = z[0]; + + if( q=='[' || q=='\'' || q=='"' || q=='`' ){ + int iIn = 1; + int iOut = 0; + if( q=='[' ) q = ']'; + + while( z[iIn] ){ + if( z[iIn]==q ){ + if( z[iIn+1]!=q ){ + /* Character iIn was the close quote. */ + iIn++; + break; + }else{ + /* Character iIn and iIn+1 form an escaped quote character. Skip + ** the input cursor past both and copy a single quote character + ** to the output buffer. */ + iIn += 2; + z[iOut++] = q; + } + }else{ + z[iOut++] = z[iIn++]; + } + } + + z[iOut] = '\0'; + } +} + +/* +** The second argument, argv[], is an array of pointers to nul-terminated +** strings. This function makes a copy of the array and strings into a +** single block of memory. It then dequotes any of the strings that appear +** to be quoted. +** +** If successful, output parameter *pazDequote is set to point at the +** array of dequoted strings and SQLITE_OK is returned. The caller is +** responsible for eventually calling sqlite3_free() to free the array +** in this case. Or, if an error occurs, an SQLite error code is returned. +** The final value of *pazDequote is undefined in this case. +*/ +static int fts5tokDequoteArray( + int argc, /* Number of elements in argv[] */ + const char * const *argv, /* Input array */ + char ***pazDequote /* Output array */ +){ + int rc = SQLITE_OK; /* Return code */ + if( argc==0 ){ + *pazDequote = 0; + }else{ + int i; + int nByte = 0; + char **azDequote; + + for(i=0; i0 ){ + zModule = azDequote[0]; + } + + rc = pApi->xFindTokenizer(pApi, zModule, &pTokCtx, &pTab->tok); + if( rc==SQLITE_OK ){ + const char **azArg = (const char **)&azDequote[1]; + int nArg = nDequote>0 ? nDequote-1 : 0; + rc = pTab->tok.xCreate(pTokCtx, azArg, nArg, &pTab->pTok); + } + } + + if( rc!=SQLITE_OK ){ + sqlite3_free(pTab); + pTab = 0; + } + + *ppVtab = (sqlite3_vtab*)pTab; + sqlite3_free(azDequote); + return rc; +} + +/* +** 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 fts5tokDisconnectMethod(sqlite3_vtab *pVtab){ + Fts5tokTable *pTab = (Fts5tokTable *)pVtab; + if( pTab->pTok ){ + pTab->tok.xDelete(pTab->pTok); + } + sqlite3_free(pTab); + return SQLITE_OK; +} + +/* +** xBestIndex - Analyze a WHERE and ORDER BY clause. +*/ +static int fts5tokBestIndexMethod( + sqlite3_vtab *pVTab, + sqlite3_index_info *pInfo +){ + int i; + + for(i=0; inConstraint; i++){ + if( pInfo->aConstraint[i].usable + && pInfo->aConstraint[i].iColumn==0 + && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ + ){ + pInfo->idxNum = 1; + pInfo->aConstraintUsage[i].argvIndex = 1; + pInfo->aConstraintUsage[i].omit = 1; + pInfo->estimatedCost = 1; + return SQLITE_OK; + } + } + + pInfo->idxNum = 0; + assert( pInfo->estimatedCost>1000000.0 ); + + return SQLITE_OK; +} + +/* +** xOpen - Open a cursor. +*/ +static int fts5tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ + Fts5tokCursor *pCsr; + + pCsr = (Fts5tokCursor *)sqlite3_malloc(sizeof(Fts5tokCursor)); + if( pCsr==0 ){ + return SQLITE_NOMEM; + } + memset(pCsr, 0, sizeof(Fts5tokCursor)); + + *ppCsr = (sqlite3_vtab_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** Reset the tokenizer cursor passed as the only argument. As if it had +** just been returned by fts5tokOpenMethod(). +*/ +static void fts5tokResetCursor(Fts5tokCursor *pCsr){ + int i; + for(i=0; inRow; i++){ + sqlite3_free(pCsr->aRow[i].zToken); + } + sqlite3_free(pCsr->zInput); + sqlite3_free(pCsr->aRow); + pCsr->zInput = 0; + pCsr->aRow = 0; + pCsr->nRow = 0; + pCsr->iRowid = 0; +} + +/* +** xClose - Close a cursor. +*/ +static int fts5tokCloseMethod(sqlite3_vtab_cursor *pCursor){ + Fts5tokCursor *pCsr = (Fts5tokCursor *)pCursor; + fts5tokResetCursor(pCsr); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** xNext - Advance the cursor to the next row, if any. +*/ +static int fts5tokNextMethod(sqlite3_vtab_cursor *pCursor){ + Fts5tokCursor *pCsr = (Fts5tokCursor *)pCursor; + pCsr->iRowid++; + return SQLITE_OK; +} + +static int fts5tokCb( + void *pCtx, /* Pointer to Fts5tokCursor */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStart, /* Byte offset of token within input text */ + int iEnd /* Byte offset of end of token within input text */ +){ + Fts5tokCursor *pCsr = (Fts5tokCursor*)pCtx; + Fts5tokRow *pRow; + + if( (pCsr->nRow & (pCsr->nRow-1))==0 ){ + int nNew = pCsr->nRow ? pCsr->nRow*2 : 32; + Fts5tokRow *aNew; + aNew = (Fts5tokRow*)sqlite3_realloc(pCsr->aRow, nNew*sizeof(Fts5tokRow)); + if( aNew==0 ) return SQLITE_NOMEM; + memset(&aNew[pCsr->nRow], 0, sizeof(Fts5tokRow)*(nNew-pCsr->nRow)); + pCsr->aRow = aNew; + } + + pRow = &pCsr->aRow[pCsr->nRow]; + pRow->iStart = iStart; + pRow->iEnd = iEnd; + if( pCsr->nRow ){ + pRow->iPos = pRow[-1].iPos + ((tflags & FTS5_TOKEN_COLOCATED) ? 0 : 1); + } + pRow->zToken = sqlite3_malloc(nToken+1); + if( pRow->zToken==0 ) return SQLITE_NOMEM; + memcpy(pRow->zToken, pToken, nToken); + pRow->zToken[nToken] = 0; + pCsr->nRow++; + + return SQLITE_OK; +} + +/* +** xFilter - Initialize a cursor to point at the start of its data. +*/ +static int fts5tokFilterMethod( + 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 */ +){ + int rc = SQLITE_ERROR; + Fts5tokCursor *pCsr = (Fts5tokCursor *)pCursor; + Fts5tokTable *pTab = (Fts5tokTable *)(pCursor->pVtab); + + fts5tokResetCursor(pCsr); + if( idxNum==1 ){ + const char *zByte = (const char *)sqlite3_value_text(apVal[0]); + int nByte = sqlite3_value_bytes(apVal[0]); + pCsr->zInput = sqlite3_malloc(nByte+1); + if( pCsr->zInput==0 ){ + rc = SQLITE_NOMEM; + }else{ + memcpy(pCsr->zInput, zByte, nByte); + pCsr->zInput[nByte] = 0; + rc = pTab->tok.xTokenize( + pTab->pTok, (void*)pCsr, 0, zByte, nByte, fts5tokCb + ); + } + } + + if( rc!=SQLITE_OK ) return rc; + return fts5tokNextMethod(pCursor); +} + +/* +** xEof - Return true if the cursor is at EOF, or false otherwise. +*/ +static int fts5tokEofMethod(sqlite3_vtab_cursor *pCursor){ + Fts5tokCursor *pCsr = (Fts5tokCursor *)pCursor; + return (pCsr->iRowid>pCsr->nRow); +} + +/* +** xColumn - Return a column value. +*/ +static int fts5tokColumnMethod( + 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 */ +){ + Fts5tokCursor *pCsr = (Fts5tokCursor *)pCursor; + Fts5tokRow *pRow = &pCsr->aRow[pCsr->iRowid-1]; + + /* CREATE TABLE x(input, token, start, end, position) */ + switch( iCol ){ + case 0: + sqlite3_result_text(pCtx, pCsr->zInput, -1, SQLITE_TRANSIENT); + break; + case 1: + sqlite3_result_text(pCtx, pRow->zToken, -1, SQLITE_TRANSIENT); + break; + case 2: + sqlite3_result_int(pCtx, pRow->iStart); + break; + case 3: + sqlite3_result_int(pCtx, pRow->iEnd); + break; + default: + assert( iCol==4 ); + sqlite3_result_int(pCtx, pRow->iPos); + break; + } + return SQLITE_OK; +} + +/* +** xRowid - Return the current rowid for the cursor. +*/ +static int fts5tokRowidMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite_int64 *pRowid /* OUT: Rowid value */ +){ + Fts5tokCursor *pCsr = (Fts5tokCursor *)pCursor; + *pRowid = (sqlite3_int64)pCsr->iRowid; + return SQLITE_OK; +} + +/* +** Register the fts5tok module with database connection db. Return SQLITE_OK +** if successful or an error code if sqlite3_create_module() fails. +*/ +int sqlite3Fts5TestRegisterTok(sqlite3 *db, fts5_api *pApi){ + static const sqlite3_module fts5tok_module = { + 0, /* iVersion */ + fts5tokConnectMethod, /* xCreate */ + fts5tokConnectMethod, /* xConnect */ + fts5tokBestIndexMethod, /* xBestIndex */ + fts5tokDisconnectMethod, /* xDisconnect */ + fts5tokDisconnectMethod, /* xDestroy */ + fts5tokOpenMethod, /* xOpen */ + fts5tokCloseMethod, /* xClose */ + fts5tokFilterMethod, /* xFilter */ + fts5tokNextMethod, /* xNext */ + fts5tokEofMethod, /* xEof */ + fts5tokColumnMethod, /* xColumn */ + fts5tokRowidMethod, /* xRowid */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindFunction */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0 /* xRollbackTo */ + }; + int rc; /* Return code */ + + rc = sqlite3_create_module(db, "fts5tokenize", &fts5tok_module, (void*)pApi); + return rc; +} + +#endif /* defined(SQLITE_TEST) && defined(SQLITE_ENABLE_FTS5) */ diff --git a/ext/fts5/fts5_tokenize.c b/ext/fts5/fts5_tokenize.c new file mode 100644 index 0000000..b72a0c2 --- /dev/null +++ b/ext/fts5/fts5_tokenize.c @@ -0,0 +1,1242 @@ +/* +** 2014 May 31 +** +** 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. +** +****************************************************************************** +*/ + + +#include "fts5Int.h" + +/************************************************************************** +** Start of ascii tokenizer implementation. +*/ + +/* +** For tokenizers with no "unicode" modifier, the set of token characters +** is the same as the set of ASCII range alphanumeric characters. +*/ +static unsigned char aAsciiTokenChar[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00..0x0F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10..0x1F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20..0x2F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30..0x3F */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40..0x4F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x50..0x5F */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60..0x6F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x70..0x7F */ +}; + +typedef struct AsciiTokenizer AsciiTokenizer; +struct AsciiTokenizer { + unsigned char aTokenChar[128]; +}; + +static void fts5AsciiAddExceptions( + AsciiTokenizer *p, + const char *zArg, + int bTokenChars +){ + int i; + for(i=0; zArg[i]; i++){ + if( (zArg[i] & 0x80)==0 ){ + p->aTokenChar[(int)zArg[i]] = (unsigned char)bTokenChars; + } + } +} + +/* +** Delete a "ascii" tokenizer. +*/ +static void fts5AsciiDelete(Fts5Tokenizer *p){ + sqlite3_free(p); +} + +/* +** Create an "ascii" tokenizer. +*/ +static int fts5AsciiCreate( + void *pUnused, + const char **azArg, int nArg, + Fts5Tokenizer **ppOut +){ + int rc = SQLITE_OK; + AsciiTokenizer *p = 0; + UNUSED_PARAM(pUnused); + if( nArg%2 ){ + rc = SQLITE_ERROR; + }else{ + p = sqlite3_malloc(sizeof(AsciiTokenizer)); + if( p==0 ){ + rc = SQLITE_NOMEM; + }else{ + int i; + memset(p, 0, sizeof(AsciiTokenizer)); + memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar)); + for(i=0; rc==SQLITE_OK && i='A' && c<='Z' ) c += 32; + aOut[i] = c; + } +} + +/* +** Tokenize some text using the ascii tokenizer. +*/ +static int fts5AsciiTokenize( + Fts5Tokenizer *pTokenizer, + void *pCtx, + int iUnused, + const char *pText, int nText, + int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd) +){ + AsciiTokenizer *p = (AsciiTokenizer*)pTokenizer; + int rc = SQLITE_OK; + int ie; + int is = 0; + + char aFold[64]; + int nFold = sizeof(aFold); + char *pFold = aFold; + unsigned char *a = p->aTokenChar; + + UNUSED_PARAM(iUnused); + + while( isnFold ){ + if( pFold!=aFold ) sqlite3_free(pFold); + pFold = sqlite3_malloc(nByte*2); + if( pFold==0 ){ + rc = SQLITE_NOMEM; + break; + } + nFold = nByte*2; + } + asciiFold(pFold, &pText[is], nByte); + + /* Invoke the token callback */ + rc = xToken(pCtx, 0, pFold, nByte, is, ie); + is = ie+1; + } + + if( pFold!=aFold ) sqlite3_free(pFold); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + return rc; +} + +/************************************************************************** +** Start of unicode61 tokenizer implementation. +*/ + + +/* +** The following two macros - READ_UTF8 and WRITE_UTF8 - have been copied +** from the sqlite3 source file utf.c. If this file is compiled as part +** of the amalgamation, they are not required. +*/ +#ifndef SQLITE_AMALGAMATION + +static const unsigned char sqlite3Utf8Trans1[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, +}; + +#define READ_UTF8(zIn, zTerm, c) \ + c = *(zIn++); \ + if( c>=0xc0 ){ \ + c = sqlite3Utf8Trans1[c-0xc0]; \ + while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ + c = (c<<6) + (0x3f & *(zIn++)); \ + } \ + if( c<0x80 \ + || (c&0xFFFFF800)==0xD800 \ + || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ + } + + +#define WRITE_UTF8(zOut, c) { \ + if( c<0x00080 ){ \ + *zOut++ = (unsigned char)(c&0xFF); \ + } \ + else if( c<0x00800 ){ \ + *zOut++ = 0xC0 + (unsigned char)((c>>6)&0x1F); \ + *zOut++ = 0x80 + (unsigned char)(c & 0x3F); \ + } \ + else if( c<0x10000 ){ \ + *zOut++ = 0xE0 + (unsigned char)((c>>12)&0x0F); \ + *zOut++ = 0x80 + (unsigned char)((c>>6) & 0x3F); \ + *zOut++ = 0x80 + (unsigned char)(c & 0x3F); \ + }else{ \ + *zOut++ = 0xF0 + (unsigned char)((c>>18) & 0x07); \ + *zOut++ = 0x80 + (unsigned char)((c>>12) & 0x3F); \ + *zOut++ = 0x80 + (unsigned char)((c>>6) & 0x3F); \ + *zOut++ = 0x80 + (unsigned char)(c & 0x3F); \ + } \ +} + +#endif /* ifndef SQLITE_AMALGAMATION */ + +typedef struct Unicode61Tokenizer Unicode61Tokenizer; +struct Unicode61Tokenizer { + unsigned char aTokenChar[128]; /* ASCII range token characters */ + char *aFold; /* Buffer to fold text into */ + int nFold; /* Size of aFold[] in bytes */ + int bRemoveDiacritic; /* True if remove_diacritics=1 is set */ + int nException; + int *aiException; +}; + +static int fts5UnicodeAddExceptions( + Unicode61Tokenizer *p, /* Tokenizer object */ + const char *z, /* Characters to treat as exceptions */ + int bTokenChars /* 1 for 'tokenchars', 0 for 'separators' */ +){ + int rc = SQLITE_OK; + int n = (int)strlen(z); + int *aNew; + + if( n>0 ){ + aNew = (int*)sqlite3_realloc(p->aiException, (n+p->nException)*sizeof(int)); + if( aNew ){ + int nNew = p->nException; + const unsigned char *zCsr = (const unsigned char*)z; + const unsigned char *zTerm = (const unsigned char*)&z[n]; + while( zCsraTokenChar[iCode] = (unsigned char)bTokenChars; + }else{ + bToken = sqlite3Fts5UnicodeIsalnum(iCode); + assert( (bToken==0 || bToken==1) ); + assert( (bTokenChars==0 || bTokenChars==1) ); + if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){ + int i; + for(i=0; iiCode ) break; + } + memmove(&aNew[i+1], &aNew[i], (nNew-i)*sizeof(int)); + aNew[i] = iCode; + nNew++; + } + } + } + p->aiException = aNew; + p->nException = nNew; + }else{ + rc = SQLITE_NOMEM; + } + } + + return rc; +} + +/* +** Return true if the p->aiException[] array contains the value iCode. +*/ +static int fts5UnicodeIsException(Unicode61Tokenizer *p, int iCode){ + if( p->nException>0 ){ + int *a = p->aiException; + int iLo = 0; + int iHi = p->nException-1; + + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( iCode==a[iTest] ){ + return 1; + }else if( iCode>a[iTest] ){ + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + } + + return 0; +} + +/* +** Delete a "unicode61" tokenizer. +*/ +static void fts5UnicodeDelete(Fts5Tokenizer *pTok){ + if( pTok ){ + Unicode61Tokenizer *p = (Unicode61Tokenizer*)pTok; + sqlite3_free(p->aiException); + sqlite3_free(p->aFold); + sqlite3_free(p); + } + return; +} + +/* +** Create a "unicode61" tokenizer. +*/ +static int fts5UnicodeCreate( + void *pUnused, + const char **azArg, int nArg, + Fts5Tokenizer **ppOut +){ + int rc = SQLITE_OK; /* Return code */ + Unicode61Tokenizer *p = 0; /* New tokenizer object */ + + UNUSED_PARAM(pUnused); + + if( nArg%2 ){ + rc = SQLITE_ERROR; + }else{ + p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer)); + if( p ){ + int i; + memset(p, 0, sizeof(Unicode61Tokenizer)); + memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar)); + p->bRemoveDiacritic = 1; + p->nFold = 64; + p->aFold = sqlite3_malloc(p->nFold * sizeof(char)); + if( p->aFold==0 ){ + rc = SQLITE_NOMEM; + } + for(i=0; rc==SQLITE_OK && ibRemoveDiacritic = (zArg[0]=='1'); + }else + if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){ + rc = fts5UnicodeAddExceptions(p, zArg, 1); + }else + if( 0==sqlite3_stricmp(azArg[i], "separators") ){ + rc = fts5UnicodeAddExceptions(p, zArg, 0); + }else{ + rc = SQLITE_ERROR; + } + } + }else{ + rc = SQLITE_NOMEM; + } + if( rc!=SQLITE_OK ){ + fts5UnicodeDelete((Fts5Tokenizer*)p); + p = 0; + } + *ppOut = (Fts5Tokenizer*)p; + } + return rc; +} + +/* +** Return true if, for the purposes of tokenizing with the tokenizer +** passed as the first argument, codepoint iCode is considered a token +** character (not a separator). +*/ +static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){ + assert( (sqlite3Fts5UnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 ); + return sqlite3Fts5UnicodeIsalnum(iCode) ^ fts5UnicodeIsException(p, iCode); +} + +static int fts5UnicodeTokenize( + Fts5Tokenizer *pTokenizer, + void *pCtx, + int iUnused, + const char *pText, int nText, + int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd) +){ + Unicode61Tokenizer *p = (Unicode61Tokenizer*)pTokenizer; + int rc = SQLITE_OK; + unsigned char *a = p->aTokenChar; + + unsigned char *zTerm = (unsigned char*)&pText[nText]; + unsigned char *zCsr = (unsigned char *)pText; + + /* Output buffer */ + char *aFold = p->aFold; + int nFold = p->nFold; + const char *pEnd = &aFold[nFold-6]; + + UNUSED_PARAM(iUnused); + + /* Each iteration of this loop gobbles up a contiguous run of separators, + ** then the next token. */ + while( rc==SQLITE_OK ){ + int iCode; /* non-ASCII codepoint read from input */ + char *zOut = aFold; + int is; + int ie; + + /* Skip any separator characters. */ + while( 1 ){ + if( zCsr>=zTerm ) goto tokenize_done; + if( *zCsr & 0x80 ) { + /* A character outside of the ascii range. Skip past it if it is + ** a separator character. Or break out of the loop if it is not. */ + is = zCsr - (unsigned char*)pText; + READ_UTF8(zCsr, zTerm, iCode); + if( fts5UnicodeIsAlnum(p, iCode) ){ + goto non_ascii_tokenchar; + } + }else{ + if( a[*zCsr] ){ + is = zCsr - (unsigned char*)pText; + goto ascii_tokenchar; + } + zCsr++; + } + } + + /* Run through the tokenchars. Fold them into the output buffer along + ** the way. */ + while( zCsrpEnd ){ + aFold = sqlite3_malloc(nFold*2); + if( aFold==0 ){ + rc = SQLITE_NOMEM; + goto tokenize_done; + } + zOut = &aFold[zOut - p->aFold]; + memcpy(aFold, p->aFold, nFold); + sqlite3_free(p->aFold); + p->aFold = aFold; + p->nFold = nFold = nFold*2; + pEnd = &aFold[nFold-6]; + } + + if( *zCsr & 0x80 ){ + /* An non-ascii-range character. Fold it into the output buffer if + ** it is a token character, or break out of the loop if it is not. */ + READ_UTF8(zCsr, zTerm, iCode); + if( fts5UnicodeIsAlnum(p,iCode)||sqlite3Fts5UnicodeIsdiacritic(iCode) ){ + non_ascii_tokenchar: + iCode = sqlite3Fts5UnicodeFold(iCode, p->bRemoveDiacritic); + if( iCode ) WRITE_UTF8(zOut, iCode); + }else{ + break; + } + }else if( a[*zCsr]==0 ){ + /* An ascii-range separator character. End of token. */ + break; + }else{ + ascii_tokenchar: + if( *zCsr>='A' && *zCsr<='Z' ){ + *zOut++ = *zCsr + 32; + }else{ + *zOut++ = *zCsr; + } + zCsr++; + } + ie = zCsr - (unsigned char*)pText; + } + + /* Invoke the token callback */ + rc = xToken(pCtx, 0, aFold, zOut-aFold, is, ie); + } + + tokenize_done: + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + return rc; +} + +/************************************************************************** +** Start of porter stemmer implementation. +*/ + +/* Any tokens larger than this (in bytes) are passed through without +** stemming. */ +#define FTS5_PORTER_MAX_TOKEN 64 + +typedef struct PorterTokenizer PorterTokenizer; +struct PorterTokenizer { + fts5_tokenizer tokenizer; /* Parent tokenizer module */ + Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */ + char aBuf[FTS5_PORTER_MAX_TOKEN + 64]; +}; + +/* +** Delete a "porter" tokenizer. +*/ +static void fts5PorterDelete(Fts5Tokenizer *pTok){ + if( pTok ){ + PorterTokenizer *p = (PorterTokenizer*)pTok; + if( p->pTokenizer ){ + p->tokenizer.xDelete(p->pTokenizer); + } + sqlite3_free(p); + } +} + +/* +** Create a "porter" tokenizer. +*/ +static int fts5PorterCreate( + void *pCtx, + const char **azArg, int nArg, + Fts5Tokenizer **ppOut +){ + fts5_api *pApi = (fts5_api*)pCtx; + int rc = SQLITE_OK; + PorterTokenizer *pRet; + void *pUserdata = 0; + const char *zBase = "unicode61"; + + if( nArg>0 ){ + zBase = azArg[0]; + } + + pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer)); + if( pRet ){ + memset(pRet, 0, sizeof(PorterTokenizer)); + rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer); + }else{ + rc = SQLITE_NOMEM; + } + if( rc==SQLITE_OK ){ + int nArg2 = (nArg>0 ? nArg-1 : 0); + const char **azArg2 = (nArg2 ? &azArg[1] : 0); + rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer); + } + + if( rc!=SQLITE_OK ){ + fts5PorterDelete((Fts5Tokenizer*)pRet); + pRet = 0; + } + *ppOut = (Fts5Tokenizer*)pRet; + return rc; +} + +typedef struct PorterContext PorterContext; +struct PorterContext { + void *pCtx; + int (*xToken)(void*, int, const char*, int, int, int); + char *aBuf; +}; + +typedef struct PorterRule PorterRule; +struct PorterRule { + const char *zSuffix; + int nSuffix; + int (*xCond)(char *zStem, int nStem); + const char *zOutput; + int nOutput; +}; + +#if 0 +static int fts5PorterApply(char *aBuf, int *pnBuf, PorterRule *aRule){ + int ret = -1; + int nBuf = *pnBuf; + PorterRule *p; + + for(p=aRule; p->zSuffix; p++){ + assert( strlen(p->zSuffix)==p->nSuffix ); + assert( strlen(p->zOutput)==p->nOutput ); + if( nBufnSuffix ) continue; + if( 0==memcmp(&aBuf[nBuf - p->nSuffix], p->zSuffix, p->nSuffix) ) break; + } + + if( p->zSuffix ){ + int nStem = nBuf - p->nSuffix; + if( p->xCond==0 || p->xCond(aBuf, nStem) ){ + memcpy(&aBuf[nStem], p->zOutput, p->nOutput); + *pnBuf = nStem + p->nOutput; + ret = p - aRule; + } + } + + return ret; +} +#endif + +static int fts5PorterIsVowel(char c, int bYIsVowel){ + return ( + c=='a' || c=='e' || c=='i' || c=='o' || c=='u' || (bYIsVowel && c=='y') + ); +} + +static int fts5PorterGobbleVC(char *zStem, int nStem, int bPrevCons){ + int i; + int bCons = bPrevCons; + + /* Scan for a vowel */ + for(i=0; i 0) */ +static int fts5Porter_MGt0(char *zStem, int nStem){ + return !!fts5PorterGobbleVC(zStem, nStem, 0); +} + +/* porter rule condition: (m > 1) */ +static int fts5Porter_MGt1(char *zStem, int nStem){ + int n; + n = fts5PorterGobbleVC(zStem, nStem, 0); + if( n && fts5PorterGobbleVC(&zStem[n], nStem-n, 1) ){ + return 1; + } + return 0; +} + +/* porter rule condition: (m = 1) */ +static int fts5Porter_MEq1(char *zStem, int nStem){ + int n; + n = fts5PorterGobbleVC(zStem, nStem, 0); + if( n && 0==fts5PorterGobbleVC(&zStem[n], nStem-n, 1) ){ + return 1; + } + return 0; +} + +/* porter rule condition: (*o) */ +static int fts5Porter_Ostar(char *zStem, int nStem){ + if( zStem[nStem-1]=='w' || zStem[nStem-1]=='x' || zStem[nStem-1]=='y' ){ + return 0; + }else{ + int i; + int mask = 0; + int bCons = 0; + for(i=0; i 1 and (*S or *T)) */ +static int fts5Porter_MGt1_and_S_or_T(char *zStem, int nStem){ + assert( nStem>0 ); + return (zStem[nStem-1]=='s' || zStem[nStem-1]=='t') + && fts5Porter_MGt1(zStem, nStem); +} + +/* porter rule condition: (*v*) */ +static int fts5Porter_Vowel(char *zStem, int nStem){ + int i; + for(i=0; i0) ){ + return 1; + } + } + return 0; +} + + +/************************************************************************** +*************************************************************************** +** GENERATED CODE STARTS HERE (mkportersteps.tcl) +*/ + +static int fts5PorterStep4(char *aBuf, int *pnBuf){ + int ret = 0; + int nBuf = *pnBuf; + switch( aBuf[nBuf-2] ){ + + case 'a': + if( nBuf>2 && 0==memcmp("al", &aBuf[nBuf-2], 2) ){ + if( fts5Porter_MGt1(aBuf, nBuf-2) ){ + *pnBuf = nBuf - 2; + } + } + break; + + case 'c': + if( nBuf>4 && 0==memcmp("ance", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt1(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + }else if( nBuf>4 && 0==memcmp("ence", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt1(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + } + break; + + case 'e': + if( nBuf>2 && 0==memcmp("er", &aBuf[nBuf-2], 2) ){ + if( fts5Porter_MGt1(aBuf, nBuf-2) ){ + *pnBuf = nBuf - 2; + } + } + break; + + case 'i': + if( nBuf>2 && 0==memcmp("ic", &aBuf[nBuf-2], 2) ){ + if( fts5Porter_MGt1(aBuf, nBuf-2) ){ + *pnBuf = nBuf - 2; + } + } + break; + + case 'l': + if( nBuf>4 && 0==memcmp("able", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt1(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + }else if( nBuf>4 && 0==memcmp("ible", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt1(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + } + break; + + case 'n': + if( nBuf>3 && 0==memcmp("ant", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + }else if( nBuf>5 && 0==memcmp("ement", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt1(aBuf, nBuf-5) ){ + *pnBuf = nBuf - 5; + } + }else if( nBuf>4 && 0==memcmp("ment", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt1(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + }else if( nBuf>3 && 0==memcmp("ent", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 'o': + if( nBuf>3 && 0==memcmp("ion", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1_and_S_or_T(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + }else if( nBuf>2 && 0==memcmp("ou", &aBuf[nBuf-2], 2) ){ + if( fts5Porter_MGt1(aBuf, nBuf-2) ){ + *pnBuf = nBuf - 2; + } + } + break; + + case 's': + if( nBuf>3 && 0==memcmp("ism", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 't': + if( nBuf>3 && 0==memcmp("ate", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + }else if( nBuf>3 && 0==memcmp("iti", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 'u': + if( nBuf>3 && 0==memcmp("ous", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 'v': + if( nBuf>3 && 0==memcmp("ive", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 'z': + if( nBuf>3 && 0==memcmp("ize", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + } + return ret; +} + + +static int fts5PorterStep1B2(char *aBuf, int *pnBuf){ + int ret = 0; + int nBuf = *pnBuf; + switch( aBuf[nBuf-2] ){ + + case 'a': + if( nBuf>2 && 0==memcmp("at", &aBuf[nBuf-2], 2) ){ + memcpy(&aBuf[nBuf-2], "ate", 3); + *pnBuf = nBuf - 2 + 3; + ret = 1; + } + break; + + case 'b': + if( nBuf>2 && 0==memcmp("bl", &aBuf[nBuf-2], 2) ){ + memcpy(&aBuf[nBuf-2], "ble", 3); + *pnBuf = nBuf - 2 + 3; + ret = 1; + } + break; + + case 'i': + if( nBuf>2 && 0==memcmp("iz", &aBuf[nBuf-2], 2) ){ + memcpy(&aBuf[nBuf-2], "ize", 3); + *pnBuf = nBuf - 2 + 3; + ret = 1; + } + break; + + } + return ret; +} + + +static int fts5PorterStep2(char *aBuf, int *pnBuf){ + int ret = 0; + int nBuf = *pnBuf; + switch( aBuf[nBuf-2] ){ + + case 'a': + if( nBuf>7 && 0==memcmp("ational", &aBuf[nBuf-7], 7) ){ + if( fts5Porter_MGt0(aBuf, nBuf-7) ){ + memcpy(&aBuf[nBuf-7], "ate", 3); + *pnBuf = nBuf - 7 + 3; + } + }else if( nBuf>6 && 0==memcmp("tional", &aBuf[nBuf-6], 6) ){ + if( fts5Porter_MGt0(aBuf, nBuf-6) ){ + memcpy(&aBuf[nBuf-6], "tion", 4); + *pnBuf = nBuf - 6 + 4; + } + } + break; + + case 'c': + if( nBuf>4 && 0==memcmp("enci", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "ence", 4); + *pnBuf = nBuf - 4 + 4; + } + }else if( nBuf>4 && 0==memcmp("anci", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "ance", 4); + *pnBuf = nBuf - 4 + 4; + } + } + break; + + case 'e': + if( nBuf>4 && 0==memcmp("izer", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "ize", 3); + *pnBuf = nBuf - 4 + 3; + } + } + break; + + case 'g': + if( nBuf>4 && 0==memcmp("logi", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "log", 3); + *pnBuf = nBuf - 4 + 3; + } + } + break; + + case 'l': + if( nBuf>3 && 0==memcmp("bli", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt0(aBuf, nBuf-3) ){ + memcpy(&aBuf[nBuf-3], "ble", 3); + *pnBuf = nBuf - 3 + 3; + } + }else if( nBuf>4 && 0==memcmp("alli", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "al", 2); + *pnBuf = nBuf - 4 + 2; + } + }else if( nBuf>5 && 0==memcmp("entli", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ent", 3); + *pnBuf = nBuf - 5 + 3; + } + }else if( nBuf>3 && 0==memcmp("eli", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt0(aBuf, nBuf-3) ){ + memcpy(&aBuf[nBuf-3], "e", 1); + *pnBuf = nBuf - 3 + 1; + } + }else if( nBuf>5 && 0==memcmp("ousli", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ous", 3); + *pnBuf = nBuf - 5 + 3; + } + } + break; + + case 'o': + if( nBuf>7 && 0==memcmp("ization", &aBuf[nBuf-7], 7) ){ + if( fts5Porter_MGt0(aBuf, nBuf-7) ){ + memcpy(&aBuf[nBuf-7], "ize", 3); + *pnBuf = nBuf - 7 + 3; + } + }else if( nBuf>5 && 0==memcmp("ation", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ate", 3); + *pnBuf = nBuf - 5 + 3; + } + }else if( nBuf>4 && 0==memcmp("ator", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "ate", 3); + *pnBuf = nBuf - 4 + 3; + } + } + break; + + case 's': + if( nBuf>5 && 0==memcmp("alism", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "al", 2); + *pnBuf = nBuf - 5 + 2; + } + }else if( nBuf>7 && 0==memcmp("iveness", &aBuf[nBuf-7], 7) ){ + if( fts5Porter_MGt0(aBuf, nBuf-7) ){ + memcpy(&aBuf[nBuf-7], "ive", 3); + *pnBuf = nBuf - 7 + 3; + } + }else if( nBuf>7 && 0==memcmp("fulness", &aBuf[nBuf-7], 7) ){ + if( fts5Porter_MGt0(aBuf, nBuf-7) ){ + memcpy(&aBuf[nBuf-7], "ful", 3); + *pnBuf = nBuf - 7 + 3; + } + }else if( nBuf>7 && 0==memcmp("ousness", &aBuf[nBuf-7], 7) ){ + if( fts5Porter_MGt0(aBuf, nBuf-7) ){ + memcpy(&aBuf[nBuf-7], "ous", 3); + *pnBuf = nBuf - 7 + 3; + } + } + break; + + case 't': + if( nBuf>5 && 0==memcmp("aliti", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "al", 2); + *pnBuf = nBuf - 5 + 2; + } + }else if( nBuf>5 && 0==memcmp("iviti", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ive", 3); + *pnBuf = nBuf - 5 + 3; + } + }else if( nBuf>6 && 0==memcmp("biliti", &aBuf[nBuf-6], 6) ){ + if( fts5Porter_MGt0(aBuf, nBuf-6) ){ + memcpy(&aBuf[nBuf-6], "ble", 3); + *pnBuf = nBuf - 6 + 3; + } + } + break; + + } + return ret; +} + + +static int fts5PorterStep3(char *aBuf, int *pnBuf){ + int ret = 0; + int nBuf = *pnBuf; + switch( aBuf[nBuf-2] ){ + + case 'a': + if( nBuf>4 && 0==memcmp("ical", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "ic", 2); + *pnBuf = nBuf - 4 + 2; + } + } + break; + + case 's': + if( nBuf>4 && 0==memcmp("ness", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + } + break; + + case 't': + if( nBuf>5 && 0==memcmp("icate", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ic", 2); + *pnBuf = nBuf - 5 + 2; + } + }else if( nBuf>5 && 0==memcmp("iciti", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ic", 2); + *pnBuf = nBuf - 5 + 2; + } + } + break; + + case 'u': + if( nBuf>3 && 0==memcmp("ful", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt0(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 'v': + if( nBuf>5 && 0==memcmp("ative", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + *pnBuf = nBuf - 5; + } + } + break; + + case 'z': + if( nBuf>5 && 0==memcmp("alize", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "al", 2); + *pnBuf = nBuf - 5 + 2; + } + } + break; + + } + return ret; +} + + +static int fts5PorterStep1B(char *aBuf, int *pnBuf){ + int ret = 0; + int nBuf = *pnBuf; + switch( aBuf[nBuf-2] ){ + + case 'e': + if( nBuf>3 && 0==memcmp("eed", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt0(aBuf, nBuf-3) ){ + memcpy(&aBuf[nBuf-3], "ee", 2); + *pnBuf = nBuf - 3 + 2; + } + }else if( nBuf>2 && 0==memcmp("ed", &aBuf[nBuf-2], 2) ){ + if( fts5Porter_Vowel(aBuf, nBuf-2) ){ + *pnBuf = nBuf - 2; + ret = 1; + } + } + break; + + case 'n': + if( nBuf>3 && 0==memcmp("ing", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_Vowel(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + ret = 1; + } + } + break; + + } + return ret; +} + +/* +** GENERATED CODE ENDS HERE (mkportersteps.tcl) +*************************************************************************** +**************************************************************************/ + +static void fts5PorterStep1A(char *aBuf, int *pnBuf){ + int nBuf = *pnBuf; + if( aBuf[nBuf-1]=='s' ){ + if( aBuf[nBuf-2]=='e' ){ + if( (nBuf>4 && aBuf[nBuf-4]=='s' && aBuf[nBuf-3]=='s') + || (nBuf>3 && aBuf[nBuf-3]=='i' ) + ){ + *pnBuf = nBuf-2; + }else{ + *pnBuf = nBuf-1; + } + } + else if( aBuf[nBuf-2]!='s' ){ + *pnBuf = nBuf-1; + } + } +} + +static int fts5PorterCb( + void *pCtx, + int tflags, + const char *pToken, + int nToken, + int iStart, + int iEnd +){ + PorterContext *p = (PorterContext*)pCtx; + + char *aBuf; + int nBuf; + + if( nToken>FTS5_PORTER_MAX_TOKEN || nToken<3 ) goto pass_through; + aBuf = p->aBuf; + nBuf = nToken; + memcpy(aBuf, pToken, nBuf); + + /* Step 1. */ + fts5PorterStep1A(aBuf, &nBuf); + if( fts5PorterStep1B(aBuf, &nBuf) ){ + if( fts5PorterStep1B2(aBuf, &nBuf)==0 ){ + char c = aBuf[nBuf-1]; + if( fts5PorterIsVowel(c, 0)==0 + && c!='l' && c!='s' && c!='z' && c==aBuf[nBuf-2] + ){ + nBuf--; + }else if( fts5Porter_MEq1(aBuf, nBuf) && fts5Porter_Ostar(aBuf, nBuf) ){ + aBuf[nBuf++] = 'e'; + } + } + } + + /* Step 1C. */ + if( aBuf[nBuf-1]=='y' && fts5Porter_Vowel(aBuf, nBuf-1) ){ + aBuf[nBuf-1] = 'i'; + } + + /* Steps 2 through 4. */ + fts5PorterStep2(aBuf, &nBuf); + fts5PorterStep3(aBuf, &nBuf); + fts5PorterStep4(aBuf, &nBuf); + + /* Step 5a. */ + assert( nBuf>0 ); + if( aBuf[nBuf-1]=='e' ){ + if( fts5Porter_MGt1(aBuf, nBuf-1) + || (fts5Porter_MEq1(aBuf, nBuf-1) && !fts5Porter_Ostar(aBuf, nBuf-1)) + ){ + nBuf--; + } + } + + /* Step 5b. */ + if( nBuf>1 && aBuf[nBuf-1]=='l' + && aBuf[nBuf-2]=='l' && fts5Porter_MGt1(aBuf, nBuf-1) + ){ + nBuf--; + } + + return p->xToken(p->pCtx, tflags, aBuf, nBuf, iStart, iEnd); + + pass_through: + return p->xToken(p->pCtx, tflags, pToken, nToken, iStart, iEnd); +} + +/* +** Tokenize using the porter tokenizer. +*/ +static int fts5PorterTokenize( + Fts5Tokenizer *pTokenizer, + void *pCtx, + int flags, + const char *pText, int nText, + int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd) +){ + PorterTokenizer *p = (PorterTokenizer*)pTokenizer; + PorterContext sCtx; + sCtx.xToken = xToken; + sCtx.pCtx = pCtx; + sCtx.aBuf = p->aBuf; + return p->tokenizer.xTokenize( + p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb + ); +} + +/* +** Register all built-in tokenizers with FTS5. +*/ +int sqlite3Fts5TokenizerInit(fts5_api *pApi){ + struct BuiltinTokenizer { + const char *zName; + fts5_tokenizer x; + } aBuiltin[] = { + { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}}, + { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }}, + { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }}, + }; + + int rc = SQLITE_OK; /* Return code */ + int i; /* To iterate through builtin functions */ + + for(i=0; rc==SQLITE_OK && ixCreateTokenizer(pApi, + aBuiltin[i].zName, + (void*)pApi, + &aBuiltin[i].x, + 0 + ); + } + + return rc; +} + + diff --git a/ext/fts5/fts5_unicode2.c b/ext/fts5/fts5_unicode2.c new file mode 100644 index 0000000..1ef56f6 --- /dev/null +++ b/ext/fts5/fts5_unicode2.c @@ -0,0 +1,360 @@ +/* +** 2012 May 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. +** +****************************************************************************** +*/ + +/* +** DO NOT EDIT THIS MACHINE GENERATED FILE. +*/ + + +#include + +/* +** Return true if the argument corresponds to a unicode codepoint +** classified as either a letter or a number. Otherwise false. +** +** The results are undefined if the value passed to this function +** is less than zero. +*/ +int sqlite3Fts5UnicodeIsalnum(int c){ + /* Each unsigned integer in the following array corresponds to a contiguous + ** range of unicode codepoints that are not either letters or numbers (i.e. + ** codepoints for which this function should return 0). + ** + ** The most significant 22 bits in each 32-bit value contain the first + ** codepoint in the range. The least significant 10 bits are used to store + ** the size of the range (always at least 1). In other words, the value + ** ((C<<22) + N) represents a range of N codepoints starting with codepoint + ** C. It is not possible to represent a range larger than 1023 codepoints + ** using this format. + */ + static const unsigned int aEntry[] = { + 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07, + 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01, + 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401, + 0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01, + 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01, + 0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802, + 0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F, + 0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401, + 0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804, + 0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403, + 0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812, + 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001, + 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, + 0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805, + 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401, + 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03, + 0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807, + 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001, + 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01, + 0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804, + 0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001, + 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802, + 0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01, + 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06, + 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, + 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006, + 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417, + 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14, + 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07, + 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01, + 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001, + 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802, + 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F, + 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, + 0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802, + 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006, + 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D, + 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802, + 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027, + 0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, + 0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805, + 0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04, + 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401, + 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, + 0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B, + 0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A, + 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, + 0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59, + 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, + 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, + 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, + 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100, + 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10, + 0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402, + 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804, + 0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012, + 0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004, + 0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002, + 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803, + 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07, + 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02, + 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802, + 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013, + 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06, + 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003, + 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01, + 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403, + 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009, + 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003, + 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003, + 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E, + 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046, + 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401, + 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401, + 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, + 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C, + 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002, + 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025, + 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6, + 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46, + 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060, + 0x380400F0, + }; + static const unsigned int aAscii[4] = { + 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, + }; + + if( (unsigned int)c<128 ){ + return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 ); + }else if( (unsigned int)c<(1<<22) ){ + unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; + int iRes = 0; + int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; + int iLo = 0; + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( key >= aEntry[iTest] ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + assert( aEntry[0]=aEntry[iRes] ); + return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF))); + } + return 1; +} + + +/* +** If the argument is a codepoint corresponding to a lowercase letter +** in the ASCII range with a diacritic added, return the codepoint +** of the ASCII letter only. For example, if passed 235 - "LATIN +** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER +** E"). The resuls of passing a codepoint that corresponds to an +** uppercase letter are undefined. +*/ +static int fts5_remove_diacritic(int c){ + unsigned short aDia[] = { + 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995, + 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286, + 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732, + 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336, + 3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928, + 3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234, + 4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504, + 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529, + 61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726, + 61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122, + 62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536, + 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, + 62924, 63050, 63082, 63274, 63390, + }; + char aChar[] = { + '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c', + 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r', + 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o', + 'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r', + 'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h', + 'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't', + 'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a', + 'e', 'i', 'o', 'u', 'y', + }; + + unsigned int key = (((unsigned int)c)<<3) | 0x00000007; + int iRes = 0; + int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1; + int iLo = 0; + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( key >= aDia[iTest] ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + assert( key>=aDia[iRes] ); + return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]); +} + + +/* +** Return true if the argument interpreted as a unicode codepoint +** is a diacritical modifier character. +*/ +int sqlite3Fts5UnicodeIsdiacritic(int c){ + unsigned int mask0 = 0x08029FDF; + unsigned int mask1 = 0x000361F8; + if( c<768 || c>817 ) return 0; + return (c < 768+32) ? + (mask0 & (1 << (c-768))) : + (mask1 & (1 << (c-768-32))); +} + + +/* +** Interpret the argument as a unicode codepoint. If the codepoint +** is an upper case character that has a lower case equivalent, +** return the codepoint corresponding to the lower case version. +** Otherwise, return a copy of the argument. +** +** The results are undefined if the value passed to this function +** is less than zero. +*/ +int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){ + /* Each entry in the following array defines a rule for folding a range + ** of codepoints to lower case. The rule applies to a range of nRange + ** codepoints starting at codepoint iCode. + ** + ** If the least significant bit in flags is clear, then the rule applies + ** to all nRange codepoints (i.e. all nRange codepoints are upper case and + ** need to be folded). Or, if it is set, then the rule only applies to + ** every second codepoint in the range, starting with codepoint C. + ** + ** The 7 most significant bits in flags are an index into the aiOff[] + ** array. If a specific codepoint C does require folding, then its lower + ** case equivalent is ((C + aiOff[flags>>1]) & 0xFFFF). + ** + ** The contents of this array are generated by parsing the CaseFolding.txt + ** file distributed as part of the "Unicode Character Database". See + ** http://www.unicode.org for details. + */ + static const struct TableEntry { + unsigned short iCode; + unsigned char flags; + unsigned char nRange; + } aEntry[] = { + {65, 14, 26}, {181, 64, 1}, {192, 14, 23}, + {216, 14, 7}, {256, 1, 48}, {306, 1, 6}, + {313, 1, 16}, {330, 1, 46}, {376, 116, 1}, + {377, 1, 6}, {383, 104, 1}, {385, 50, 1}, + {386, 1, 4}, {390, 44, 1}, {391, 0, 1}, + {393, 42, 2}, {395, 0, 1}, {398, 32, 1}, + {399, 38, 1}, {400, 40, 1}, {401, 0, 1}, + {403, 42, 1}, {404, 46, 1}, {406, 52, 1}, + {407, 48, 1}, {408, 0, 1}, {412, 52, 1}, + {413, 54, 1}, {415, 56, 1}, {416, 1, 6}, + {422, 60, 1}, {423, 0, 1}, {425, 60, 1}, + {428, 0, 1}, {430, 60, 1}, {431, 0, 1}, + {433, 58, 2}, {435, 1, 4}, {439, 62, 1}, + {440, 0, 1}, {444, 0, 1}, {452, 2, 1}, + {453, 0, 1}, {455, 2, 1}, {456, 0, 1}, + {458, 2, 1}, {459, 1, 18}, {478, 1, 18}, + {497, 2, 1}, {498, 1, 4}, {502, 122, 1}, + {503, 134, 1}, {504, 1, 40}, {544, 110, 1}, + {546, 1, 18}, {570, 70, 1}, {571, 0, 1}, + {573, 108, 1}, {574, 68, 1}, {577, 0, 1}, + {579, 106, 1}, {580, 28, 1}, {581, 30, 1}, + {582, 1, 10}, {837, 36, 1}, {880, 1, 4}, + {886, 0, 1}, {902, 18, 1}, {904, 16, 3}, + {908, 26, 1}, {910, 24, 2}, {913, 14, 17}, + {931, 14, 9}, {962, 0, 1}, {975, 4, 1}, + {976, 140, 1}, {977, 142, 1}, {981, 146, 1}, + {982, 144, 1}, {984, 1, 24}, {1008, 136, 1}, + {1009, 138, 1}, {1012, 130, 1}, {1013, 128, 1}, + {1015, 0, 1}, {1017, 152, 1}, {1018, 0, 1}, + {1021, 110, 3}, {1024, 34, 16}, {1040, 14, 32}, + {1120, 1, 34}, {1162, 1, 54}, {1216, 6, 1}, + {1217, 1, 14}, {1232, 1, 88}, {1329, 22, 38}, + {4256, 66, 38}, {4295, 66, 1}, {4301, 66, 1}, + {7680, 1, 150}, {7835, 132, 1}, {7838, 96, 1}, + {7840, 1, 96}, {7944, 150, 8}, {7960, 150, 6}, + {7976, 150, 8}, {7992, 150, 8}, {8008, 150, 6}, + {8025, 151, 8}, {8040, 150, 8}, {8072, 150, 8}, + {8088, 150, 8}, {8104, 150, 8}, {8120, 150, 2}, + {8122, 126, 2}, {8124, 148, 1}, {8126, 100, 1}, + {8136, 124, 4}, {8140, 148, 1}, {8152, 150, 2}, + {8154, 120, 2}, {8168, 150, 2}, {8170, 118, 2}, + {8172, 152, 1}, {8184, 112, 2}, {8186, 114, 2}, + {8188, 148, 1}, {8486, 98, 1}, {8490, 92, 1}, + {8491, 94, 1}, {8498, 12, 1}, {8544, 8, 16}, + {8579, 0, 1}, {9398, 10, 26}, {11264, 22, 47}, + {11360, 0, 1}, {11362, 88, 1}, {11363, 102, 1}, + {11364, 90, 1}, {11367, 1, 6}, {11373, 84, 1}, + {11374, 86, 1}, {11375, 80, 1}, {11376, 82, 1}, + {11378, 0, 1}, {11381, 0, 1}, {11390, 78, 2}, + {11392, 1, 100}, {11499, 1, 4}, {11506, 0, 1}, + {42560, 1, 46}, {42624, 1, 24}, {42786, 1, 14}, + {42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1}, + {42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1}, + {42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1}, + {65313, 14, 26}, + }; + static const unsigned short aiOff[] = { + 1, 2, 8, 15, 16, 26, 28, 32, + 37, 38, 40, 48, 63, 64, 69, 71, + 79, 80, 116, 202, 203, 205, 206, 207, + 209, 210, 211, 213, 214, 217, 218, 219, + 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721, + 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274, + 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406, + 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462, + 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511, + 65514, 65521, 65527, 65528, 65529, + }; + + int ret = c; + + assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 ); + + if( c<128 ){ + if( c>='A' && c<='Z' ) ret = c + ('a' - 'A'); + }else if( c<65536 ){ + const struct TableEntry *p; + int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; + int iLo = 0; + int iRes = -1; + + assert( c>aEntry[0].iCode ); + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + int cmp = (c - aEntry[iTest].iCode); + if( cmp>=0 ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + + assert( iRes>=0 && c>=aEntry[iRes].iCode ); + p = &aEntry[iRes]; + if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ + ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; + assert( ret>0 ); + } + + if( bRemoveDiacritic ) ret = fts5_remove_diacritic(ret); + } + + else if( c>=66560 && c<66600 ){ + ret = c + 40; + } + + return ret; +} diff --git a/ext/fts5/fts5_varint.c b/ext/fts5/fts5_varint.c new file mode 100644 index 0000000..bb212ab --- /dev/null +++ b/ext/fts5/fts5_varint.c @@ -0,0 +1,345 @@ +/* +** 2015 May 30 +** +** 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. +** +****************************************************************************** +** +** Routines for varint serialization and deserialization. +*/ + + +#include "fts5Int.h" + +/* +** This is a copy of the sqlite3GetVarint32() routine from the SQLite core. +** Except, this version does handle the single byte case that the core +** version depends on being handled before its function is called. +*/ +int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v){ + u32 a,b; + + /* The 1-byte case. Overwhelmingly the most common. */ + a = *p; + /* a: p0 (unmasked) */ + if (!(a&0x80)) + { + /* Values between 0 and 127 */ + *v = a; + return 1; + } + + /* The 2-byte case */ + p++; + b = *p; + /* b: p1 (unmasked) */ + if (!(b&0x80)) + { + /* Values between 128 and 16383 */ + a &= 0x7f; + a = a<<7; + *v = a | b; + return 2; + } + + /* The 3-byte case */ + p++; + a = a<<14; + a |= *p; + /* a: p0<<14 | p2 (unmasked) */ + if (!(a&0x80)) + { + /* Values between 16384 and 2097151 */ + a &= (0x7f<<14)|(0x7f); + b &= 0x7f; + b = b<<7; + *v = a | b; + return 3; + } + + /* A 32-bit varint is used to store size information in btrees. + ** Objects are rarely larger than 2MiB limit of a 3-byte varint. + ** A 3-byte varint is sufficient, for example, to record the size + ** of a 1048569-byte BLOB or string. + ** + ** We only unroll the first 1-, 2-, and 3- byte cases. The very + ** rare larger cases can be handled by the slower 64-bit varint + ** routine. + */ + { + u64 v64; + u8 n; + p -= 2; + n = sqlite3Fts5GetVarint(p, &v64); + *v = (u32)v64; + assert( n>3 && n<=9 ); + return n; + } +} + + +/* +** Bitmasks used by sqlite3GetVarint(). These precomputed constants +** are defined here rather than simply putting the constant expressions +** inline in order to work around bugs in the RVT compiler. +** +** SLOT_2_0 A mask for (0x7f<<14) | 0x7f +** +** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0 +*/ +#define SLOT_2_0 0x001fc07f +#define SLOT_4_2_0 0xf01fc07f + +/* +** Read a 64-bit variable-length integer from memory starting at p[0]. +** Return the number of bytes read. The value is stored in *v. +*/ +u8 sqlite3Fts5GetVarint(const unsigned char *p, u64 *v){ + u32 a,b,s; + + a = *p; + /* a: p0 (unmasked) */ + if (!(a&0x80)) + { + *v = a; + return 1; + } + + p++; + b = *p; + /* b: p1 (unmasked) */ + if (!(b&0x80)) + { + a &= 0x7f; + a = a<<7; + a |= b; + *v = a; + return 2; + } + + /* Verify that constants are precomputed correctly */ + assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); + assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); + + p++; + a = a<<14; + a |= *p; + /* a: p0<<14 | p2 (unmasked) */ + if (!(a&0x80)) + { + a &= SLOT_2_0; + b &= 0x7f; + b = b<<7; + a |= b; + *v = a; + return 3; + } + + /* CSE1 from below */ + a &= SLOT_2_0; + p++; + b = b<<14; + b |= *p; + /* b: p1<<14 | p3 (unmasked) */ + if (!(b&0x80)) + { + b &= SLOT_2_0; + /* moved CSE1 up */ + /* a &= (0x7f<<14)|(0x7f); */ + a = a<<7; + a |= b; + *v = a; + return 4; + } + + /* a: p0<<14 | p2 (masked) */ + /* b: p1<<14 | p3 (unmasked) */ + /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ + /* moved CSE1 up */ + /* a &= (0x7f<<14)|(0x7f); */ + b &= SLOT_2_0; + s = a; + /* s: p0<<14 | p2 (masked) */ + + p++; + a = a<<14; + a |= *p; + /* a: p0<<28 | p2<<14 | p4 (unmasked) */ + if (!(a&0x80)) + { + /* we can skip these cause they were (effectively) done above in calc'ing s */ + /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ + /* b &= (0x7f<<14)|(0x7f); */ + b = b<<7; + a |= b; + s = s>>18; + *v = ((u64)s)<<32 | a; + return 5; + } + + /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ + s = s<<7; + s |= b; + /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ + + p++; + b = b<<14; + b |= *p; + /* b: p1<<28 | p3<<14 | p5 (unmasked) */ + if (!(b&0x80)) + { + /* we can skip this cause it was (effectively) done above in calc'ing s */ + /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ + a &= SLOT_2_0; + a = a<<7; + a |= b; + s = s>>18; + *v = ((u64)s)<<32 | a; + return 6; + } + + p++; + a = a<<14; + a |= *p; + /* a: p2<<28 | p4<<14 | p6 (unmasked) */ + if (!(a&0x80)) + { + a &= SLOT_4_2_0; + b &= SLOT_2_0; + b = b<<7; + a |= b; + s = s>>11; + *v = ((u64)s)<<32 | a; + return 7; + } + + /* CSE2 from below */ + a &= SLOT_2_0; + p++; + b = b<<14; + b |= *p; + /* b: p3<<28 | p5<<14 | p7 (unmasked) */ + if (!(b&0x80)) + { + b &= SLOT_4_2_0; + /* moved CSE2 up */ + /* a &= (0x7f<<14)|(0x7f); */ + a = a<<7; + a |= b; + s = s>>4; + *v = ((u64)s)<<32 | a; + return 8; + } + + p++; + a = a<<15; + a |= *p; + /* a: p4<<29 | p6<<15 | p8 (unmasked) */ + + /* moved CSE2 up */ + /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */ + b &= SLOT_2_0; + b = b<<8; + a |= b; + + s = s<<4; + b = p[-4]; + b &= 0x7f; + b = b>>3; + s |= b; + + *v = ((u64)s)<<32 | a; + + return 9; +} + +/* +** The variable-length integer encoding is as follows: +** +** KEY: +** A = 0xxxxxxx 7 bits of data and one flag bit +** B = 1xxxxxxx 7 bits of data and one flag bit +** C = xxxxxxxx 8 bits of data +** +** 7 bits - A +** 14 bits - BA +** 21 bits - BBA +** 28 bits - BBBA +** 35 bits - BBBBA +** 42 bits - BBBBBA +** 49 bits - BBBBBBA +** 56 bits - BBBBBBBA +** 64 bits - BBBBBBBBC +*/ + +#ifdef SQLITE_NOINLINE +# define FTS5_NOINLINE SQLITE_NOINLINE +#else +# define FTS5_NOINLINE +#endif + +/* +** Write a 64-bit variable-length integer to memory starting at p[0]. +** The length of data write will be between 1 and 9 bytes. The number +** of bytes written is returned. +** +** A variable-length integer consists of the lower 7 bits of each byte +** for all bytes that have the 8th bit set and one byte with the 8th +** bit clear. Except, if we get to the 9th byte, it stores the full +** 8 bits and is the last byte. +*/ +static int FTS5_NOINLINE fts5PutVarint64(unsigned char *p, u64 v){ + int i, j, n; + u8 buf[10]; + if( v & (((u64)0xff000000)<<32) ){ + p[8] = (u8)v; + v >>= 8; + for(i=7; i>=0; i--){ + p[i] = (u8)((v & 0x7f) | 0x80); + v >>= 7; + } + return 9; + } + n = 0; + do{ + buf[n++] = (u8)((v & 0x7f) | 0x80); + v >>= 7; + }while( v!=0 ); + buf[0] &= 0x7f; + assert( n<=9 ); + for(i=0, j=n-1; j>=0; j--, i++){ + p[i] = buf[j]; + } + return n; +} + +int sqlite3Fts5PutVarint(unsigned char *p, u64 v){ + if( v<=0x7f ){ + p[0] = v&0x7f; + return 1; + } + if( v<=0x3fff ){ + p[0] = ((v>>7)&0x7f)|0x80; + p[1] = v&0x7f; + return 2; + } + return fts5PutVarint64(p,v); +} + + +int sqlite3Fts5GetVarintLen(u32 iVal){ +#if 0 + if( iVal<(1 << 7 ) ) return 1; +#endif + assert( iVal>=(1 << 7) ); + if( iVal<(1 << 14) ) return 2; + if( iVal<(1 << 21) ) return 3; + if( iVal<(1 << 28) ) return 4; + return 5; +} + diff --git a/ext/fts5/fts5_vocab.c b/ext/fts5/fts5_vocab.c new file mode 100644 index 0000000..f3a2381 --- /dev/null +++ b/ext/fts5/fts5_vocab.c @@ -0,0 +1,641 @@ +/* +** 2015 May 08 +** +** 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 is an SQLite virtual table module implementing direct access to an +** existing FTS5 index. The module may create several different types of +** tables: +** +** col: +** CREATE TABLE vocab(term, col, doc, cnt, PRIMARY KEY(term, col)); +** +** One row for each term/column combination. The value of $doc is set to +** the number of fts5 rows that contain at least one instance of term +** $term within column $col. Field $cnt is set to the total number of +** instances of term $term in column $col (in any row of the fts5 table). +** +** row: +** CREATE TABLE vocab(term, doc, cnt, PRIMARY KEY(term)); +** +** One row for each term in the database. The value of $doc is set to +** the number of fts5 rows that contain at least one instance of term +** $term. Field $cnt is set to the total number of instances of term +** $term in the database. +*/ + + +#include "fts5Int.h" + + +typedef struct Fts5VocabTable Fts5VocabTable; +typedef struct Fts5VocabCursor Fts5VocabCursor; + +struct Fts5VocabTable { + sqlite3_vtab base; + char *zFts5Tbl; /* Name of fts5 table */ + char *zFts5Db; /* Db containing fts5 table */ + sqlite3 *db; /* Database handle */ + Fts5Global *pGlobal; /* FTS5 global object for this database */ + int eType; /* FTS5_VOCAB_COL or ROW */ +}; + +struct Fts5VocabCursor { + sqlite3_vtab_cursor base; + sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */ + Fts5Index *pIndex; /* Associated FTS5 index */ + + int bEof; /* True if this cursor is at EOF */ + Fts5IndexIter *pIter; /* Term/rowid iterator object */ + + int nLeTerm; /* Size of zLeTerm in bytes */ + char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */ + + /* These are used by 'col' tables only */ + Fts5Config *pConfig; /* Fts5 table configuration */ + int iCol; + i64 *aCnt; + i64 *aDoc; + + /* Output values used by 'row' and 'col' tables */ + i64 rowid; /* This table's current rowid value */ + Fts5Buffer term; /* Current value of 'term' column */ +}; + +#define FTS5_VOCAB_COL 0 +#define FTS5_VOCAB_ROW 1 + +#define FTS5_VOCAB_COL_SCHEMA "term, col, doc, cnt" +#define FTS5_VOCAB_ROW_SCHEMA "term, doc, cnt" + +/* +** Bits for the mask used as the idxNum value by xBestIndex/xFilter. +*/ +#define FTS5_VOCAB_TERM_EQ 0x01 +#define FTS5_VOCAB_TERM_GE 0x02 +#define FTS5_VOCAB_TERM_LE 0x04 + + +/* +** Translate a string containing an fts5vocab table type to an +** FTS5_VOCAB_XXX constant. If successful, set *peType to the output +** value and return SQLITE_OK. Otherwise, set *pzErr to an error message +** and return SQLITE_ERROR. +*/ +static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){ + int rc = SQLITE_OK; + char *zCopy = sqlite3Fts5Strndup(&rc, zType, -1); + if( rc==SQLITE_OK ){ + sqlite3Fts5Dequote(zCopy); + if( sqlite3_stricmp(zCopy, "col")==0 ){ + *peType = FTS5_VOCAB_COL; + }else + + if( sqlite3_stricmp(zCopy, "row")==0 ){ + *peType = FTS5_VOCAB_ROW; + }else + { + *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy); + rc = SQLITE_ERROR; + } + sqlite3_free(zCopy); + } + + return rc; +} + + +/* +** The xDisconnect() virtual table method. +*/ +static int fts5VocabDisconnectMethod(sqlite3_vtab *pVtab){ + Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab; + sqlite3_free(pTab); + return SQLITE_OK; +} + +/* +** The xDestroy() virtual table method. +*/ +static int fts5VocabDestroyMethod(sqlite3_vtab *pVtab){ + Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab; + sqlite3_free(pTab); + return SQLITE_OK; +} + +/* +** This function is the implementation of both the xConnect and xCreate +** methods of the FTS3 virtual table. +** +** The argv[] array contains the following: +** +** argv[0] -> module name ("fts5vocab") +** argv[1] -> database name +** argv[2] -> table name +** +** then: +** +** argv[3] -> name of fts5 table +** argv[4] -> type of fts5vocab table +** +** or, for tables in the TEMP schema only. +** +** argv[3] -> name of fts5 tables database +** argv[4] -> name of fts5 table +** argv[5] -> type of fts5vocab table +*/ +static int fts5VocabInitVtab( + sqlite3 *db, /* The SQLite database connection */ + void *pAux, /* Pointer to Fts5Global object */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ + char **pzErr /* Write any error message here */ +){ + const char *azSchema[] = { + "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")", + "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")" + }; + + Fts5VocabTable *pRet = 0; + int rc = SQLITE_OK; /* Return code */ + int bDb; + + bDb = (argc==6 && strlen(argv[1])==4 && memcmp("temp", argv[1], 4)==0); + + if( argc!=5 && bDb==0 ){ + *pzErr = sqlite3_mprintf("wrong number of vtable arguments"); + rc = SQLITE_ERROR; + }else{ + int nByte; /* Bytes of space to allocate */ + const char *zDb = bDb ? argv[3] : argv[1]; + const char *zTab = bDb ? argv[4] : argv[3]; + const char *zType = bDb ? argv[5] : argv[4]; + int nDb = (int)strlen(zDb)+1; + int nTab = (int)strlen(zTab)+1; + int eType = 0; + + rc = fts5VocabTableType(zType, pzErr, &eType); + if( rc==SQLITE_OK ){ + assert( eType>=0 && eTypepGlobal = (Fts5Global*)pAux; + pRet->eType = eType; + pRet->db = db; + pRet->zFts5Tbl = (char*)&pRet[1]; + pRet->zFts5Db = &pRet->zFts5Tbl[nTab]; + memcpy(pRet->zFts5Tbl, zTab, nTab); + memcpy(pRet->zFts5Db, zDb, nDb); + sqlite3Fts5Dequote(pRet->zFts5Tbl); + sqlite3Fts5Dequote(pRet->zFts5Db); + } + } + + *ppVTab = (sqlite3_vtab*)pRet; + return rc; +} + + +/* +** The xConnect() and xCreate() methods for the virtual table. All the +** work is done in function fts5VocabInitVtab(). +*/ +static int fts5VocabConnectMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + 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 */ +){ + return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr); +} +static int fts5VocabCreateMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + 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 */ +){ + return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr); +} + +/* +** Implementation of the xBestIndex method. +*/ +static int fts5VocabBestIndexMethod( + sqlite3_vtab *pUnused, + sqlite3_index_info *pInfo +){ + int i; + int iTermEq = -1; + int iTermGe = -1; + int iTermLe = -1; + int idxNum = 0; + int nArg = 0; + + UNUSED_PARAM(pUnused); + + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; + if( p->usable==0 ) continue; + if( p->iColumn==0 ){ /* term column */ + if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ) iTermEq = i; + if( p->op==SQLITE_INDEX_CONSTRAINT_LE ) iTermLe = i; + if( p->op==SQLITE_INDEX_CONSTRAINT_LT ) iTermLe = i; + if( p->op==SQLITE_INDEX_CONSTRAINT_GE ) iTermGe = i; + if( p->op==SQLITE_INDEX_CONSTRAINT_GT ) iTermGe = i; + } + } + + if( iTermEq>=0 ){ + idxNum |= FTS5_VOCAB_TERM_EQ; + pInfo->aConstraintUsage[iTermEq].argvIndex = ++nArg; + pInfo->estimatedCost = 100; + }else{ + pInfo->estimatedCost = 1000000; + if( iTermGe>=0 ){ + idxNum |= FTS5_VOCAB_TERM_GE; + pInfo->aConstraintUsage[iTermGe].argvIndex = ++nArg; + pInfo->estimatedCost = pInfo->estimatedCost / 2; + } + if( iTermLe>=0 ){ + idxNum |= FTS5_VOCAB_TERM_LE; + pInfo->aConstraintUsage[iTermLe].argvIndex = ++nArg; + pInfo->estimatedCost = pInfo->estimatedCost / 2; + } + } + + pInfo->idxNum = idxNum; + + return SQLITE_OK; +} + +/* +** Implementation of xOpen method. +*/ +static int fts5VocabOpenMethod( + sqlite3_vtab *pVTab, + sqlite3_vtab_cursor **ppCsr +){ + Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab; + Fts5Index *pIndex = 0; + Fts5Config *pConfig = 0; + Fts5VocabCursor *pCsr = 0; + int rc = SQLITE_OK; + sqlite3_stmt *pStmt = 0; + char *zSql = 0; + + zSql = sqlite3Fts5Mprintf(&rc, + "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'", + pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl + ); + if( zSql ){ + rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0); + } + sqlite3_free(zSql); + assert( rc==SQLITE_OK || pStmt==0 ); + if( rc==SQLITE_ERROR ) rc = SQLITE_OK; + + if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ + i64 iId = sqlite3_column_int64(pStmt, 0); + pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig); + } + + if( rc==SQLITE_OK && pIndex==0 ){ + rc = sqlite3_finalize(pStmt); + pStmt = 0; + if( rc==SQLITE_OK ){ + pVTab->zErrMsg = sqlite3_mprintf( + "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl + ); + rc = SQLITE_ERROR; + } + } + + if( rc==SQLITE_OK ){ + int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor); + pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte); + } + + if( pCsr ){ + pCsr->pIndex = pIndex; + pCsr->pStmt = pStmt; + pCsr->pConfig = pConfig; + pCsr->aCnt = (i64*)&pCsr[1]; + pCsr->aDoc = &pCsr->aCnt[pConfig->nCol]; + }else{ + sqlite3_finalize(pStmt); + } + + *ppCsr = (sqlite3_vtab_cursor*)pCsr; + return rc; +} + +static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){ + pCsr->rowid = 0; + sqlite3Fts5IterClose(pCsr->pIter); + pCsr->pIter = 0; + sqlite3_free(pCsr->zLeTerm); + pCsr->nLeTerm = -1; + pCsr->zLeTerm = 0; +} + +/* +** Close the cursor. For additional information see the documentation +** on the xClose method of the virtual table interface. +*/ +static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + fts5VocabResetCursor(pCsr); + sqlite3Fts5BufferFree(&pCsr->term); + sqlite3_finalize(pCsr->pStmt); + sqlite3_free(pCsr); + return SQLITE_OK; +} + + +/* +** Advance the cursor to the next row in the table. +*/ +static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; + int rc = SQLITE_OK; + int nCol = pCsr->pConfig->nCol; + + pCsr->rowid++; + + if( pTab->eType==FTS5_VOCAB_COL ){ + for(pCsr->iCol++; pCsr->iColiCol++){ + if( pCsr->aDoc[pCsr->iCol] ) break; + } + } + + if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){ + if( sqlite3Fts5IterEof(pCsr->pIter) ){ + pCsr->bEof = 1; + }else{ + const char *zTerm; + int nTerm; + + zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); + if( pCsr->nLeTerm>=0 ){ + int nCmp = MIN(nTerm, pCsr->nLeTerm); + int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp); + if( bCmp<0 || (bCmp==0 && pCsr->nLeTermbEof = 1; + return SQLITE_OK; + } + } + + sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm); + memset(pCsr->aCnt, 0, nCol * sizeof(i64)); + memset(pCsr->aDoc, 0, nCol * sizeof(i64)); + pCsr->iCol = 0; + + assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW ); + while( rc==SQLITE_OK ){ + const u8 *pPos; int nPos; /* Position list */ + i64 iPos = 0; /* 64-bit position read from poslist */ + int iOff = 0; /* Current offset within position list */ + + pPos = pCsr->pIter->pData; + nPos = pCsr->pIter->nData; + switch( pCsr->pConfig->eDetail ){ + case FTS5_DETAIL_FULL: + pPos = pCsr->pIter->pData; + nPos = pCsr->pIter->nData; + if( pTab->eType==FTS5_VOCAB_ROW ){ + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ + pCsr->aCnt[0]++; + } + pCsr->aDoc[0]++; + }else{ + int iCol = -1; + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ + int ii = FTS5_POS2COLUMN(iPos); + pCsr->aCnt[ii]++; + if( iCol!=ii ){ + if( ii>=nCol ){ + rc = FTS5_CORRUPT; + break; + } + pCsr->aDoc[ii]++; + iCol = ii; + } + } + } + break; + + case FTS5_DETAIL_COLUMNS: + if( pTab->eType==FTS5_VOCAB_ROW ){ + pCsr->aDoc[0]++; + }else{ + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){ + assert_nc( iPos>=0 && iPos=nCol ){ + rc = FTS5_CORRUPT; + break; + } + pCsr->aDoc[iPos]++; + } + } + break; + + default: + assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE ); + pCsr->aDoc[0]++; + break; + } + + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IterNextScan(pCsr->pIter); + } + + if( rc==SQLITE_OK ){ + zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); + if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){ + break; + } + if( sqlite3Fts5IterEof(pCsr->pIter) ) break; + } + } + } + } + + if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ + while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++; + assert( pCsr->iColpConfig->nCol ); + } + return rc; +} + +/* +** This is the xFilter implementation for the virtual table. +*/ +static int fts5VocabFilterMethod( + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ + int idxNum, /* Strategy index */ + const char *zUnused, /* Unused */ + int nUnused, /* Number of elements in apVal */ + sqlite3_value **apVal /* Arguments for the indexing scheme */ +){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + int rc = SQLITE_OK; + + int iVal = 0; + int f = FTS5INDEX_QUERY_SCAN; + const char *zTerm = 0; + int nTerm = 0; + + sqlite3_value *pEq = 0; + sqlite3_value *pGe = 0; + sqlite3_value *pLe = 0; + + UNUSED_PARAM2(zUnused, nUnused); + + fts5VocabResetCursor(pCsr); + if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++]; + if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++]; + if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++]; + + if( pEq ){ + zTerm = (const char *)sqlite3_value_text(pEq); + nTerm = sqlite3_value_bytes(pEq); + f = 0; + }else{ + if( pGe ){ + zTerm = (const char *)sqlite3_value_text(pGe); + nTerm = sqlite3_value_bytes(pGe); + } + if( pLe ){ + const char *zCopy = (const char *)sqlite3_value_text(pLe); + pCsr->nLeTerm = sqlite3_value_bytes(pLe); + pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1); + if( pCsr->zLeTerm==0 ){ + rc = SQLITE_NOMEM; + }else{ + memcpy(pCsr->zLeTerm, zCopy, pCsr->nLeTerm+1); + } + } + } + + + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); + } + if( rc==SQLITE_OK ){ + rc = fts5VocabNextMethod(pCursor); + } + + return rc; +} + +/* +** This is the xEof method of the virtual table. SQLite calls this +** routine to find out if it has reached the end of a result set. +*/ +static int fts5VocabEofMethod(sqlite3_vtab_cursor *pCursor){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + return pCsr->bEof; +} + +static int fts5VocabColumnMethod( + 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 */ +){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + int eDetail = pCsr->pConfig->eDetail; + int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType; + i64 iVal = 0; + + if( iCol==0 ){ + sqlite3_result_text( + pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT + ); + }else if( eType==FTS5_VOCAB_COL ){ + assert( iCol==1 || iCol==2 || iCol==3 ); + if( iCol==1 ){ + if( eDetail!=FTS5_DETAIL_NONE ){ + const char *z = pCsr->pConfig->azCol[pCsr->iCol]; + sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); + } + }else if( iCol==2 ){ + iVal = pCsr->aDoc[pCsr->iCol]; + }else{ + iVal = pCsr->aCnt[pCsr->iCol]; + } + }else{ + assert( iCol==1 || iCol==2 ); + if( iCol==1 ){ + iVal = pCsr->aDoc[0]; + }else{ + iVal = pCsr->aCnt[0]; + } + } + + if( iVal>0 ) sqlite3_result_int64(pCtx, iVal); + return SQLITE_OK; +} + +/* +** This is the xRowid method. The SQLite core calls this routine to +** retrieve the rowid for the current row of the result set. The +** rowid should be written to *pRowid. +*/ +static int fts5VocabRowidMethod( + sqlite3_vtab_cursor *pCursor, + sqlite_int64 *pRowid +){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + *pRowid = pCsr->rowid; + return SQLITE_OK; +} + +int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ + static const sqlite3_module fts5Vocab = { + /* iVersion */ 2, + /* xCreate */ fts5VocabCreateMethod, + /* xConnect */ fts5VocabConnectMethod, + /* xBestIndex */ fts5VocabBestIndexMethod, + /* xDisconnect */ fts5VocabDisconnectMethod, + /* xDestroy */ fts5VocabDestroyMethod, + /* xOpen */ fts5VocabOpenMethod, + /* xClose */ fts5VocabCloseMethod, + /* xFilter */ fts5VocabFilterMethod, + /* xNext */ fts5VocabNextMethod, + /* xEof */ fts5VocabEofMethod, + /* xColumn */ fts5VocabColumnMethod, + /* xRowid */ fts5VocabRowidMethod, + /* xUpdate */ 0, + /* xBegin */ 0, + /* xSync */ 0, + /* xCommit */ 0, + /* xRollback */ 0, + /* xFindFunction */ 0, + /* xRename */ 0, + /* xSavepoint */ 0, + /* xRelease */ 0, + /* xRollbackTo */ 0, + }; + void *p = (void*)pGlobal; + + return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0); +} + + diff --git a/ext/fts5/fts5parse.y b/ext/fts5/fts5parse.y new file mode 100644 index 0000000..4393676 --- /dev/null +++ b/ext/fts5/fts5parse.y @@ -0,0 +1,184 @@ +/* +** 2014 May 31 +** +** 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. +** +****************************************************************************** +** +*/ + + +// All token codes are small integers with #defines that begin with "TK_" +%token_prefix FTS5_ + +// The type of the data attached to each token is Token. This is also the +// default type for non-terminals. +// +%token_type {Fts5Token} +%default_type {Fts5Token} + +// The generated parser function takes a 4th argument as follows: +%extra_argument {Fts5Parse *pParse} + +// This code runs whenever there is a syntax error +// +%syntax_error { + UNUSED_PARAM(yymajor); /* Silence a compiler warning */ + sqlite3Fts5ParseError( + pParse, "fts5: syntax error near \"%.*s\"",TOKEN.n,TOKEN.p + ); +} +%stack_overflow { + UNUSED_PARAM(yypMinor); /* Silence a compiler warning */ + sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow"); +} + +// The name of the generated procedure that implements the parser +// is as follows: +%name sqlite3Fts5Parser + +// The following text is included near the beginning of the C source +// code file that implements the parser. +// +%include { +#include "fts5Int.h" +#include "fts5parse.h" + +/* +** Disable all error recovery processing in the parser push-down +** automaton. +*/ +#define YYNOERRORRECOVERY 1 + +/* +** Make yytestcase() the same as testcase() +*/ +#define yytestcase(X) testcase(X) + +/* +** Indicate that sqlite3ParserFree() will never be called with a null +** pointer. +*/ +#define YYPARSEFREENOTNULL 1 + +/* +** Alternative datatype for the argument to the malloc() routine passed +** into sqlite3ParserAlloc(). The default is size_t. +*/ +#define YYMALLOCARGTYPE u64 + +} // end %include + +%left OR. +%left AND. +%left NOT. +%left TERM. +%left COLON. + +input ::= expr(X). { sqlite3Fts5ParseFinished(pParse, X); } +%destructor input { (void)pParse; } + +%type cnearset {Fts5ExprNode*} +%type expr {Fts5ExprNode*} +%type exprlist {Fts5ExprNode*} +%destructor cnearset { sqlite3Fts5ParseNodeFree($$); } +%destructor expr { sqlite3Fts5ParseNodeFree($$); } +%destructor exprlist { sqlite3Fts5ParseNodeFree($$); } + +expr(A) ::= expr(X) AND expr(Y). { + A = sqlite3Fts5ParseNode(pParse, FTS5_AND, X, Y, 0); +} +expr(A) ::= expr(X) OR expr(Y). { + A = sqlite3Fts5ParseNode(pParse, FTS5_OR, X, Y, 0); +} +expr(A) ::= expr(X) NOT expr(Y). { + A = sqlite3Fts5ParseNode(pParse, FTS5_NOT, X, Y, 0); +} + +expr(A) ::= LP expr(X) RP. {A = X;} +expr(A) ::= exprlist(X). {A = X;} + +exprlist(A) ::= cnearset(X). {A = X;} +exprlist(A) ::= exprlist(X) cnearset(Y). { + A = sqlite3Fts5ParseNode(pParse, FTS5_AND, X, Y, 0); +} + +cnearset(A) ::= nearset(X). { + A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, X); +} +cnearset(A) ::= colset(X) COLON nearset(Y). { + sqlite3Fts5ParseSetColset(pParse, Y, X); + A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, Y); +} + +%type colset {Fts5Colset*} +%destructor colset { sqlite3_free($$); } +%type colsetlist {Fts5Colset*} +%destructor colsetlist { sqlite3_free($$); } + +colset(A) ::= LCP colsetlist(X) RCP. { A = X; } +colset(A) ::= STRING(X). { + A = sqlite3Fts5ParseColset(pParse, 0, &X); +} + +colsetlist(A) ::= colsetlist(Y) STRING(X). { + A = sqlite3Fts5ParseColset(pParse, Y, &X); } +colsetlist(A) ::= STRING(X). { + A = sqlite3Fts5ParseColset(pParse, 0, &X); +} + + +%type nearset {Fts5ExprNearset*} +%type nearphrases {Fts5ExprNearset*} +%destructor nearset { sqlite3Fts5ParseNearsetFree($$); } +%destructor nearphrases { sqlite3Fts5ParseNearsetFree($$); } + +nearset(A) ::= phrase(X). { A = sqlite3Fts5ParseNearset(pParse, 0, X); } +nearset(A) ::= STRING(X) LP nearphrases(Y) neardist_opt(Z) RP. { + sqlite3Fts5ParseNear(pParse, &X); + sqlite3Fts5ParseSetDistance(pParse, Y, &Z); + A = Y; +} + +nearphrases(A) ::= phrase(X). { + A = sqlite3Fts5ParseNearset(pParse, 0, X); +} +nearphrases(A) ::= nearphrases(X) phrase(Y). { + A = sqlite3Fts5ParseNearset(pParse, X, Y); +} + +/* +** The optional ", " at the end of the NEAR() arguments. +*/ +neardist_opt(A) ::= . { A.p = 0; A.n = 0; } +neardist_opt(A) ::= COMMA STRING(X). { A = X; } + +/* +** A phrase. A set of primitives connected by "+" operators. Examples: +** +** "the" + "quick brown" + fo * +** "the quick brown fo" * +** the+quick+brown+fo* +*/ +%type phrase {Fts5ExprPhrase*} +%destructor phrase { sqlite3Fts5ParsePhraseFree($$); } + +phrase(A) ::= phrase(X) PLUS STRING(Y) star_opt(Z). { + A = sqlite3Fts5ParseTerm(pParse, X, &Y, Z); +} +phrase(A) ::= STRING(Y) star_opt(Z). { + A = sqlite3Fts5ParseTerm(pParse, 0, &Y, Z); +} + +/* +** Optional "*" character. +*/ +%type star_opt {int} + +star_opt(A) ::= STAR. { A = 1; } +star_opt(A) ::= . { A = 0; } diff --git a/ext/fts5/mkportersteps.tcl b/ext/fts5/mkportersteps.tcl new file mode 100644 index 0000000..b6214c6 --- /dev/null +++ b/ext/fts5/mkportersteps.tcl @@ -0,0 +1,222 @@ +# +# 2014 Jun 09 +# +# 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 script generates the implementations of the following C functions, +# which are part of the porter tokenizer implementation: +# +# static int fts5PorterStep1B(char *aBuf, int *pnBuf); +# static int fts5PorterStep1B2(char *aBuf, int *pnBuf); +# static int fts5PorterStep2(char *aBuf, int *pnBuf); +# static int fts5PorterStep3(char *aBuf, int *pnBuf); +# static int fts5PorterStep4(char *aBuf, int *pnBuf); +# + +set O(Step1B2) { + { at {} ate 1 } + { bl {} ble 1 } + { iz {} ize 1 } +} + +set O(Step1B) { + { "eed" fts5Porter_MGt0 "ee" 0 } + { "ed" fts5Porter_Vowel "" 1 } + { "ing" fts5Porter_Vowel "" 1 } +} + +set O(Step2) { + { "ational" fts5Porter_MGt0 "ate" } + { "tional" fts5Porter_MGt0 "tion" } + { "enci" fts5Porter_MGt0 "ence" } + { "anci" fts5Porter_MGt0 "ance" } + { "izer" fts5Porter_MGt0 "ize" } + { "logi" fts5Porter_MGt0 "log" } + { "bli" fts5Porter_MGt0 "ble" } + { "alli" fts5Porter_MGt0 "al" } + { "entli" fts5Porter_MGt0 "ent" } + { "eli" fts5Porter_MGt0 "e" } + { "ousli" fts5Porter_MGt0 "ous" } + { "ization" fts5Porter_MGt0 "ize" } + { "ation" fts5Porter_MGt0 "ate" } + { "ator" fts5Porter_MGt0 "ate" } + { "alism" fts5Porter_MGt0 "al" } + { "iveness" fts5Porter_MGt0 "ive" } + { "fulness" fts5Porter_MGt0 "ful" } + { "ousness" fts5Porter_MGt0 "ous" } + { "aliti" fts5Porter_MGt0 "al" } + { "iviti" fts5Porter_MGt0 "ive" } + { "biliti" fts5Porter_MGt0 "ble" } +} + +set O(Step3) { + { "icate" fts5Porter_MGt0 "ic" } + { "ative" fts5Porter_MGt0 "" } + { "alize" fts5Porter_MGt0 "al" } + { "iciti" fts5Porter_MGt0 "ic" } + { "ical" fts5Porter_MGt0 "ic" } + { "ful" fts5Porter_MGt0 "" } + { "ness" fts5Porter_MGt0 "" } +} + +set O(Step4) { + { "al" fts5Porter_MGt1 "" } + { "ance" fts5Porter_MGt1 "" } + { "ence" fts5Porter_MGt1 "" } + { "er" fts5Porter_MGt1 "" } + { "ic" fts5Porter_MGt1 "" } + { "able" fts5Porter_MGt1 "" } + { "ible" fts5Porter_MGt1 "" } + { "ant" fts5Porter_MGt1 "" } + { "ement" fts5Porter_MGt1 "" } + { "ment" fts5Porter_MGt1 "" } + { "ent" fts5Porter_MGt1 "" } + { "ion" fts5Porter_MGt1_and_S_or_T "" } + { "ou" fts5Porter_MGt1 "" } + { "ism" fts5Porter_MGt1 "" } + { "ate" fts5Porter_MGt1 "" } + { "iti" fts5Porter_MGt1 "" } + { "ous" fts5Porter_MGt1 "" } + { "ive" fts5Porter_MGt1 "" } + { "ize" fts5Porter_MGt1 "" } +} + +proc sort_cb {lhs rhs} { + set L [string range [lindex $lhs 0] end-1 end-1] + set R [string range [lindex $rhs 0] end-1 end-1] + string compare $L $R +} + +proc create_step_function {name data} { + + set T(function) { +static int fts5Porter${name}(char *aBuf, int *pnBuf){ + int ret = 0; + int nBuf = *pnBuf; + switch( aBuf[nBuf-2] ){ + ${switchbody} + } + return ret; +} + } + + set T(case) { + case '${k}': + ${ifstmts} + break; + } + + set T(if_0_0_0) { + if( ${match} ){ + *pnBuf = nBuf - $n; + } + } + set T(if_1_0_0) { + if( ${match} ){ + if( ${cond} ){ + *pnBuf = nBuf - $n; + } + } + } + set T(if_0_1_0) { + if( ${match} ){ + ${memcpy} + *pnBuf = nBuf - $n + $nRep; + } + } + set T(if_1_1_0) { + if( ${match} ){ + if( ${cond} ){ + ${memcpy} + *pnBuf = nBuf - $n + $nRep; + } + } + } + set T(if_1_0_1) { + if( ${match} ){ + if( ${cond} ){ + *pnBuf = nBuf - $n; + ret = 1; + } + } + } + set T(if_0_1_1) { + if( ${match} ){ + ${memcpy} + *pnBuf = nBuf - $n + $nRep; + ret = 1; + } + } + set T(if_1_1_1) { + if( ${match} ){ + if( ${cond} ){ + ${memcpy} + *pnBuf = nBuf - $n + $nRep; + ret = 1; + } + } + } + + set switchbody "" + + foreach I $data { + set k [string range [lindex $I 0] end-1 end-1] + lappend aCase($k) $I + } + foreach k [lsort [array names aCase]] { + set ifstmts "" + foreach I $aCase($k) { + set zSuffix [lindex $I 0] ;# Suffix text for this rule + set zRep [lindex $I 2] ;# Replacement text for rule + set xCond [lindex $I 1] ;# Condition callback (or "") + + set n [string length $zSuffix] + set nRep [string length $zRep] + + set match "nBuf>$n && 0==memcmp(\"$zSuffix\", &aBuf\[nBuf-$n\], $n)" + set memcpy "memcpy(&aBuf\[nBuf-$n\], \"$zRep\", $nRep);" + set cond "${xCond}(aBuf, nBuf-$n)" + + set bMemcpy [expr {$nRep>0}] + set bCond [expr {$xCond!=""}] + set bRet [expr {[llength $I]>3 && [lindex $I 3]}] + + set t $T(if_${bCond}_${bMemcpy}_${bRet}) + lappend ifstmts [string trim [subst -nocommands $t]] + } + + set ifstmts [join $ifstmts "else "] + + append switchbody [subst -nocommands $T(case)] + } + + + puts [subst -nocommands $T(function)] +} + + +puts [string trim { +/************************************************************************** +*************************************************************************** +** GENERATED CODE STARTS HERE (mkportersteps.tcl) +*/ +}] +foreach step [array names O] { + create_step_function $step $O($step) +} +puts [string trim { +/* +** GENERATED CODE ENDS HERE (mkportersteps.tcl) +*************************************************************************** +**************************************************************************/ +}] + + + diff --git a/ext/fts5/test/fts5_common.tcl b/ext/fts5/test/fts5_common.tcl new file mode 100644 index 0000000..cf688dc --- /dev/null +++ b/ext/fts5/test/fts5_common.tcl @@ -0,0 +1,642 @@ +# 2014 Dec 19 +# +# 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 {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. .. test] +} +source $testdir/tester.tcl + +ifcapable !fts5 { + finish_test + return +} + +catch { + sqlite3_fts5_may_be_corrupt 0 + reset_db +} + +# If SQLITE_ENABLE_FTS5 is not defined, skip this test. +ifcapable !fts5 { + finish_test + return +} + +proc fts5_test_poslist {cmd} { + set res [list] + for {set i 0} {$i < [$cmd xInstCount]} {incr i} { + lappend res [string map {{ } .} [$cmd xInst $i]] + } + set res +} + +proc fts5_test_poslist2 {cmd} { + set res [list] + + for {set i 0} {$i < [$cmd xPhraseCount]} {incr i} { + $cmd xPhraseForeach $i c o { + lappend res $i.$c.$o + } + } + + #set res + sort_poslist $res +} + +proc fts5_test_collist {cmd} { + set res [list] + + for {set i 0} {$i < [$cmd xPhraseCount]} {incr i} { + $cmd xPhraseColumnForeach $i c { lappend res $i.$c } + } + + set res +} + +proc fts5_test_columnsize {cmd} { + set res [list] + for {set i 0} {$i < [$cmd xColumnCount]} {incr i} { + lappend res [$cmd xColumnSize $i] + } + set res +} + +proc fts5_test_columntext {cmd} { + set res [list] + for {set i 0} {$i < [$cmd xColumnCount]} {incr i} { + lappend res [$cmd xColumnText $i] + } + set res +} + +proc fts5_test_columntotalsize {cmd} { + set res [list] + for {set i 0} {$i < [$cmd xColumnCount]} {incr i} { + lappend res [$cmd xColumnTotalSize $i] + } + set res +} + +proc test_append_token {varname token iStart iEnd} { + upvar $varname var + lappend var $token + return "SQLITE_OK" +} +proc fts5_test_tokenize {cmd} { + set res [list] + for {set i 0} {$i < [$cmd xColumnCount]} {incr i} { + set tokens [list] + $cmd xTokenize [$cmd xColumnText $i] [list test_append_token tokens] + lappend res $tokens + } + set res +} + +proc fts5_test_rowcount {cmd} { + $cmd xRowCount +} + +proc test_queryphrase_cb {cnt cmd} { + upvar $cnt L + for {set i 0} {$i < [$cmd xInstCount]} {incr i} { + foreach {ip ic io} [$cmd xInst $i] break + set A($ic) 1 + } + foreach ic [array names A] { + lset L $ic [expr {[lindex $L $ic] + 1}] + } +} +proc fts5_test_queryphrase {cmd} { + set res [list] + for {set i 0} {$i < [$cmd xPhraseCount]} {incr i} { + set cnt [list] + for {set j 0} {$j < [$cmd xColumnCount]} {incr j} { lappend cnt 0 } + $cmd xQueryPhrase $i [list test_queryphrase_cb cnt] + lappend res $cnt + } + set res +} + +proc fts5_test_phrasecount {cmd} { + $cmd xPhraseCount +} + +proc fts5_test_all {cmd} { + set res [list] + lappend res columnsize [fts5_test_columnsize $cmd] + lappend res columntext [fts5_test_columntext $cmd] + lappend res columntotalsize [fts5_test_columntotalsize $cmd] + lappend res poslist [fts5_test_poslist $cmd] + lappend res tokenize [fts5_test_tokenize $cmd] + lappend res rowcount [fts5_test_rowcount $cmd] + set res +} + +proc fts5_aux_test_functions {db} { + foreach f { + fts5_test_columnsize + fts5_test_columntext + fts5_test_columntotalsize + fts5_test_poslist + fts5_test_poslist2 + fts5_test_collist + fts5_test_tokenize + fts5_test_rowcount + fts5_test_all + + fts5_test_queryphrase + fts5_test_phrasecount + } { + sqlite3_fts5_create_function $db $f $f + } +} + +proc fts5_level_segs {tbl} { + set sql "SELECT fts5_decode(rowid,block) aS r FROM ${tbl}_data WHERE rowid=10" + set ret [list] + foreach L [lrange [db one $sql] 1 end] { + lappend ret [expr [llength $L] - 3] + } + set ret +} + +proc fts5_level_segids {tbl} { + set sql "SELECT fts5_decode(rowid,block) aS r FROM ${tbl}_data WHERE rowid=10" + set ret [list] + foreach L [lrange [db one $sql] 1 end] { + set lvl [list] + foreach S [lrange $L 3 end] { + regexp {id=([1234567890]*)} $S -> segid + lappend lvl $segid + } + lappend ret $lvl + } + set ret +} + +proc fts5_rnddoc {n} { + set map [list 0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j] + set doc [list] + for {set i 0} {$i < $n} {incr i} { + lappend doc "x[string map $map [format %.3d [expr int(rand()*1000)]]]" + } + set doc +} + +#------------------------------------------------------------------------- +# Usage: +# +# nearset aCol ?-pc VARNAME? ?-near N? ?-col C? -- phrase1 phrase2... +# +# This command is used to test if a document (set of column values) matches +# the logical equivalent of a single FTS5 NEAR() clump and, if so, return +# the equivalent of an FTS5 position list. +# +# Parameter $aCol is passed a list of the column values for the document +# to test. Parameters $phrase1 and so on are the phrases. +# +# The result is a list of phrase hits. Each phrase hit is formatted as +# three integers separated by "." characters, in the following format: +# +# . . +# +# Options: +# +# -near N (NEAR distance. Default 10) +# -col C (List of column indexes to match against) +# -pc VARNAME (variable in caller frame to use for phrase numbering) +# -dict VARNAME (array in caller frame to use for synonyms) +# +proc nearset {aCol args} { + + # Process the command line options. + # + set O(-near) 10 + set O(-col) {} + set O(-pc) "" + set O(-dict) "" + + set nOpt [lsearch -exact $args --] + if {$nOpt<0} { error "no -- option" } + + # Set $lPhrase to be a list of phrases. $nPhrase its length. + set lPhrase [lrange $args [expr $nOpt+1] end] + set nPhrase [llength $lPhrase] + + foreach {k v} [lrange $args 0 [expr $nOpt-1]] { + if {[info exists O($k)]==0} { error "unrecognized option $k" } + set O($k) $v + } + + if {$O(-pc) == ""} { + set counter 0 + } else { + upvar $O(-pc) counter + } + + if {$O(-dict)!=""} { upvar $O(-dict) aDict } + + for {set j 0} {$j < [llength $aCol]} {incr j} { + for {set i 0} {$i < $nPhrase} {incr i} { + set A($j,$i) [list] + } + } + + # Loop through each column of the current row. + for {set iCol 0} {$iCol < [llength $aCol]} {incr iCol} { + + # If there is a column filter, test whether this column is excluded. If + # so, skip to the next iteration of this loop. Otherwise, set zCol to the + # column value and nToken to the number of tokens that comprise it. + if {$O(-col)!="" && [lsearch $O(-col) $iCol]<0} continue + set zCol [lindex $aCol $iCol] + set nToken [llength $zCol] + + # Each iteration of the following loop searches a substring of the + # column value for phrase matches. The last token of the substring + # is token $iLast of the column value. The first token is: + # + # iFirst = ($iLast - $O(-near) - 1) + # + # where $sz is the length of the phrase being searched for. A phrase + # counts as matching the substring if its first token lies on or before + # $iLast and its last token on or after $iFirst. + # + # For example, if the query is "NEAR(a+b c, 2)" and the column value: + # + # "x x x x A B x x C x" + # 0 1 2 3 4 5 6 7 8 9" + # + # when (iLast==8 && iFirst=5) the range will contain both phrases and + # so both instances can be added to the output poslists. + # + set iLast [expr $O(-near) >= $nToken ? $nToken - 1 : $O(-near)] + for { } {$iLast < $nToken} {incr iLast} { + + catch { array unset B } + + for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { + set p [lindex $lPhrase $iPhrase] + set nPm1 [expr {[llength $p] - 1}] + set iFirst [expr $iLast - $O(-near) - [llength $p]] + + for {set i $iFirst} {$i <= $iLast} {incr i} { + set lCand [lrange $zCol $i [expr $i+$nPm1]] + set bMatch 1 + foreach tok $p term $lCand { + if {[nearset_match aDict $tok $term]==0} { set bMatch 0 ; break } + } + if {$bMatch} { lappend B($iPhrase) $i } + } + + if {![info exists B($iPhrase)]} break + } + + if {$iPhrase==$nPhrase} { + for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { + set A($iCol,$iPhrase) [concat $A($iCol,$iPhrase) $B($iPhrase)] + set A($iCol,$iPhrase) [lsort -integer -uniq $A($iCol,$iPhrase)] + } + } + } + } + + set res [list] + #puts [array names A] + + for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { + for {set iCol 0} {$iCol < [llength $aCol]} {incr iCol} { + foreach a $A($iCol,$iPhrase) { + lappend res "$counter.$iCol.$a" + } + } + incr counter + } + + #puts "$aCol -> $res" + sort_poslist $res +} + +proc nearset_match {aDictVar tok term} { + if {[string match $tok $term]} { return 1 } + + upvar $aDictVar aDict + if {[info exists aDict($tok)]} { + foreach s $aDict($tok) { + if {[string match $s $term]} { return 1 } + } + } + return 0; +} + +#------------------------------------------------------------------------- +# Usage: +# +# sort_poslist LIST +# +# Sort a position list of the type returned by command [nearset] +# +proc sort_poslist {L} { + lsort -command instcompare $L +} +proc instcompare {lhs rhs} { + foreach {p1 c1 o1} [split $lhs .] {} + foreach {p2 c2 o2} [split $rhs .] {} + + set res [expr $c1 - $c2] + if {$res==0} { set res [expr $o1 - $o2] } + if {$res==0} { set res [expr $p1 - $p2] } + + return $res +} + +#------------------------------------------------------------------------- +# Logical operators used by the commands returned by fts5_tcl_expr(). +# +proc AND {args} { + foreach a $args { + if {[llength $a]==0} { return [list] } + } + sort_poslist [concat {*}$args] +} +proc OR {args} { + sort_poslist [concat {*}$args] +} +proc NOT {a b} { + if {[llength $b]>0} { return [list] } + return $a +} + +#------------------------------------------------------------------------- +# This command is similar to [split], except that it also provides the +# start and end offsets of each token. For example: +# +# [fts5_tokenize_split "abc d ef"] -> {abc 0 3 d 4 5 ef 6 8} +# + +proc gobble_whitespace {textvar} { + upvar $textvar t + regexp {([ ]*)(.*)} $t -> space t + return [string length $space] +} + +proc gobble_text {textvar wordvar} { + upvar $textvar t + upvar $wordvar w + regexp {([^ ]*)(.*)} $t -> w t + return [string length $w] +} + +proc fts5_tokenize_split {text} { + set token "" + set ret [list] + set iOff [gobble_whitespace text] + while {[set nToken [gobble_text text word]]} { + lappend ret $word $iOff [expr $iOff+$nToken] + incr iOff $nToken + incr iOff [gobble_whitespace text] + } + + set ret +} + +#------------------------------------------------------------------------- +# +proc foreach_detail_mode {prefix script} { + set saved $::testprefix + foreach d [list full col none] { + set s [string map [list %DETAIL% $d] $script] + set ::detail $d + set ::testprefix "$prefix-$d" + reset_db + uplevel $s + unset ::detail + } + set ::testprefix $saved +} + +proc detail_check {} { + if {$::detail != "none" && $::detail!="full" && $::detail!="col"} { + error "not in foreach_detail_mode {...} block" + } +} +proc detail_is_none {} { detail_check ; expr {$::detail == "none"} } +proc detail_is_col {} { detail_check ; expr {$::detail == "col" } } +proc detail_is_full {} { detail_check ; expr {$::detail == "full"} } + + +#------------------------------------------------------------------------- +# Convert a poslist of the type returned by fts5_test_poslist() to a +# collist as returned by fts5_test_collist(). +# +proc fts5_poslist2collist {poslist} { + set res [list] + foreach h $poslist { + regexp {(.*)\.[1234567890]+} $h -> cand + lappend res $cand + } + set res [lsort -command fts5_collist_elem_compare -unique $res] + return $res +} + +# Comparison function used by fts5_poslist2collist to sort collist entries. +proc fts5_collist_elem_compare {a b} { + foreach {a1 a2} [split $a .] {} + foreach {b1 b2} [split $b .] {} + + if {$a1==$b1} { return [expr $a2 - $b2] } + return [expr $a1 - $b1] +} + + +#-------------------------------------------------------------------------- +# Construct and return a tcl list equivalent to that returned by the SQL +# query executed against database handle [db]: +# +# SELECT +# rowid, +# fts5_test_poslist($tbl), +# fts5_test_collist($tbl) +# FROM $tbl('$expr') +# ORDER BY rowid $order; +# +proc fts5_query_data {expr tbl {order ASC} {aDictVar ""}} { + + # Figure out the set of columns in the FTS5 table. This routine does + # not handle tables with UNINDEXED columns, but if it did, it would + # have to be here. + db eval "PRAGMA table_info = $tbl" x { lappend lCols $x(name) } + + set d "" + if {$aDictVar != ""} { + upvar $aDictVar aDict + set d aDict + } + + set cols "" + foreach e $lCols { append cols ", '$e'" } + set tclexpr [db one [subst -novar { + SELECT fts5_expr_tcl( $expr, 'nearset $cols -dict $d -pc ::pc' [set cols] ) + }]] + + set res [list] + db eval "SELECT rowid, * FROM $tbl ORDER BY rowid $order" x { + set cols [list] + foreach col $lCols { lappend cols $x($col) } + + set ::pc 0 + set rowdata [eval $tclexpr] + if {$rowdata != ""} { + lappend res $x(rowid) $rowdata [fts5_poslist2collist $rowdata] + } + } + + set res +} + +#------------------------------------------------------------------------- +# Similar to [fts5_query_data], but omit the collist field. +# +proc fts5_poslist_data {expr tbl {order ASC} {aDictVar ""}} { + set res [list] + + if {$aDictVar!=""} { + upvar $aDictVar aDict + set dict aDict + } else { + set dict "" + } + + foreach {rowid poslist collist} [fts5_query_data $expr $tbl $order $dict] { + lappend res $rowid $poslist + } + set res +} + +proc fts5_collist_data {expr tbl {order ASC} {aDictVar ""}} { + set res [list] + + if {$aDictVar!=""} { + upvar $aDictVar aDict + set dict aDict + } else { + set dict "" + } + + foreach {rowid poslist collist} [fts5_query_data $expr $tbl $order $dict] { + lappend res $rowid $collist + } + set res +} + +#------------------------------------------------------------------------- +# + +# This command will only work inside a [foreach_detail_mode] block. It tests +# whether or not expression $expr run on FTS5 table $tbl is supported by +# the current mode. If so, 1 is returned. If not, 0. +# +# detail=full (all queries supported) +# detail=col (all but phrase queries and NEAR queries) +# detail=none (all but phrase queries, NEAR queries, and column filters) +# +proc fts5_expr_ok {expr tbl} { + + if {![detail_is_full]} { + set nearset "nearset_rc" + if {[detail_is_col]} { set nearset "nearset_rf" } + + set ::expr_not_ok 0 + db eval "PRAGMA table_info = $tbl" x { lappend lCols $x(name) } + + set cols "" + foreach e $lCols { append cols ", '$e'" } + set ::pc 0 + set tclexpr [db one [subst -novar { + SELECT fts5_expr_tcl( $expr, '[set nearset] $cols -pc ::pc' [set cols] ) + }]] + eval $tclexpr + if {$::expr_not_ok} { return 0 } + } + + return 1 +} + +# Helper for [fts5_expr_ok] +proc nearset_rf {aCol args} { + set idx [lsearch -exact $args --] + if {$idx != [llength $args]-2 || [llength [lindex $args end]]!=1} { + set ::expr_not_ok 1 + } + list +} + +# Helper for [fts5_expr_ok] +proc nearset_rc {aCol args} { + nearset_rf $aCol {*}$args + if {[lsearch $args -col]>=0} { + set ::expr_not_ok 1 + } + list +} + + +#------------------------------------------------------------------------- +# Code for a simple Tcl tokenizer that supports synonyms at query time. +# +proc tclnum_tokenize {mode tflags text} { + foreach {w iStart iEnd} [fts5_tokenize_split $text] { + sqlite3_fts5_token $w $iStart $iEnd + if {$tflags == $mode && [info exists ::tclnum_syn($w)]} { + foreach s $::tclnum_syn($w) { sqlite3_fts5_token -colo $s $iStart $iEnd } + } + } +} + +proc tclnum_create {args} { + set mode query + if {[llength $args]} { + set mode [lindex $args 0] + } + if {$mode != "query" && $mode != "document"} { error "bad mode: $mode" } + return [list tclnum_tokenize $mode] +} + +proc fts5_tclnum_register {db} { + foreach SYNDICT { + {zero 0} + {one 1 i} + {two 2 ii} + {three 3 iii} + {four 4 iv} + {five 5 v} + {six 6 vi} + {seven 7 vii} + {eight 8 viii} + {nine 9 ix} + + {a1 a2 a3 a4 a5 a6 a7 a8 a9} + {b1 b2 b3 b4 b5 b6 b7 b8 b9} + {c1 c2 c3 c4 c5 c6 c7 c8 c9} + } { + foreach s $SYNDICT { + set o [list] + foreach x $SYNDICT {if {$x!=$s} {lappend o $x}} + set ::tclnum_syn($s) $o + } + } + sqlite3_fts5_create_tokenizer db tclnum tclnum_create +} +# +# End of tokenizer code. +#------------------------------------------------------------------------- + diff --git a/ext/fts5/test/fts5aa.test b/ext/fts5/test/fts5aa.test new file mode 100644 index 0000000..fdcf083 --- /dev/null +++ b/ext/fts5/test/fts5aa.test @@ -0,0 +1,562 @@ +# 2014 June 17 +# +# 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 FTS5 module. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5aa + +# If SQLITE_ENABLE_FTS5 is not defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $::testprefix { + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, c); + SELECT name, sql FROM sqlite_master; +} { + t1 {CREATE VIRTUAL TABLE t1 USING fts5(a, b, c)} + t1_data {CREATE TABLE 't1_data'(id INTEGER PRIMARY KEY, block BLOB)} + t1_idx {CREATE TABLE 't1_idx'(segid, term, pgno, PRIMARY KEY(segid, term)) WITHOUT ROWID} + t1_content {CREATE TABLE 't1_content'(id INTEGER PRIMARY KEY, c0, c1, c2)} + t1_docsize {CREATE TABLE 't1_docsize'(id INTEGER PRIMARY KEY, sz BLOB)} + t1_config {CREATE TABLE 't1_config'(k PRIMARY KEY, v) WITHOUT ROWID} +} + +do_execsql_test 1.1 { + DROP TABLE t1; + SELECT name, sql FROM sqlite_master; +} { +} + +#------------------------------------------------------------------------- +# + +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%); +} +do_execsql_test 2.1 { + INSERT INTO t1 VALUES('a b c', 'd e f'); +} + +do_test 2.2 { + execsql { SELECT fts5_decode(id, block) FROM t1_data WHERE id==10 } +} {/{{structure} {lvl=0 nMerge=0 nSeg=1 {id=[0123456789]* leaves=1..1}}}/} + +foreach w {a b c d e f} { + do_execsql_test 2.3.$w.asc { + SELECT rowid FROM t1 WHERE t1 MATCH $w; + } {1} + do_execsql_test 2.3.$w.desc { + SELECT rowid FROM t1 WHERE t1 MATCH $w ORDER BY rowid DESC; + } {1} +} + +do_execsql_test 2.4 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} + + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%); +} +foreach {i x y} { + 1 {g f d b f} {h h e i a} + 2 {f i g j e} {i j c f f} + 3 {e e i f a} {e h f d f} + 4 {h j f j i} {h a c f j} + 5 {d b j c g} {f e i b e} + 6 {a j a e e} {j d f d e} + 7 {g i j c h} {j d h c a} + 8 {j j i d d} {e e d f b} + 9 {c j j d c} {h j i f g} + 10 {b f h i a} {c f b b j} +} { + do_execsql_test 3.$i.1 { INSERT INTO t1 VALUES($x, $y) } + do_execsql_test 3.$i.2 { INSERT INTO t1(t1) VALUES('integrity-check') } + if {[set_test_counter errors]} break +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); +} +foreach {i x y} { + 1 {g f d b f} {h h e i a} + 2 {f i g j e} {i j c f f} + 3 {e e i f a} {e h f d f} + 4 {h j f j i} {h a c f j} + 5 {d b j c g} {f e i b e} + 6 {a j a e e} {j d f d e} + 7 {g i j c h} {j d h c a} + 8 {j j i d d} {e e d f b} + 9 {c j j d c} {h j i f g} + 10 {b f h i a} {c f b b j} +} { + do_execsql_test 4.$i.1 { INSERT INTO t1 VALUES($x, $y) } + do_execsql_test 4.$i.2 { INSERT INTO t1(t1) VALUES('integrity-check') } + if {[set_test_counter errors]} break +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); +} +foreach {i x y} { + 1 {dd abc abc abc abcde} {aaa dd ddd ddd aab} + 2 {dd aab d aaa b} {abcde c aaa aaa aaa} + 3 {abcde dd b b dd} {abc abc d abc ddddd} + 4 {aaa abcde dddd dddd abcde} {abc b b abcde abc} + 5 {aab dddd d dddd c} {ddd abcde dddd abcde c} + 6 {ddd dd b aab abcde} {d ddddd dddd c abc} + 7 {d ddddd ddd c abcde} {c aab d abcde ddd} + 8 {abcde aaa aab c c} {ddd c dddd b aaa} + 9 {abcde aab ddddd c aab} {dddd dddd b c dd} + 10 {ddd abcde dddd dd c} {dddd c c d abcde} +} { + do_execsql_test 5.$i.1 { INSERT INTO t1 VALUES($x, $y) } + do_execsql_test 5.$i.2 { INSERT INTO t1(t1) VALUES('integrity-check') } + if {[set_test_counter errors]} break +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 6.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); +} + +do_execsql_test 6.1 { + INSERT INTO t1(rowid, x, y) VALUES(22, 'a b c', 'c b a'); + REPLACE INTO t1(rowid, x, y) VALUES(22, 'd e f', 'f e d'); +} + +do_execsql_test 6.2 { + INSERT INTO t1(t1) VALUES('integrity-check') +} + +do_execsql_test 6.3 { + REPLACE INTO t1(rowid, x, y) VALUES('22', 'l l l', 'l l l'); +} + +do_execsql_test 6.4 { + REPLACE INTO t1(x, y) VALUES('x y z', 'x y z'); +} + +do_execsql_test 6.5 { + INSERT INTO t1(t1) VALUES('integrity-check') +} + +do_execsql_test 6.6 { + SELECT rowid, * FROM t1; +} { + 22 {l l l} {l l l} + 23 {x y z} {x y z} +} + +#------------------------------------------------------------------------- +# +reset_db +expr srand(0) +do_execsql_test 7.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x,y,z); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); +} + +proc doc {} { + set v [list aaa aab abc abcde b c d dd ddd dddd ddddd] + set ret [list] + for {set j 0} {$j < 20} {incr j} { + lappend ret [lindex $v [expr int(rand()*[llength $v])]] + } + return $ret +} + +proc dump_structure {} { + db eval {SELECT fts5_decode(id, block) AS t FROM t1_data WHERE id=10} { + foreach lvl [lrange $t 1 end] { + set seg [string repeat . [expr [llength $lvl]-2]] + puts "[lrange $lvl 0 1] $seg" + } + } +} + +for {set i 1} {$i <= 10} {incr i} { + do_test 7.$i { + for {set j 0} {$j < 10} {incr j} { + set x [doc] + set y [doc] + set z [doc] + set rowid [expr int(rand() * 100)] + execsql { REPLACE INTO t1(rowid,x,y,z) VALUES($rowid, $x, $y, $z) } + } + execsql { INSERT INTO t1(t1) VALUES('integrity-check'); } + } {} + if {[set_test_counter errors]} break +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 8.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x, prefix="1,2,3"); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); +} + +do_execsql_test 8.1 { + INSERT INTO t1 VALUES('the quick brown fox'); + INSERT INTO t1(t1) VALUES('integrity-check'); +} + + +#------------------------------------------------------------------------- +# +reset_db + +expr srand(0) + +do_execsql_test 9.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x,y,z, prefix="1,2,3"); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); +} + +proc doc {} { + set v [list aaa aab abc abcde b c d dd ddd dddd ddddd] + set ret [list] + for {set j 0} {$j < 20} {incr j} { + lappend ret [lindex $v [expr int(rand()*[llength $v])]] + } + return $ret +} + +proc dump_structure {} { + db eval {SELECT fts5_decode(id, block) AS t FROM t1_data WHERE id=10} { + foreach lvl [lrange $t 1 end] { + set seg [string repeat . [expr [llength $lvl]-2]] + puts "[lrange $lvl 0 1] $seg" + } + } +} + +for {set i 1} {$i <= 10} {incr i} { + do_test 9.$i { + for {set j 0} {$j < 100} {incr j} { + set x [doc] + set y [doc] + set z [doc] + set rowid [expr int(rand() * 100)] + execsql { REPLACE INTO t1(rowid,x,y,z) VALUES($rowid, $x, $y, $z) } + } + execsql { INSERT INTO t1(t1) VALUES('integrity-check'); } + } {} + if {[set_test_counter errors]} break +} + + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 10.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%); +} +set d10 { + 1 {g f d b f} {h h e i a} + 2 {f i g j e} {i j c f f} + 3 {e e i f a} {e h f d f} + 4 {h j f j i} {h a c f j} + 5 {d b j c g} {f e i b e} + 6 {a j a e e} {j d f d e} + 7 {g i j c h} {j d h c a} + 8 {j j i d d} {e e d f b} + 9 {c j j d c} {h j i f g} + 10 {b f h i a} {c f b b j} +} +foreach {rowid x y} $d10 { + do_execsql_test 10.1.$rowid.1 { INSERT INTO t1 VALUES($x, $y) } + do_execsql_test 10.1.$rowid.2 { INSERT INTO t1(t1) VALUES('integrity-check') } +} +foreach rowid {5 9 8 1 2 4 10 7 3 5 6} { + do_execsql_test 10.2.$rowid.1 { DELETE FROM t1 WHERE rowid = $rowid } + do_execsql_test 10.2.$rowid.2 { INSERT INTO t1(t1) VALUES('integrity-check') } +} +foreach {rowid x y} $d10 { + do_execsql_test 10.3.$rowid.1 { INSERT INTO t1 VALUES($x, $y) } + do_execsql_test 10.3.$rowid.2 { INSERT INTO t1(t1) VALUES('integrity-check') } +} + +do_execsql_test 10.4.1 { DELETE FROM t1 } +do_execsql_test 10.4.2 { INSERT INTO t1(t1) VALUES('integrity-check') } + +#------------------------------------------------------------------------- +# +do_catchsql_test 11.1 { + CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rank, detail=%DETAIL%); +} {1 {reserved fts5 column name: rank}} +do_catchsql_test 11.2 { + CREATE VIRTUAL TABLE rank USING fts5(a, b, c, detail=%DETAIL%); +} {1 {reserved fts5 table name: rank}} +do_catchsql_test 11.3 { + CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rowid, detail=%DETAIL%); +} {1 {reserved fts5 column name: rowid}} + +#------------------------------------------------------------------------- +# +do_execsql_test 12.1 { + CREATE VIRTUAL TABLE t2 USING fts5(x,y, detail=%DETAIL%); +} {} + +do_catchsql_test 12.2 { + SELECT t2 FROM t2 WHERE t2 MATCH '*stuff' +} {1 {unknown special query: stuff}} + +do_test 12.3 { + set res [db eval { SELECT t2 FROM t2 WHERE t2 MATCH '* reads ' }] + string is integer $res +} {1} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 13.1 { + CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%); + INSERT INTO t1(rowid, x) VALUES(1, 'o n e'), (2, 't w o'); +} {} + +do_execsql_test 13.2 { + SELECT rowid FROM t1 WHERE t1 MATCH 'o'; +} {1 2} + +do_execsql_test 13.4 { + DELETE FROM t1 WHERE rowid=2; +} {} + +do_execsql_test 13.5 { + SELECT rowid FROM t1 WHERE t1 MATCH 'o'; +} {1} + +do_execsql_test 13.6 { + SELECT rowid FROM t1 WHERE t1 MATCH '""'; +} {} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 14.1 { + CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + WITH d(x,y) AS ( + SELECT NULL, 'xyz xyz xyz xyz xyz xyz' + UNION ALL + SELECT NULL, 'xyz xyz xyz xyz xyz xyz' FROM d + ) + INSERT INTO t1 SELECT * FROM d LIMIT 200; +} + +do_execsql_test 15.x { + INSERT INTO t1(t1) VALUES('integrity-check'); +} + +do_test 14.2 { + set nRow 0 + db eval { SELECT * FROM t1 WHERE t1 MATCH 'xyz' } { + db eval { + BEGIN; + CREATE TABLE t2(a, b); + ROLLBACK; + } + incr nRow + } + set nRow +} {200} + +do_test 14.3 { + set nRow 0 + db eval { BEGIN; } + db eval { SELECT * FROM t1 WHERE t1 MATCH 'xyz' } { + db eval { + SAVEPOINT aaa; + CREATE TABLE t2(a, b); + ROLLBACK TO aaa; + RELEASE aaa; + } + incr nRow + } + set nRow +} {200} + +do_execsql_test 15.0 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} +do_execsql_test 15.1 { + UPDATE t1_content SET c1 = 'xyz xyz xyz xyz xyz abc' WHERE rowid = 1; +} +do_catchsql_test 15.2 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +#------------------------------------------------------------------------- +# +do_execsql_test 16.1 { + CREATE VIRTUAL TABLE n1 USING fts5(a); + INSERT INTO n1 VALUES('a b c d'); +} + +proc funk {} { + db eval { UPDATE n1_config SET v=50 WHERE k='version' } + set fd [db incrblob main n1_data block 10] + fconfigure $fd -encoding binary -translation binary + puts -nonewline $fd "\x44\x45" + close $fd +} +db func funk funk + +do_catchsql_test 16.2 { + SELECT funk(), bm25(n1), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d' +} {1 {SQL logic error or missing database}} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 17.1 { + CREATE VIRTUAL TABLE b2 USING fts5(x, detail=%DETAIL%); + INSERT INTO b2 VALUES('a'); + INSERT INTO b2 VALUES('b'); + INSERT INTO b2 VALUES('c'); +} + +do_test 17.2 { + set res [list] + db eval { SELECT * FROM b2 ORDER BY rowid ASC } { + lappend res [execsql { SELECT * FROM b2 ORDER BY rowid ASC }] + } + set res +} {{a b c} {a b c} {a b c}} + +if {[string match n* %DETAIL%]==0} { + reset_db + do_execsql_test 17.3 { + CREATE VIRTUAL TABLE c2 USING fts5(x, y, detail=%DETAIL%); + INSERT INTO c2 VALUES('x x x', 'x x x'); + SELECT rowid FROM c2 WHERE c2 MATCH 'y:x'; + } {1} +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 17.1 { + CREATE VIRTUAL TABLE uio USING fts5(ttt, detail=%DETAIL%); + INSERT INTO uio VALUES(NULL); + INSERT INTO uio SELECT NULL FROM uio; + INSERT INTO uio SELECT NULL FROM uio; + INSERT INTO uio SELECT NULL FROM uio; + INSERT INTO uio SELECT NULL FROM uio; + INSERT INTO uio SELECT NULL FROM uio; + INSERT INTO uio SELECT NULL FROM uio; + INSERT INTO uio SELECT NULL FROM uio; + INSERT INTO uio SELECT NULL FROM uio; + SELECT count(*) FROM uio; +} {256} + +do_execsql_test 17.2 { + SELECT count(*) FROM uio WHERE rowid BETWEEN 8 AND 17 +} {10} +do_execsql_test 17.3 { + SELECT rowid FROM uio WHERE rowid BETWEEN 8 AND 17 +} {8 9 10 11 12 13 14 15 16 17} +do_execsql_test 17.4 { + SELECT rowid FROM uio WHERE rowid BETWEEN 8 AND 17 ORDER BY rowid DESC +} {17 16 15 14 13 12 11 10 9 8} +do_execsql_test 17.5 { + SELECT count(*) FROM uio +} {256} + +do_execsql_test 17.6 { + INSERT INTO uio(rowid) VALUES(9223372036854775807); + INSERT INTO uio(rowid) VALUES(-9223372036854775808); + SELECT count(*) FROM uio; +} {258} +do_execsql_test 17.7 { + SELECT min(rowid), max(rowid) FROM uio; +} {-9223372036854775808 9223372036854775807} + +do_execsql_test 17.8 { + INSERT INTO uio DEFAULT VALUES; + SELECT min(rowid), max(rowid), count(*) FROM uio; +} {-9223372036854775808 9223372036854775807 259} + +do_execsql_test 17.9 { + SELECT min(rowid), max(rowid), count(*) FROM uio WHERE rowid < 10; +} {-9223372036854775808 9 10} + +#-------------------------------------------------------------------- +# +do_execsql_test 18.1 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%); + CREATE VIRTUAL TABLE t2 USING fts5(c, d, detail=%DETAIL%); + INSERT INTO t1 VALUES('abc*', NULL); + INSERT INTO t2 VALUES(1, 'abcdefg'); +} +do_execsql_test 18.2 { + SELECT t1.rowid, t2.rowid FROM t1, t2 WHERE t2 MATCH t1.a AND t1.rowid = t2.c +} {1 1} +do_execsql_test 18.3 { + SELECT t1.rowid, t2.rowid FROM t2, t1 WHERE t2 MATCH t1.a AND t1.rowid = t2.c +} {1 1} + +#-------------------------------------------------------------------- +# fts5 table in the temp schema. +# +reset_db +do_execsql_test 19.0 { + CREATE VIRTUAL TABLE temp.t1 USING fts5(x, detail=%DETAIL%); + INSERT INTO t1 VALUES('x y z'); + INSERT INTO t1 VALUES('w x 1'); + SELECT rowid FROM t1 WHERE t1 MATCH 'x'; +} {1 2} + +#-------------------------------------------------------------------- +# Test that 6 and 7 byte varints can be read. +# +reset_db +do_execsql_test 20.0 { + CREATE VIRTUAL TABLE temp.tmp USING fts5(x, detail=%DETAIL%); +} +set ::ids [list \ + 0 [expr 1<<36] [expr 2<<36] [expr 1<<43] [expr 2<<43] +] +do_test 20.1 { + foreach id $::ids { + execsql { INSERT INTO tmp(rowid, x) VALUES($id, 'x y z') } + } + execsql { SELECT rowid FROM tmp WHERE tmp MATCH 'y' } +} $::ids + +} + + +finish_test + + diff --git a/ext/fts5/test/fts5ab.test b/ext/fts5/test/fts5ab.test new file mode 100644 index 0000000..95da2cd --- /dev/null +++ b/ext/fts5/test/fts5ab.test @@ -0,0 +1,297 @@ +# 2014 June 17 +# +# 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 FTS5 module. +# +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5ab + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%); + INSERT INTO t1 VALUES('hello', 'world'); + INSERT INTO t1 VALUES('one two', 'three four'); + INSERT INTO t1(rowid, a, b) VALUES(45, 'forty', 'five'); +} + +do_execsql_test 1.1 { + SELECT * FROM t1 ORDER BY rowid DESC; +} { forty five {one two} {three four} hello world } + +do_execsql_test 1.2 { + SELECT rowid FROM t1 ORDER BY rowid DESC; +} {45 2 1} + +do_execsql_test 1.3 { + SELECT rowid FROM t1 ORDER BY rowid ASC; +} {1 2 45} + +do_execsql_test 1.4 { + SELECT * FROM t1 WHERE rowid=2; +} {{one two} {three four}} + +do_execsql_test 1.5 { + SELECT * FROM t1 WHERE rowid=2.01; +} {} + +do_execsql_test 1.6 { + SELECT * FROM t1 WHERE rowid=1.99; +} {} + +#------------------------------------------------------------------------- + +reset_db +do_execsql_test 2.1 { + CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + INSERT INTO t1 VALUES('one'); + INSERT INTO t1 VALUES('two'); + INSERT INTO t1 VALUES('three'); +} + +do_catchsql_test 2.2 { + SELECT rowid, * FROM t1 WHERE t1 MATCH 'AND AND' +} {1 {fts5: syntax error near "AND"}} + +do_execsql_test 2.3 { SELECT rowid, * FROM t1 WHERE t1 MATCH 'two' } {2 two} +do_execsql_test 2.4 { SELECT rowid, * FROM t1 WHERE t1 MATCH 'three' } {3 three} +do_execsql_test 2.5 { SELECT rowid, * FROM t1 WHERE t1 MATCH 'one' } {1 one} + +do_execsql_test 2.6 { + INSERT INTO t1 VALUES('a b c d e f g'); + INSERT INTO t1 VALUES('b d e a a a i'); + INSERT INTO t1 VALUES('x y z b c c c'); +} + +foreach {tn expr res} { + 1 a {5 4} + 2 b {6 5 4} + 3 c {6 4} + 4 d {5 4} + 5 e {5 4} + 6 f {4} + 7 g {4} + 8 x {6} + 9 y {6} + 10 z {6} +} { + do_execsql_test 2.7.$tn.1 { + SELECT rowid FROM t1 WHERE t1 MATCH $expr ORDER BY rowid DESC + } $res + do_execsql_test 2.7.$tn.2 { + SELECT rowid FROM t1 WHERE t1 MATCH $expr ORDER BY rowid ASC + } [lsort -integer $res] +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a,b); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); +} + +foreach {tn a b} { + 1 {abashed abandons abase abash abaft} {abases abased} + 2 {abasing abases abaft abated abandons} {abases abandoned} + 3 {abatement abash abash abated abase} {abasements abashing} + 4 {abaft abasements abase abasement abasing} {abasement abases} + 5 {abaft abashing abatement abash abasements} {abandons abandoning} + 6 {aback abate abasements abashes abandoned} {abasement abased} + 7 {abandons abated abased aback abandoning} {abases abandoned} + 8 {abashing abases abasement abaft abashing} {abashed abate} + 9 {abash abase abate abashing abashed} {abandon abandoned} + 10 {abate abandoning abandons abasement aback} {abandon abandoning} +} { + do_execsql_test 3.1.$tn.1 { INSERT INTO t1 VALUES($a, $b) } + do_execsql_test 3.1.$tn.2 { INSERT INTO t1(t1) VALUES('integrity-check') } +} + +foreach {tn expr res} { + 1 {abash} {9 5 3 1} + 2 {abase} {9 4 3 1} + 3 {abase + abash} {1} + 4 {abash + abase} {9} + 5 {abaft + abashing} {8 5} + 6 {abandon + abandoning} {10} + 7 {"abashing abases abasement abaft abashing"} {8} +} { + do_execsql_test 3.2.$tn { + SELECT rowid FROM t1 WHERE t1 MATCH $expr ORDER BY rowid DESC + } $res +} + +do_execsql_test 3.3 { + SELECT rowid FROM t1 WHERE t1 MATCH 'NEAR(aback abate, 2)' +} {6} + +foreach {tn expr res} { + 1 {abash} {1 3 5 9} + 2 {abase} {1 3 4 9} + 3 {abase + abash} {1} + 4 {abash + abase} {9} + 5 {abaft + abashing} {5 8} + 6 {abandon + abandoning} {10} + 7 {"abashing abases abasement abaft abashing"} {8} +} { + do_execsql_test 3.4.$tn { + SELECT rowid FROM t1 WHERE t1 MATCH $expr + } $res +} + +#------------------------------------------------------------------------- +# Documents with more than 2M tokens. +# + +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE s1 USING fts5(x, detail=%DETAIL%); +} +foreach {tn doc} [list \ + 1 [string repeat {a x } 1500000] \ + 2 "[string repeat {a a } 1500000] x" \ +] { + do_execsql_test 4.$tn { INSERT INTO s1 VALUES($doc) } +} + +do_execsql_test 4.3 { + SELECT rowid FROM s1 WHERE s1 MATCH 'x' +} {1 2} + +if {[detail_is_full]} { + do_execsql_test 4.4 { + SELECT rowid FROM s1 WHERE s1 MATCH '"a x"' + } {1 2} +} + +do_execsql_test 4.5 { + SELECT rowid FROM s1 WHERE s1 MATCH 'a x' +} {1 2} + +#------------------------------------------------------------------------- +# Check that a special case of segment promotion works. The case is where +# a new segment is written to level L, but the oldest segment within level +# (L-2) is larger than it. +# +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE s2 USING fts5(x, detail=%DETAIL%); + INSERT INTO s2(s2, rank) VALUES('pgsz', 32); + INSERT INTO s2(s2, rank) VALUES('automerge', 0); +} + +proc rnddoc {n} { + set map [list 0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j] + set doc [list] + for {set i 0} {$i < $n} {incr i} { + lappend doc [string map $map [format %.3d [expr int(rand()*1000)]]] + } + set doc +} +db func rnddoc rnddoc + +do_test 5.1 { + for {set i 1} {$i <= 65} {incr i} { + execsql { INSERT INTO s2 VALUES(rnddoc(10)) } + } + for {set i 1} {$i <= 63} {incr i} { + execsql { DELETE FROM s2 WHERE rowid = $i } + } + fts5_level_segs s2 +} {0 8} + +do_test 5.2 { + execsql { + INSERT INTO s2(s2, rank) VALUES('automerge', 8); + } + for {set i 0} {$i < 7} {incr i} { + execsql { INSERT INTO s2 VALUES(rnddoc(50)) } + } + fts5_level_segs s2 +} {8 0 0} + +# Test also the other type of segment promotion - when a new segment is written +# that is larger than segments immediately following it. +do_test 5.3 { + execsql { + DROP TABLE s2; + CREATE VIRTUAL TABLE s2 USING fts5(x, detail=%DETAIL%); + INSERT INTO s2(s2, rank) VALUES('pgsz', 32); + INSERT INTO s2(s2, rank) VALUES('automerge', 0); + } + + for {set i 1} {$i <= 16} {incr i} { + execsql { INSERT INTO s2 VALUES(rnddoc(5)) } + } + fts5_level_segs s2 +} {0 1} + +do_test 5.4 { + execsql { INSERT INTO s2 VALUES(rnddoc(160)) } + fts5_level_segs s2 +} {2 0} + +#------------------------------------------------------------------------- +# +do_execsql_test 6.0 { + CREATE VIRTUAL TABLE s3 USING fts5(x, detail=%DETAIL%); + BEGIN; + INSERT INTO s3 VALUES('a b c'); + INSERT INTO s3 VALUES('A B C'); +} + +do_execsql_test 6.1.1 { + SELECT rowid FROM s3 WHERE s3 MATCH 'a' +} {1 2} + +do_execsql_test 6.1.2 { + SELECT rowid FROM s3 WHERE s3 MATCH 'a' ORDER BY rowid DESC +} {2 1} + +do_execsql_test 6.2 { + COMMIT; +} + +do_execsql_test 6.3 { + SELECT rowid FROM s3 WHERE s3 MATCH 'a' +} {1 2} + +do_test 6.4 { + db close + sqlite3 db test.db + execsql { + BEGIN; + INSERT INTO s3(s3) VALUES('optimize'); + ROLLBACK; + } +} {} + +#------------------------------------------------------------------------- +# +set doc [string repeat "a b c " 500] +do_execsql_test 7.0 { + CREATE VIRTUAL TABLE x1 USING fts5(x, detail=%DETAIL%); + INSERT INTO x1(x1, rank) VALUES('pgsz', 32); + INSERT INTO x1 VALUES($doc); +} + +} ;# foreach_detail_mode... + + +finish_test + diff --git a/ext/fts5/test/fts5ac.test b/ext/fts5/test/fts5ac.test new file mode 100644 index 0000000..61b3230 --- /dev/null +++ b/ext/fts5/test/fts5ac.test @@ -0,0 +1,279 @@ +# 2014 June 17 +# +# 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 FTS5 module. +# +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5ac + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + +set data { + 0 {p o q e z k z p n f y u z y n y} {l o o l v v k} + 1 {p k h h p y l l h i p v n} {p p l u r i f a j g e r r x w} + 2 {l s z j k i m p s} {l w e j t j e e i t w r o p o} + 3 {x g y m y m h p} {k j j b r e y y a k y} + 4 {q m a i y i z} {o w a g k x g j m w e u k} + 5 {k o a w y b s z} {s g l m m l m g p} + 6 {d a q i z h b l c p k j g k} {p x u j x t v c z} + 7 {f d a g o c t i} {w f c x l d r k i j} + 8 {y g w u b q p o m j y b p a e k} {r i d k y w o z q m a t p} + 9 {r k o m c c j s x m x m x m q r} {y r c a q d z k n x n} + 10 {k j q m g q a j d} {d d e z g w h c d o o g x d} + 11 {j z u m o y q j f w e e w t r j w} {g m o r x n t n w i f g l z f} + 12 {s y w a w d o h x m k} {c w k z b p o r a} + 13 {u t h x e g s k n g i} {f j w g c s r} + 14 {b f i c s u z t k} {c k q s j u i z o} + 15 {n a f n u s w h y n s i q e w} {x g e g a s s h n} + 16 {k s q e j n p} {t r j f t o e k k l m i} + 17 {g d t u w r o p m n m n p h b o u} {h s w o s l j e} + 18 {f l q y q q g e e x j r} {n b r r g e i r t x q k} + 19 {f i r g o a w e p i l o a w} {e k r z t d g h g i b d i e m} + 20 {l d u u f p y} {g o m m u x m g l j t t x x u} + 21 {m c d k x i c z l} {m i a i e u h} + 22 {w b f o c g x y j} {z d w x d f h i p} + 23 {w u i u x t c h k i b} {b y k h b v r t g j} + 24 {h f d j s w s b a p k} {a q y u z e y m m j q r} + 25 {d i x y x x k i y f s d j h z p n} {l l q m e t c w g y h t s v g} + 26 {g s q w t d k x g f m j p k y} {r m b x e l t d} + 27 {j l s q u g y v e c l o} {m f l m m m h g x x l n c} + 28 {c t j g v r s b z j} {l c f y d t q n} + 29 {e x z y w i h l} {b n b x e y q e n u m} + 30 {g y y h j b w r} {q b q f u s k c k g r} + 31 {g u l x l b r c m z b u c} {k g t b x k x n t e z d h o} + 32 {w g v l z f b z h p s c v h} {g e w v m h k r g w a r f q} + 33 {c g n f u d o y o b} {e y o h x x y y i z s b h a j} + 34 {v y h c q u u s q y x x k s q} {d n r m y k n t i r n w e} + 35 {o u c x l e b t a} {y b a x y f z x r} + 36 {x p h l j a a u u j h} {x o f s z m b c q p} + 37 {k q t i c a q n m v v} {v r z e f m y o} + 38 {r w t t t t r v v o e p g h} {l w x a g a u h y} + 39 {o p v g v b a g o} {j t q c r b b g y z} + 40 {f s o r o d t h q f x l} {r d b m k i f s t d l m y x j w} + 41 {t m o t m f m f} {i p i q j v n v m b q} + 42 {t x w a r l w d t b c o d o} {a h f h w z d n s} + 43 {t u q c d g p q x j o l c x c} {m n t o z z j a y} + 44 {v d i i k b f s z r v r z y} {g n q y s x x m b x c l w} + 45 {p v v a c s z y e o l} {m v t u d k m k q b d c v z r} + 46 {f y k l d r q w r s t r e} {h m v r r l r r t f q e x y} + 47 {w l n l t y x} {n h s l a f c h u f l x x m v n o} + 48 {t n v i k e b p z p d j j l i o} {i v z p g u e j s i k n h w d c} + 49 {z v x p n l t a j c} {e j l e n c e t a d} + 50 {w u b x u i v h a i y m m r p m s} {s r h d o g z y f f x e} + 51 {d c c x b c a x g} {p r a j v u y} + 52 {f w g r c o d l t u e z h i} {j l l s s b j m} + 53 {p m t f k i x} {u v y a z g w v v m x h i} + 54 {l c z g l o j i c d e b} {b f v y w u i b e i y} + 55 {r h c x f x a d s} {z x y k f l r b q c v} + 56 {v x x c y h z x b g m o q n c} {h n b i t g h a q b c o r u} + 57 {d g l o h t b s b r} {n u e p t i m u} + 58 {t d y e t d c w u o s w x f c h} {i o s v y b r d r} + 59 {l b a p q n d r} {k d c c d n y q h g a o p e x} + 60 {f r z v m p k r} {x x r i s b a g f c} + 61 {s a z i e r f i w c n y v z t k s} {y y i r y n l s b w i e k n} + 62 {n x p r e x q r m v i b y} {f o o z n b s r q j} + 63 {y j s u j x o n r q t f} {f v k n v x u s o a d e f e} + 64 {u s i l y c x q} {r k c h p c h b o s s u s p b} + 65 {m p i o s h o} {s w h u n d m n q t y k b w c} + 66 {l d f g m x x x o} {s w d d f b y j j h h t i y p j o} + 67 {c b m h f n v w n h} {i r w i e x r w l z p x u g u l s} + 68 {y a h u h i m a y q} {d d r x h e v q n z y c j} + 69 {c x f d x o n p o b r t b l p l} {m i t k b x v f p t m l l y r o} + 70 {u t l w w m s} {m f m o l t k o p e} + 71 {f g q e l n d m z x q} {z s i i i m f w w f n g p e q} + 72 {n l h a v u o d f j d e x} {v v s l f g d g r a j x i f z x} + 73 {x v m v f i g q e w} {r y s j i k m j j e d g r n o i f} + 74 {g d y n o h p s y q z j d w n h w} {x o d l t j i b r d o r y} + 75 {p g b i u r b e q d v o a g w m k} {q y z s f q o h} + 76 {u z a q u f i f f b} {b s p b a a d x r r i q f} + 77 {w h h z t h p o a h h e e} {h w r p h k z v y f r x} + 78 {c a r k i a p u x} {f w l p t e m l} + 79 {q q u k o t r k z} {f b m c w p s s o z} + 80 {t i g v y q s r x m r x z e f} {x o j w a u e y s j c b u p p r o} + 81 {n j n h r l a r e o z w e} {v o r r j a v b} + 82 {i f i d k w d n h} {o i d z i z l m w s b q v u} + 83 {m d g q q b k b w f q q p p} {j m q f b y c i z k y q p l e a} + 84 {m x o n y f g} {y c n x n q j i y c l h b r q z} + 85 {v o z l n p c} {g n j n t b b x n c l d a g j v} + 86 {z n a y f b t k k t d b z a v} {r p c n r u k u} + 87 {b q t x z e c w} {q a o a l o a h i m j r} + 88 {j f h o x x a z g b a f a m i b} {j z c z y x e x w t} + 89 {t c t p r s u c q n} {z x l i k n f q l n t} + 90 {w t d q j g m r f k n} {l e w f w w a l y q k i q t p c t} + 91 {c b o k l i c b s j n m b l} {y f p q o w g} + 92 {f y d j o q t c c q m f j s t} {f h e d y m o k} + 93 {k x j r m a d o i z j} {r t t t f e b r x i v j v g o} + 94 {s f e a e t i h h d q p z t q} {b k m k w h c} + 95 {h b n j t k i h o q u} {w n g i t o k c a m y p f l x c p} + 96 {f c x p y r b m o l m o a} {p c a q s u n n x d c f a o} + 97 {u h h k m n k} {u b v n u a o c} + 98 {s p e t c z d f n w f} {l s f j b l c e s h} + 99 {r c v w i v h a t a c v c r e} {h h u m g o f b a e o} +} + +foreach {tn2 sql} { + 1 {} + 2 {BEGIN} +} { + reset_db + fts5_aux_test_functions db + + do_execsql_test 1.$tn2.0 { + CREATE VIRTUAL TABLE xx USING fts5(x,y, detail=%DETAIL%); + INSERT INTO xx(xx, rank) VALUES('pgsz', 32); + } + + execsql $sql + + do_test 1.$tn2.1.1 { + foreach {id x y} $data { + execsql { INSERT INTO xx(rowid, x, y) VALUES($id, $x, $y) } + } + execsql { INSERT INTO xx(xx) VALUES('integrity-check') } + } {} + + + #------------------------------------------------------------------------- + # + do_execsql_test 1.$tn2.integrity { + INSERT INTO xx(xx) VALUES('integrity-check'); + } + + #------------------------------------------------------------------------- + # + foreach {tn expr} { + 1.1 "a AND b" + 1.2 "a OR b" + 1.3 "o" + 1.4 "b q" + 1.5 "e a e" + 1.6 "m d g q q b k b w f q q p p" + 1.7 "l o o l v v k" + 1.8 "a" + 1.9 "b" + 1.10 "c" + 1.11 "no" + 1.12 "L O O L V V K" + 1.13 "a AND b AND c" + 1.14 "x:a" + + 2.1 "x:a" + 2.2 "y:a" + 2.3 "x:b" + 2.4 "y:b" + + 3.1 "{x}:a" + 3.2 "{y}:a" + 3.3 "{x}:b" + 3.4 "{y}:b" + + 4.1 "{x y}:a" + 4.2 "{y x}:a" + 4.3 "{x x}:b" + 4.4 "{y y}:b" + + 5.1 {{"x" "y"}:a} + 5.2 {{"y" x}:a} + 5.3 {{x "x"}:b} + 5.4 {{"y" y}:b} + + 6.1 "b + q" + 6.2 "e + a + e" + 6.3 "m + d + g + q + q + b + k + b + w + f + q + q + p + p" + 6.4 "l + o + o + l + v + v + k" + 6.5 "L + O + O + L + V + V + K" + + 7.1 "a+b AND c" + 7.2 "d+c AND u" + 7.3 "d+c AND u+d" + 7.4 "a+b OR c" + 7.5 "d+c OR u" + 7.6 "d+c OR u+d" + + 8.1 "NEAR(a b)" + 8.2 "NEAR(r c)" + 8.2 { NEAR(r c, 5) } + 8.3 { NEAR(r c, 3) } + 8.4 { NEAR(r c, 2) } + 8.5 { NEAR(r c, 0) } + 8.6 { NEAR(a b c) } + 8.7 { NEAR(a b c, 8) } + 8.8 { x : NEAR(r c) } + 8.9 { y : NEAR(r c) } + + 9.1 { NEAR(r c) } + 9.2 { NEAR(r c, 5) } + 9.3 { NEAR(r c, 3) } + 9.4 { NEAR(r c, 2) } + 9.5 { NEAR(r c, 0) } + 9.6 { NEAR(a b c) } + 9.7 { NEAR(a b c, 8) } + 9.8 { x : NEAR(r c) } + 9.9 { y : NEAR(r c) } + 9.10 { x : "r c" } + 9.11 { y : "r c" } + 9.12 { a AND b } + 9.13 { a AND b AND c } + 9.14a { a } + 9.14b { a OR b } + 9.15 { a OR b AND c } + 9.16 { c AND b OR a } + 9.17 { c AND (b OR a) } + 9.18 { c NOT (b OR a) } + 9.19 { (c NOT b) OR (a AND d) } + } { + + if {[fts5_expr_ok $expr xx]==0} { + do_test 1.$tn2.$tn.OMITTED { list } [list] + continue + } + + set res [fts5_query_data $expr xx] + do_execsql_test 1.$tn2.$tn.[llength $res].asc { + SELECT rowid, fts5_test_poslist(xx), fts5_test_collist(xx) + FROM xx WHERE xx match $expr + } $res + + set res [fts5_query_data $expr xx DESC] + do_execsql_test 1.$tn2.$tn.[llength $res].desc { + SELECT rowid, fts5_test_poslist(xx), fts5_test_collist(xx) + FROM xx WHERE xx match $expr ORDER BY 1 DESC + } $res + } +} + +} + +do_execsql_test 2.1 { + SELECT fts5_expr_tcl('a AND b'); +} {{AND [nearset -- {a}] [nearset -- {b}]}} + +do_test 2.2.1 { nearset {{a b c}} -- a } {0.0.0} +do_test 2.2.2 { nearset {{a b c}} -- c } {0.0.2} + +foreach {tn expr tclexpr} { + 1 {a b} {AND [N $x -- {a}] [N $x -- {b}]} +} { + do_execsql_test 2.3.$tn { + SELECT fts5_expr_tcl($expr, 'N $x') + } [list $tclexpr] +} + +finish_test + diff --git a/ext/fts5/test/fts5ad.test b/ext/fts5/test/fts5ad.test new file mode 100644 index 0000000..974aa78 --- /dev/null +++ b/ext/fts5/test/fts5ad.test @@ -0,0 +1,245 @@ +# 2014 June 17 +# +# 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 FTS5 module. +# +# More specifically, the focus is on testing prefix queries, both with and +# without prefix indexes. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5ad + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE yy USING fts5(x, y, detail=%DETAIL%); + INSERT INTO yy VALUES('Changes the result to be', 'the list of all matching'); + INSERT INTO yy VALUES('indices (or all matching', 'values if -inline is'); + INSERT INTO yy VALUES('specified as well.) If', 'indices are returned, the'); +} {} + +foreach {tn match res} { + 1 {c*} {1} + 2 {i*} {3 2} + 3 {t*} {3 1} + 4 {r*} {3 1} +} { + do_execsql_test 1.$tn { + SELECT rowid FROM yy WHERE yy MATCH $match ORDER BY rowid DESC + } $res +} + +foreach {tn match res} { + 5 {c*} {1} + 6 {i*} {2 3} + 7 {t*} {1 3} + 8 {r*} {1 3} +} { + do_execsql_test 1.$tn { + SELECT rowid FROM yy WHERE yy MATCH $match + } $res +} + +foreach {T create} { + 2 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + } + + 3 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix="1,2,3,4", detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + } + + 4 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + BEGIN; + } + + 5 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix="1,2,3,4", detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + BEGIN; + } + +} { + + do_test $T.1 { + execsql { DROP TABLE IF EXISTS t1 } + execsql $create + } {} + + do_test $T.1 { + foreach {rowid a b} { + 0 {fghij uvwxyz klmn pq uvwx} {klmn f fgh uv fghij klmno} + 1 {uv f abcd abcd fghi} {pq klm uv uv fgh uv a} + 2 {klmn klm pqrs fghij uv} {f k uvw ab abcd pqr uv} + 3 {ab pqrst a fghi ab pqr fg} {k klmno a fg abcd} + 4 {abcd pqrst uvwx a fgh} {f klmno fghij kl pqrst} + 5 {uvwxyz k abcde u a} {uv k k kl klmn} + 6 {uvwxyz k klmn pqrst uv} {fghi pqrs abcde u k} + 7 {uvwxy klmn u p pqrst fgh} {p f fghi abcd uvw kl uv} + 8 {f klmno pqrst uvwxy pqrst} {uv abcde klm pq pqr} + 9 {f abcde a uvwxyz pqrst} {fghij abc k uvwx pqr fghij uvwxy} + 10 {ab uv f fg pqrst uvwxy} {fgh p uv k abc klm uvw} + 11 {pq klmno a uvw abcde uvwxyz} {fghij pq uvwxyz pqr fghi} + 12 {fgh u pq fgh uvw} {uvw pqr f uvwxy uvwx} + 13 {uvwx klmn f fgh abcd pqr} {uvw k fg uv klm abcd} + 14 {ab uvwx pqrst pqr uvwxyz pqrs} {uvwxyz abcde ab ab uvw abcde} + 15 {abc abcde uvwxyz abc kl k pqr} {klm k k klmno u fgh} + 16 {fghi abcd fghij uv uvwxyz ab uv} {klmn pqr a uvw fghi} + 17 {abc pqrst fghi uvwx uvw klmn fghi} {ab fg pqr pqrs p} + 18 {pqr kl a fghij fgh fg kl} {pqr uvwxyz uvw abcd uvwxyz} + 19 {fghi fghi pqr kl fghi f} {klmn u u klmno klmno} + 20 {abc pqrst klmno kl pq uvwxy} {abc k fghi pqrs klm} + 21 {a pqr uvwxyz uv fghi a fgh} {abc pqrs pqrst pq klm} + 22 {klm abc uvwxyz klm pqrst} {fghij k pq pqr u klm fghij} + 23 {p klm uv p a a} {uvwxy klmn uvw abcde pq} + 24 {uv fgh fg pq uvwxy u uvwxy} {pqrs a uvw p uvwx uvwxyz fg} + 25 {fghij fghi klmn abcd pq kl} {fghi abcde pqrs abcd fgh uvwxy} + 26 {pq fgh a abc klmno klmn} {fgh p k p fg fghij} + 27 {fg pq kl uvwx fghij pqrst klmn} {abcd uvw abcd fghij f fghij} + 28 {uvw fghi p fghij pq fgh uvwx} {k fghij abcd uvwx pqr fghi} + 29 {klm pq abcd pq f uvwxy} {pqrst p fghij pqr p} + 30 {ab uvwx fg uvwx klmn klm} {klmn klmno fghij klmn klm} + 31 {pq k pqr abcd a pqrs} {abcd abcd uvw a abcd klmno ab} + 32 {pqrst u abc pq klm} {abc kl uvwxyz fghij u fghi p} + 33 {f uvwxy u k f uvw uvwx} {pqrs uvw fghi fg pqrst klm} + 34 {pqrs pq fghij uvwxyz pqr} {ab abc abc uvw f pq f} + 35 {uvwxy ab uvwxy klmno kl pqrs} {abcde uvw pqrs uvwx k k} + 36 {uvwxyz k ab abcde abc uvw} {uvw abcde uvw klmn uv klmn} + 37 {k kl uv abcde uvwx fg u} {u abc uvwxy k fg abcd} + 38 {fghi pqrst fghi pqr pqrst uvwx} {u uv uvwx fghi abcde} + 39 {k pqrst k uvw fg pqrst fghij} {uvwxy ab kl klmn uvwxyz abcde} + 40 {fg uvwxy pqrs klmn uvwxyz klm p} {k uv ab fghij fgh k pqrs} + 41 {uvwx abc f pq uvwxy k} {ab uvwxyz abc f fghij} + 42 {uvwxy klmno uvwxyz uvwxyz pqrst} {uv kl kl klmno k f abcde} + 43 {abcde ab pqrs fg f fgh} {abc fghij fghi k k} + 44 {uvw abcd a ab pqrst klmn fg} {pqrst u uvwx pqrst fghij f pqrst} + 45 {uvwxy p kl uvwxyz ab pqrst fghi} {abc f pqr fg a k} + 46 {u p f a fgh} {a kl pq uv f} + 47 {pqrs abc fghij fg abcde ab a} {p ab uv pqrs kl fghi abcd} + 48 {abcde uvwxy pqrst uv abc pqr uvwx} {uvwxy klm uvwxy uvwx k} + 49 {fgh klm abcde klmno u} {a f fghij f uvwxyz abc u} + 50 {uv uvw uvwxyz uvwxyz uv ab} {uvwx pq fg u k uvwxy} + 51 {uvwxy pq p kl fghi} {pqrs fghi pqrs abcde uvwxyz ab} + 52 {pqr p uvwxy kl pqrs klmno fghij} {ab abcde abc pqrst pqrs uv} + 53 {fgh pqrst p a klmno} {ab ab pqrst pqr kl pqrst} + 54 {abcd klm ab uvw a fg u} {f pqr f abcd uv} + 55 {u fg uvwxyz k uvw} {abc pqrs f fghij fg pqrs uvwxy} + 56 {klm fg p fghi fg a} {uv a fghi uvwxyz a fghi} + 57 {uvwxy k abcde fgh f fghi} {f kl klmn f fghi klm} + 58 {klm k fgh uvw fgh fghi} {klmno uvwx u pqrst u} + 59 {fghi pqr pqrst p uvw fghij} {uv pqrst pqrs pq fghij klm} + 60 {uvwx klm uvwxy uv klmn} {p a a abc klmn ab k} + 61 {uvwxy uvwx klm uvwx klm} {pqrs ab ab uvwxyz fg} + 62 {kl uv uv uvw fg kl k} {abcde uvw fgh uvwxy klm} + 63 {a abc fgh u klm abcd} {fgh pqr uv klmn fghij} + 64 {klmn k klmn klmno pqrs pqr} {fg kl abcde klmno uvwxy kl pq} + 65 {uvwxyz klm fghi abc abcde kl} {uvwxy uvw uvwxyz uvwxyz pq pqrst} + 66 {pq klm abc pqrst fgh f} {u abcde pqrst abcde fg} + 67 {u pqrst kl u uvw klmno} {u pqr pqrs fgh u p} + 68 {abc fghi uvwxy fgh k pq} {uv p uvwx uvwxyz ab} + 69 {klmno f uvwxyz uvwxy klmn fg ab} {fgh kl a pqr abcd pqr} + 70 {fghi pqrst pqrst uv a} {uvwxy k p uvw uvwx a} + 71 {a fghij f p uvw} {klm fg abcd abcde klmno pqrs} + 72 {uv uvwx uvwx uvw klm} {uv fghi klmno uvwxy uvw} + 73 {kl uvwxy ab f pq klm u} {uvwxy klmn klm abcd pq fg k} + 74 {uvw pqrst abcd uvwxyz ab} {fgh fgh klmn abc pq} + 75 {uvwxyz klm pq abcd klmno pqr uvwxyz} {kl f a fg pqr klmn} + 76 {uvw uvwxy pqr k pqrst kl} {uvwxy abc uvw uvw u} + 77 {fgh klm u uvwxyz f uvwxy abcde} {uv abcde klmno u u ab} + 78 {klmno abc pq pqr fgh} {p uv abcd fgh abc u k} + 79 {fg pqr uvw pq uvwx} {uv uvw fghij pqrs fg p} + 80 {abcd pqrs uvwx uvwxy uvwx} {u uvw pqrst pqr abcde pqrs kl} + 81 {uvwxyz klm pq uvwxy fghij} {p pq klm fghij u a a} + 82 {uvwx k uvwxyz klmno pqrst kl} {abcde p f pqrst abcd uvwxyz p} + 83 {abcd abcde klm pqrst uvwxyz} {uvw pqrst u p uvwxyz a pqrs} + 84 {k klm abc uv uvwxy klm klmn} {k abc pqr a abc p kl} + 85 {klmn abcd pqrs p pq klm a} {klmn kl ab uvw pq} + 86 {klmn a pqrs abc uvw pqrst} {a pqr kl klm a k f} + 87 {pqrs ab uvwx uvwxy a pqr f} {fg klm uvwx pqr pqr} + 88 {klmno ab k kl u uvwxyz} {uv kl uvw fghi uv uvw} + 89 {pq fghi pqrst klmn uvwxy abc pqrs} {fg f f fg abc abcde klm} + 90 {kl a k fghi uvwx fghi u} {ab uvw pqr fg a p abc} + 91 {uvwx pqrs klmno ab fgh uvwx} {pqr uvwx abc kl f klmno kl} + 92 {fghij pq pqrs fghij f pqrst} {u abcde fg pq pqr fgh k} + 93 {fgh u pqrs abcde klmno abc} {abc fg pqrst pqr abcde} + 94 {uvwx p abc f pqr p} {k pqrs kl klm abc fghi klm} + 95 {kl p klmno uvwxyz klmn} {fghi ab a fghi pqrs kl} + 96 {pqr fgh pq uvwx a} {uvw klm klmno fg uvwxy uvwx} + 97 {fg abc uvwxyz fghi pqrst pq} {abc k a ab abcde f} + 98 {uvwxy fghi uvwxy u abcde abcde uvw} {klmn uvwx pqrs uvw uvwxy abcde} + 99 {pq fg fghi uvwx uvwx fghij uvwxy} {klmn klmn f abc fg a} + } { + execsql { + INSERT INTO t1(rowid, a, b) VALUES($rowid, $a, $b); + } + } + } {} + + proc prefix_query {prefixlist} { + set ret [list] + db eval {SELECT rowid, a, b FROM t1 ORDER BY rowid DESC} { + set bMatch 1 + foreach pref $prefixlist { + if { [lsearch -glob $a $pref]<0 && [lsearch -glob $b $pref]<0 } { + set bMatch 0 + break + } + } + if {$bMatch} { lappend ret $rowid } + } + return $ret + } + + do_execsql_test $T.integrity { + INSERT INTO t1(t1) VALUES('integrity-check'); + } + + foreach {bAsc sql} { + 1 {SELECT rowid FROM t1 WHERE t1 MATCH $prefix} + 0 {SELECT rowid FROM t1 WHERE t1 MATCH $prefix ORDER BY rowid DESC} + } { + foreach {tn prefix} { + 1 {a*} 2 {ab*} 3 {abc*} 4 {abcd*} 5 {abcde*} + 6 {f*} 7 {fg*} 8 {fgh*} 9 {fghi*} 10 {fghij*} + 11 {k*} 12 {kl*} 13 {klm*} 14 {klmn*} 15 {klmno*} + 16 {p*} 17 {pq*} 18 {pqr*} 19 {pqrs*} 20 {pqrst*} + 21 {u*} 22 {uv*} 23 {uvw*} 24 {uvwx*} 25 {uvwxy*} 26 {uvwxyz*} + 27 {x*} + 28 {a f*} 29 {a* f*} 30 {a* fghij*} + } { + set res [prefix_query $prefix] + if {$bAsc} { + set res [lsort -integer -increasing $res] + } + set n [llength $res] + if {$T==5} breakpoint + do_execsql_test $T.$bAsc.$tn.$n $sql $res + } + } + + catchsql COMMIT +} + +} + +finish_test + diff --git a/ext/fts5/test/fts5ae.test b/ext/fts5/test/fts5ae.test new file mode 100644 index 0000000..5153306 --- /dev/null +++ b/ext/fts5/test/fts5ae.test @@ -0,0 +1,312 @@ +# 2014 June 17 +# +# 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 FTS5 module. +# +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5ae + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); +} + +do_execsql_test 1.1 { + INSERT INTO t1 VALUES('hello', 'world'); + SELECT rowid FROM t1 WHERE t1 MATCH 'hello' ORDER BY rowid ASC; +} {1} + +do_execsql_test 1.2 { + INSERT INTO t1 VALUES('world', 'hello'); + SELECT rowid FROM t1 WHERE t1 MATCH 'hello' ORDER BY rowid ASC; +} {1 2} + +do_execsql_test 1.3 { + INSERT INTO t1 VALUES('world', 'world'); + SELECT rowid FROM t1 WHERE t1 MATCH 'hello' ORDER BY rowid ASC; +} {1 2} + +do_execsql_test 1.4.1 { + INSERT INTO t1 VALUES('hello', 'hello'); +} + +do_execsql_test 1.4.2 { + SELECT rowid FROM t1 WHERE t1 MATCH 'hello' ORDER BY rowid ASC; +} {1 2 4} + +fts5_aux_test_functions db + +#------------------------------------------------------------------------- +# +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE t2 USING fts5(x, y, detail=%DETAIL%); + INSERT INTO t2 VALUES('u t l w w m s', 'm f m o l t k o p e'); + INSERT INTO t2 VALUES('f g q e l n d m z x q', 'z s i i i m f w w f n g p'); +} + +do_execsql_test 2.1 { + SELECT rowid, fts5_test_poslist(t2) FROM t2 + WHERE t2 MATCH 'm' ORDER BY rowid; +} { + 1 {0.0.5 0.1.0 0.1.2} + 2 {0.0.7 0.1.5} +} + +do_execsql_test 2.2 { + SELECT rowid, fts5_test_poslist(t2) FROM t2 + WHERE t2 MATCH 'u OR q' ORDER BY rowid; +} { + 1 {0.0.0} + 2 {1.0.2 1.0.10} +} + +if {[detail_is_full]} { + do_execsql_test 2.3 { + SELECT rowid, fts5_test_poslist(t2) FROM t2 + WHERE t2 MATCH 'y:o' ORDER BY rowid; + } { + 1 {0.1.3 0.1.7} + } +} + +#------------------------------------------------------------------------- +# +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE t3 USING fts5(x, y, detail=%DETAIL%); + INSERT INTO t3 VALUES( 'j f h o x x a z g b a f a m i b', 'j z c z y x w t'); + INSERT INTO t3 VALUES( 'r c', ''); +} + +if {[detail_is_full]} { + do_execsql_test 3.1 { + SELECT rowid, fts5_test_poslist(t3) FROM t3 WHERE t3 MATCH 'NEAR(a b)'; + } { + 1 {0.0.6 1.0.9 0.0.10 0.0.12 1.0.15} + } + + do_execsql_test 3.2 { + SELECT rowid, fts5_test_poslist(t3) FROM t3 WHERE t3 MATCH 'NEAR(r c)'; + } { + 2 {0.0.0 1.0.1} + } +} + +do_execsql_test 3.3 { + INSERT INTO t3 + VALUES('k x j r m a d o i z j', 'r t t t f e b r x i v j v g o'); + SELECT rowid, fts5_test_poslist(t3) + FROM t3 WHERE t3 MATCH 'a OR b AND c'; +} { + 1 {0.0.6 1.0.9 0.0.10 0.0.12 1.0.15 2.1.2} + 3 0.0.5 +} + +#------------------------------------------------------------------------- +# +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE t4 USING fts5(x, y, detail=%DETAIL%); + INSERT INTO t4 + VALUES('k x j r m a d o i z j', 'r t t t f e b r x i v j v g o'); +} + +do_execsql_test 4.1 { + SELECT rowid, fts5_test_poslist(t4) FROM t4 WHERE t4 MATCH 'a OR b AND c'; +} { + 1 0.0.5 +} + +#------------------------------------------------------------------------- +# Test that the xColumnSize() and xColumnAvgsize() APIs work. +# +reset_db +fts5_aux_test_functions db + +do_execsql_test 5.1 { + CREATE VIRTUAL TABLE t5 USING fts5(x, y, detail=%DETAIL%); + INSERT INTO t5 VALUES('a b c d', 'e f g h i j'); + INSERT INTO t5 VALUES('', 'a'); + INSERT INTO t5 VALUES('a', ''); +} +do_execsql_test 5.2 { + SELECT rowid, fts5_test_columnsize(t5) FROM t5 WHERE t5 MATCH 'a' + ORDER BY rowid DESC; +} { + 3 {1 0} + 2 {0 1} + 1 {4 6} +} + +do_execsql_test 5.3 { + SELECT rowid, fts5_test_columntext(t5) FROM t5 WHERE t5 MATCH 'a' + ORDER BY rowid DESC; +} { + 3 {a {}} + 2 {{} a} + 1 {{a b c d} {e f g h i j}} +} + +do_execsql_test 5.4 { + SELECT rowid, fts5_test_columntotalsize(t5) FROM t5 WHERE t5 MATCH 'a' + ORDER BY rowid DESC; +} { + 3 {5 7} + 2 {5 7} + 1 {5 7} +} + +do_execsql_test 5.5 { + INSERT INTO t5 VALUES('x y z', 'v w x y z'); + SELECT rowid, fts5_test_columntotalsize(t5) FROM t5 WHERE t5 MATCH 'a' + ORDER BY rowid DESC; +} { + 3 {8 12} + 2 {8 12} + 1 {8 12} +} + +#------------------------------------------------------------------------- +# Test the xTokenize() API +# +reset_db +fts5_aux_test_functions db +do_execsql_test 6.1 { + CREATE VIRTUAL TABLE t6 USING fts5(x, y, detail=%DETAIL%); + INSERT INTO t6 VALUES('There are more', 'things in heaven and earth'); + INSERT INTO t6 VALUES(', Horatio, Than are', 'dreamt of in your philosophy.'); +} + +do_execsql_test 6.2 { + SELECT rowid, fts5_test_tokenize(t6) FROM t6 WHERE t6 MATCH 't*' +} { + 1 {{there are more} {things in heaven and earth}} + 2 {{horatio than are} {dreamt of in your philosophy}} +} + +#------------------------------------------------------------------------- +# Test the xQueryPhrase() API +# +reset_db +fts5_aux_test_functions db +do_execsql_test 7.1 { + CREATE VIRTUAL TABLE t7 USING fts5(x, y, detail=%DETAIL%); +} +do_test 7.2 { + foreach {x y} { + {q i b w s a a e l o} {i b z a l f p t e u} + {b a z t a l o x d i} {b p a d b f h d w y} + {z m h n p p u i e g} {v h d v b x j j c z} + {a g i m v a u c b i} {p k s o t l r t b m} + {v v c j o d a s c p} {f f v o k p o f o g} + } { + execsql {INSERT INTO t7 VALUES($x, $y)} + } + execsql { SELECT count(*) FROM t7 } +} {5} + +foreach {tn q res} { + 1 a {{4 2}} + 2 b {{3 4}} + 3 c {{2 1}} + 4 d {{2 2}} + 5 {a AND b} {{4 2} {3 4}} + 6 {a OR b OR c OR d} {{4 2} {3 4} {2 1} {2 2}} +} { + do_execsql_test 7.3.$tn { + SELECT fts5_test_queryphrase(t7) FROM t7 WHERE t7 MATCH $q LIMIT 1 + } [list $res] +} + +do_execsql_test 7.4 { + SELECT fts5_test_rowcount(t7) FROM t7 WHERE t7 MATCH 'a'; +} {5 5 5 5} + +#do_execsql_test 7.4 { +# SELECT rowid, bm25debug(t7) FROM t7 WHERE t7 MATCH 'a'; +#} {5 5 5 5} +# + +#------------------------------------------------------------------------- +# +do_test 8.1 { + execsql { CREATE VIRTUAL TABLE t8 USING fts5(x, y, detail=%DETAIL%) } + foreach {rowid x y} { + 0 {A o} {o o o C o o o o o o o o} + 1 {o o B} {o o o C C o o o o o o o} + 2 {A o o} {o o o o D D o o o o o o} + 3 {o B} {o o o o o D o o o o o o} + 4 {E o G} {H o o o o o o o o o o o} + 5 {F o G} {I o J o o o o o o o o o} + 6 {E o o} {H o J o o o o o o o o o} + 7 {o o o} {o o o o o o o o o o o o} + 9 {o o o} {o o o o o o o o o o o o} + } { + execsql { INSERT INTO t8(rowid, x, y) VALUES($rowid, $x, $y) } + } +} {} + +foreach {tn q res} { + 1 {a} {0 2} + 2 {b} {3 1} + 3 {c} {1 0} + 4 {d} {2 3} + 5 {g AND (e OR f)} {5 4} + 6 {j AND (h OR i)} {5 6} +} { + do_execsql_test 8.2.$tn.1 { + SELECT rowid FROM t8 WHERE t8 MATCH $q ORDER BY bm25(t8); + } $res + + do_execsql_test 8.2.$tn.2 { + SELECT rowid FROM t8 WHERE t8 MATCH $q ORDER BY +rank; + } $res + + do_execsql_test 8.2.$tn.3 { + SELECT rowid FROM t8 WHERE t8 MATCH $q ORDER BY rank; + } $res +} + +#------------------------------------------------------------------------- +# Test xPhraseCount() for some different queries. +# +do_test 9.1 { + execsql { CREATE VIRTUAL TABLE t9 USING fts5(x) } + foreach x { + "a b c" "d e f" + } { + execsql { INSERT INTO t9 VALUES($x) } + } +} {} + +foreach {tn q cnt} { + 1 {a AND b} 2 + 2 {a OR b} 2 + 3 {a OR b OR c} 3 + 4 {NEAR(a b)} 2 +} { + do_execsql_test 9.2.$tn { + SELECT fts5_test_phrasecount(t9) FROM t9 WHERE t9 MATCH $q LIMIT 1 + } $cnt +} + +} + +finish_test + diff --git a/ext/fts5/test/fts5af.test b/ext/fts5/test/fts5af.test new file mode 100644 index 0000000..d6b2241 --- /dev/null +++ b/ext/fts5/test/fts5af.test @@ -0,0 +1,148 @@ +# 2014 June 17 +# +# 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 FTS5 module. +# +# More specifically, the tests in this file focus on the built-in +# snippet() function. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5af + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%); +} + +proc do_snippet_test {tn doc match res} { + + uplevel #0 [list set v1 $doc] + uplevel #0 [list set v2 $match] + + do_execsql_test $tn.1 { + DELETE FROM t1; + INSERT INTO t1 VALUES($v1, NULL); + SELECT snippet(t1, -1, '[', ']', '...', 7) FROM t1 WHERE t1 MATCH $v2; + } [list $res] + + do_execsql_test $tn.2 { + DELETE FROM t1; + INSERT INTO t1 VALUES(NULL, $v1); + SELECT snippet(t1, -1, '[', ']', '...', 7) FROM t1 WHERE t1 MATCH $v2; + } [list $res] + + do_execsql_test $tn.3 { + DELETE FROM t1; + INSERT INTO t1 VALUES($v1, NULL); + SELECT snippet(t1, -1, '[', ']', '...', 7) FROM t1 WHERE t1 MATCH $v2 + ORDER BY rank DESC; + } [list $res] + + +} + + +foreach {tn doc res} { + + 1.1 {X o o o o o o} {[X] o o o o o o} + 1.2 {o X o o o o o} {o [X] o o o o o} + 1.3 {o o X o o o o} {o o [X] o o o o} + 1.4 {o o o X o o o} {o o o [X] o o o} + 1.5 {o o o o X o o} {o o o o [X] o o} + 1.6 {o o o o o X o} {o o o o o [X] o} + 1.7 {o o o o o o X} {o o o o o o [X]} + + 2.1 {X o o o o o o o} {[X] o o o o o o...} + 2.2 {o X o o o o o o} {o [X] o o o o o...} + 2.3 {o o X o o o o o} {o o [X] o o o o...} + 2.4 {o o o X o o o o} {o o o [X] o o o...} + 2.5 {o o o o X o o o} {...o o o [X] o o o} + 2.6 {o o o o o X o o} {...o o o o [X] o o} + 2.7 {o o o o o o X o} {...o o o o o [X] o} + 2.8 {o o o o o o o X} {...o o o o o o [X]} + + 3.1 {X o o o o o o o o} {[X] o o o o o o...} + 3.2 {o X o o o o o o o} {o [X] o o o o o...} + 3.3 {o o X o o o o o o} {o o [X] o o o o...} + 3.4 {o o o X o o o o o} {o o o [X] o o o...} + 3.5 {o o o o X o o o o} {...o o o [X] o o o...} + 3.6 {o o o o o X o o o} {...o o o [X] o o o} + 3.7 {o o o o o o X o o} {...o o o o [X] o o} + 3.8 {o o o o o o o X o} {...o o o o o [X] o} + 3.9 {o o o o o o o o X} {...o o o o o o [X]} + + 4.1 {X o o o o o X o o} {[X] o o o o o [X]...} + 4.2 {o X o o o o o X o} {...[X] o o o o o [X]...} + 4.3 {o o X o o o o o X} {...[X] o o o o o [X]} + + 5.1 {X o o o o X o o o} {[X] o o o o [X] o...} + 5.2 {o X o o o o X o o} {...[X] o o o o [X] o...} + 5.3 {o o X o o o o X o} {...[X] o o o o [X] o} + 5.4 {o o o X o o o o X} {...o [X] o o o o [X]} + + 6.1 {X o o o X o o o} {[X] o o o [X] o o...} + 6.2 {o X o o o X o o o} {o [X] o o o [X] o...} + 6.3 {o o X o o o X o o} {...o [X] o o o [X] o...} + 6.4 {o o o X o o o X o} {...o [X] o o o [X] o} + 6.5 {o o o o X o o o X} {...o o [X] o o o [X]} + + 7.1 {X o o X o o o o o} {[X] o o [X] o o o...} + 7.2 {o X o o X o o o o} {o [X] o o [X] o o...} + 7.3 {o o X o o X o o o} {...o [X] o o [X] o o...} + 7.4 {o o o X o o X o o} {...o [X] o o [X] o o} + 7.5 {o o o o X o o X o} {...o o [X] o o [X] o} + 7.6 {o o o o o X o o X} {...o o o [X] o o [X]} +} { + do_snippet_test 1.$tn $doc X $res +} + +if {[detail_is_full]} { + foreach {tn doc res} { + 1.1 {X Y o o o o o} {[X Y] o o o o o} + 1.2 {o X Y o o o o} {o [X Y] o o o o} + 1.3 {o o X Y o o o} {o o [X Y] o o o} + 1.4 {o o o X Y o o} {o o o [X Y] o o} + 1.5 {o o o o X Y o} {o o o o [X Y] o} + 1.6 {o o o o o X Y} {o o o o o [X Y]} + + 2.1 {X Y o o o o o o} {[X Y] o o o o o...} + 2.2 {o X Y o o o o o} {o [X Y] o o o o...} + 2.3 {o o X Y o o o o} {o o [X Y] o o o...} + 2.4 {o o o X Y o o o} {...o o [X Y] o o o} + 2.5 {o o o o X Y o o} {...o o o [X Y] o o} + 2.6 {o o o o o X Y o} {...o o o o [X Y] o} + 2.7 {o o o o o o X Y} {...o o o o o [X Y]} + + 3.1 {X Y o o o o o o o} {[X Y] o o o o o...} + 3.2 {o X Y o o o o o o} {o [X Y] o o o o...} + 3.3 {o o X Y o o o o o} {o o [X Y] o o o...} + 3.4 {o o o X Y o o o o} {...o o [X Y] o o o...} + 3.5 {o o o o X Y o o o} {...o o [X Y] o o o} + 3.6 {o o o o o X Y o o} {...o o o [X Y] o o} + 3.7 {o o o o o o X Y o} {...o o o o [X Y] o} + 3.8 {o o o o o o o X Y} {...o o o o o [X Y]} + } { + do_snippet_test 2.$tn $doc "X + Y" $res + } +} + +} ;# foreach_detail_mode + +finish_test + diff --git a/ext/fts5/test/fts5ag.test b/ext/fts5/test/fts5ag.test new file mode 100644 index 0000000..de126a2 --- /dev/null +++ b/ext/fts5/test/fts5ag.test @@ -0,0 +1,145 @@ +# 2014 June 17 +# +# 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 FTS5 module. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5ag + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +#------------------------------------------------------------------------- +# This file attempts to verify that the extension APIs work with +# "ORDER BY rank" queries. This is done by comparing the results of +# the fts5_test() function when run with queries of the form: +# +# ... WHERE fts MATCH ? ORDER BY bm25(fts) [ASC|DESC] +# +# and +# +# ... WHERE fts MATCH ? ORDER BY rank [ASC|DESC] +# + +foreach_detail_mode $testprefix { + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x, y, z, detail=%DETAIL%); +} + +do_test 1.1 { + foreach {x y z} { + {j s m y m r n l u k} {z k f u z g h s w g} {r n o s s b v n w w} + {m v g n d x q r r s} {q t d a q a v l h j} {s k l f s i n v q v} + {m f f d h h s o h a} {y e v r q i u m h d} {b c k q m z l z h n} + {j e m v k p e c j m} {m p v z d x l n i a} {v p u p m t p q i f} + {v r w l e e t d z p} {c s b w k m n k o u} {w g y f v w v w v p} + {k d g o u j p z n o} {t g e q l z i g b j} {f i q q j y h b g h} + {j s w x o t j b t m} {v a v v r t x c q a} {r t k x w u l h a g} + {j y b i u d e m d w} {y s o j h i n a u p} {n a g b u c w e b m} + {b c k s c w j p w b} {m o c o w o b d q q} {n t y o y z y r z e} + {p n q l e l h z q c} {n s e i h c v b b u} {m p d i t a o o f f} + {k c o n v e z l b m} {s m n i n s d e s u} {t a u e q d a o u c} + {h d t o i a g b b p} {k x c i g f g b b k} {x f i v n a n n j i} + {f z k r b u s k z e} {n z v z w l e r h t} {t i s v v a v p n s} + {k f e c t z r e f d} {f m g r c w q k b v} {v y s y f r b f e f} + {z r c t d q q h x b} {u c g z n z u v s s} {y t n f f x b f d x} + {u n p n u t i m e j} {p j j d m f k p m z} {d o l v c o e a h w} + {h o q w t f v i c y} {c q u n r z s l l q} {z x a q w s b w s y} + {y m s x k i m n x c} {b i a n v h z n k a} {w l q p b h h g d y} + {z v s j f p v l f w} {c s b i z e k i g c} {x b v d w j f e d z} + {r k k j e o m k g b} {h b d c h m y b t u} {u j s h k z c u d y} + {v h i v s y z i k l} {d t m w q w c a z p} {r s e s x v d w k b} + {u r e q j y h o o s} {x x z r x y t f j s} {k n h x i i u e c v} + {q l f d a p w l q o} {y z q w j o p b o v} {s u h z h f d f n l} + {q o e o x x l g q i} {j g m h q q w c d b} {o m d h w a g b f n} + {m x k t s s y l v a} {j x t c a u w b w g} {n f j b v x y p u t} + {u w k a q b u w k w} {a h j u o w f s k p} {j o f s h y t j h g} + {x v b l m t l m h l} {t p y i y i q b q a} {k o o z w a c h c f} + {j g c d k w b d t v} {a k v c m a v h v p} {i c a i j g h l j h} + {l m v l c z j b p b} {z p z f l n k i b a} {j v q k g i x g i b} + {m c i w u z m i s z} {i z r f n l q z k w} {x n b p b q r g i z} + {d g i o o x l f x d} {r t m f b n q y c b} {i u g k w x n m p o} + {t o s i q d z x d t} {v a k s q z j c o o} {z f n n r l y w v v} + {w k h d t l j g n n} {r z m v y b l n c u} {v b v s c l n k g v} + {m a g r a b u u n z} {u y l h v w v k b f} {x l p g i s j f x v} + {v s g x k z a k a r} {l t g v j q l k p l} {f h n a x t v s t y} + {z u v u x p s j y t} {g b q e e g l n w g} {e n p j i g j f u r} + {q z l t w o l m p e} {t s g h r p r o t z} {y b f a o n u m z g} + {d t w n y b o g f o} {d a j e r l g g s h} {d z e l w q l t h f} + {f l u w q v x j a h} {f n u l l d m h h w} {d x c c e r o d q j} + {b y f q s q f u l g} {u z w l f d b i a g} {m v q b g u o z e z} + {h z p t s e x i v m} {l h q m e o x x x j} {e e d n p r m g j f} + {k h s g o n s d a x} {u d t t s j o v h a} {z r b a e u v o e s} + {m b b g a f c p a t} {w c m j o d b l g e} {f p j p m o s y v j} + {c r n h d w c a b l} {s g e u s d n j b g} {b o n a x a b x y l} + {r h u x f c d z n o} {x y l g u m i i w d} {t f h b z v r s r g} + {t i o r b v g g p a} {d x l u q k m o s u} {j f h t u n z u k m} + {g j t y d c n j y g} {w e s k v c w i g t} {g a h r g v g h r o} + {e j l a q j g i n h} {d z k c u p n u p p} {t u e e v z v r r g} + {l j s g k j k h z l} {p v d a t x d e q u} {r l u z b m g k s j} + {i e y d u x d i n l} {p f z k m m w p u l} {z l p m r q w n d a} + } { + execsql { INSERT INTO t1 VALUES($x, $y, $z) } + } + set {} {} +} {} + +fts5_aux_test_functions db + +proc do_fts5ag_test {tn E} { + set q1 {SELECT fts5_test_all(t1) FROM t1 WHERE t1 MATCH $E ORDER BY rank} + set q2 {SELECT fts5_test_all(t1) FROM t1 WHERE t1 MATCH $E ORDER BY bm25(t1)} + + set res [execsql $q1] + set expected [execsql $q2] + uplevel [list do_test $tn.1 [list set {} $res] $expected] + + append q1 " DESC" + append q2 " DESC" + + set res [execsql $q1] + set expected [execsql $q2] + uplevel [list do_test $tn.2 [list set {} $res] $expected] +} + +foreach {tn expr} { + 2.1 a + 2.2 b + 2.3 c + 2.4 d + + 3.0 {a AND b} + 3.1 {a OR b} + 3.2 {b OR c AND d} +} { + do_fts5ag_test $tn $expr +} + +if {[detail_is_full]} { + foreach {tn expr} { + 4.1 {"m m"} + 4.2 {e + s} + 4.3 {NEAR(c d)} + } { + do_fts5ag_test $tn $expr + } +} + +} ;# foreach_detail_mode + + +finish_test + diff --git a/ext/fts5/test/fts5ah.test b/ext/fts5/test/fts5ah.test new file mode 100644 index 0000000..b7beb56 --- /dev/null +++ b/ext/fts5/test/fts5ah.test @@ -0,0 +1,170 @@ +# 2014 June 17 +# +# 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 FTS5 module. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5ah + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + +#------------------------------------------------------------------------- +# This file contains tests for very large doclists. +# + +set Y [list] +set W [list] +do_test 1.0 { + execsql { CREATE VIRTUAL TABLE t1 USING fts5(a, detail=%DETAIL%) } + execsql { INSERT INTO t1(t1, rank) VALUES('pgsz', 128) } + set v {w w w w w w w w w w w w w w w w w w w w} + execsql { INSERT INTO t1(rowid, a) VALUES(0, $v) } + for {set i 1} {$i <= 10000} {incr i} { + set v {x x x x x x x x x x x x x x x x x x x x} + if {($i % 2139)==0} {lset v 3 Y ; lappend Y $i} + if {($i % 1577)==0} {lset v 5 W ; lappend W $i} + execsql { INSERT INTO t1 VALUES($v) } + } + set v {w w w w w w w w w w w w w w w w w w w w} + execsql { INSERT INTO t1 VALUES($v) } +} {} + +do_execsql_test 1.1.1 { + SELECT rowid FROM t1 WHERE t1 MATCH 'x AND w' +} [lsort -integer -incr $W] + +do_execsql_test 1.1.2 { + SELECT rowid FROM t1 WHERE t1 MATCH 'x* AND w*' +} [lsort -integer -incr $W] + +do_execsql_test 1.2 { + SELECT rowid FROM t1 WHERE t1 MATCH 'y AND x' +} [lsort -integer -incr $Y] + +do_execsql_test 1.3 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} + +proc reads {} { + db one {SELECT t1 FROM t1 WHERE t1 MATCH '*reads'} +} + +proc execsql_reads {sql} { + set nRead [reads] + execsql $sql + expr [reads] - $nRead +} + +do_test 1.4 { + set nRead [reads] + execsql { SELECT rowid FROM t1 WHERE t1 MATCH 'x' } + set nReadX [expr [reads] - $nRead] + #puts -nonewline "(nReadX=$nReadX)" + if {[detail_is_full]} { set expect 1000 } + if {[detail_is_col]} { set expect 250 } + if {[detail_is_none]} { set expect 80 } + + expr $nReadX>$expect +} {1} + +do_test 1.5 { + set fwd [execsql_reads {SELECT rowid FROM t1 WHERE t1 MATCH 'x' }] + set bwd [execsql_reads { + SELECT rowid FROM t1 WHERE t1 MATCH 'x' ORDER BY 1 ASC + }] + expr {$bwd < $fwd + 12} +} {1} + +foreach {tn q res} " + 1 { SELECT rowid FROM t1 WHERE t1 MATCH 'w + x' } [list $W] + 2 { SELECT rowid FROM t1 WHERE t1 MATCH 'x + w' } [list $W] + 3 { SELECT rowid FROM t1 WHERE t1 MATCH 'x AND w' } [list $W] + 4 { SELECT rowid FROM t1 WHERE t1 MATCH 'y AND x' } [list $Y] +" { + if {[detail_is_full]==0 && ($tn==1 || $tn==2)} continue + + if {[detail_is_full]} { set ratio 8 } + if {[detail_is_col]} { set ratio 4 } + if {[detail_is_none]} { set ratio 2 } + + do_test 1.6.$tn.1 { + set n [execsql_reads $q] + #puts -nonewline "(n=$n nReadX=$nReadX)" + expr {$n < ($nReadX / $ratio)} + } {1} + + do_test 1.6.$tn.2 { + set n [execsql_reads "$q ORDER BY rowid DESC"] + #puts -nonewline "(n=$n nReadX=$nReadX)" + expr {$n < ($nReadX / $ratio)} + } {1} + + do_execsql_test 1.6.$tn.3 $q [lsort -int -incr $res] + do_execsql_test 1.6.$tn.4 "$q ORDER BY rowid DESC" [lsort -int -decr $res] +} + +#------------------------------------------------------------------------- +# Now test that adding range constraints on the rowid field reduces the +# number of pages loaded from disk. +# +foreach {tn fraction tail cnt} { + 1 0.6 {rowid > 5000} 5000 + 2 0.2 {rowid > 9000} 1000 + 3 0.2 {rowid < 1000} 999 + 4 0.2 {rowid BETWEEN 4000 AND 5000} 1001 + 5 0.6 {rowid >= 5000} 5001 + 6 0.2 {rowid >= 9000} 1001 + 7 0.2 {rowid <= 1000} 1000 + 8 0.6 {rowid > '5000'} 5000 + 9 0.2 {rowid > '9000'} 1000 + 10 0.1 {rowid = 444} 1 +} { + set q "SELECT rowid FROM t1 WHERE t1 MATCH 'x' AND $tail" + set n [execsql_reads $q] + set ret [llength [execsql $q]] + + # Because the position lists for 'x' are quite long in this db, the + # advantage is a bit smaller in detail=none mode. Update $fraction to + # reflect this. + if {[detail_is_none] && $fraction<0.5} { set fraction [expr $fraction*2] } + + do_test "1.7.$tn.asc.(n=$n ret=$ret)" { + expr {$n < ($fraction*$nReadX) && $ret==$cnt} + } {1} + + set q "SELECT rowid FROM t1 WHERE t1 MATCH 'x' AND $tail ORDER BY rowid DESC" + set n [execsql_reads $q] + set ret [llength [execsql $q]] + do_test "1.7.$tn.desc.(n=$n ret=$ret)" { + expr {$n < 2*$fraction*$nReadX && $ret==$cnt} + } {1} +} + +do_execsql_test 1.8.1 { + SELECT count(*) FROM t1 WHERE t1 MATCH 'x' AND +rowid < 'text'; +} {10000} +do_execsql_test 1.8.2 { + SELECT count(*) FROM t1 WHERE t1 MATCH 'x' AND rowid < 'text'; +} {10000} + +} ;# foreach_detail_mode + +#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM t1_data} {puts $r} + +finish_test + diff --git a/ext/fts5/test/fts5ai.test b/ext/fts5/test/fts5ai.test new file mode 100644 index 0000000..e32c806 --- /dev/null +++ b/ext/fts5/test/fts5ai.test @@ -0,0 +1,58 @@ +# 2014 June 17 +# +# 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 FTS5 module. +# +# Specifically, it tests transactions and savepoints +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5ai + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=%DETAIL%); +} {} + +do_execsql_test 1.1 { + BEGIN; + INSERT INTO t1 VALUES('a b c'); + INSERT INTO t1 VALUES('d e f'); + SAVEPOINT one; + INSERT INTO t1 VALUES('g h i'); + SAVEPOINT two; + INSERT INTO t1 VALUES('j k l'); + ROLLBACK TO one; + INSERT INTO t1 VALUES('m n o'); + SAVEPOINT two; + INSERT INTO t1 VALUES('p q r'); + RELEASE one; + SAVEPOINT one; + INSERT INTO t1 VALUES('s t u'); + ROLLBACK TO one; + COMMIT; +} + +do_execsql_test 1.2 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} +} + + +finish_test + diff --git a/ext/fts5/test/fts5aj.test b/ext/fts5/test/fts5aj.test new file mode 100644 index 0000000..6b9dddd --- /dev/null +++ b/ext/fts5/test/fts5aj.test @@ -0,0 +1,69 @@ +# 2014 June 17 +# +# 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 FTS5 module. +# +# Specifically, this tests that, provided the amount of data remains +# constant, the FTS index does not grow indefinitely as rows are inserted +# and deleted, +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5aj + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +proc doc {} { + set dict [list a b c d e f g h i j k l m n o p q r s t u v w x y z] + set res [list] + for {set i 0} {$i < 20} {incr i} { + lappend res [lindex $dict [expr int(rand() * 26)]] + } + set res +} + +proc structure {} { + set val [db one {SELECT fts5_decode(rowid,block) FROM t1_data WHERE rowid=10}] + foreach lvl [lrange $val 1 end] { + lappend res [expr [llength $lvl]-2] + } + set res +} + +expr srand(0) +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x); + INSERT INTO t1(t1, rank) VALUES('pgsz', 64); +} + +for {set iTest 0} {$iTest < 50000} {incr iTest} { + if {$iTest > 1000} { execsql { DELETE FROM t1 WHERE rowid=($iTest-1000) } } + set new [doc] + execsql { INSERT INTO t1 VALUES($new) } + if {$iTest==10000} { set sz1 [db one {SELECT count(*) FROM t1_data}] } + if {0==($iTest % 1000)} { + set sz [db one {SELECT count(*) FROM t1_data}] + set s [structure] + do_execsql_test 1.$iTest.$sz.{$s} { + INSERT INTO t1(t1) VALUES('integrity-check') + } + } +} + +do_execsql_test 2.0 { INSERT INTO t1(t1) VALUES('integrity-check') } + + +finish_test + diff --git a/ext/fts5/test/fts5ak.test b/ext/fts5/test/fts5ak.test new file mode 100644 index 0000000..0f699a6 --- /dev/null +++ b/ext/fts5/test/fts5ak.test @@ -0,0 +1,150 @@ +# 2014 November 24 +# +# 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 FTS5 module. +# +# Specifically, the auxiliary function "highlight". +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5ak + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + +do_execsql_test 1.1 { + CREATE VIRTUAL TABLE ft1 USING fts5(x, detail=%DETAIL%); + INSERT INTO ft1 VALUES('i d d a g i b g d d'); + INSERT INTO ft1 VALUES('h d b j c c g a c a'); + INSERT INTO ft1 VALUES('e j a e f h b f h h'); + INSERT INTO ft1 VALUES('j f h d g h i b d f'); + INSERT INTO ft1 VALUES('d c j d c j b c g e'); + INSERT INTO ft1 VALUES('i a d e g j g d a a'); + INSERT INTO ft1 VALUES('j f c e d a h j d b'); + INSERT INTO ft1 VALUES('i c c f a d g h j e'); + INSERT INTO ft1 VALUES('i d i g c d c h b f'); + INSERT INTO ft1 VALUES('g d a e h a b c f j'); + + CREATE VIRTUAL TABLE ft2 USING fts5(x, detail=%DETAIL%); + INSERT INTO ft2 VALUES('a b c d e f g h i j'); +} + +do_execsql_test 1.2 { + SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'e'; +} { + {[e] j a [e] f h b f h h} + {d c j d c j b c g [e]} + {i a d [e] g j g d a a} + {j f c [e] d a h j d b} + {i c c f a d g h j [e]} + {g d a [e] h a b c f j} +} + +do_execsql_test 1.3 { + SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'e e e' +} { + {[e] j a [e] f h b f h h} + {d c j d c j b c g [e]} + {i a d [e] g j g d a a} + {j f c [e] d a h j d b} + {i c c f a d g h j [e]} + {g d a [e] h a b c f j} +} + +do_execsql_test 1.4 { + SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'f d' +} { + {a b c [d] e [f] g h i j} +} + +do_execsql_test 1.5 { + SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'd f' +} { + {a b c [d] e [f] g h i j} +} + +#------------------------------------------------------------------------- +# Tests below this point require detail=full. +#------------------------------------------------------------------------- +if {[detail_is_full]==0} continue + + +do_execsql_test 2.1 { + SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'h + d'; +} { + {[h d] b j c c g a c a} + {j f [h d] g h i b d f} +} + +do_execsql_test 2.2 { + SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'd + d'; +} { + {i [d d] a g i b g [d d]} +} + +do_execsql_test 2.3 { + SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'd + d d + d'; +} { + {i [d d] a g i b g [d d]} +} + +do_execsql_test 2.4 { + SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'b+c+d c+d+e' +} {{a [b c d e] f g h i j}} + +do_execsql_test 2.5 { + SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'b+c+d e+f+g' +} { + {a [b c d] [e f g] h i j} +} + +do_execsql_test 2.6 { + SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'b+c+d c' +} { + {a [b c d] e f g h i j} +} + +do_execsql_test 2.7 { + SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'b+c c+d+e' +} { + {a [b c d e] f g h i j} +} + +#------------------------------------------------------------------------- +# The example from the docs. +# +do_execsql_test 3.1 { + -- Assuming this: + CREATE VIRTUAL TABLE ft USING fts5(a, detail=%DETAIL%); + INSERT INTO ft VALUES('a b c x c d e'); + INSERT INTO ft VALUES('a b c c d e'); + INSERT INTO ft VALUES('a b c d e'); + + -- The following SELECT statement returns these three rows: + -- '[a b c] x [c d e]' + -- '[a b c] [c d e]' + -- '[a b c d e]' + SELECT highlight(ft, 0, '[', ']') FROM ft WHERE ft MATCH 'a+b+c AND c+d+e'; +} { + {[a b c] x [c d e]} + {[a b c] [c d e]} + {[a b c d e]} +} + +} + +finish_test + diff --git a/ext/fts5/test/fts5al.test b/ext/fts5/test/fts5al.test new file mode 100644 index 0000000..c0dd211 --- /dev/null +++ b/ext/fts5/test/fts5al.test @@ -0,0 +1,300 @@ +# 2014 November 24 +# +# 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 FTS5 module. +# +# Specifically, this function tests the %_config table. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5al + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + +do_execsql_test 1.1 { + CREATE VIRTUAL TABLE ft1 USING fts5(x, detail=%DETAIL%); + SELECT * FROM ft1_config; +} {version 4} + +do_execsql_test 1.2 { + INSERT INTO ft1(ft1, rank) VALUES('pgsz', 32); + SELECT * FROM ft1_config; +} {pgsz 32 version 4} + +do_execsql_test 1.3 { + INSERT INTO ft1(ft1, rank) VALUES('pgsz', 64); + SELECT * FROM ft1_config; +} {pgsz 64 version 4} + +#-------------------------------------------------------------------------- +# Test the logic for parsing the rank() function definition. +# +foreach {tn defn} { + 1 "fname()" + 2 "fname(1)" + 3 "fname(1,2)" + 4 "fname(null,NULL,nUlL)" + 5 " fname ( null , NULL , nUlL ) " + 6 "fname('abc')" + 7 "fname('a''bc')" + 8 "fname('''abc')" + 9 "fname('abc''')" + + 7 "fname( 'a''bc' )" + 8 "fname('''abc' )" + 9 "fname( 'abc''' )" + + 10 "fname(X'1234ab')" + + 11 "myfunc(1.2)" + 12 "myfunc(-1.0)" + 13 "myfunc(.01,'abc')" +} { + do_execsql_test 2.1.$tn { + INSERT INTO ft1(ft1, rank) VALUES('rank', $defn); + } +} + +foreach {tn defn} { + 1 "" + 2 "fname" + 3 "fname(X'234ab')" + 4 "myfunc(-1.,'abc')" +} { + do_test 2.2.$tn { + catchsql { INSERT INTO ft1(ft1, rank) VALUES('rank', $defn) } + } {1 {SQL logic error or missing database}} +} + +#------------------------------------------------------------------------- +# Assorted tests of the tcl interface for creating extension functions. +# + +do_execsql_test 3.1 { + CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%); + INSERT INTO t1 VALUES('q w e r t y'); + INSERT INTO t1 VALUES('y t r e w q'); +} + +proc argtest {cmd args} { return $args } +sqlite3_fts5_create_function db argtest argtest + +do_execsql_test 3.2.1 { + SELECT argtest(t1, 123) FROM t1 WHERE t1 MATCH 'q' +} {123 123} + +do_execsql_test 3.2.2 { + SELECT argtest(t1, 123, 456) FROM t1 WHERE t1 MATCH 'q' +} {{123 456} {123 456}} + +proc rowidtest {cmd} { $cmd xRowid } +sqlite3_fts5_create_function db rowidtest rowidtest + +do_execsql_test 3.3.1 { + SELECT rowidtest(t1) FROM t1 WHERE t1 MATCH 'q' +} {1 2} + +proc insttest {cmd} { + set res [list] + for {set i 0} {$i < [$cmd xInstCount]} {incr i} { + lappend res [$cmd xInst $i] + } + set res +} +sqlite3_fts5_create_function db insttest insttest + +do_execsql_test 3.4.1 { + SELECT insttest(t1) FROM t1 WHERE t1 MATCH 'q' +} { + {{0 0 0}} + {{0 0 5}} +} + +if {[detail_is_full]} { + do_execsql_test 3.4.2 { + SELECT insttest(t1) FROM t1 WHERE t1 MATCH 'r+e OR w' + } { + {{1 0 1}} + {{0 0 2} {1 0 4}} + } +} + +proc coltest {cmd} { + list [$cmd xColumnSize 0] [$cmd xColumnText 0] +} +sqlite3_fts5_create_function db coltest coltest + +do_execsql_test 3.5.1 { + SELECT coltest(t1) FROM t1 WHERE t1 MATCH 'q' +} { + {6 {q w e r t y}} + {6 {y t r e w q}} +} + +#------------------------------------------------------------------------- +# Tests for remapping the "rank" column. +# +# 4.1.*: Mapped to a function with no arguments. +# 4.2.*: Mapped to a function with one or more arguments. +# + +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE t2 USING fts5(a, b, detail=%DETAIL%); + INSERT INTO t2 VALUES('a s h g s b j m r h', 's b p a d b b a o e'); + INSERT INTO t2 VALUES('r h n t a g r d d i', 'l d n j r c f t o q'); + INSERT INTO t2 VALUES('q k n i k c a a e m', 'c h n j p g s c i t'); + INSERT INTO t2 VALUES('h j g t r e l s g s', 'k q k c i i c k n s'); + INSERT INTO t2 VALUES('b l k h d n n n m i', 'p t i a r b t q o l'); + INSERT INTO t2 VALUES('k r i l j b g i p a', 't q c h a i m g n l'); + INSERT INTO t2 VALUES('a e c q n m o m d g', 'l c t g i s q g q e'); + INSERT INTO t2 VALUES('b o j h f o g b p e', 'r t l h s b g i c p'); + INSERT INTO t2 VALUES('s q k f q b j g h f', 'n m a o p e i e k t'); + INSERT INTO t2 VALUES('o q g g q c o k a b', 'r t k p t f t h p c'); +} + +proc firstinst {cmd} { + foreach {p c o} [$cmd xInst 0] {} + expr $c*100 + $o +} +sqlite3_fts5_create_function db firstinst firstinst + +do_execsql_test 4.1.1 { + SELECT rowid, firstinst(t2) FROM t2 WHERE t2 MATCH 'a' ORDER BY rowid ASC +} { + 1 0 2 4 3 6 5 103 + 6 9 7 0 9 102 10 8 +} + +do_execsql_test 4.1.2 { + SELECT rowid, rank FROM t2 + WHERE t2 MATCH 'a' AND rank MATCH 'firstinst()' + ORDER BY rowid ASC +} { + 1 0 2 4 3 6 5 103 + 6 9 7 0 9 102 10 8 +} + +do_execsql_test 4.1.3 { + SELECT rowid, rank FROM t2 + WHERE t2 MATCH 'a' AND rank MATCH 'firstinst()' + ORDER BY rank DESC +} { + 5 103 9 102 6 9 10 8 3 6 2 4 1 0 7 0 +} + +do_execsql_test 4.1.4 { + INSERT INTO t2(t2, rank) VALUES('rank', 'firstinst()'); + SELECT rowid, rank FROM t2 WHERE t2 MATCH 'a' ORDER BY rowid ASC +} { + 1 0 2 4 3 6 5 103 + 6 9 7 0 9 102 10 8 +} + +do_execsql_test 4.1.5 { + SELECT rowid, rank FROM t2 WHERE t2 MATCH 'a' ORDER BY rank DESC +} { + 5 103 9 102 6 9 10 8 3 6 2 4 1 0 7 0 +} + +do_execsql_test 4.1.6 { + INSERT INTO t2(t2, rank) VALUES('rank', 'firstinst ( ) '); + SELECT rowid, rank FROM t2 WHERE t2 MATCH 'a' ORDER BY rank DESC +} { + 5 103 9 102 6 9 10 8 3 6 2 4 1 0 7 0 +} + +proc rowidplus {cmd ival} { + expr [$cmd xRowid] + $ival +} +sqlite3_fts5_create_function db rowidplus rowidplus + +if {[detail_is_full]} { + do_execsql_test 4.2.1 { + INSERT INTO t2(t2, rank) VALUES('rank', 'rowidplus(100) '); + SELECT rowid, rank FROM t2 WHERE t2 MATCH 'o + q + g' + } { + 10 110 + } + do_execsql_test 4.2.2 { + INSERT INTO t2(t2, rank) VALUES('rank', 'rowidplus(111) '); + SELECT rowid, rank FROM t2 WHERE t2 MATCH 'o + q + g' + } { + 10 121 + } + + do_execsql_test 4.2.3 { + SELECT rowid, rank FROM t2 + WHERE t2 MATCH 'o + q + g' AND rank MATCH 'rowidplus(112)' + } { + 10 122 + } +} + +proc rowidmod {cmd imod} { + expr [$cmd xRowid] % $imod +} +sqlite3_fts5_create_function db rowidmod rowidmod +do_execsql_test 4.3.1 { + CREATE VIRTUAL TABLE t3 USING fts5(x, detail=%DETAIL%); + INSERT INTO t3 VALUES('a one'); + INSERT INTO t3 VALUES('a two'); + INSERT INTO t3 VALUES('a three'); + INSERT INTO t3 VALUES('a four'); + INSERT INTO t3 VALUES('a five'); + INSERT INTO t3(t3, rank) VALUES('rank', 'bm25()'); +} + +do_execsql_test 4.3.2 { + SELECT * FROM t3 + WHERE t3 MATCH 'a' AND rank MATCH 'rowidmod(4)' + ORDER BY rank ASC +} { + {a four} {a one} {a five} {a two} {a three} +} + +do_execsql_test 4.3.3 { + SELECT *, rank FROM t3 + WHERE t3 MATCH 'a' AND rank MATCH 'rowidmod(3)' + ORDER BY rank ASC +} { + {a three} 0 {a one} 1 {a four} 1 {a two} 2 {a five} 2 +} + +do_execsql_test 4.3.4 { + SELECT * FROM t3('a', 'rowidmod(4)') ORDER BY rank ASC; +} { + {a four} {a one} {a five} {a two} {a three} +} + +do_execsql_test 4.3.5 { + SELECT *, rank FROM t3('a', 'rowidmod(3)') ORDER BY rank ASC +} { + {a three} 0 {a one} 1 {a four} 1 {a two} 2 {a five} 2 +} + +do_catchsql_test 4.4.3 { + SELECT *, rank FROM t3 WHERE t3 MATCH 'a' AND rank MATCH 'xyz(3)' +} {1 {no such function: xyz}} +do_catchsql_test 4.4.4 { + SELECT *, rank FROM t3 WHERE t3 MATCH 'a' AND rank MATCH NULL +} {1 {parse error in rank function: }} + +} ;# foreach_detail_mode + + +finish_test + diff --git a/ext/fts5/test/fts5alter.test b/ext/fts5/test/fts5alter.test new file mode 100644 index 0000000..eae01b7 --- /dev/null +++ b/ext/fts5/test/fts5alter.test @@ -0,0 +1,103 @@ +# 2015 Jun 10 +# +# 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. +# +#*********************************************************************** +# +# The tests in this file focus on renaming FTS5 tables using the +# "ALTER TABLE ... RENAME TO ..." command +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5alter + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +#------------------------------------------------------------------------- +# Test renaming regular, contentless and columnsize=0 FTS5 tables. +# +do_execsql_test 1.1.0 { + CREATE VIRTUAL TABLE "a x" USING fts5(a, x); + INSERT INTO "a x" VALUES('a a a', 'x x x'); + ALTER TABLE "a x" RENAME TO "x y"; +} +do_execsql_test 1.1.1 { + SELECT * FROM "x y"; + SELECT rowid FROM "x y" WHERE "x y" MATCH 'a' +} {{a a a} {x x x} 1} + +do_execsql_test 1.2.0 { + CREATE VIRTUAL TABLE "one/two" USING fts5(one, columnsize=0); + INSERT INTO "one/two"(rowid, one) VALUES(456, 'd d d'); + ALTER TABLE "one/two" RENAME TO "three/four"; +} +do_execsql_test 1.2.1 { + SELECT * FROM "three/four"; + SELECT rowid FROM "three/four" WHERE "three/four" MATCH 'd' +} {{d d d} 456} + +do_execsql_test 1.3.0 { + CREATE VIRTUAL TABLE t1 USING fts5(val, content=''); + INSERT INTO t1(rowid, val) VALUES(-1, 'drop table'); + INSERT INTO t1(rowid, val) VALUES(-2, 'drop view'); + ALTER TABLE t1 RENAME TO t2; +} +do_execsql_test 1.3.1 { + SELECT rowid, * FROM t2; + SELECT rowid FROM t2 WHERE t2 MATCH 'table' +} {-2 {} -1 {} -1} + +#------------------------------------------------------------------------- +# Test renaming an FTS5 table within a transaction. +# +do_execsql_test 2.1 { + CREATE VIRTUAL TABLE zz USING fts5(a); + INSERT INTO zz(rowid, a) VALUES(-56, 'a b c'); + BEGIN; + INSERT INTO zz(rowid, a) VALUES(-22, 'a b c'); + ALTER TABLE zz RENAME TO yy; + SELECT rowid FROM yy WHERE yy MATCH 'a + b + c'; + COMMIT; +} {-56 -22} + +do_execsql_test 2.2 { + BEGIN; + ALTER TABLE yy RENAME TO ww; + INSERT INTO ww(rowid, a) VALUES(-11, 'a b c'); + SELECT rowid FROM ww WHERE ww MATCH 'a + b + c'; +} {-56 -22 -11} + +do_execsql_test 2.3 { + ROLLBACK; + SELECT rowid FROM yy WHERE yy MATCH 'a + b + c'; +} {-56 -22} + +#------------------------------------------------------------------------- + +do_execsql_test 3.1 { + CREATE VIRTUAL TABLE abc USING fts5(a); + INSERT INTO abc(rowid, a) VALUES(1, 'a'); + BEGIN; + INSERT INTO abc(rowid, a) VALUES(2, 'a'); +} +breakpoint +do_execsql_test 3.2 { + SELECT rowid FROM abc WHERE abc MATCH 'a'; +} {1 2} + +do_execsql_test 3.3 { + COMMIT; + SELECT rowid FROM abc WHERE abc MATCH 'a'; +} {1 2} + +finish_test + diff --git a/ext/fts5/test/fts5auto.test b/ext/fts5/test/fts5auto.test new file mode 100644 index 0000000..218b3f4 --- /dev/null +++ b/ext/fts5/test/fts5auto.test @@ -0,0 +1,345 @@ +# 2015 May 30 +# +# 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 contains automatically generated tests for various types +# of MATCH expressions. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5auto + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +set data { + -4026076 + {n x w k b p x b n t t d s} {f j j s p j o} + {w v i y r} {i p y s} + {a o q v e n q r} {q v g u c y a z y} + 3995120 + {c} {e e w d t} + {x c p f w r s m l r b f d} {g g u e} + {s n u t d v p d} {b k v p m f} + -2913881 + {k m} {a} + {w r j z n s l} {m j i w d t w e l} + {z n c} {v f b m} + 174082 + {j} {q l w u k e q v r i} + {j l} {u v w r s p e l} + {p i k j k q c t g u s} {g u y s m h q k g t e s o r} + 3207399 + {e t} {} + {p} {y v r b e k h d e v} + {t m w z b g q t s d d h} {o n v u i t o y k j} + 182399 + {} {m o s o x d y f a x j z} + {x n z r c d} {n r x i r} + {s v s} {a u} + 768994 + {e u t q v z q k j p u f j p} {y c b} + {p s d} {k n w p m p p} + {u o x s d} {f s g r d b d r m m m z y} + 3931037 + {c j p x e} {c n k t h z o i} + {} {r r p j k x w q} + {o r d z d} {x} + 3105748 + {p x r u} {x i s w o t o g x m z i w} + {q x m z} {h c j w b l y w x c o} + {m b k v} {t v q i s a d x} + -2501642 + {o u d n w o m o o s n t r h} {k p e u y p e z d j r y g} + {v b b h d d q y j q j} {a m w d t} + {y e f n} {a k x i x} + -1745680 + {z u w j f d b f} {j w i c g u d w e} + {m f p v m a s p v c o s} {s c r z o t w l b e a q} + {m k q} {k b a v o} + -932328 + {r v i u m q d r} {f z u v h c m r f g} + {r x r} {k p i d h h w h z u a x} + {k m j p} {h l j a e u c i q x x f x g} + -3923818 + {t t p b n u i h e c k} {m z} + {v u d c} {v y y j s g} + {o a f k k q p h g x e n z x} {h d w c o l} + -2145922 + {z z l f a l g e d c d h} {j b j p k o o u b q} + {d i g q t f d r h k} {n w g j c x r p t y f l c t} + {d o c u k f o} {r y s x z s p p h g t p y c} + 4552917 + {j w j y h l k u} {n a} + {y h w c n k} {b} + {w} {z l r t s i m v c y} + 2292008 + {q v q j w y y x u t} {r q z n h a b o} + {d q y} {y v o e j} + {} {a b h c d l p d x} + 1407892 + {n j j u q d o a u c f} {r d b w o q n g} + {d e v w s} {v d v o u o x s l s j z y} + {j y w h i f g i h m} {v n z b n y} + -4412544 + {g h h r s} {h e r e} + {n q s} {o p z r m l l t} + {p} {f s u o b j} + 1209110 + {o a a z t t u h j} {z z i r k r} + {i c x q w g v o x z i z p} {q o g k i n z x e d v w v} + {p f v b g f e d n p u c y k} {q z z a i p a a s r e z} + 3448977 + {i v} {l u x t b o k} + {f h u v p} {k a o y j} + {d m k c j} {v c e r u e f i t} + -4703774 + {d h v w u z r e h x o l t} {p s f y w y r q d a m w} + {c h g c g j j f t b i c q} {s e} + {c t q j g f} {v n r w y r a g e j d} + 2414151 + {s o o s d s k q b f q v p e} {j r o b t o p d l o o x} + {d d k t v e} {} + {t v o d w} {w e q w h y c y y i j b a m} + -3342407 + {m c h n e p d o c r w n t} {j d k s p q l} + {t g s r w x j l r z r} {h} + {r q v x i r a n h s} {m y p b v w r a u o g q r} + -993951 + {l n p u o j d x t u u c o j} {k r n a r e k v i t o e} + {q f t t a a c z v f} {o n m p v f o e n} + {h z h i p s b j z h} {i t w m k c u g n i} + 1575251 + {} {z s i j d o x j a r t} + {h g j u j n v e n z} {p z j n n f} + {s q q f d w r l y i z d o m} {b a n d h t b y g h d} + 4263668 + {q g t h f s} {s g x p f q z i s o f l i} + {q k} {w v h a x n a r b} + {m j a h o b i x k r w z q u} {m t r g j o e q t m p u l} + 2487819 + {m w g x r n e u t s r} {b x a t u u j c r n} + {j} {w f j r e e y l p} + {o u h b} {o c a c a b v} + 167966 + {o d b s d o a u m o x y} {c} + {r w d o b v} {z e b} + {i n z a f g z o} {m u b a g} + 1948599 + {n r g q d j s} {n k} + {l b p d v t k h y y} {u m k e c} + {t b n y o t b} {j w c i r x x} + 2941631 + {l d p l b g f} {e k e} + {p j} {m c s w t b k n l d x} + {f o v y v l} {c w p s w j w c u t y} + 3561104 + {d r j j r j i g p} {u} + {g r j q} {z l p d s n f c h t d c v z} + {w r c f s x z y} {g f o k g g} + -2223281 + {y e t j j z f p o m m z} {h k o g o} + {m x a t} {l q x l} + {r w k d l s y b} {q g k b} + -4502874 + {k k b x k l f} {r} + {} {q m z b k h k u n e z} + {z q g y m y u} {} + 1757599 + {d p z j y u r} {z p l q w j t j} + {n i r x r y j} {} + {h} {w t d q c x z z x e e} + -4809589 + {} {z p x u h i i n g} + {w q s u d b f x n} {l y k b b r x t i} + {n d v j q o t o d p z e} {u r y u v u c} + 1068408 + {y e} {e g s k e w t p v o b k} + {z c m s} {r u r u h n h b p q g b} + {j k b l} {m c d t s r s q a d b o f} + -1972554 + {m s w} {d k v s a r k p a r i v} + {g j z k p} {y k c v r e u o q f i b a} + {i p i} {c z w c y b n z i v} + -2052385 + {} {x e u f f g n c i x n e i e} + {} {p s w d x p g} + {} {s j a h n} + 2805981 + {m x g c w o e} {k g u y r y i u e g g} + {f k j v t x p h x k u} {w i} + {b l f z f v t n} {i u d o d p h s m u} + 2507621 + {} {u b n l x f n j t} + {u r x l h} {h r l m r} + {d y e n b s q v t k n q q} {x l t v w h a s k} + -3138375 + {e o f j y x u w v e w z} {r d q g k n n v r c z n e w} + {l y i q z k j p u f q s k} {c i l l i m a a g a z r x f} + {a v k h m q z b y n z} {q g w c y r r o a} + -457971 + {j x a w e c s h f l f} {q} + {j f v j u m d q r v v} {x n v a w} + {i e h d h f u w t t z} {v s u l s v o v i k n e} + 2265221 + {z t c y w n y r t} {n b a x s} + {q w a v} {a b s d x i g w t e z h} + {t l} {j k r w f f y j o k u} + -3941280 + {r x t o z} {f j n z k} + {t x e b t d b k w i s} {j t y h i h} + {y q g n g s u v c z j z n g} {n n g t l p h} + 2084745 + {z d z d} {j} + {o e k t b k a z l w} {o p i h k c x} + {c r b t i j f} {z e n m} + 1265843 + {} {j s g j j x u y} + {u q t f} {g o g} + {w o j e d} {w q n a c t q x j} + -2941116 + {i n c u o} {f b} + {o m s q d o z a q} {f s v o b b} + {o a z c h r} {j e w h b f z} + -1265441 + {p g z q v a o a x a} {s t h} + {w i p o c} {s n d g f z w q o d v v l j} + {y f b i a s v} {u m o z k k s t s d p b l p} + -1989158 + {r i c n} {r e w w i n z} + {q u s y b w u g y g f o} {y} + {d} {j x i b x u y d c p v a h} + 2391989 + {b n w x w f q h p i} {e u b b i n a i o c d g} + {v a z o i e n l x l r} {r u f o r k w m d w} + {k s} {r f e j q p w} +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE tt USING fts5(a, b, c, d, e, f); +} {} + +fts5_aux_test_functions db + +proc do_auto_test {tn tbl expr} { + foreach order {asc desc} { + set res [fts5_poslist_data $expr $tbl $order] + set testname "$tn.[string range $order 0 0].rows=[expr [llength $res]/2]" + + set ::autotest_expr $expr + do_execsql_test $testname [subst -novar { + SELECT rowid, fts5_test_poslist([set tbl]) FROM [set tbl] + WHERE [set tbl] MATCH $::autotest_expr ORDER BY rowid [set order] + }] $res + } +} + +#------------------------------------------------------------------------- +# + +for {set fold 0} {$fold < 3} {incr fold} { + switch $fold { + 0 { set map {} } + 1 { set map { + a a b a c b d b e c f c g d h d + i e j e k f l f m g g g o h p h + q i r i s j t j u k v k w l x l + y m z m + }} + + 2 { set map { + a a b a c a d a e a f a g a h a + i b j b k b l b m b g b o b p b + q c r c s c t c u c v c w c x c + }} + } + + execsql { + BEGIN; + DELETE FROM tt; + } + foreach {rowid a b c d e f} [string map $map $data] { + if {$rowid==-4703774} { + execsql { + INSERT INTO tt(rowid, a, b, c, d, e, f) + VALUES($rowid, $a, $b, $c, $d, $e, $f) + } + } + } + execsql COMMIT + + + foreach {tn expr} { + A.1 { {a} : x } + A.2 { {a b} : x } + A.3 { {a b f} : x } + A.4 { {f a b} : x } + A.5 { {f a b} : x y } + A.6 { {f a b} : x + y } + A.7 { {c a b} : x + c } + A.8 { {c d} : "l m" } + A.9 { {c e} : "l m" } + A.10 { {a b c a b c a b c f f e} : "l m" } + + B.1 { a NOT b } + B.2 { a NOT a:b } + B.3 { a OR (b AND c) } + B.4 { a OR (b AND {a b c}:c) } + B.5 { a OR "b c" } + B.6 { a OR b OR c } + + C.1 { a OR (b AND "b c") } + C.2 { a OR (b AND "z c") } + } { + do_auto_test 3.$fold.$tn tt $expr + } +} + +proc replace_elems {list args} { + set ret $list + foreach {idx elem} $args { + set ret [lreplace $ret $idx $idx $elem] + } + set ret +} + +#------------------------------------------------------------------------- +# +set bigdoc [string trim [string repeat "a " 1000]] +do_test 4.0 { + set a [replace_elems $bigdoc 50 x 950 x] + set b [replace_elems $bigdoc 20 y 21 x 887 x 888 y] + set c [replace_elems $bigdoc 1 z 444 z 789 z] + execsql { + CREATE VIRTUAL TABLE yy USING fts5(c1, c2, c3); + INSERT INTO yy(rowid, c1, c2, c3) VALUES(-56789, $a, $b, $c); + INSERT INTO yy(rowid, c1, c2, c3) VALUES(250, $a, $b, $c); + } +} {} + +foreach {tn expr} { + 1 x + 2 y + 3 z + + 4 {c1 : x} 5 {c2 : x} 6 {c3 : x} + 7 {c1 : y} 8 {c2 : y} 9 {c3 : y} + 10 {c1 : z} 11 {c2 : z} 12 {c3 : z} +} { + do_auto_test 4.$tn yy $expr +} + + + +finish_test + diff --git a/ext/fts5/test/fts5aux.test b/ext/fts5/test/fts5aux.test new file mode 100644 index 0000000..995fe85 --- /dev/null +++ b/ext/fts5/test/fts5aux.test @@ -0,0 +1,250 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Tests focusing on the auxiliary function APIs. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5aux + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +proc inst {cmd i} { + $cmd xInst $i +} +sqlite3_fts5_create_function db inst inst + +proc colsize {cmd i} { + $cmd xColumnSize $i +} +sqlite3_fts5_create_function db colsize colsize + +proc totalsize {cmd i} { + $cmd xColumnTotalSize $i +} +sqlite3_fts5_create_function db totalsize totalsize + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE f1 USING fts5(a, b); + INSERT INTO f1 VALUES('one two', 'two one zero'); + INSERT INTO f1 VALUES('one one', 'one one one'); +} + +do_catchsql_test 1.1 { + SELECT inst(f1, -1) FROM f1 WHERE f1 MATCH 'two'; +} {1 SQLITE_RANGE} +do_catchsql_test 1.2 { + SELECT inst(f1, 0) FROM f1 WHERE f1 MATCH 'two'; +} {0 {{0 0 1}}} +do_catchsql_test 1.3 { + SELECT inst(f1, 1) FROM f1 WHERE f1 MATCH 'two'; +} {0 {{0 1 0}}} +do_catchsql_test 1.4 { + SELECT inst(f1, 2) FROM f1 WHERE f1 MATCH 'two'; +} {1 SQLITE_RANGE} + +do_catchsql_test 2.1 { + SELECT colsize(f1, 2) FROM f1 WHERE f1 MATCH 'two'; +} {1 SQLITE_RANGE} +do_execsql_test 2.2 { + SELECT colsize(f1, 0), colsize(f1, 1) FROM f1 WHERE f1 MATCH 'zero'; +} {2 3} +do_execsql_test 2.3 { + SELECT colsize(f1, -1) FROM f1 WHERE f1 MATCH 'zero'; +} {5} + +do_execsql_test 2.4.1 { + SELECT totalsize(f1, -1) FROM f1 WHERE f1 MATCH 'zero'; +} {10} +do_execsql_test 2.4.2 { + SELECT totalsize(f1, 0) FROM f1 WHERE f1 MATCH 'zero'; +} {4} +do_execsql_test 2.4.3 { + SELECT totalsize(f1, 1) FROM f1 WHERE f1 MATCH 'zero'; +} {6} +do_catchsql_test 2.4.4 { + SELECT totalsize(f1, 2) FROM f1 WHERE f1 MATCH 'zero'; +} {1 SQLITE_RANGE} + +#------------------------------------------------------------------------- +# Test the xSet and xGetAuxdata APIs with a NULL destructor. +# +proc prevrowid {add cmd} { + set res [$cmd xGetAuxdataInt 0] + set r [$cmd xRowid] + $cmd xSetAuxdataInt $r + return [expr $res + $add] +} +sqlite3_fts5_create_function db prevrowid [list prevrowid 0] +sqlite3_fts5_create_function db prevrowid1 [list prevrowid 1] + +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE e5 USING fts5(x); + INSERT INTO e5 VALUES('a b c'); + INSERT INTO e5 VALUES('d e f'); + INSERT INTO e5 VALUES('a b c'); + INSERT INTO e5 VALUES('d e f'); + INSERT INTO e5 VALUES('a b c'); +} + +do_execsql_test 3.1 { + SELECT prevrowid(e5) || '+' || rowid FROM e5 WHERE e5 MATCH 'c' +} {0+1 1+3 3+5} + +do_execsql_test 3.2 { + SELECT prevrowid(e5) || '+' || prevrowid1(e5) || '+' || rowid + FROM e5 WHERE e5 MATCH 'e' +} {0+1+2 2+3+4} + +#------------------------------------------------------------------------- +# Test that if the xQueryPhrase callback returns other than SQLITE_OK, +# the query is abandoned. And that if it returns an error code other than +# SQLITE_DONE, the error is propagated back to the caller. +# +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE e7 USING fts5(x); + INSERT INTO e7 VALUES('a x a'); + INSERT INTO e7 VALUES('b x b'); + INSERT INTO e7 VALUES('c x c'); + INSERT INTO e7 VALUES('d x d'); + INSERT INTO e7 VALUES('e x e'); +} + +proc xCallback {rowid code cmd} { + set r [$cmd xRowid] + lappend ::cb $r + if {$r==$rowid} { return $code } + return "" +} + +proc phrasequery {cmd code} { + set ::cb [list] + $cmd xQueryPhrase 1 [list xCallback [$cmd xRowid] $code] + set ::cb +} + +sqlite3_fts5_create_function db phrasequery phrasequery + +do_execsql_test 4.1 { + SELECT phrasequery(e7, 'SQLITE_OK') FROM e7 WHERE e7 MATCH 'c x' +} {{1 2 3 4 5}} + +do_execsql_test 4.2 { + SELECT phrasequery(e7, 'SQLITE_DONE') FROM e7 WHERE e7 MATCH 'c x' +} {{1 2 3}} + +do_catchsql_test 4.3 { + SELECT phrasequery(e7, 'SQLITE_ERROR') FROM e7 WHERE e7 MATCH 'c x' +} {1 SQLITE_ERROR} + +#------------------------------------------------------------------------- +# Auxiliary function calls with many cursors in the global cursor list. +# +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE e9 USING fts5(y); + INSERT INTO e9(rowid, y) VALUES(1, 'i iii'); + INSERT INTO e9(rowid, y) VALUES(2, 'ii iv'); + INSERT INTO e9(rowid, y) VALUES(3, 'ii'); + INSERT INTO e9(rowid, y) VALUES(4, 'i iv'); + INSERT INTO e9(rowid, y) VALUES(5, 'iii'); +} + +proc my_rowid {cmd} { $cmd xRowid } +sqlite3_fts5_create_function db my_rowid my_rowid + +foreach {var q} { + s1 i + s2 ii + s3 iii + s4 iv +} { + set sql "SELECT my_rowid(e9) FROM e9 WHERE e9 MATCH '$q'" + set $var [sqlite3_prepare db $sql -1 dummy] +} + +do_test 5.1.1 { sqlite3_step $s1 ; sqlite3_column_int $s1 0 } 1 +do_test 5.1.2 { sqlite3_step $s2 ; sqlite3_column_int $s2 0 } 2 +do_test 5.1.3 { sqlite3_step $s3 ; sqlite3_column_int $s3 0 } 1 +do_test 5.1.4 { sqlite3_step $s4 ; sqlite3_column_int $s4 0 } 2 + +do_test 5.2.1 { sqlite3_step $s1 ; sqlite3_column_int $s1 0 } 4 +do_test 5.2.2 { sqlite3_step $s2 ; sqlite3_column_int $s2 0 } 3 +do_test 5.2.3 { sqlite3_step $s3 ; sqlite3_column_int $s3 0 } 5 +do_test 5.2.4 { sqlite3_step $s4 ; sqlite3_column_int $s4 0 } 4 + +sqlite3_finalize $s1 +sqlite3_finalize $s2 +sqlite3_finalize $s3 +sqlite3_finalize $s4 + +#------------------------------------------------------------------------- +# Passing an invalid first argument to an auxiliary function is detected. +# +do_execsql_test 6.0 { + CREATE VIRTUAL TABLE e11 USING fts5(y, z); + INSERT INTO e11(rowid, y, z) VALUES(1, 'a b', 45); + INSERT INTO e11(rowid, y, z) VALUES(2, 'b c', 46); +} + +do_catchsql_test 6.1 { + SELECT my_rowid(z) FROM e11 WHERE e11 MATCH 'b' +} {1 {no such cursor: 45}} + +do_catchsql_test 6.2 { + SELECT my_rowid(y) FROM e11 WHERE e11 MATCH 'b' +} {1 {no such cursor: 0}} + +#------------------------------------------------------------------------- +# Test passing an out-of-range phrase number to xPhraseSize (should +# return 0). +# +proc my_phrasesize {cmd iPhrase} { $cmd xPhraseSize $iPhrase } +sqlite3_fts5_create_function db my_phrasesize my_phrasesize + +do_execsql_test 7.1 { + CREATE VIRTUAL TABLE t1 USING fts5(a); + INSERT INTO t1 VALUES('a b c'); +} +do_execsql_test 7.2 { + SELECT + my_phrasesize(t1, -1), + my_phrasesize(t1, 0), + my_phrasesize(t1, 1), + my_phrasesize(t1, 2) + FROM t1 WHERE t1 MATCH 'a OR b+c' +} {0 1 2 0} + +#------------------------------------------------------------------------- +# +do_execsql_test 8.0 { + CREATE VIRTUAL TABLE x1 USING fts5(a); +} + +foreach {tn lRow res} { + 4 {"a a a" "b" "a d"} {"[a] [a] [a]" "[a] d"} + 1 {"b d" "a b"} {"[b] [d]" "[a] b"} + 2 {"d b" "a d"} {"[d] [b]" "[a] d"} + 3 {"a a d"} {"[a] [a] d"} +} { + execsql { DELETE FROM x1 } + foreach row $lRow { execsql { INSERT INTO x1 VALUES($row) } } + breakpoint + do_execsql_test 8.$tn { + SELECT highlight(x1, 0, '[', ']') FROM x1 WHERE x1 MATCH 'a OR (b AND d)'; + } $res +} + +finish_test + diff --git a/ext/fts5/test/fts5auxdata.test b/ext/fts5/test/fts5auxdata.test new file mode 100644 index 0000000..dbbb1db --- /dev/null +++ b/ext/fts5/test/fts5auxdata.test @@ -0,0 +1,115 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Tests focusing on the fts5 xSetAuxdata() and xGetAuxdata() APIs. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5auxdata + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE f1 USING fts5(a, b); + INSERT INTO f1(rowid, a, b) VALUES(1, 'a', 'b1'); + INSERT INTO f1(rowid, a, b) VALUES(2, 'a', 'b2'); + INSERT INTO f1(rowid, a, b) VALUES(3, 'a', 'b3'); + INSERT INTO f1(rowid, a, b) VALUES(4, 'a', 'b4'); + INSERT INTO f1(rowid, a, b) VALUES(5, 'a', 'b5'); +} + +proc aux_function_1 {cmd tn} { + switch [$cmd xRowid] { + 1 { + do_test $tn.1 [list $cmd xGetAuxdata 0 ] {} + $cmd xSetAuxdata "one" + } + + 2 { + do_test $tn.2 [list $cmd xGetAuxdata 0 ] {one} + $cmd xSetAuxdata "two" + } + + 3 { + do_test $tn.3 [list $cmd xGetAuxdata 0 ] {two} + } + + 4 { + do_test $tn.4 [list $cmd xGetAuxdata 1 ] {two} + } + + 5 { + do_test $tn.5 [list $cmd xGetAuxdata 0 ] {} + } + } +} + +sqlite3_fts5_create_function db aux_function_1 aux_function_1 +db eval { + SELECT aux_function_1(f1, 1) FROM f1 WHERE f1 MATCH 'a' + ORDER BY rowid ASC +} + +proc aux_function_2 {cmd tn inst} { + if {$inst == "A"} { + switch [$cmd xRowid] { + 1 { + do_test $tn.1.$inst [list $cmd xGetAuxdata 0 ] {} + $cmd xSetAuxdata "one $inst" + } + 2 { + do_test $tn.2.$inst [list $cmd xGetAuxdata 0 ] "one $inst" + $cmd xSetAuxdata "two $inst" + } + 3 { + do_test $tn.3.$inst [list $cmd xGetAuxdata 0 ] "two $inst" + } + 4 { + do_test $tn.4.$inst [list $cmd xGetAuxdata 1 ] "two $inst" + } + 5 { + do_test $tn.5.$inst [list $cmd xGetAuxdata 0 ] {} + } + } + } else { + switch [$cmd xRowid] { + 1 { + do_test $tn.1.$inst [list $cmd xGetAuxdata 0 ] "one A" + } + 2 { + do_test $tn.2.$inst [list $cmd xGetAuxdata 0 ] "two A" + } + 3 { + do_test $tn.3.$inst [list $cmd xGetAuxdata 0 ] "two A" + } + 4 { + do_test $tn.4.$inst [list $cmd xGetAuxdata 0 ] {} + } + 5 { + do_test $tn.5.$inst [list $cmd xGetAuxdata 0 ] {} + } + } + } +} + +sqlite3_fts5_create_function db aux_function_2 aux_function_2 +db eval { + SELECT aux_function_2(f1, 2, 'A'), aux_function_2(f1, 2, 'B') + FROM f1 WHERE f1 MATCH 'a' + ORDER BY rowid ASC +} + +finish_test + diff --git a/ext/fts5/test/fts5bigpl.test b/ext/fts5/test/fts5bigpl.test new file mode 100644 index 0000000..85f7460 --- /dev/null +++ b/ext/fts5/test/fts5bigpl.test @@ -0,0 +1,64 @@ +# 2015 April 21 +# +# 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 test is focused on really large position lists. Those that require +# 4 or 5 byte position-list size varints. Because of the amount of memory +# required, these tests only run on 64-bit platforms. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5bigpl + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +if { $tcl_platform(wordSize)<8 } { + finish_test + return +} + +do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts5(x) } + +do_test 1.1 { + foreach t {a b c d e f g h i j} { + set doc [string repeat "$t " 1200000] + execsql { INSERT INTO t1 VALUES($doc) } + } + execsql { INSERT INTO t1(t1) VALUES('integrity-check') } +} {} + +do_test 1.2 { + execsql { DELETE FROM t1 } + foreach t {"a b" "b a" "c d" "d c"} { + set doc [string repeat "$t " 600000] + execsql { INSERT INTO t1 VALUES($doc) } + } + execsql { INSERT INTO t1(t1) VALUES('integrity-check') } +} {} + + +# 5-byte varint. This test takes 30 seconds or so on a 2014 workstation. +# The generated database is roughly 635MiB. +# +do_test 2.1...slow { + execsql { DELETE FROM t1 } + foreach t {a} { + set doc [string repeat "$t " 150000000] + execsql { INSERT INTO t1 VALUES($doc) } + } + execsql { INSERT INTO t1(t1) VALUES('integrity-check') } +} {} + +finish_test + diff --git a/ext/fts5/test/fts5bigtok.test b/ext/fts5/test/fts5bigtok.test new file mode 100644 index 0000000..2267be5 --- /dev/null +++ b/ext/fts5/test/fts5bigtok.test @@ -0,0 +1,67 @@ +# 2016 Jan 19 +# +# 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 FTS5 module. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5bigtok + +proc rndterm {} { + set L [list a b c d e f g h i j k l m n o p q r s t u v w x y z] + set l [lindex $L [expr int(rand() * [llength $L])]] + string repeat $l [expr int(rand() * 5) + 60] +} + +proc rnddoc {n} { + set res [list] + for {set i 0} {$i < $n} {incr i} { + lappend res [rndterm] + } + set res +} + +foreach_detail_mode $::testprefix { + db func rnddoc rnddoc + do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + CREATE VIRTUAL TABLE t1vocab USING fts5vocab(t1, row); + + WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10 ) + INSERT INTO t1 SELECT rnddoc(3) FROM s; + + WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10 ) + INSERT INTO t1 SELECT rnddoc(3) FROM s; + } + + foreach v [db eval {SELECT term FROM t1vocab}] { + set res [db eval {SELECT rowid FROM t1($v)}] + do_execsql_test 1.[string range $v 0 0] { + SELECT rowid FROM t1($v) ORDER BY rowid DESC + } [lsort -integer -decr $res] + } + + do_execsql_test 2.0 { + INSERT INTO t1(t1) VALUES('optimize'); + } + + foreach v [db eval {SELECT term FROM t1vocab}] { + set res [db eval {SELECT rowid FROM t1($v)}] + do_execsql_test 2.[string range $v 0 0] { + SELECT rowid FROM t1($v) ORDER BY rowid DESC + } [lsort -integer -decr $res] + } +} + +finish_test + + diff --git a/ext/fts5/test/fts5columnsize.test b/ext/fts5/test/fts5columnsize.test new file mode 100644 index 0000000..dec9b58 --- /dev/null +++ b/ext/fts5/test/fts5columnsize.test @@ -0,0 +1,151 @@ +# 2015 Jun 10 +# +# 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. +# +#*********************************************************************** +# +# Tests focusing on fts5 tables with the columnsize=0 option. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5columnsize + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +#------------------------------------------------------------------------- +# Check that the option can be parsed and that the %_docsize table is +# only created if it is set to true. +# +foreach {tn outcome stmt} { + 1 0 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize=0) } + 2 1 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize=1) } + 3 0 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize='0') } + 4 1 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize='1') } + 5 2 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize='') } + 6 2 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize=2) } + 7 1 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize=0, columnsize=1) } + 8 1 { CREATE VIRTUAL TABLE t1 USING fts5(x) } + 9 2 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize=11) } +} { + execsql { + DROP TABLE IF EXISTS t1; + } + if {$outcome==2} { + do_catchsql_test 1.$tn.1 $stmt {1 {malformed columnsize=... directive}} + } else { + do_execsql_test 1.$tn.2 $stmt + do_execsql_test 1.$tn.3 { + SELECT count(*) FROM sqlite_master WHERE name = 't1_docsize' + } $outcome + } +} + +#------------------------------------------------------------------------- +# Run tests on a table with no %_content or %_docsize backing store. +# +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE t2 USING fts5(x, columnsize=0, content=''); +} +do_catchsql_test 2.1 { + INSERT INTO t2 VALUES('a b c d e f'); +} {1 {datatype mismatch}} +do_execsql_test 2.2 { + INSERT INTO t2(rowid, x) VALUES(1, 'c d e f'); + INSERT INTO t2(rowid, x) VALUES(2, 'c d e f g h'); + INSERT INTO t2(rowid, x) VALUES(3, 'a b c d e f g h'); +} {} +do_execsql_test 2.3 { + SELECT rowid FROM t2 WHERE t2 MATCH 'b'; SELECT '::'; + SELECT rowid FROM t2 WHERE t2 MATCH 'e'; SELECT '::'; + SELECT rowid FROM t2 WHERE t2 MATCH 'h'; +} {3 :: 1 2 3 :: 2 3} +do_execsql_test 2.4 { + INSERT INTO t2(t2, rowid, x) VALUES('delete', 2, 'c d e f g h'); + SELECT rowid FROM t2 WHERE t2 MATCH 'b'; SELECT '::'; + SELECT rowid FROM t2 WHERE t2 MATCH 'e'; SELECT '::'; + SELECT rowid FROM t2 WHERE t2 MATCH 'h'; +} {3 :: 1 3 :: 3} +do_execsql_test 2.5 { + INSERT INTO t2(t2) VALUES('delete-all'); + SELECT rowid FROM t2 WHERE t2 MATCH 'b'; SELECT '::'; + SELECT rowid FROM t2 WHERE t2 MATCH 'e'; SELECT '::'; + SELECT rowid FROM t2 WHERE t2 MATCH 'h'; +} {:: ::} +do_execsql_test 2.6 { + INSERT INTO t2(rowid, x) VALUES(1, 'o t t f'); + INSERT INTO t2(rowid, x) VALUES(2, 'f s s e'); + INSERT INTO t2(rowid, x) VALUES(3, 'n t e t'); +} + +do_catchsql_test 2.7.1 { + SELECT rowid FROM t2 +} {1 {t2: table does not support scanning}} +do_catchsql_test 2.7.2 { + SELECT rowid FROM t2 WHERE rowid=2 +} {1 {t2: table does not support scanning}} +do_catchsql_test 2.7.3 { + SELECT rowid FROM t2 WHERE rowid BETWEEN 1 AND 3 +} {1 {t2: table does not support scanning}} + +do_execsql_test 2.X { + DROP TABLE t2 +} + +#------------------------------------------------------------------------- +# Test the xColumnSize() API +# +fts5_aux_test_functions db + +do_execsql_test 3.1.0 { + CREATE VIRTUAL TABLE t3 USING fts5(x, y UNINDEXED, z, columnsize=0); + INSERT INTO t3 VALUES('a a', 'b b b', 'c'); + INSERT INTO t3 VALUES('x a x', 'b b b y', ''); +} +do_execsql_test 3.1.1 { + SELECT rowid, fts5_test_columnsize(t3) FROM t3 WHERE t3 MATCH 'a' +} { + 1 {2 0 1} 2 {3 0 0} +} +do_execsql_test 3.1.2 { + INSERT INTO t3 VALUES(NULL, NULL, 'a a a a'); + DELETE FROM t3 WHERE rowid = 1; + SELECT rowid, fts5_test_columnsize(t3) FROM t3 WHERE t3 MATCH 'a' +} { + 2 {3 0 0} 3 {0 0 4} +} + +do_execsql_test 3.2.0 { + CREATE VIRTUAL TABLE t4 USING fts5(x, y UNINDEXED, z, columnsize=0, content=''); + INSERT INTO t4(rowid, x, y, z) VALUES(1, 'a a', 'b b b', 'c'); + INSERT INTO t4(rowid, x, y, z) VALUES(2, 'x a x', 'b b b y', ''); +} +do_execsql_test 3.2.1 { + SELECT rowid, fts5_test_columnsize(t4) FROM t4 WHERE t4 MATCH 'a' +} { + 1 {-1 0 -1} 2 {-1 0 -1} +} + +#------------------------------------------------------------------------- +# Test the integrity-check +# +do_execsql_test 4.1.1 { + CREATE VIRTUAL TABLE t5 USING fts5(x, columnsize=0); + INSERT INTO t5 VALUES('1 2 3 4'); + INSERT INTO t5 VALUES('2 4 6 8'); +} + +breakpoint +do_execsql_test 4.1.2 { + INSERT INTO t5(t5) VALUES('integrity-check'); +} + +finish_test diff --git a/ext/fts5/test/fts5config.test b/ext/fts5/test/fts5config.test new file mode 100644 index 0000000..c30a597 --- /dev/null +++ b/ext/fts5/test/fts5config.test @@ -0,0 +1,251 @@ +# 2015 Jan 13 +# +# 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 focuses on the code in fts5_config.c, which is largely concerned +# with parsing the various configuration and CREATE TABLE options. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5config + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +#------------------------------------------------------------------------- +# Try different types of quote characters. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5('a', "b", [c], `d`); + PRAGMA table_info = t1; +} { + 0 a {} 0 {} 0 + 1 b {} 0 {} 0 + 2 c {} 0 {} 0 + 3 d {} 0 {} 0 +} + +#------------------------------------------------------------------------- +# Syntax errors in the prefix= option. +# +foreach {tn opt} { + 1 {prefix=x} + 2 {prefix='x'} + 3 {prefix='$'} + 4 {prefix='1,2,'} + 5 {prefix=',1'} + 6 {prefix='1,2,3...'} + 7 {prefix='1,2,3xyz'} +} { + set res [list 1 {malformed prefix=... directive}] + do_catchsql_test 2.$tn "CREATE VIRTUAL TABLE f1 USING fts5(x, $opt)" $res +} + +#------------------------------------------------------------------------- +# Syntax errors in the 'rank' option. +# +foreach {tn val} { + 1 "f1(xyz)" + 2 "f1(zyx)" + 3 "f1(nzz)" + 4 "f1(x'!!')" + 5 "f1(x':;')" + 6 "f1(x'[]')" + 7 "f1(x'{}')" + 8 "f1('abc)" +} { + do_catchsql_test 3.$tn { + INSERT INTO t1(t1, rank) VALUES('rank', $val); + } {1 {SQL logic error or missing database}} +} + +#------------------------------------------------------------------------- +# The parsing of SQL literals specified as part of 'rank' options. +# +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE zzz USING fts5(one); + INSERT INTO zzz VALUES('a b c'); +} +proc first {cmd A} { return $A } +sqlite3_fts5_create_function db first first + +foreach {tn arg} { + 1 "123" + 2 "'01234567890ABCDEF'" + 3 "x'0123'" + 4 "x'ABCD'" + 5 "x'0123456789ABCDEF'" + 6 "x'0123456789abcdef'" + 7 "22.5" + 8 "-91.5" + 9 "-.5" + 10 "''''" + 11 "+.5" +} { + set func [string map {' ''} "first($arg)"] + do_execsql_test 4.1.$tn " + INSERT INTO zzz(zzz, rank) VALUES('rank', '$func'); + SELECT rank IS $arg FROM zzz WHERE zzz MATCH 'a + b + c' + " 1 +} + +do_execsql_test 4.2 { + INSERT INTO zzz(zzz, rank) VALUES('rank', 'f1()'); +} {} + +#------------------------------------------------------------------------- +# Misquoting in tokenize= and other options. +# +do_catchsql_test 5.1 { + CREATE VIRTUAL TABLE xx USING fts5(x, tokenize="porter 'ascii"); +} {1 {parse error in tokenize directive}} + +breakpoint +do_catchsql_test 5.2 { + CREATE VIRTUAL TABLE xx USING fts5(x, [y[]); +} {0 {}} + +do_catchsql_test 5.3 { + CREATE VIRTUAL TABLE yy USING fts5(x, [y]]); +} {1 {unrecognized token: "]"}} + +#------------------------------------------------------------------------- +# Errors in prefix= directives. +# +do_catchsql_test 6.2 { + CREATE VIRTUAL TABLE abc USING fts5(a, prefix='1, 2, 1001'); +} {1 {prefix length out of range (max 999)}} +do_catchsql_test 6.3 { + CREATE VIRTUAL TAbLE abc USING fts5(a, prefix='1, 2, 0000'); +} {1 {prefix length out of range (max 999)}} +do_catchsql_test 6.4 { + CREATE VIRTUAL TABLE abc USING fts5(a, prefix='1 , 1000000'); +} {1 {prefix length out of range (max 999)}} + +#------------------------------------------------------------------------- +# Duplicate tokenize= and other options. +# +do_catchsql_test 7.1 { + CREATE VIRTUAL TABLE abc USING fts5(a, tokenize=porter, tokenize=ascii); +} {1 {multiple tokenize=... directives}} +do_catchsql_test 7.2 { + CREATE VIRTUAL TABLE abc USING fts5(a, content=porter, content=ascii); +} {1 {multiple content=... directives}} +do_catchsql_test 7.3 { + CREATE VIRTUAL TABLE abc USING fts5(a, content_rowid=porter, content_rowid=a); +} {1 {multiple content_rowid=... directives}} + +#------------------------------------------------------------------------- +# Unrecognized option. +# +do_catchsql_test 8.0 { + CREATE VIRTUAL TABLE abc USING fts5(a, nosuchoption=123); +} {1 {unrecognized option: "nosuchoption"}} +do_catchsql_test 8.1 { + CREATE VIRTUAL TABLE abc USING fts5(a, "nosuchoption"=123); +} {1 {parse error in ""nosuchoption"=123"}} + +#------------------------------------------------------------------------- +# Errors in: +# +# 9.1.* 'pgsz' options. +# 9.2.* 'automerge' options. +# 9.3.* 'crisismerge' options. +# 9.4.* a non-existant option. +# 9.5.* 'hashsize' options. +# +do_execsql_test 9.0 { + CREATE VIRTUAL TABLE abc USING fts5(a, b); +} {} +do_catchsql_test 9.1.1 { + INSERT INTO abc(abc, rank) VALUES('pgsz', -5); +} {1 {SQL logic error or missing database}} +do_catchsql_test 9.1.2 { + INSERT INTO abc(abc, rank) VALUES('pgsz', 50000000); +} {1 {SQL logic error or missing database}} +do_catchsql_test 9.1.3 { + INSERT INTO abc(abc, rank) VALUES('pgsz', 66.67); +} {1 {SQL logic error or missing database}} + +do_catchsql_test 9.2.1 { + INSERT INTO abc(abc, rank) VALUES('automerge', -5); +} {1 {SQL logic error or missing database}} +do_catchsql_test 9.2.2 { + INSERT INTO abc(abc, rank) VALUES('automerge', 50000000); +} {1 {SQL logic error or missing database}} +do_catchsql_test 9.2.3 { + INSERT INTO abc(abc, rank) VALUES('automerge', 66.67); +} {1 {SQL logic error or missing database}} +do_execsql_test 9.2.4 { + INSERT INTO abc(abc, rank) VALUES('automerge', 1); +} {} + +do_catchsql_test 9.3.1 { + INSERT INTO abc(abc, rank) VALUES('crisismerge', -5); +} {1 {SQL logic error or missing database}} +do_catchsql_test 9.3.2 { + INSERT INTO abc(abc, rank) VALUES('crisismerge', 66.67); +} {1 {SQL logic error or missing database}} +do_execsql_test 9.3.3 { + INSERT INTO abc(abc, rank) VALUES('crisismerge', 1); +} {} +do_execsql_test 9.3.4 { + INSERT INTO abc(abc, rank) VALUES('crisismerge', 50000000); +} {} + +do_catchsql_test 9.4.1 { + INSERT INTO abc(abc, rank) VALUES('nosuchoption', 1); +} {1 {SQL logic error or missing database}} + +do_catchsql_test 9.5.1 { + INSERT INTO abc(abc, rank) VALUES('hashsize', 'not an integer'); +} {1 {SQL logic error or missing database}} +do_catchsql_test 9.5.2 { + INSERT INTO abc(abc, rank) VALUES('hashsize', -500000); +} {1 {SQL logic error or missing database}} +do_catchsql_test 9.5.3 { + INSERT INTO abc(abc, rank) VALUES('hashsize', 500000); +} {0 {}} + +#------------------------------------------------------------------------- +# Too many prefix indexes. Maximum allowed is 31. +# +foreach {tn spec} { + 1 {prefix="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32"} + 2 {prefix="1 2 3 4", prefix="5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32"} +} { + set sql "CREATE VIRTUAL TABLE xyz USING fts5(x, $spec)" + do_catchsql_test 10.$tn $sql {1 {too many prefix indexes (max 31)}} +} + +#------------------------------------------------------------------------- +# errors in the detail= option. +# +foreach {tn opt} { + 1 {detail=x} + 2 {detail='x'} + 3 {detail='$'} + 4 {detail='1,2,'} + 5 {detail=',1'} + 6 {detail=''} +} { + set res [list 1 {malformed detail=... directive}] + do_catchsql_test 11.$tn "CREATE VIRTUAL TABLE f1 USING fts5(x, $opt)" $res +} + +do_catchsql_test 12.1 { + INSERT INTO t1(t1, rank) VALUES('rank', NULL);; +} {1 {SQL logic error or missing database}} + +finish_test + diff --git a/ext/fts5/test/fts5conflict.test b/ext/fts5/test/fts5conflict.test new file mode 100644 index 0000000..5c1e593 --- /dev/null +++ b/ext/fts5/test/fts5conflict.test @@ -0,0 +1,70 @@ +# 2015 October 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. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the FTS5 module. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5conflict + +# If SQLITE_ENABLE_FTS5 is not defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE TABLE t1(x INTEGER PRIMARY KEY, a, b); + CREATE VIRTUAL TABLE ft USING fts5(a, b, content=t1, content_rowid=x); +} + +do_execsql_test 1.1 { + REPLACE INTO ft(rowid, a, b) VALUES(1, 'a b c', 'a b c'); + REPLACE INTO t1 VALUES(1, 'a b c', 'a b c'); +} + +do_execsql_test 1.2 { + INSERT INTO ft(ft) VALUES('integrity-check'); +} + +do_execsql_test 2.0 { + CREATE TABLE tbl(a INTEGER PRIMARY KEY, b, c); + CREATE VIRTUAL TABLE fts_idx USING fts5(b, c, content=tbl, content_rowid=a); + CREATE TRIGGER tbl_ai AFTER INSERT ON tbl BEGIN + INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c); + END; + CREATE TRIGGER tbl_ad AFTER DELETE ON tbl BEGIN + INSERT INTO fts_idx(fts_idx, rowid, b, c) + VALUES('delete', old.a, old.b, old.c); + END; + CREATE TRIGGER tbl_au AFTER UPDATE ON tbl BEGIN + INSERT INTO fts_idx(fts_idx, rowid, b, c) + VALUES('delete', old.a, old.b, old.c); + INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c); + END; +} + +do_execsql_test 2.1 { + PRAGMA recursive_triggers = 1; + INSERT INTO tbl VALUES(1, 'x y z', '1 2 3'); + INSERT INTO tbl VALUES(10, 'x y z', '1 2 3'); + INSERT INTO tbl VALUES(100, 'x 1 z', '1 y 3'); + + UPDATE tbl SET b = '1 2 x' WHERE rowid=10; + REPLACE INTO tbl VALUES(1, '4 5 6', '3 2 1'); + DELETE FROM tbl WHERE a=100; + + INSERT INTO fts_idx(fts_idx) VALUES('integrity-check'); +} + +finish_test + + diff --git a/ext/fts5/test/fts5content.test b/ext/fts5/test/fts5content.test new file mode 100644 index 0000000..69e66a5 --- /dev/null +++ b/ext/fts5/test/fts5content.test @@ -0,0 +1,258 @@ +# 2014 Dec 20 +# +# 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 contains tests for the content= and content_rowid= options. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5content + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +#------------------------------------------------------------------------- +# Contentless tables +# +do_execsql_test 1.1 { + CREATE VIRTUAL TABLE f1 USING fts5(a, b, content=''); + INSERT INTO f1(rowid, a, b) VALUES(1, 'one', 'o n e'); + INSERT INTO f1(rowid, a, b) VALUES(2, 'two', 't w o'); + INSERT INTO f1(rowid, a, b) VALUES(3, 'three', 't h r e e'); +} + +do_execsql_test 1.2 { + SELECT rowid FROM f1 WHERE f1 MATCH 'o'; +} {1 2} + +do_execsql_test 1.3 { + INSERT INTO f1(a, b) VALUES('four', 'f o u r'); + SELECT rowid FROM f1 WHERE f1 MATCH 'o'; +} {1 2 4} + +do_execsql_test 1.4 { + SELECT rowid, a, b FROM f1 WHERE f1 MATCH 'o'; +} {1 {} {} 2 {} {} 4 {} {}} + +do_execsql_test 1.5 { + SELECT rowid, highlight(f1, 0, '[', ']') FROM f1 WHERE f1 MATCH 'o'; +} {1 {} 2 {} 4 {}} + +do_execsql_test 1.6 { + SELECT rowid, highlight(f1, 0, '[', ']') IS NULL FROM f1 WHERE f1 MATCH 'o'; +} {1 1 2 1 4 1} + +do_execsql_test 1.7 { + SELECT rowid, snippet(f1, -1, '[', ']', '...', 5) IS NULL + FROM f1 WHERE f1 MATCH 'o'; +} {1 1 2 1 4 1} + +do_execsql_test 1.8 { + SELECT rowid, snippet(f1, 1, '[', ']', '...', 5) IS NULL + FROM f1 WHERE f1 MATCH 'o'; +} {1 1 2 1 4 1} + +do_execsql_test 1.9 { + SELECT rowid FROM f1; +} {1 2 3 4} + +do_execsql_test 1.10 { + SELECT * FROM f1; +} {{} {} {} {} {} {} {} {}} + +do_execsql_test 1.11 { + SELECT rowid, a, b FROM f1 ORDER BY rowid ASC; +} {1 {} {} 2 {} {} 3 {} {} 4 {} {}} + +do_execsql_test 1.12 { + SELECT a IS NULL FROM f1; +} {1 1 1 1} + +do_catchsql_test 1.13 { + DELETE FROM f1 WHERE rowid = 2; +} {1 {cannot DELETE from contentless fts5 table: f1}} + +do_catchsql_test 1.14 { + UPDATE f1 SET a = 'a b c' WHERE rowid = 2; +} {1 {cannot UPDATE contentless fts5 table: f1}} + +do_execsql_test 1.15 { + INSERT INTO f1(f1, rowid, a, b) VALUES('delete', 2, 'two', 't w o'); +} {} + +do_execsql_test 1.16 { + SELECT rowid FROM f1 WHERE f1 MATCH 'o'; +} {1 4} + +do_execsql_test 1.17 { + SELECT rowid FROM f1; +} {1 3 4} + +#------------------------------------------------------------------------- +# External content tables +# +reset_db +do_execsql_test 2.1 { + -- Create a table. And an external content fts5 table to index it. + CREATE TABLE tbl(a INTEGER PRIMARY KEY, b, c); + CREATE VIRTUAL TABLE fts_idx USING fts5(b, c, content='tbl', content_rowid='a'); + + -- Triggers to keep the FTS index up to date. + CREATE TRIGGER tbl_ai AFTER INSERT ON tbl BEGIN + INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c); + END; + CREATE TRIGGER tbl_ad AFTER DELETE ON tbl BEGIN + INSERT INTO fts_idx(fts_idx, rowid, b, c) + VALUES('delete', old.a, old.b, old.c); + END; + CREATE TRIGGER tbl_au AFTER UPDATE ON tbl BEGIN + INSERT INTO fts_idx(fts_idx, rowid, b, c) + VALUES('delete', old.a, old.b, old.c); + INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c); + END; +} + +do_execsql_test 2.2 { + INSERT INTO tbl VALUES(1, 'one', 'o n e'); + INSERT INTO tbl VALUES(NULL, 'two', 't w o'); + INSERT INTO tbl VALUES(3, 'three', 't h r e e'); +} + +do_execsql_test 2.3 { + INSERT INTO fts_idx(fts_idx) VALUES('integrity-check'); +} + +do_execsql_test 2.4 { + DELETE FROM tbl WHERE rowid=2; + INSERT INTO fts_idx(fts_idx) VALUES('integrity-check'); +} + +do_execsql_test 2.5 { + UPDATE tbl SET c = c || ' x y z'; + INSERT INTO fts_idx(fts_idx) VALUES('integrity-check'); +} + +do_execsql_test 2.6 { + SELECT * FROM fts_idx WHERE fts_idx MATCH 't AND x'; +} {three {t h r e e x y z}} + +do_execsql_test 2.7 { + SELECT highlight(fts_idx, 1, '[', ']') FROM fts_idx + WHERE fts_idx MATCH 't AND x'; +} {{[t] h r e e [x] y z}} + +#------------------------------------------------------------------------- +# Quick tests of the 'delete-all' command. +# +do_execsql_test 3.1 { + CREATE VIRTUAL TABLE t3 USING fts5(x, content=''); + INSERT INTO t3 VALUES('a b c'); + INSERT INTO t3 VALUES('d e f'); +} + +do_execsql_test 3.2 { + SELECT count(*) FROM t3_docsize; + SELECT count(*) FROM t3_data; +} {2 4} + +do_execsql_test 3.3 { + INSERT INTO t3(t3) VALUES('delete-all'); + SELECT count(*) FROM t3_docsize; + SELECT count(*) FROM t3_data; +} {0 2} + +do_execsql_test 3.4 { + INSERT INTO t3 VALUES('a b c'); + INSERT INTO t3 VALUES('d e f'); + SELECT rowid FROM t3 WHERE t3 MATCH 'e'; +} {2} + +do_execsql_test 3.5 { + SELECT rowid FROM t3 WHERE t3 MATCH 'c'; +} {1} + +do_execsql_test 3.6 { + SELECT count(*) FROM t3_docsize; + SELECT count(*) FROM t3_data; +} {2 4} + +do_execsql_test 3.7 { + CREATE VIRTUAL TABLE t4 USING fts5(x); +} {} +do_catchsql_test 3.8 { + INSERT INTO t4(t4) VALUES('delete-all'); +} {1 {'delete-all' may only be used with a contentless or external content fts5 table}} + +#------------------------------------------------------------------------- +# Test an external content table with a more interesting schema. +# +do_execsql_test 4.1 { + CREATE TABLE x2(a, "key col" PRIMARY KEY, b, c) WITHOUT ROWID; + INSERT INTO x2 VALUES('a b', 1, 'c d' , 'e f'); + INSERT INTO x2 VALUES('x y', -40, 'z z' , 'y x'); + + CREATE VIRTUAL TABLE t2 USING fts5(a, c, content=x2, content_rowid='key col'); + INSERT INTO t2(t2) VALUES('rebuild'); +} + +do_execsql_test 4.2 { SELECT rowid FROM t2 } {-40 1} +do_execsql_test 4.3 { SELECT rowid FROM t2 WHERE t2 MATCH 'c'} {} +do_execsql_test 4.4 { SELECT rowid FROM t2 WHERE t2 MATCH 'a'} {1} +do_execsql_test 4.5 { SELECT rowid FROM t2 WHERE t2 MATCH 'x'} {-40} + +do_execsql_test 4.6 { INSERT INTO t2(t2) VALUES('integrity-check') } {} + +do_execsql_test 4.7 { + DELETE FROM x2 WHERE "key col" = 1; + INSERT INTO t2(t2, rowid, a, c) VALUES('delete', 1, 'a b', 'e f'); + INSERT INTO t2(t2) VALUES('integrity-check'); +} + +do_execsql_test 4.8 { SELECT rowid FROM t2 WHERE t2 MATCH 'b'} {} +do_execsql_test 4.9 { SELECT rowid FROM t2 WHERE t2 MATCH 'y'} {-40} + +#------------------------------------------------------------------------- +# Test that if the 'rowid' field of a 'delete' is not an integer, no +# changes are made to the FTS index. +# +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE t5 USING fts5(a, b, content=); + INSERT INTO t5(rowid, a, b) VALUES(-1, 'one', 'two'); + INSERT INTO t5(rowid, a, b) VALUES( 0, 'three', 'four'); + INSERT INTO t5(rowid, a, b) VALUES( 1, 'five', 'six'); +} + +set ::checksum [execsql {SELECT md5sum(id, block) FROM t5_data}] + +do_execsql_test 5.1 { + INSERT INTO t5(t5, rowid, a, b) VALUES('delete', NULL, 'three', 'four'); + SELECT md5sum(id, block) FROM t5_data; +} $::checksum + + +#------------------------------------------------------------------------- +# Check that a contentless table can be dropped. +# +reset_db +do_execsql_test 6.1 { + CREATE VIRTUAL TABLE xx USING fts5(x, y, content=""); + SELECT name FROM sqlite_master; +} {xx xx_data xx_idx xx_docsize xx_config} +do_execsql_test 6.2 { + DROP TABLE xx; + SELECT name FROM sqlite_master; +} {} + + +finish_test + diff --git a/ext/fts5/test/fts5corrupt.test b/ext/fts5/test/fts5corrupt.test new file mode 100644 index 0000000..edaafb2 --- /dev/null +++ b/ext/fts5/test/fts5corrupt.test @@ -0,0 +1,99 @@ +# 2014 Dec 20 +# +# 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 tests that the FTS5 'integrity-check' command detects +# inconsistencies (corruption) in the on-disk backing tables. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5corrupt + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); +} + +do_test 1.1 { + db transaction { + for {set i 1} {$i < 200} {incr i} { + set doc [list [string repeat x $i] [string repeat y $i]] + execsql { INSERT INTO t1(rowid, x) VALUES($i, $doc) } + } + } + fts5_level_segs t1 +} {1} +db_save + +do_execsql_test 1.2 { INSERT INTO t1(t1) VALUES('integrity-check') } +set segid [lindex [fts5_level_segids t1] 0] + +do_test 1.3 { + execsql { + DELETE FROM t1_data WHERE rowid = fts5_rowid('segment', $segid, 4); + } + catchsql { INSERT INTO t1(t1) VALUES('integrity-check') } +} {1 {database disk image is malformed}} + +do_test 1.4 { + db_restore_and_reopen + execsql { + UPDATE t1_data set block = X'00000000' || substr(block, 5) WHERE + rowid = fts5_rowid('segment', $segid, 4); + } + catchsql { INSERT INTO t1(t1) VALUES('integrity-check') } +} {1 {database disk image is malformed}} + +db_restore_and_reopen +#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM t1_data} {puts $r} + + +#-------------------------------------------------------------------- +# +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE t2 USING fts5(x); + INSERT INTO t2(t2, rank) VALUES('pgsz', 64); +} +db func rnddoc fts5_rnddoc +do_test 2.1 { + for {set i 0} {$i < 500} {incr i} { + execsql { INSERT INTO t2 VALUES(rnddoc(50)) } + } + execsql { INSERT INTO t2(t2) VALUES('integrity-check') } +} {} + +#-------------------------------------------------------------------- +# A mundane test - missing row in the %_content table. +# +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE t3 USING fts5(x); + INSERT INTO t3 VALUES('one o'); + INSERT INTO t3 VALUES('two e'); + INSERT INTO t3 VALUES('three o'); + INSERT INTO t3 VALUES('four e'); + INSERT INTO t3 VALUES('five o'); +} +do_execsql_test 3.1 { + SELECT * FROM t3 WHERE t3 MATCH 'o' +} {{one o} {three o} {five o}} + +do_catchsql_test 3.1 { + DELETE FROM t3_content WHERE rowid = 3; + SELECT * FROM t3 WHERE t3 MATCH 'o'; +} {1 {database disk image is malformed}} + +finish_test + diff --git a/ext/fts5/test/fts5corrupt2.test b/ext/fts5/test/fts5corrupt2.test new file mode 100644 index 0000000..3a4fcfa --- /dev/null +++ b/ext/fts5/test/fts5corrupt2.test @@ -0,0 +1,272 @@ +# 2015 Apr 24 +# +# 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 tests that FTS5 handles corrupt databases (i.e. internal +# inconsistencies in the backing tables) correctly. In this case +# "correctly" means without crashing. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5corrupt2 + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} +sqlite3_fts5_may_be_corrupt 1 + +# Create a simple FTS5 table containing 100 documents. Each document +# contains 10 terms, each of which start with the character "x". +# +expr srand(0) +db func rnddoc fts5_rnddoc +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + WITH ii(i) AS (SELECT 1 UNION SELECT i+1 FROM ii WHERE i<100) + INSERT INTO t1 SELECT rnddoc(10) FROM ii; +} +set mask [expr 31 << 31] + +if 1 { + +# Test 1: +# +# For each page in the t1_data table, open a transaction and DELETE +# the t1_data entry. Then run: +# +# * an integrity-check, and +# * unless the deleted block was a b-tree node, a query for "t1 MATCH 'x*'" +# +# and check that the corruption is detected in both cases. The +# rollback the transaction. +# +# Test 2: +# +# Same thing, except instead of deleting a row from t1_data, replace its +# blob content with integer value 14. +# +foreach {tno stmt} { + 1 { DELETE FROM t1_data WHERE rowid=$rowid } + 2 { UPDATE t1_data SET block=14 WHERE rowid=$rowid } +} { + set tn 0 + foreach rowid [db eval {SELECT rowid FROM t1_data WHERE rowid>10}] { + incr tn + #if {$tn!=224} continue + + do_test 1.$tno.$tn.1.$rowid { + execsql { BEGIN } + execsql $stmt + catchsql { INSERT INTO t1(t1) VALUES('integrity-check') } + } {1 {database disk image is malformed}} + + if {($rowid & $mask)==0} { + # Node is a leaf node, not a b-tree node. + do_catchsql_test 1.$tno.$tn.2.$rowid { + SELECT rowid FROM t1 WHERE t1 MATCH 'x*' + } {1 {database disk image is malformed}} + } + + do_execsql_test 1.$tno.$tn.3.$rowid { + ROLLBACK; + INSERT INTO t1(t1) VALUES('integrity-check'); + } {} + } +} + +# Using the same database as the 1.* tests. +# +# Run N-1 tests, where N is the number of bytes in the rightmost leaf page +# of the fts index. For test $i, truncate the rightmost leafpage to $i +# bytes. Then test both the integrity-check detects the corruption. +# +# Also tested is that "MATCH 'x*'" does not crash and sometimes reports +# corruption. It may not report the db as corrupt because truncating the +# final leaf to some sizes may create a valid leaf page. +# +set lrowid [db one {SELECT max(rowid) FROM t1_data WHERE (rowid & $mask)=0}] +set nbyte [db one {SELECT length(block) FROM t1_data WHERE rowid=$lrowid}] +set all [db eval {SELECT rowid FROM t1}] +for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} { + do_execsql_test 2.$i.1 { + BEGIN; + UPDATE t1_data SET block = substr(block, 1, $i) WHERE rowid=$lrowid; + } + + do_catchsql_test 2.$i.2 { + INSERT INTO t1(t1) VALUES('integrity-check'); + } {1 {database disk image is malformed}} + + do_test 2.$i.3 { + set res [catchsql {SELECT rowid FROM t1 WHERE t1 MATCH 'x*'}] + expr { + $res=="1 {database disk image is malformed}" + || $res=="0 {$all}" + } + } 1 + + do_execsql_test 2.$i.4 { + ROLLBACK; + INSERT INTO t1(t1) VALUES('integrity-check'); + } {} +} + +#------------------------------------------------------------------------- +# Test that corruption in leaf page headers is detected by queries that use +# doclist-indexes. +# +set doc "A B C D E F G H I J " +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE x3 USING fts5(tt); + INSERT INTO x3(x3, rank) VALUES('pgsz', 32); + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<1000) + INSERT INTO x3 + SELECT ($doc || CASE WHEN (i%50)==0 THEN 'X' ELSE 'Y' END) FROM ii; +} + +foreach {tn hdr} { + 1 "\x00\x00\x00\x00" + 2 "\xFF\xFF\xFF\xFF" + 3 "\x44\x45" +} { + set tn2 0 + set nCorrupt 0 + set nCorrupt2 0 + foreach rowid [db eval {SELECT rowid FROM x3_data WHERE rowid>10}] { + if {$rowid & $mask} continue + incr tn2 + do_test 3.$tn.$tn2.1 { + execsql BEGIN + + set fd [db incrblob main x3_data block $rowid] + fconfigure $fd -encoding binary -translation binary + set existing [read $fd [string length $hdr]] + seek $fd 0 + puts -nonewline $fd $hdr + close $fd + + set res [catchsql {SELECT rowid FROM x3 WHERE x3 MATCH 'x AND a'}] + if {$res == "1 {database disk image is malformed}"} {incr nCorrupt} + set {} 1 + } {1} + + if {($tn2 % 10)==0 && $existing != $hdr} { + do_test 3.$tn.$tn2.2 { + catchsql { INSERT INTO x3(x3) VALUES('integrity-check') } + } {1 {database disk image is malformed}} + } + + execsql ROLLBACK + } + + do_test 3.$tn.x { expr $nCorrupt>0 } 1 +} + +#-------------------------------------------------------------------- +# +set doc "A B C D E F G H I J " +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE x4 USING fts5(tt); + INSERT INTO x4(x4, rank) VALUES('pgsz', 32); + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<10) + INSERT INTO x4 + SELECT ($doc || CASE WHEN (i%50)==0 THEN 'X' ELSE 'Y' END) FROM ii; +} + +foreach {tn nCut} { + 1 1 + 2 10 +} { + set tn2 0 + set nCorrupt 0 + foreach rowid [db eval {SELECT rowid FROM x4_data WHERE rowid>10}] { + if {$rowid & $mask} continue + incr tn2 + do_test 4.$tn.$tn2 { + execsql { + BEGIN; + UPDATE x4_data SET block = substr(block, 1, length(block)-$nCut) + WHERE id = $rowid; + } + + set res [catchsql { + SELECT rowid FROM x4 WHERE x4 MATCH 'a' ORDER BY 1 DESC + }] + if {$res == "1 {database disk image is malformed}"} {incr nCorrupt} + set {} 1 + } {1} + + execsql ROLLBACK + } + + # do_test 4.$tn.x { expr $nCorrupt>0 } 1 +} + +} + +set doc [string repeat "A B C " 1000] +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE x5 USING fts5(tt); + INSERT INTO x5(x5, rank) VALUES('pgsz', 32); + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<10) + INSERT INTO x5 SELECT $doc FROM ii; +} + +foreach {tn hdr} { + 1 "\x00\x01" +} { + set tn2 0 + set nCorrupt 0 + foreach rowid [db eval {SELECT rowid FROM x5_data WHERE rowid>10}] { + if {$rowid & $mask} continue + incr tn2 + do_test 5.$tn.$tn2 { + execsql BEGIN + + set fd [db incrblob main x5_data block $rowid] + fconfigure $fd -encoding binary -translation binary + puts -nonewline $fd $hdr + close $fd + + catchsql { INSERT INTO x5(x5) VALUES('integrity-check') } + set {} {} + } {} + + execsql ROLLBACK + } +} + +#-------------------------------------------------------------------- +reset_db +do_execsql_test 6.1 { + CREATE VIRTUAL TABLE x5 USING fts5(tt); + INSERT INTO x5 VALUES('a'); + INSERT INTO x5 VALUES('a a'); + INSERT INTO x5 VALUES('a a a'); + INSERT INTO x5 VALUES('a a a a'); + + UPDATE x5_docsize SET sz = X'' WHERE id=3; +} +proc colsize {cmd i} { + $cmd xColumnSize $i +} +sqlite3_fts5_create_function db colsize colsize + +do_catchsql_test 6.2 { + SELECT colsize(x5, 0) FROM x5 WHERE x5 MATCH 'a' +} {1 SQLITE_CORRUPT_VTAB} + + +sqlite3_fts5_may_be_corrupt 0 +finish_test + diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test new file mode 100644 index 0000000..7a8cb5c --- /dev/null +++ b/ext/fts5/test/fts5corrupt3.test @@ -0,0 +1,408 @@ +# 2015 Apr 24 +# +# 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 tests that FTS5 handles corrupt databases (i.e. internal +# inconsistencies in the backing tables) correctly. In this case +# "correctly" means without crashing. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5corrupt3 + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} +sqlite3_fts5_may_be_corrupt 1 + +proc create_t1 {} { + expr srand(0) + db func rnddoc fts5_rnddoc + db eval { + CREATE VIRTUAL TABLE t1 USING fts5(x); + INSERT INTO t1(t1, rank) VALUES('pgsz', 64); + WITH ii(i) AS (SELECT 1 UNION SELECT i+1 FROM ii WHERE i<100) + INSERT INTO t1 SELECT rnddoc(10) FROM ii; + } +} + +if 1 { + +# Create a simple FTS5 table containing 100 documents. Each document +# contains 10 terms, each of which start with the character "x". +# +do_test 1.0 { create_t1 } {} + +do_test 1.1 { + # Pick out the rowid of the right-most b-tree leaf in the new segment. + set rowid [db one { + SELECT max(rowid) FROM t1_data WHERE ((rowid>>31) & 0x0F)==1 + }] + set L [db one {SELECT length(block) FROM t1_data WHERE rowid = $rowid}] + set {} {} +} {} + +for {set i 0} {$i < $L} {incr i} { + do_test 1.2.$i { + catchsql { + BEGIN; + UPDATE t1_data SET block = substr(block, 1, $i) WHERE id = $rowid; + INSERT INTO t1(t1) VALUES('integrity-check'); + } + } {1 {database disk image is malformed}} + catchsql ROLLBACK +} + +#------------------------------------------------------------------------- +# Test that trailing bytes appended to the averages record are ignored. +# +do_execsql_test 2.1 { + CREATE VIRTUAL TABLE t2 USING fts5(x); + INSERT INTO t2 VALUES(rnddoc(10)); + INSERT INTO t2 VALUES(rnddoc(10)); + SELECT length(block) FROM t2_data WHERE id=1; +} {2} +do_execsql_test 2.2 { + UPDATE t2_data SET block = block || 'abcd' WHERE id=1; + SELECT length(block) FROM t2_data WHERE id=1; +} {6} +do_execsql_test 2.2 { + INSERT INTO t2 VALUES(rnddoc(10)); + SELECT length(block) FROM t2_data WHERE id=1; +} {2} + + +#------------------------------------------------------------------------- +# Test that missing leaf pages are recognized as corruption. +# +reset_db +do_test 3.0 { create_t1 } {} + +do_execsql_test 3.1 { + SELECT count(*) FROM t1_data; +} {105} + +proc do_3_test {tn} { + set i 0 + foreach ::rowid [db eval "SELECT rowid FROM t1_data WHERE rowid>100"] { + incr i + do_test $tn.$i { + db eval BEGIN + db eval {DELETE FROM t1_data WHERE rowid = $::rowid} + list [ + catch { db eval {SELECT rowid FROM t1 WHERE t1 MATCH 'x*'} } msg + ] $msg + } {1 {database disk image is malformed}} + catch { db eval ROLLBACK } + } +} + +do_3_test 3.2 + +do_execsql_test 3.3 { + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + INSERT INTO t1 SELECT x FROM t1; + INSERT INTO t1(t1) VALUES('optimize'); +} {} + +do_3_test 3.4 + +do_test 3.5 { + execsql { + DELETE FROM t1; + INSERT INTO t1(t1, rank) VALUES('pgsz', 40); + } + for {set i 0} {$i < 1000} {incr i} { + set rnd [expr int(rand() * 1000)] + set doc [string repeat "x$rnd " [expr int(rand() * 3) + 1]] + execsql { INSERT INTO t1(rowid, x) VALUES($i, $doc) } + } +} {} + +do_3_test 3.6 + +do_test 3.7 { + execsql { + INSERT INTO t1(t1, rank) VALUES('pgsz', 40); + INSERT INTO t1 SELECT x FROM t1; + INSERT INTO t1(t1) VALUES('optimize'); + } +} {} + +do_3_test 3.8 + +do_test 3.9 { + execsql { + DELETE FROM t1; + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + } + for {set i 0} {$i < 100} {incr i} { + set rnd [expr int(rand() * 100)] + set doc "x[string repeat $rnd 20]" + execsql { INSERT INTO t1(rowid, x) VALUES($i, $doc) } + } +} {} + +do_3_test 3.10 + +#------------------------------------------------------------------------- +# Test that segments that end unexpectedly are identified as corruption. +# +reset_db +do_test 4.0 { + execsql { + CREATE VIRTUAL TABLE t1 USING fts5(x); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + } + for {set i 0} {$i < 100} {incr i} { + set rnd [expr int(rand() * 100)] + set doc "x[string repeat $rnd 20]" + execsql { INSERT INTO t1(rowid, x) VALUES($i, $doc) } + } + execsql { INSERT INTO t1(t1) VALUES('optimize') } +} {} + +set nErr 0 +for {set i 1} {1} {incr i} { + set struct [db one {SELECT block FROM t1_data WHERE id=10}] + binary scan $struct c* var + set end [lindex $var end] + if {$end<=$i} break + lset var end [expr $end - $i] + set struct [binary format c* $var] + db eval { + BEGIN; + UPDATE t1_data SET block = $struct WHERE id=10; + } + do_test 4.1.$i { + incr nErr [catch { db eval { SELECT rowid FROM t1 WHERE t1 MATCH 'x*' } }] + set {} {} + } {} + catch { db eval ROLLBACK } +} +do_test 4.1.x { expr $nErr>45 } 1 + +#------------------------------------------------------------------------- +# + +# The first argument passed to this command must be a binary blob +# containing an FTS5 leaf page. This command returns a copy of this +# blob, with the pgidx of the leaf page replaced by a single varint +# containing value $iVal. +# +proc rewrite_pgidx {blob iVal} { + binary scan $blob SS off1 szLeaf + if {$iVal<0 || $iVal>=128} { + error "$iVal out of range!" + } else { + set pgidx [binary format c $iVal] + } + + binary format a${szLeaf}a* $blob $pgidx +} + +reset_db +do_execsql_test 5.1 { + CREATE VIRTUAL TABLE x1 USING fts5(x); + INSERT INTO x1(x1, rank) VALUES('pgsz', 40); + BEGIN; + INSERT INTO x1 VALUES('xaaa xabb xccc xcdd xeee xeff xggg xghh xiii xijj'); + INSERT INTO x1 SELECT x FROM x1; + INSERT INTO x1 SELECT x FROM x1; + INSERT INTO x1 SELECT x FROM x1; + INSERT INTO x1 SELECT x FROM x1; + INSERT INTO x1(x1) VALUES('optimize'); + COMMIT; +} + +#db eval { SELECT fts5_decode(id, block) b from x1_data } { puts $b } +# +db func rewrite_pgidx rewrite_pgidx +set i 0 +foreach rowid [db eval {SELECT rowid FROM x1_data WHERE rowid>100}] { + foreach val {2 100} { + do_test 5.2.$val.[incr i] { + catchsql { + BEGIN; + UPDATE x1_data SET block=rewrite_pgidx(block, $val) WHERE id=$rowid; + SELECT rowid FROM x1 WHERE x1 MATCH 'xa*'; + SELECT rowid FROM x1 WHERE x1 MATCH 'xb*'; + SELECT rowid FROM x1 WHERE x1 MATCH 'xc*'; + SELECT rowid FROM x1 WHERE x1 MATCH 'xd*'; + SELECT rowid FROM x1 WHERE x1 MATCH 'xe*'; + SELECT rowid FROM x1 WHERE x1 MATCH 'xf*'; + SELECT rowid FROM x1 WHERE x1 MATCH 'xg*'; + SELECT rowid FROM x1 WHERE x1 MATCH 'xh*'; + SELECT rowid FROM x1 WHERE x1 MATCH 'xi*'; + } + set {} {} + } {} + catch { db eval ROLLBACK } + } +} + +#------------------------------------------------------------------------ +# +reset_db +do_execsql_test 6.1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a); + INSERT INTO t1 VALUES('bbbbb ccccc'); + SELECT quote(block) FROM t1_data WHERE rowid>100; +} {X'000000180630626262626201020201056363636363010203040A'} +do_execsql_test 6.1.1 { + UPDATE t1_data SET block = + X'000000180630626262626201020201056161616161010203040A' + WHERE rowid>100; +} +do_catchsql_test 6.1.2 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +#------- +reset_db +do_execsql_test 6.2.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + INSERT INTO t1 VALUES('aa bb cc dd ee'); + SELECT pgno, quote(term) FROM t1_idx; +} {2 X'' 4 X'3064'} +do_execsql_test 6.2.1 { + UPDATE t1_idx SET term = X'3065' WHERE pgno=4; +} +do_catchsql_test 6.2.2 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +#------- +reset_db +do_execsql_test 6.3.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a); + INSERT INTO t1 VALUES('abc abcdef abcdefghi'); + SELECT quote(block) FROM t1_data WHERE id>100; +} {X'0000001C043061626301020204036465660102030703676869010204040808'} +do_execsql_test 6.3.1 { + BEGIN; + UPDATE t1_data SET block = + X'0000001C043061626301020204036465660102035003676869010204040808' + ------------------------------------------^^--------------------- + WHERE id>100; +} +do_catchsql_test 6.3.2 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {1 {database disk image is malformed}} +do_execsql_test 6.3.3 { + ROLLBACK; + BEGIN; + UPDATE t1_data SET block = + X'0000001C043061626301020204036465660102030750676869010204040808' + --------------------------------------------^^------------------- + WHERE id>100; +} +do_catchsql_test 6.3.3 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {1 {database disk image is malformed}} +do_execsql_test 6.3.4 { + ROLLBACK; + BEGIN; + UPDATE t1_data SET block = + X'0000001C043061626301020204036465660102030707676869010204040850' + --------------------------------------------------------------^^- + WHERE id>100; +} +do_catchsql_test 6.3.5 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {1 {database disk image is malformed}} +do_execsql_test 6.3.6 { + ROLLBACK; + BEGIN; + UPDATE t1_data SET block = + X'0000001C503061626301020204036465660102030707676869010204040808' + ----------^^----------------------------------------------------- + WHERE id>100; +} +do_catchsql_test 6.3.5 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + + +#------------------------------------------------------------------------ +# +reset_db +proc rnddoc {n} { + set map [list a b c d] + set doc [list] + for {set i 0} {$i < $n} {incr i} { + lappend doc "x[lindex $map [expr int(rand()*4)]]" + } + set doc +} + +db func rnddoc rnddoc +do_test 7.0 { + execsql { + CREATE VIRTUAL TABLE t5 USING fts5(x); + INSERT INTO t5 VALUES( rnddoc(10000) ); + INSERT INTO t5 VALUES( rnddoc(10000) ); + INSERT INTO t5 VALUES( rnddoc(10000) ); + INSERT INTO t5 VALUES( rnddoc(10000) ); + INSERT INTO t5(t5) VALUES('optimize'); + } +} {} + +do_test 7.1 { + foreach i [db eval { SELECT rowid FROM t5_data WHERE rowid>100 }] { + db eval BEGIN + db eval {DELETE FROM t5_data WHERE rowid = $i} + set r [catchsql { INSERT INTO t5(t5) VALUES('integrity-check')} ] + if {$r != "1 {database disk image is malformed}"} { error $r } + db eval ROLLBACK + } +} {} + +} + +#------------------------------------------------------------------------ +# Corruption within the structure record. +# +reset_db +do_execsql_test 8.1 { + CREATE VIRTUAL TABLE t1 USING fts5(x, y); + INSERT INTO t1 VALUES('one', 'two'); +} + +do_test 9.1.1 { + set blob "12345678" ;# cookie + append blob "0105" ;# 1 level, total of 5 segments + append blob "06" ;# write counter + append blob "0002" ;# first level has 0 segments merging, 2 other. + append blob "450108" ;# first segment + execsql "REPLACE INTO t1_data VALUES(10, X'$blob')" +} {} +do_catchsql_test 9.1.2 { + SELECT * FROM t1('one AND two'); +} {1 {database disk image is malformed}} + +do_test 9.2.1 { + set blob "12345678" ;# cookie + append blob "0205" ;# 2 levels, total of 5 segments + append blob "06" ;# write counter + append blob "0001" ;# first level has 0 segments merging, 1 other. + append blob "450108" ;# first segment + execsql "REPLACE INTO t1_data VALUES(10, X'$blob')" +} {} +do_catchsql_test 9.2.2 { + SELECT * FROM t1('one AND two'); +} {1 {database disk image is malformed}} + +sqlite3_fts5_may_be_corrupt 0 +finish_test + diff --git a/ext/fts5/test/fts5detail.test b/ext/fts5/test/fts5detail.test new file mode 100644 index 0000000..58fda3e --- /dev/null +++ b/ext/fts5/test/fts5detail.test @@ -0,0 +1,244 @@ +# 2015 December 18 +# +# 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 FTS5 module. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5detail + +# If SQLITE_ENABLE_FTS5 is not defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +fts5_aux_test_functions db + +#-------------------------------------------------------------------------- +# Simple tests. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, c, detail=col); + INSERT INTO t1 VALUES('h d g', 'j b b g b', 'i e i d h g g'); -- 1 + INSERT INTO t1 VALUES('h j d', 'j h d a h', 'f d d g g f b'); -- 2 + INSERT INTO t1 VALUES('j c i', 'f f h e f', 'c j i j c h f'); -- 3 + INSERT INTO t1 VALUES('e g g', 'g e d h i', 'e d b e g d c'); -- 4 + INSERT INTO t1 VALUES('b c c', 'd i h a f', 'd i j f a b c'); -- 5 + INSERT INTO t1 VALUES('e d e', 'b c j g d', 'a i f d h b d'); -- 6 + INSERT INTO t1 VALUES('g h e', 'b c d i d', 'e f c i f i c'); -- 7 + INSERT INTO t1 VALUES('c f j', 'j j i e a', 'h a c f d h e'); -- 8 + INSERT INTO t1 VALUES('a h i', 'c i a f a', 'c f d h g d g'); -- 9 + INSERT INTO t1 VALUES('j g g', 'e f e f f', 'h j b i c g e'); -- 10 +} + +do_execsql_test 1.1 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} + +foreach {tn match res} { + 1 "a:a" {9} + 2 "b:g" {1 4 6} + 3 "c:h" {1 3 6 8 9 10} +} { + do_execsql_test 1.2.$tn.1 { + SELECT rowid FROM t1($match); + } $res + + do_execsql_test 1.2.$tn.2 { + SELECT rowid FROM t1($match || '*'); + } $res +} + +do_catchsql_test 1.3.1 { + SELECT rowid FROM t1('h + d'); +} {1 {fts5: phrase queries are not supported (detail!=full)}} + +do_catchsql_test 1.3.2 { + SELECT rowid FROM t1('NEAR(h d)'); +} {1 {fts5: NEAR queries are not supported (detail!=full)}} + + +#------------------------------------------------------------------------- +# integrity-check with both detail= and prefix= options. +# +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE t2 USING fts5(a, detail=col, prefix="1"); + INSERT INTO t2(a) VALUES('aa ab'); +} + +#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM t2_data} {puts $r} + +do_execsql_test 2.1 { + INSERT INTO t2(t2) VALUES('integrity-check'); +} + +do_execsql_test 2.2 { + SELECT fts5_test_poslist(t2) FROM t2('aa'); +} {0.0.0} + +do_execsql_test 2.3 { + SELECT fts5_test_collist(t2) FROM t2('aa'); +} {0.0} + +set ::pc 0 +#puts [nearset {{ax bx cx}} -pc ::pc -near 10 -- b*] +#exit + +#------------------------------------------------------------------------- +# Check that the xInstCount, xInst, xPhraseFirst and xPhraseNext APIs +# work with detail=col tables. +# +set data { + 1 {abb aca aca} {aba bab aab aac caa} {abc cbc ccb bcc bab ccb aca} + 2 {bca aca acb} {ccb bcc bca aab bcc} {bab aaa aac cbb bba aca abc} + 3 {cca abc cab} {aab aba bcc cac baa} {bab cbb acb aba aab ccc cca} + 4 {ccb bcb aba} {aba bbb bcc cac bbb} {cbb aaa bca bcc aab cac aca} + 5 {bca bbc cac} {aba cbb cac cca aca} {cab acb cbc ccb cac bbb bcb} + 6 {acc bba cba} {bab bbc bbb bcb aca} {bca ccc cbb aca bac ccc ccb} + 7 {aba bab aaa} {abb bca aac bcb bcc} {bcb bbc aba aaa cba abc acc} + 8 {cab aba aaa} {ccb aca caa bbc bcc} {aaa abc ccb bbb cac cca abb} + 9 {bcb bab bac} {bcb cba cac bbb abc} {aba aca cbb acb abb ccc ccb} + 10 {aba aab ccc} {abc ccc bcc cab bbb} {aab bcc cbb ccc aaa bac baa} + 11 {bab acb cba} {aac cab cab bca cbc} {aab cbc aac baa ccb acc cac} + 12 {ccc cbb cbc} {aaa aab bcc aac bbc} {cbc cbc bac bac ccc bbc acc} + 13 {cab bbc abc} {bbb bab bba aca bab} {baa bbb aab bbb ccb bbb ccc} + 14 {bbc cab caa} {acb aac abb cba acc} {cba bba bba acb abc abb baa} + 15 {aba cca bcc} {aaa acb abc aab ccb} {cca bcb acc aaa caa cca cbc} + 16 {bcb bba aba} {cbc acb cab caa ccb} {aac aaa bbc cab cca cba abc} + 17 {caa cbb acc} {ccb bcb bca aaa bcc} {bbb aca bcb bca cbc cbc cca} + 18 {cbb bbc aac} {ccc bbc aaa aab baa} {cab cab cac cca bbc abc bbc} + 19 {ccc acc aaa} {aab cbb bca cca caa} {bcb aca aca cab acc bac bcc} + 20 {aab ccc bcb} {bbc cbb bbc aaa bcc} {cbc aab ccc aaa bcb bac cbc} + 21 {aba cab ccc} {bbc cbc cba acc bbb} {acc aab aac acb aca bca acb} + 22 {bcb bca baa} {cca bbc aca ccb cbb} {aab abc bbc aaa cab bcc bcc} + 23 {cac cbb caa} {bbc aba bbb bcc ccb} {bbc bbb cab bbc cac abb acc} + 24 {ccb acb caa} {cab bba cac bbc aac} {aac bca abc cab bca cab bcb} + 25 {bbb aca bca} {bcb acc ccc cac aca} {ccc acb acc cac cac bba bbc} + 26 {bab acc caa} {caa cab cac bac aca} {aba cac caa acc bac ccc aaa} + 27 {bca bca aaa} {ccb aca bca aaa baa} {bab acc aaa cca cba cca bac} + 28 {ccb cac cac} {bca abb bba bbc baa} {aca ccb aac cab ccc cab caa} + 29 {abc bca cab} {cac cbc cbb ccc bcc} {bcc aaa aaa acc aac cac aac} + 30 {aca acc acb} {aab aac cbb caa acb} {acb bbc bbc acc cbb bbc aac} + 31 {aba aca baa} {aca bcc cab bab acb} {bcc acb baa bcb bbc acc aba} + 32 {abb cbc caa} {cba abb bbb cbb aca} {bac aca caa cac caa ccb bbc} + 33 {bcc bcb bcb} {cca cab cbc abb bab} {caa bbc aac bbb cab cba aaa} + 34 {caa cab acc} {ccc ccc bcc acb bcc} {bac bba aca bcb bba bcb cac} + 35 {bac bcb cba} {bcc acb bbc cba bab} {abb cbb abc abc bac acc cbb} + 36 {cab bab ccb} {bca bba bab cca acc} {acc aab bcc bac acb cbb caa} + 37 {aca cbc cab} {bba aac aca aac aaa} {baa cbb cba aba cab bca bcb} + 38 {acb aab baa} {baa bab bca bbc bbb} {abc baa acc aba cab baa cac} + 39 {bcb aac cba} {bcb baa caa cac bbc} {cbc ccc bab ccb bbb caa aba} + 40 {cba ccb abc} {cbb caa cba aac bab} {cbb bbb bca bbb bac cac bca} +} + +set data { + 1 {abb aca aca} {aba bab aab aac caa} {abc cbc ccb bcc bab ccb aca} +} + +proc matchdata {expr {bAsc 1}} { + + set tclexpr [db one { + SELECT fts5_expr_tcl($expr, 'nearset $cols -pc ::pc', 'x', 'y', 'z') + }] + set res [list] + + #puts "$expr -> $tclexpr" + foreach {id x y z} $::data { + set cols [list $x $y $z] + set ::pc 0 + #set hits [lsort -command instcompare [eval $tclexpr]] + set hits [eval $tclexpr] + if {[llength $hits]>0} { + lappend res [list $id $hits] + } + } + + if {$bAsc} { + set res [lsort -integer -increasing -index 0 $res] + } else { + set res [lsort -integer -decreasing -index 0 $res] + } + + return [concat {*}$res] +} + +foreach {tn tbl} { + 1 { CREATE VIRTUAL TABLE t3 USING fts5(x, y, z, detail=col) } + 2 { CREATE VIRTUAL TABLE t3 USING fts5(x, y, z, detail=none) } +} { + reset_db + fts5_aux_test_functions db + execsql $tbl + foreach {id x y z} $data { + execsql { INSERT INTO t3(rowid, x, y, z) VALUES($id, $x, $y, $z) } + } + foreach {tn2 expr} { + 1 aaa 2 ccc 3 bab 4 aac + 5 aa* 6 cc* 7 ba* 8 aa* + 9 a* 10 b* 11 c* + } { + + set res [matchdata $expr] + + do_execsql_test 3.$tn.$tn2.1 { + SELECT rowid, fts5_test_poslist(t3) FROM t3($expr) + } $res + + do_execsql_test 3.$tn.$tn2.2 { + SELECT rowid, fts5_test_poslist2(t3) FROM t3($expr) + } $res + } +} + +#------------------------------------------------------------------------- +# Simple tests for detail=none tables. +# +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE t4 USING fts5(a, b, c, detail=none); + INSERT INTO t4 VALUES('a b c', 'b c d', 'e f g'); + INSERT INTO t4 VALUES('1 2 3', '4 5 6', '7 8 9'); +} + +do_catchsql_test 4.1 { + SELECT * FROM t4('a:a') +} {1 {fts5: column queries are not supported (detail=none)}} + +#------------------------------------------------------------------------- +# Test that for the same content detail=none uses less space than +# detail=col, and that detail=col uses less space than detail=full +# +reset_db +do_test 5.1 { + foreach {tbl detail} {t1 none t2 col t3 full} { + execsql "CREATE VIRTUAL TABLE $tbl USING fts5(x, y, z, detail=$detail)" + foreach {rowid x y z} $::data { + execsql "INSERT INTO $tbl (rowid, x, y, z) VALUES(\$rowid, \$x, \$y, \$z)" + } + } +} {} + +do_execsql_test 5.2 { + SELECT + (SELECT sum(length(block)) from t1_data) < + (SELECT sum(length(block)) from t2_data) +} {1} + +do_execsql_test 5.3 { + SELECT + (SELECT sum(length(block)) from t2_data) < + (SELECT sum(length(block)) from t3_data) +} {1} + + + +finish_test + diff --git a/ext/fts5/test/fts5dlidx.test b/ext/fts5/test/fts5dlidx.test new file mode 100644 index 0000000..232b502 --- /dev/null +++ b/ext/fts5/test/fts5dlidx.test @@ -0,0 +1,200 @@ +# 2015 April 21 +# +# 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 test is focused on uses of doclist-index records. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5dlidx + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +if { $tcl_platform(wordSize)<8 } { + finish_test + return +} + +foreach_detail_mode $testprefix { + +proc do_fb_test {tn sql res} { + set res2 [lsort -integer -decr $res] + uplevel [list do_execsql_test $tn.1 $sql $res] + uplevel [list do_execsql_test $tn.2 "$sql ORDER BY rowid DESC" $res2] +} + +# This test populates the FTS5 table with $nEntry entries. Rows are +# numbered from 0 to ($nEntry-1). The rowid for row $i is: +# +# ($iFirst + $i*$nStep) +# +# Each document is of the form "a b c a b c a b c...". If the row number ($i) +# is an integer multiple of $spc1, then an "x" token is appended to the +# document. If it is *also* a multiple of $spc2, a "y" token is also appended. +# +proc do_dlidx_test1 {tn spc1 spc2 nEntry iFirst nStep} { + + do_execsql_test $tn.0 { DELETE FROM t1 } + + set xdoc [list] + set ydoc [list] + + execsql BEGIN + for {set i 0} {$i < $nEntry} {incr i} { + set rowid [expr $i * $nStep] + set doc [string trim [string repeat "a b c " 100]] + if {($i % $spc1)==0} { + lappend xdoc $rowid + append doc " x" + if {($i % $spc2)==0} { + lappend ydoc $rowid + append doc " y" + } + } + execsql { INSERT INTO t1(rowid, x) VALUES($rowid, $doc) } + } + execsql COMMIT + + breakpoint + do_test $tn.1 { + execsql { INSERT INTO t1(t1) VALUES('integrity-check') } + } {} + + do_fb_test $tn.3.1 { SELECT rowid FROM t1 WHERE t1 MATCH 'a AND x' } $xdoc + do_fb_test $tn.3.2 { SELECT rowid FROM t1 WHERE t1 MATCH 'x AND a' } $xdoc + + do_fb_test $tn.4.1 { SELECT rowid FROM t1 WHERE t1 MATCH 'a AND y' } $ydoc + do_fb_test $tn.4.2 { SELECT rowid FROM t1 WHERE t1 MATCH 'y AND a' } $ydoc + + if {[detail_is_full]} { + do_fb_test $tn.5.1 { + SELECT rowid FROM t1 WHERE t1 MATCH 'a + b + c + x' } $xdoc + do_fb_test $tn.5.2 { + SELECT rowid FROM t1 WHERE t1 MATCH 'b + c + x + y' } $ydoc + } +} + + +foreach {tn pgsz} { + 1 32 + 2 200 +} { + do_execsql_test $tn.0 { + DROP TABLE IF EXISTS t1; + CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', $pgsz); + } + + do_dlidx_test1 1.$tn.1 10 100 10000 0 1000 + do_dlidx_test1 1.$tn.2 10 10 10000 0 128 + do_dlidx_test1 1.$tn.3 10 10 66 0 36028797018963970 + do_dlidx_test1 1.$tn.4 10 10 50 0 150000000000000000 + do_dlidx_test1 1.$tn.5 10 10 200 0 [expr 1<<55] + do_dlidx_test1 1.$tn.6 10 10 30 0 [expr 1<<58] +} + +proc do_dlidx_test2 {tn nEntry iFirst nStep} { + set str [string repeat "a " 500] + execsql { + BEGIN; + DROP TABLE IF EXISTS t1; + CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 64); + INSERT INTO t1 VALUES('b a'); + + WITH iii(ii, i) AS ( + SELECT 1, $iFirst UNION ALL + SELECT ii+1, i+$nStep FROM iii WHERE ii<$nEntry + ) + INSERT INTO t1(rowid,x) SELECT i, $str FROM iii; + COMMIT; + } + + do_execsql_test $tn.1 { + SELECT rowid FROM t1 WHERE t1 MATCH 'b AND a' + } {1} + breakpoint + do_execsql_test $tn.2 { + SELECT rowid FROM t1 WHERE t1 MATCH 'b AND a' ORDER BY rowid DESC + } {1} +} + +do_dlidx_test2 2.1 [expr 20] [expr 1<<57] [expr (1<<57) + 128] + +#-------------------------------------------------------------------- +# +reset_db + +set ::vocab [list \ + IteratorpItercurrentlypointstothefirstrowidofadoclist \ + Thereisadoclistindexassociatedwiththefinaltermonthecurrent \ + pageIfthecurrenttermisthelasttermonthepageloadthe \ + doclistindexfromdiskandinitializeaniteratoratpIterpDlidx \ + IteratorpItercurrentlypointstothefirstrowidofadoclist \ + Thereisadoclistindexassociatedwiththefinaltermonthecurrent \ + pageIfthecurrenttermisthelasttermonthepageloadthe \ + doclistindexfromdiskandinitializeaniteratoratpIterpDlidx \ +] +proc rnddoc {} { + global vocab + set nVocab [llength $vocab] + set ret [list] + for {set i 0} {$i < 64} {incr i} { + lappend ret [lindex $vocab [expr $i % $nVocab]] + } + set ret +} +db func rnddoc rnddoc + +do_execsql_test 3.1 { + CREATE VIRTUAL TABLE abc USING fts5(a, detail=%DETAIL%); + INSERT INTO abc(abc, rank) VALUES('pgsz', 32); + + INSERT INTO abc VALUES ( rnddoc() ); + INSERT INTO abc VALUES ( rnddoc() ); + INSERT INTO abc VALUES ( rnddoc() ); + INSERT INTO abc VALUES ( rnddoc() ); + + INSERT INTO abc SELECT rnddoc() FROM abc; + INSERT INTO abc SELECT rnddoc() FROM abc; +} + + + +do_execsql_test 3.2 { + SELECT rowid FROM abc WHERE abc + MATCH 'IteratorpItercurrentlypointstothefirstrowidofadoclist' + ORDER BY rowid DESC; +} {16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1} + +do_execsql_test 3.2 { + INSERT INTO abc(abc) VALUES('integrity-check'); + INSERT INTO abc(abc) VALUES('optimize'); + INSERT INTO abc(abc) VALUES('integrity-check'); +} + +set v [lindex $vocab 0] +set i 0 +foreach v $vocab { + do_execsql_test 3.3.[incr i] { + SELECT rowid FROM abc WHERE abc MATCH $v + } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16} +} + +} ;# foreach_detail_mode + + + +finish_test + diff --git a/ext/fts5/test/fts5doclist.test b/ext/fts5/test/fts5doclist.test new file mode 100644 index 0000000..411289a --- /dev/null +++ b/ext/fts5/test/fts5doclist.test @@ -0,0 +1,47 @@ +# 2015 April 21 +# +# 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 test is focused on edge cases in the doclist format. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5doclist + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + + +#------------------------------------------------------------------------- +# Create a table with 1000 columns. Then add some large documents to it. +# All text is in the right most column of the table. +# +do_test 1.0 { + set cols [list] + for {set i 0} {$i < 900} {incr i} { lappend cols "x$i" } + execsql "CREATE VIRTUAL TABLE ccc USING fts5([join $cols ,])" +} {} + +db func rnddoc fts5_rnddoc +do_execsql_test 1.1 { + WITH ii(i) AS (SELECT 1 UNION SELECT i+1 FROM ii WHERE i<100) + INSERT INTO ccc(x899) SELECT rnddoc(500) FROM ii; +} + +do_execsql_test 1.2 { + INSERT INTO ccc(ccc) VALUES('integrity-check'); +} + + +finish_test + diff --git a/ext/fts5/test/fts5ea.test b/ext/fts5/test/fts5ea.test new file mode 100644 index 0000000..3ccbd7d --- /dev/null +++ b/ext/fts5/test/fts5ea.test @@ -0,0 +1,99 @@ +# 2014 June 17 +# +# 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. +# +#************************************************************************* +# +# Test the fts5 expression parser directly using the fts5_expr() SQL +# test function. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5ea + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +proc do_syntax_error_test {tn expr err} { + set ::se_expr $expr + do_catchsql_test $tn {SELECT fts5_expr($se_expr)} [list 1 $err] +} + +proc do_syntax_test {tn expr res} { + set ::se_expr $expr + do_execsql_test $tn {SELECT fts5_expr($se_expr)} [list $res] +} + +foreach {tn expr res} { + 1 {abc} {"abc"} + 2 {abc def} {"abc" AND "def"} + 3 {abc*} {"abc" *} + 4 {"abc def ghi" *} {"abc" + "def" + "ghi" *} + 5 {one AND two} {"one" AND "two"} + 6 {one+two} {"one" + "two"} + 7 {one AND two OR three} {("one" AND "two") OR "three"} + 8 {one OR two AND three} {"one" OR ("two" AND "three")} + 9 {NEAR(one two)} {NEAR("one" "two", 10)} + 10 {NEAR("one three"* two, 5)} {NEAR("one" + "three" * "two", 5)} + 11 {a OR b NOT c} {"a" OR ("b" NOT "c")} + 12 "\x20one\x20two\x20three" {"one" AND "two" AND "three"} + 13 "\x09one\x0Atwo\x0Dthree" {"one" AND "two" AND "three"} + 14 {"abc""def"} {"abc" + "def"} +} { + do_execsql_test 1.$tn {SELECT fts5_expr($expr)} [list $res] +} + +foreach {tn expr res} { + 1 {c1:abc} + {c1 : "abc"} + 2 {c2 : NEAR(one two) c1:"hello world"} + {c2 : NEAR("one" "two", 10) AND c1 : "hello" + "world"} +} { + do_execsql_test 2.$tn {SELECT fts5_expr($expr, 'c1', 'c2')} [list $res] +} + +foreach {tn expr err} { + 1 {AND} {fts5: syntax error near "AND"} + 2 {abc def AND} {fts5: syntax error near ""} + 3 {abc OR AND} {fts5: syntax error near "AND"} + 4 {(a OR b) abc} {fts5: syntax error near "abc"} + 5 {NEaR (a b)} {fts5: syntax error near "NEaR"} + 6 {NEa (a b)} {fts5: syntax error near "NEa"} + 7 {(a OR b) NOT c)} {fts5: syntax error near ")"} + 8 {nosuch: a nosuch2: b} {no such column: nosuch} + 9 {addr: a nosuch2: b} {no such column: nosuch2} + 10 {NOT} {fts5: syntax error near "NOT"} + 11 {a AND "abc} {unterminated string} + + 12 {NEAR(a b, xyz)} {expected integer, got "xyz"} + 13 {NEAR(a b, // )} {fts5: syntax error near "/"} + 14 {NEAR(a b, "xyz" )} {expected integer, got ""xyz""} +} { + do_catchsql_test 3.$tn {SELECT fts5_expr($expr, 'name', 'addr')} [list 1 $err] +} + +#------------------------------------------------------------------------- +# Experiment with a tokenizer that considers " to be a token character. +# +do_execsql_test 4.0 { + SELECT fts5_expr('a AND """"', 'x', 'tokenize="unicode61 tokenchars ''""''"'); +} {{"a" AND """"}} + +#------------------------------------------------------------------------- +# Experiment with a tokenizer that considers " to be a token character. +# +do_catchsql_test 5.0 { + SELECT fts5_expr('abc | def'); +} {1 {fts5: syntax error near "|"}} + + + +finish_test diff --git a/ext/fts5/test/fts5eb.test b/ext/fts5/test/fts5eb.test new file mode 100644 index 0000000..8205396 --- /dev/null +++ b/ext/fts5/test/fts5eb.test @@ -0,0 +1,69 @@ +# 2014 June 17 +# +# 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. +# +#************************************************************************* +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5eb + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +proc do_syntax_error_test {tn expr err} { + set ::se_expr $expr + do_catchsql_test $tn {SELECT fts5_expr($se_expr)} [list 1 $err] +} + +proc do_syntax_test {tn expr res} { + set ::se_expr $expr + do_execsql_test $tn {SELECT fts5_expr($se_expr)} [list $res] +} + +foreach {tn expr res} { + 1 {abc} {"abc"} + 2 {abc ""} {"abc"} + 3 {""} {} + 4 {abc OR ""} {"abc"} + 5 {abc NOT ""} {"abc"} + 6 {abc AND ""} {"abc"} + 7 {"" OR abc} {"abc"} + 8 {"" NOT abc} {"abc"} + 9 {"" AND abc} {"abc"} + 10 {abc + "" + def} {"abc" + "def"} + 11 {abc "" def} {"abc" AND "def"} + 12 {r+e OR w} {"r" + "e" OR "w"} + + 13 {a AND b NOT c} {"a" AND ("b" NOT "c")} + 14 {a OR b NOT c} {"a" OR ("b" NOT "c")} + 15 {a NOT b AND c} {("a" NOT "b") AND "c"} + 16 {a NOT b OR c} {("a" NOT "b") OR "c"} + + 17 {a AND b OR c} {("a" AND "b") OR "c"} + 18 {a OR b AND c} {"a" OR ("b" AND "c")} + +} { + do_execsql_test 1.$tn {SELECT fts5_expr($expr)} [list $res] +} + +do_catchsql_test 2.1 { + SELECT fts5_expr() +} {1 {wrong number of arguments to function fts5_expr}} + +do_catchsql_test 2.1 { + SELECT fts5_expr_tcl() +} {1 {wrong number of arguments to function fts5_expr_tcl}} + +finish_test + + + diff --git a/ext/fts5/test/fts5fault1.test b/ext/fts5/test/fts5fault1.test new file mode 100644 index 0000000..9d63a11 --- /dev/null +++ b/ext/fts5/test/fts5fault1.test @@ -0,0 +1,354 @@ +# 2014 June 17 +# +# 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 FTS5 module. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +source $testdir/malloc_common.tcl +set testprefix fts5fault1 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +# Simple tests: +# +# 1: CREATE VIRTUAL TABLE +# 2: INSERT statement +# 3: DELETE statement +# 4: MATCH expressions +# +# + +faultsim_save_and_close +do_faultsim_test 1 -faults ioerr-t* -prep { + faultsim_restore_and_reopen +} -body { + execsql { CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix='1, 2, 3') } +} -test { + faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}} +} + +reset_db +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix='1, 2, 3'); +} +faultsim_save_and_close +do_faultsim_test 2 -prep { + faultsim_restore_and_reopen +} -body { + execsql { + INSERT INTO t1 VALUES('a b c', 'a bc def ghij klmno'); + } +} -test { + faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}} +} + +reset_db +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix='1, 2, 3'); + INSERT INTO t1 VALUES('a b c', 'a bc def ghij klmno'); +} +faultsim_save_and_close +do_faultsim_test 3 -prep { + faultsim_restore_and_reopen +} -body { + execsql { DELETE FROM t1 } +} -test { + faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}} +} + +reset_db +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE t2 USING fts5(a, b); + INSERT INTO t2 VALUES('m f a jj th q gi ar', 'hj n h h sg j i m'); + INSERT INTO t2 VALUES('nr s t g od j kf h', 'sb h aq rg op rb n nl'); + INSERT INTO t2 VALUES('do h h pb p p q fr', 'c rj qs or cr a l i'); + INSERT INTO t2 VALUES('lk gp t i lq mq qm p', 'h mr g f op ld aj h'); + INSERT INTO t2 VALUES('ct d sq kc qi k f j', 'sn gh c of g s qt q'); + INSERT INTO t2 VALUES('d ea d d om mp s ab', 'dm hg l df cm ft pa c'); + INSERT INTO t2 VALUES('tc dk c jn n t sr ge', 'a a kn bc n i af h'); + INSERT INTO t2 VALUES('ie ii d i b sa qo rf', 'a h m aq i b m fn'); + INSERT INTO t2 VALUES('gs r fo a er m h li', 'tm c p gl eb ml q r'); + INSERT INTO t2 VALUES('k fe fd rd a gi ho kk', 'ng m c r d ml rm r'); +} +faultsim_save_and_close + +foreach {tn expr res} { + 1 { dk } 7 + 2 { m f } 1 + 3 { f* } {1 3 4 5 6 8 9 10} + 4 { m OR f } {1 4 5 8 9 10} + 5 { sn + gh } {5} + 6 { "sn gh" } {5} + 7 { NEAR(r a, 5) } {9} + 8 { m* f* } {1 4 6 8 9 10} + 9 { m* + f* } {1 8} + 10 { c NOT p } {5 6 7 10} +} { + do_faultsim_test 4.$tn -prep { + faultsim_restore_and_reopen + } -body " + execsql { SELECT rowid FROM t2 WHERE t2 MATCH '$expr' } + " -test " + faultsim_test_result {[list 0 $res]} {1 {vtable constructor failed: t2}} + " +} + + +#------------------------------------------------------------------------- +# The following tests use a larger database populated with random data. +# +# The database page size is set to 512 bytes and the FTS5 page size left +# at the default 1000 bytes. This means that reading a node may require +# pulling an overflow page from disk, which is an extra opportunity for +# an error to occur. +# +reset_db +do_execsql_test 5.0.1 { + PRAGMA main.page_size = 512; + CREATE VIRTUAL TABLE x1 USING fts5(a, b); + PRAGMA main.page_size; +} {512} + +proc rnddoc {n} { + set map [list 0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j] + set doc [list] + for {set i 0} {$i < $n} {incr i} { + lappend doc [string map $map [format %.3d [expr int(rand()*1000)]]] + } + set doc +} +db func rnddoc rnddoc + +do_execsql_test 5.0.2 { + WITH r(a, b) AS ( + SELECT rnddoc(6), rnddoc(6) UNION ALL + SELECT rnddoc(6), rnddoc(6) FROM r + ) + INSERT INTO x1 SELECT * FROM r LIMIT 10000; +} + +set res [db one { + SELECT count(*) FROM x1 WHERE x1.a LIKE '%abc%' OR x1.b LIKE '%abc%'} +] + +do_faultsim_test 5.1 -faults oom* -body { + execsql { SELECT count(*) FROM x1 WHERE x1 MATCH 'abc' } +} -test { + faultsim_test_result [list 0 $::res] +} +do_faultsim_test 5.2 -faults oom* -body { + execsql { SELECT count(*) FROM x1 WHERE x1 MATCH 'abcd' } +} -test { + faultsim_test_result [list 0 0] +} + +proc test_astar {a b} { + return [expr { [regexp {a[^ ][^ ]} $a] || [regexp {a[^ ][^ ]} $b] }] +} +db func test_astar test_astar + +set res [db one { SELECT count(*) FROM x1 WHERE test_astar(a, b) } ] +do_faultsim_test 5.3 -faults oom* -body { + execsql { SELECT count(*) FROM x1 WHERE x1 MATCH 'a*' } +} -test { + faultsim_test_result [list 0 $::res] +} + +do_faultsim_test 5.4 -faults oom* -prep { + db close + sqlite3 db test.db +} -body { + execsql { INSERT INTO x1 VALUES('a b c d', 'e f g h') } +} -test { + faultsim_test_result [list 0 {}] +} + +do_faultsim_test 5.5.1 -faults oom* -body { + execsql { + SELECT count(fts5_decode(rowid, block)) FROM x1_data WHERE rowid=1 + } +} -test { + faultsim_test_result [list 0 1] +} +do_faultsim_test 5.5.2 -faults oom* -body { + execsql { + SELECT count(fts5_decode(rowid, block)) FROM x1_data WHERE rowid=10 + } +} -test { + faultsim_test_result [list 0 1] +} +do_faultsim_test 5.5.3 -faults oom* -body { + execsql { + SELECT count(fts5_decode(rowid, block)) FROM x1_data WHERE rowid = ( + SELECT min(rowid) FROM x1_data WHERE rowid>20 + ) + } +} -test { + faultsim_test_result [list 0 1] +} +do_faultsim_test 5.5.4 -faults oom* -body { + execsql { + SELECT count(fts5_decode(rowid, block)) FROM x1_data WHERE rowid = ( + SELECT max(rowid) FROM x1_data + ) + } +} -test { + faultsim_test_result [list 0 1] +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 6.0 { + CREATE VIRTUAL TABLE x1 USING fts5(x); + INSERT INTO x1(x1, rank) VALUES('automerge', 0); + + INSERT INTO x1 VALUES('a b c'); -- 1 + INSERT INTO x1 VALUES('a b c'); -- 2 + INSERT INTO x1 VALUES('a b c'); -- 3 + INSERT INTO x1 VALUES('a b c'); -- 4 + INSERT INTO x1 VALUES('a b c'); -- 5 + INSERT INTO x1 VALUES('a b c'); -- 6 + INSERT INTO x1 VALUES('a b c'); -- 7 + INSERT INTO x1 VALUES('a b c'); -- 8 + INSERT INTO x1 VALUES('a b c'); -- 9 + INSERT INTO x1 VALUES('a b c'); -- 10 + INSERT INTO x1 VALUES('a b c'); -- 11 + INSERT INTO x1 VALUES('a b c'); -- 12 + INSERT INTO x1 VALUES('a b c'); -- 13 + INSERT INTO x1 VALUES('a b c'); -- 14 + INSERT INTO x1 VALUES('a b c'); -- 15 + + SELECT count(*) FROM x1_data; +} {17} + +faultsim_save_and_close + +do_faultsim_test 6.1 -faults oom* -prep { + faultsim_restore_and_reopen +} -body { + execsql { INSERT INTO x1 VALUES('d e f') } +} -test { + faultsim_test_result [list 0 {}] + if {$testrc==0} { + set nCnt [db one {SELECT count(*) FROM x1_data}] + if {$nCnt!=3} { error "expected 3 entries but there are $nCnt" } + } +} + +do_faultsim_test 6.2 -faults oom* -prep { + faultsim_restore_and_reopen +} -body { + execsql { INSERT INTO x1(x1, rank) VALUES('pgsz', 32) } +} -test { + faultsim_test_result [list 0 {}] +} + +do_faultsim_test 6.3 -faults oom-* -prep { + faultsim_restore_and_reopen +} -body { + execsql { INSERT INTO x1(x1) VALUES('integrity-check') } +} -test { + faultsim_test_result [list 0 {}] +} + +do_faultsim_test 6.4 -faults oom-* -prep { + faultsim_restore_and_reopen +} -body { + execsql { INSERT INTO x1(x1) VALUES('optimize') } +} -test { + faultsim_test_result [list 0 {}] +} + +#------------------------------------------------------------------------- +# +do_faultsim_test 7.0 -faults oom* -prep { + catch { db close } +} -body { + sqlite3 db test.db +} -test { + faultsim_test_result [list 0 {}] {1 {}} {1 {initialization of fts5 failed: }} +} + +#------------------------------------------------------------------------- +# A prefix query against a large document set. +# +proc rnddoc {n} { + set map [list 0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j] + set doc [list] + for {set i 0} {$i < $n} {incr i} { + lappend doc "x[string map $map [format %.3d [expr int(rand()*1000)]]]" + } + set doc +} + +reset_db +db func rnddoc rnddoc + +do_test 8.0 { + execsql { CREATE VIRTUAL TABLE x1 USING fts5(a) } + set ::res [list] + for {set i 1} {$i<100} {incr i 1} { + execsql { INSERT INTO x1 VALUES( rnddoc(50) ) } + lappend ::res $i + } +} {} + +do_faultsim_test 8.1 -faults oom* -prep { +} -body { + execsql { + SELECT rowid FROM x1 WHERE x1 MATCH 'x*' + } +} -test { + faultsim_test_result [list 0 $::res] +} + +#------------------------------------------------------------------------- +# Segment promotion. +# +do_test 9.0 { + reset_db + db func rnddoc fts5_rnddoc + execsql { + CREATE VIRTUAL TABLE s2 USING fts5(x); + INSERT INTO s2(s2, rank) VALUES('pgsz', 32); + INSERT INTO s2(s2, rank) VALUES('automerge', 0); + } + + for {set i 1} {$i <= 16} {incr i} { + execsql { INSERT INTO s2 VALUES(rnddoc(5)) } + } + fts5_level_segs s2 +} {0 1} +set insert_doc [db one {SELECT rnddoc(160)}] +faultsim_save_and_close + +do_faultsim_test 9.1 -faults oom-* -prep { + faultsim_restore_and_reopen +} -body { + execsql { INSERT INTO s2 VALUES($::insert_doc) } +} -test { + faultsim_test_result {0 {}} + if {$testrc==0} { + set ls [fts5_level_segs s2] + if {$ls != "2 0"} { error "fts5_level_segs says {$ls}" } + } +} + + + +finish_test + diff --git a/ext/fts5/test/fts5fault2.test b/ext/fts5/test/fts5fault2.test new file mode 100644 index 0000000..43c7c7a --- /dev/null +++ b/ext/fts5/test/fts5fault2.test @@ -0,0 +1,140 @@ +# 2014 June 17 +# +# 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 is focused on OOM errors. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +source $testdir/malloc_common.tcl +set testprefix fts5fault2 + +# If SQLITE_ENABLE_FTS5 is not defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +set doc [string trim [string repeat "x y z " 200]] +do_execsql_test 1.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, x); + CREATE VIRTUAL TABLE x1 USING fts5(x, content='t1', content_rowid='a'); + INSERT INTO x1(x1, rank) VALUES('pgsz', 32); + WITH input(a,b) AS ( + SELECT 1, $doc UNION ALL + SELECT a+1, ($doc || CASE WHEN (a+1)%100 THEN '' ELSE ' xyz' END) + FROM input WHERE a < 1000 + ) + INSERT INTO t1 SELECT * FROM input; + + INSERT INTO x1(x1) VALUES('rebuild'); +} + +do_faultsim_test 1.1 -faults oom-* -prep { +} -body { + execsql { SELECT rowid FROM x1 WHERE x1 MATCH 'z AND xyz' } +} -test { + faultsim_test_result {0 {100 200 300 400 500 600 700 800 900 1000}} +} + +do_faultsim_test 1.2 -faults oom-* -prep { +} -body { + execsql { SELECT rowid FROM x1 WHERE x1 MATCH 'z + xyz' ORDER BY 1 DESC} +} -test { + faultsim_test_result {0 {1000 900 800 700 600 500 400 300 200 100}} +} + +#------------------------------------------------------------------------- +# OOM within a query that accesses the in-memory hash table. +# +reset_db +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE "a b c" USING fts5(a, b, c); + INSERT INTO "a b c" VALUES('one two', 'x x x', 'three four'); + INSERT INTO "a b c" VALUES('nine ten', 'y y y', 'two two'); +} + +do_faultsim_test 2.1 -faults oom-trans* -prep { + execsql { + BEGIN; + INSERT INTO "a b c" VALUES('one one', 'z z z', 'nine ten'); + } +} -body { + execsql { SELECT rowid FROM "a b c" WHERE "a b c" MATCH 'one' } +} -test { + faultsim_test_result {0 {1 3}} + catchsql { ROLLBACK } +} + +#------------------------------------------------------------------------- +# OOM within an 'optimize' operation that writes multiple pages to disk. +# +reset_db +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE zzz USING fts5(z); + INSERT INTO zzz(zzz, rank) VALUES('pgsz', 32); + INSERT INTO zzz VALUES('a b c d'); + INSERT INTO zzz SELECT 'c d e f' FROM zzz; + INSERT INTO zzz SELECT 'e f g h' FROM zzz; + INSERT INTO zzz SELECT 'i j k l' FROM zzz; + INSERT INTO zzz SELECT 'l k m n' FROM zzz; + INSERT INTO zzz SELECT 'o p q r' FROM zzz; +} +faultsim_save_and_close + +do_faultsim_test 3.1 -faults oom-trans* -prep { + faultsim_restore_and_reopen + execsql { SELECT rowid FROM zzz } +} -body { + execsql { INSERT INTO zzz(zzz) VALUES('optimize') } +} -test { + faultsim_test_result {0 {}} +} + +#------------------------------------------------------------------------- +# OOM within an 'integrity-check' operation. +# +reset_db +db func rnddoc fts5_rnddoc +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE zzz USING fts5(z); + INSERT INTO zzz(zzz, rank) VALUES('pgsz', 32); + WITH ii(i) AS (SELECT 1 UNION SELECT i+1 FROM ii WHERE i<10) + INSERT INTO zzz SELECT rnddoc(10) || ' xccc' FROM ii; +} + +do_faultsim_test 4.1 -faults oom-trans* -prep { +} -body { + execsql { INSERT INTO zzz(zzz) VALUES('integrity-check') } +} -test { + faultsim_test_result {0 {}} +} + +#------------------------------------------------------------------------- +# OOM while parsing a tokenize=option +# +reset_db +faultsim_save_and_close +do_faultsim_test 5.0 -faults oom-* -prep { + faultsim_restore_and_reopen +} -body { + execsql { + CREATE VIRTUAL TABLE uio USING fts5(a, b, + tokenize="porter 'ascii'", + content="another table", + content_rowid="somecolumn" + ); + } +} -test { + faultsim_test_result {0 {}} +} + +finish_test + diff --git a/ext/fts5/test/fts5fault3.test b/ext/fts5/test/fts5fault3.test new file mode 100644 index 0000000..bfeead4 --- /dev/null +++ b/ext/fts5/test/fts5fault3.test @@ -0,0 +1,113 @@ +# 2014 June 17 +# +# 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 is focused on OOM errors. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +source $testdir/malloc_common.tcl +set testprefix fts5fault3 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +#------------------------------------------------------------------------- +# An OOM while resuming a partially completed segment merge. +# +db func rnddoc fts5_rnddoc +do_test 1.0 { + expr srand(0) + execsql { + CREATE VIRTUAL TABLE xx USING fts5(x); + INSERT INTO xx(xx, rank) VALUES('pgsz', 32); + INSERT INTO xx(xx, rank) VALUES('automerge', 16); + } + for {set i 0} {$i < 10} {incr i} { + execsql { + BEGIN; + INSERT INTO xx(x) VALUES(rnddoc(20)); + INSERT INTO xx(x) VALUES(rnddoc(20)); + INSERT INTO xx(x) VALUES(rnddoc(20)); + COMMIT + } + } + + execsql { + INSERT INTO xx(xx, rank) VALUES('automerge', 2); + INSERT INTO xx(xx, rank) VALUES('merge', 50); + } +} {} +faultsim_save_and_close + +do_faultsim_test 1 -faults oom-* -prep { + faultsim_restore_and_reopen +} -body { + execsql { INSERT INTO xx(xx, rank) VALUES('merge', 1) } +} -test { + faultsim_test_result [list 0 {}] +} + +#------------------------------------------------------------------------- +# An OOM while flushing an unusually large term to disk. +# +reset_db +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE xx USING fts5(x); + INSERT INTO xx(xx, rank) VALUES('pgsz', 32); +} +faultsim_save_and_close + +set doc "a long term abcdefghijklmnopqrstuvwxyz " +append doc "and then abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz " +append doc [string repeat "abcdefghijklmnopqrstuvwxyz" 10] + +do_faultsim_test 2 -faults oom-* -prep { + faultsim_restore_and_reopen +} -body { + execsql { INSERT INTO xx(x) VALUES ($::doc) } +} -test { + faultsim_test_result [list 0 {}] +} + +#------------------------------------------------------------------------- +# An OOM while flushing an unusually large term to disk. +# +reset_db +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE xx USING fts5(x); +} +faultsim_save_and_close + +set doc [fts5_rnddoc 1000] +do_faultsim_test 3.1 -faults oom-* -prep { + faultsim_restore_and_reopen +} -body { + execsql { INSERT INTO xx(x) VALUES ($::doc) } +} -test { + faultsim_test_result [list 0 {}] +} + +set doc [string repeat "abc " 100] +do_faultsim_test 3.2 -faults oom-* -prep { + faultsim_restore_and_reopen +} -body { + execsql { INSERT INTO xx(x) VALUES ($::doc) } +} -test { + faultsim_test_result [list 0 {}] +} + + + +finish_test + diff --git a/ext/fts5/test/fts5fault4.test b/ext/fts5/test/fts5fault4.test new file mode 100644 index 0000000..acc43eb --- /dev/null +++ b/ext/fts5/test/fts5fault4.test @@ -0,0 +1,398 @@ +# 2014 June 17 +# +# 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 is focused on OOM errors. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +source $testdir/malloc_common.tcl +set testprefix fts5fault4 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +#------------------------------------------------------------------------- +# An OOM while dropping an fts5 table. +# +db func rnddoc fts5_rnddoc +do_test 1.0 { + execsql { CREATE VIRTUAL TABLE xx USING fts5(x) } +} {} +faultsim_save_and_close + +do_faultsim_test 1 -faults oom-* -prep { + faultsim_restore_and_reopen + execsql { SELECT * FROM xx } +} -body { + execsql { DROP TABLE xx } +} -test { + faultsim_test_result [list 0 {}] +} + +#------------------------------------------------------------------------- +# An OOM while "reseeking" an FTS cursor. +# +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE jj USING fts5(j); + INSERT INTO jj(rowid, j) VALUES(101, 'm t w t f s s'); + INSERT INTO jj(rowid, j) VALUES(202, 't w t f s'); + INSERT INTO jj(rowid, j) VALUES(303, 'w t f'); + INSERT INTO jj(rowid, j) VALUES(404, 't'); +} +faultsim_save_and_close + +do_faultsim_test 3 -faults oom-* -prep { + faultsim_restore_and_reopen + execsql { SELECT * FROM jj } +} -body { + set res [list] + db eval { SELECT rowid FROM jj WHERE jj MATCH 't' } { + lappend res $rowid + if {$rowid==303} { + execsql { DELETE FROM jj WHERE rowid=404 } + } + } + set res +} -test { + faultsim_test_result [list 0 {101 202 303}] +} + +#------------------------------------------------------------------------- +# An OOM within a special "*reads" query. +# +reset_db +db func rnddoc fts5_rnddoc +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE x1 USING fts5(x); + INSERT INTO x1(x1, rank) VALUES('pgsz', 32); + + WITH ii(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<10 ) + INSERT INTO x1 SELECT rnddoc(5) FROM ii; +} + +set ::res [db eval {SELECT rowid, x1 FROM x1 WHERE x1 MATCH '*reads'}] + +do_faultsim_test 4 -faults oom-* -body { + db eval {SELECT rowid, x, x1 FROM x1 WHERE x1 MATCH '*reads'} +} -test { + faultsim_test_result {0 {0 {} 4}} +} + +#------------------------------------------------------------------------- +# An OOM within a query that uses a custom rank function. +# +reset_db +do_execsql_test 5.0 { + PRAGMA encoding='utf16'; + CREATE VIRTUAL TABLE x2 USING fts5(x); + INSERT INTO x2(rowid, x) VALUES(10, 'a b c'); -- 3 + INSERT INTO x2(rowid, x) VALUES(20, 'a b c'); -- 6 + INSERT INTO x2(rowid, x) VALUES(30, 'a b c'); -- 2 + INSERT INTO x2(rowid, x) VALUES(40, 'a b c'); -- 5 + INSERT INTO x2(rowid, x) VALUES(50, 'a b c'); -- 1 +} + +proc rowidmod {cmd mod} { + set row [$cmd xRowid] + expr {$row % $mod} +} +sqlite3_fts5_create_function db rowidmod rowidmod + +do_faultsim_test 5.1 -faults oom-* -body { + db eval { + SELECT rowid || '-' || rank FROM x2 WHERE x2 MATCH 'b' AND + rank MATCH "rowidmod('7')" ORDER BY rank + } +} -test { + faultsim_test_result {0 {50-1 30-2 10-3 40-5 20-6}} +} + +proc rowidprefix {cmd prefix} { + set row [$cmd xRowid] + set {} "${row}-${prefix}" +} +sqlite3_fts5_create_function db rowidprefix rowidprefix + +set str [string repeat abcdefghijklmnopqrstuvwxyz 10] +do_faultsim_test 5.2 -faults oom-* -body { + db eval " + SELECT rank, x FROM x2 WHERE x2 MATCH 'b' AND + rank MATCH 'rowidprefix(''$::str'')' + LIMIT 1 + " +} -test { + faultsim_test_result "0 {10-$::str {a b c}}" +} + + +#------------------------------------------------------------------------- +# OOM errors within auxiliary functions. +# +reset_db +do_execsql_test 6.0 { + CREATE VIRTUAL TABLE x3 USING fts5(xxx); + INSERT INTO x3 VALUES('a b c d c b a'); + INSERT INTO x3 VALUES('a a a a a a a'); + INSERT INTO x3 VALUES('a a a a a a a'); +} + +do_faultsim_test 6.1 -faults oom-t* -body { + db eval { SELECT highlight(x3, 0, '*', '*') FROM x3 WHERE x3 MATCH 'c' } +} -test { + faultsim_test_result {0 {{a b *c* d *c* b a}}} +} + +proc firstinst {cmd} { + foreach {p c o} [$cmd xInst 0] {} + expr $c*100 + $o +} +sqlite3_fts5_create_function db firstinst firstinst + +do_faultsim_test 6.2 -faults oom-t* -body { + db eval { SELECT firstinst(x3) FROM x3 WHERE x3 MATCH 'c' } +} -test { + faultsim_test_result {0 2} {1 SQLITE_NOMEM} +} + +proc previc {cmd} { + set res [$cmd xGetAuxdataInt 0] + $cmd xSetAuxdataInt [$cmd xInstCount] + return $res +} +sqlite3_fts5_create_function db previc previc + +do_faultsim_test 6.2 -faults oom-t* -body { + db eval { SELECT previc(x3) FROM x3 WHERE x3 MATCH 'a' } +} -test { + faultsim_test_result {0 {0 2 7}} {1 SQLITE_NOMEM} +} + +#------------------------------------------------------------------------- +# OOM error when querying for a phrase with many tokens. +# +reset_db +do_execsql_test 7.0 { + CREATE VIRTUAL TABLE tt USING fts5(x, y); + INSERT INTO tt VALUES('f b g b c b', 'f a d c c b'); -- 1 + INSERT INTO tt VALUES('d a e f e d', 'f b b d e e'); -- 2 + INSERT INTO tt VALUES('f b g a d c', 'e f c f a d'); -- 3 + INSERT INTO tt VALUES('f f c d g f', 'f a e b g b'); -- 4 + INSERT INTO tt VALUES('a g b d a g', 'e g a e a c'); -- 5 + INSERT INTO tt VALUES('c d b d e f', 'f g e g e e'); -- 6 + INSERT INTO tt VALUES('e g f f b c', 'f c e f g f'); -- 7 + INSERT INTO tt VALUES('e g c f c e', 'f e e a f g'); -- 8 + INSERT INTO tt VALUES('e a e b e e', 'd c c f f f'); -- 9 + INSERT INTO tt VALUES('f a g g c c', 'e g d g c e'); -- 10 + INSERT INTO tt VALUES('c d b a e f', 'f g e h e e'); -- 11 + + CREATE VIRTUAL TABLE tt2 USING fts5(o); + INSERT INTO tt2(rowid, o) SELECT rowid, x||' '||y FROM tt; + INSERT INTO tt2(rowid, o) VALUES(12, 'a b c d e f g h i j k l'); +} + +do_faultsim_test 7.2 -faults oom-* -body { + db eval { SELECT rowid FROM tt WHERE tt MATCH 'f+g+e+g+e+e' } +} -test { + faultsim_test_result {0 6} {1 SQLITE_NOMEM} +} + +do_faultsim_test 7.3 -faults oom-* -body { + db eval { SELECT rowid FROM tt WHERE tt MATCH 'NEAR(a b c d e f)' } +} -test { + faultsim_test_result {0 11} {1 SQLITE_NOMEM} +} + +do_faultsim_test 7.4 -faults oom-t* -body { + db eval { SELECT rowid FROM tt2 WHERE tt2 MATCH '"g c f c e f e e a f"' } +} -test { + faultsim_test_result {0 8} {1 SQLITE_NOMEM} +} + +do_faultsim_test 7.5 -faults oom-* -body { + db eval {SELECT rowid FROM tt2 WHERE tt2 MATCH 'NEAR(a b c d e f g h i j k)'} +} -test { + faultsim_test_result {0 12} {1 SQLITE_NOMEM} +} + +do_faultsim_test 7.6 -faults oom-* -body { + db eval {SELECT rowid FROM tt WHERE tt MATCH 'y: "c c"'} +} -test { + faultsim_test_result {0 {1 9}} {1 SQLITE_NOMEM} +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 8.0 { + CREATE VIRTUAL TABLE tt USING fts5(x); + INSERT INTO tt(tt, rank) VALUES('pgsz', 32); + BEGIN; + INSERT INTO tt(rowid, x) VALUES(1, 'a b c d x x'); + WITH ii(i) AS (SELECT 2 UNION ALL SELECT i+1 FROM ii WHERE i<99) + INSERT INTO tt(rowid, x) SELECT i, 'a b c x x d' FROM ii; + INSERT INTO tt(rowid, x) VALUES(100, 'a b c d x x'); + COMMIT; +} + +do_faultsim_test 8.1 -faults oom-t* -body { + db eval { SELECT rowid FROM tt WHERE tt MATCH 'NEAR(a b c d, 2)' } +} -test { + faultsim_test_result {0 {1 100}} {1 SQLITE_NOMEM} +} + +do_faultsim_test 8.2 -faults oom-t* -body { + db eval { SELECT count(*) FROM tt WHERE tt MATCH 'a OR d' } +} -test { + faultsim_test_result {0 100} {1 SQLITE_NOMEM} +} + + +#------------------------------------------------------------------------- +# Fault in NOT query. +# +reset_db +do_execsql_test 9.0 { + CREATE VIRTUAL TABLE tt USING fts5(x); + INSERT INTO tt(tt, rank) VALUES('pgsz', 32); + BEGIN; + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<200) + INSERT INTO tt(rowid, x) + SELECT i, CASE WHEN (i%50)==0 THEN 'a a a a a a' ELSE 'a x a x a x' END + FROM ii; + COMMIT; +} + +do_faultsim_test 9.1 -faults oom-* -body { + db eval { SELECT rowid FROM tt WHERE tt MATCH 'a NOT x' } +} -test { + faultsim_test_result {0 {50 100 150 200}} {1 SQLITE_NOMEM} +} + +#------------------------------------------------------------------------- +# OOM in fts5_expr() SQL function. +# +do_faultsim_test 10.1 -faults oom-t* -body { + db one { SELECT fts5_expr('a AND b NEAR(a b)') } +} -test { + faultsim_test_result {0 {"a" AND "b" AND NEAR("a" "b", 10)}} +} + +do_faultsim_test 10.2 -faults oom-t* -body { + db one { SELECT fts5_expr_tcl('x:"a b c" AND b NEAR(a b)', 'ns', 'x') } +} -test { + set res {AND [ns -col 0 -- {a b c}] [ns -- {b}] [ns -near 10 -- {a} {b}]} + faultsim_test_result [list 0 $res] +} + +do_faultsim_test 10.3 -faults oom-t* -body { + db one { SELECT fts5_expr('x:a', 'x') } +} -test { + faultsim_test_result {0 {x : "a"}} +} + +#------------------------------------------------------------------------- +# OOM while configuring 'rank' option. +# +reset_db +do_execsql_test 11.0 { + CREATE VIRTUAL TABLE ft USING fts5(x); +} +do_faultsim_test 11.1 -faults oom-t* -body { + db eval { INSERT INTO ft(ft, rank) VALUES('rank', 'bm25(10.0, 5.0)') } +} -test { + faultsim_test_result {0 {}} {1 {disk I/O error}} +} + +#------------------------------------------------------------------------- +# OOM while creating an fts5vocab table. +# +reset_db +do_execsql_test 12.0 { + CREATE VIRTUAL TABLE ft USING fts5(x); +} +faultsim_save_and_close +do_faultsim_test 12.1 -faults oom-t* -prep { + faultsim_restore_and_reopen + db eval { SELECT * FROM sqlite_master } +} -body { + db eval { CREATE VIRTUAL TABLE vv USING fts5vocab(ft, 'row') } +} -test { + faultsim_test_result {0 {}} +} + +#------------------------------------------------------------------------- +# OOM while querying an fts5vocab table. +# +reset_db +do_execsql_test 13.0 { + CREATE VIRTUAL TABLE ft USING fts5(x); + INSERT INTO ft VALUES('a b'); + CREATE VIRTUAL TABLE vv USING fts5vocab(ft, 'row'); +} +faultsim_save_and_close +do_faultsim_test 13.1 -faults oom-t* -prep { + faultsim_restore_and_reopen + db eval { SELECT * FROM vv } +} -body { + db eval { SELECT * FROM vv } +} -test { + faultsim_test_result {0 {a 1 1 b 1 1}} +} + +#------------------------------------------------------------------------- +# OOM in multi-column token query. +# +reset_db +do_execsql_test 13.0 { + CREATE VIRTUAL TABLE ft USING fts5(x, y, z); + INSERT INTO ft(ft, rank) VALUES('pgsz', 32); + INSERT INTO ft VALUES( + 'x x x x x x x x x x x x x x x x', + 'y y y y y y y y y y y y y y y y', + 'z z z z z z z z x x x x x x x x' + ); + INSERT INTO ft SELECT * FROM ft; + INSERT INTO ft SELECT * FROM ft; + INSERT INTO ft SELECT * FROM ft; + INSERT INTO ft SELECT * FROM ft; +} +faultsim_save_and_close +do_faultsim_test 13.1 -faults oom-t* -prep { + faultsim_restore_and_reopen + db eval { SELECT * FROM ft } +} -body { + db eval { SELECT rowid FROM ft WHERE ft MATCH '{x z}: x' } +} -test { + faultsim_test_result {0 {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}} +} + +#------------------------------------------------------------------------- +# OOM in an "ALTER TABLE RENAME TO" +# +reset_db +do_execsql_test 14.0 { + CREATE VIRTUAL TABLE "tbl one" USING fts5(x, y, z); +} +faultsim_save_and_close +do_faultsim_test 14.1 -faults oom-t* -prep { + faultsim_restore_and_reopen + db eval { SELECT * FROM "tbl one" } +} -body { + db eval { ALTER TABLE "tbl one" RENAME TO "tbl two" } +} -test { + faultsim_test_result {0 {}} +} + +finish_test + diff --git a/ext/fts5/test/fts5fault5.test b/ext/fts5/test/fts5fault5.test new file mode 100644 index 0000000..75b7d9a --- /dev/null +++ b/ext/fts5/test/fts5fault5.test @@ -0,0 +1,133 @@ +# 2014 June 17 +# +# 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 is focused on OOM errors. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +source $testdir/malloc_common.tcl +set testprefix fts5fault5 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +#------------------------------------------------------------------------- +# OOM while creating an FTS5 table. +# +do_faultsim_test 1.1 -faults oom-t* -prep { + db eval { DROP TABLE IF EXISTS abc } +} -body { + db eval { CREATE VIRTUAL TABLE abc USING fts5(x,y) } +} -test { + faultsim_test_result {0 {}} +} + + +#------------------------------------------------------------------------- +# OOM while writing a multi-tier doclist-index. And while running +# integrity-check on the same. +# +reset_db +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE tt USING fts5(x); + INSERT INTO tt(tt, rank) VALUES('pgsz', 32); +} +faultsim_save_and_close + +do_faultsim_test 2.1 -faults oom-t* -prep { + faultsim_restore_and_reopen + db eval { SELECT * FROM tt } +} -body { + set str [string repeat "abc " 50] + db eval { + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100) + INSERT INTO tt(rowid, x) SELECT i, $str FROM ii; + } +} -test { + faultsim_test_result {0 {}} +} + +do_faultsim_test 2.2 -faults oom-t* -body { + db eval { INSERT INTO tt(tt) VALUES('integrity-check') } +} -test { + faultsim_test_result {0 {}} +} + +#------------------------------------------------------------------------- +# OOM while scanning fts5vocab tables. +# +reset_db +do_test 3.0 { + execsql { + CREATE VIRTUAL TABLE tt USING fts5(x); + CREATE VIRTUAL TABLE tv USING fts5vocab(tt, 'row'); + + CREATE VIRTUAL TABLE tt2 USING fts5(x, detail=col); + CREATE VIRTUAL TABLE tv2 USING fts5vocab(tt2, 'col'); + + INSERT INTO tt(tt, rank) VALUES('pgsz', 32); + INSERT INTO tt2(tt2, rank) VALUES('pgsz', 32); + BEGIN; + } + + for {set i 0} {$i < 20} {incr i} { + set str [string repeat "$i " 50] + execsql { INSERT INTO tt VALUES($str) } + execsql { INSERT INTO tt2 VALUES($str) } + } + execsql COMMIT +} {} + +do_faultsim_test 3.1 -faults oom-t* -body { + db eval { + SELECT term FROM tv; + } +} -test { + faultsim_test_result {0 {0 1 10 11 12 13 14 15 16 17 18 19 2 3 4 5 6 7 8 9}} +} + +do_faultsim_test 3.2 -faults oom-t* -body { + db eval { + SELECT term FROM tv WHERE term BETWEEN '1' AND '2'; + } +} -test { + faultsim_test_result {0 {1 10 11 12 13 14 15 16 17 18 19 2}} +} + +breakpoint +do_execsql_test 3.3.0 { + SELECT * FROM tv2; +} { + 0 x 1 {} 1 x 1 {} 10 x 1 {} 11 x 1 {} 12 x 1 {} 13 x 1 {} + 14 x 1 {} 15 x 1 {} 16 x 1 {} 17 x 1 {} 18 x 1 {} 19 x 1 {} + 2 x 1 {} 3 x 1 {} 4 x 1 {} 5 x 1 {} 6 x 1 {} 7 x 1 {} 8 x 1 {} + 9 x 1 {} +} +do_faultsim_test 3.3 -faults oom-t* -body { + db eval { + SELECT * FROM tv2; + } +} -test { + faultsim_test_result [list 0 [list \ + 0 x 1 {} 1 x 1 {} 10 x 1 {} 11 x 1 {} 12 x 1 {} 13 x 1 {} \ + 14 x 1 {} 15 x 1 {} 16 x 1 {} 17 x 1 {} 18 x 1 {} 19 x 1 {} \ + 2 x 1 {} 3 x 1 {} 4 x 1 {} 5 x 1 {} 6 x 1 {} 7 x 1 {} 8 x 1 {} \ + 9 x 1 {} + ]] +} + + + +finish_test + diff --git a/ext/fts5/test/fts5fault6.test b/ext/fts5/test/fts5fault6.test new file mode 100644 index 0000000..118761f --- /dev/null +++ b/ext/fts5/test/fts5fault6.test @@ -0,0 +1,295 @@ +# 2014 June 17 +# +# 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 is focused on OOM errors. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +source $testdir/malloc_common.tcl +set testprefix fts5fault6 + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + + +#------------------------------------------------------------------------- +# OOM while rebuilding an FTS5 table. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE tt USING fts5(a, b); + INSERT INTO tt VALUES('c d c g g f', 'a a a d g a'); + INSERT INTO tt VALUES('c d g b f d', 'b g e c g c'); + INSERT INTO tt VALUES('c c f d e d', 'c e g d b c'); + INSERT INTO tt VALUES('e a f c e f', 'g b a c d g'); + INSERT INTO tt VALUES('c g f b b d', 'g c d c f g'); + INSERT INTO tt VALUES('d a g a b b', 'g c g g c e'); + INSERT INTO tt VALUES('e f a b c e', 'f d c d c c'); + INSERT INTO tt VALUES('e c a g c d', 'b b g f f b'); + INSERT INTO tt VALUES('g b d d e b', 'f f b d a c'); + INSERT INTO tt VALUES('e a d a e d', 'c e a e f g'); +} +faultsim_save_and_close + +do_faultsim_test 1.1 -faults oom-t* -prep { + faultsim_restore_and_reopen +} -body { + db eval { INSERT INTO tt(tt) VALUES('rebuild') } +} -test { + faultsim_test_result {0 {}} +} + +do_faultsim_test 1.2 -faults oom-t* -prep { + faultsim_restore_and_reopen +} -body { + db eval { REPLACE INTO tt(rowid, a, b) VALUES(6, 'x y z', 'l l l'); } +} -test { + faultsim_test_result {0 {}} +} + + +#------------------------------------------------------------------------- +# OOM within a special delete. +# +reset_db +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE tt USING fts5(a, content=""); + INSERT INTO tt VALUES('c d c g g f'); + INSERT INTO tt VALUES('c d g b f d'); + INSERT INTO tt VALUES('c c f d e d'); + INSERT INTO tt VALUES('e a f c e f'); + INSERT INTO tt VALUES('c g f b b d'); + INSERT INTO tt VALUES('d a g a b b'); + INSERT INTO tt VALUES('e f a b c e'); + INSERT INTO tt VALUES('e c a g c d'); + INSERT INTO tt VALUES('g b d d e b'); + INSERT INTO tt VALUES('e a d a e d'); +} +faultsim_save_and_close + +do_faultsim_test 2.1 -faults oom-t* -prep { + faultsim_restore_and_reopen +} -body { + db eval { INSERT INTO tt(tt, rowid, a) VALUES('delete', 3, 'c d g b f d'); } +} -test { + faultsim_test_result {0 {}} +} + +do_faultsim_test 2.2 -faults oom-t* -prep { + faultsim_restore_and_reopen +} -body { + db eval { INSERT INTO tt(tt) VALUES('delete-all') } +} -test { + faultsim_test_result {0 {}} +} + +do_faultsim_test 2.3 -faults oom-t* -prep { + faultsim_restore_and_reopen +} -body { + db eval { INSERT INTO tt VALUES('x y z') } +} -test { + faultsim_test_result {0 {}} +} + +#------------------------------------------------------------------------- +# OOM in the ASCII tokenizer with very large tokens. +# +# Also the unicode tokenizer. +# +set t1 [string repeat wxyz 20] +set t2 [string repeat wxyz 200] +set t3 [string repeat wxyz 2000] +set doc "$t1 $t2 $t3" +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE xyz USING fts5(c, tokenize=ascii, content=""); + CREATE VIRTUAL TABLE xyz2 USING fts5(c, content=""); +} +faultsim_save_and_close + +do_faultsim_test 3.1 -faults oom-t* -prep { + faultsim_restore_and_reopen + db eval { SELECT * FROM xyz } +} -body { + db eval { INSERT INTO xyz VALUES($::doc) } +} -test { + faultsim_test_result {0 {}} +} + +do_faultsim_test 3.2 -faults oom-t* -prep { + faultsim_restore_and_reopen + db eval { SELECT * FROM xyz2 } +} -body { + db eval { INSERT INTO xyz2 VALUES($::doc) } +} -test { + faultsim_test_result {0 {}} +} + +#------------------------------------------------------------------------- +# OOM while initializing a unicode61 tokenizer. +# +reset_db +faultsim_save_and_close +do_faultsim_test 4.1 -faults oom-t* -prep { + faultsim_restore_and_reopen +} -body { + db eval { + CREATE VIRTUAL TABLE yu USING fts5(x, tokenize="unicode61 separators abc"); + } +} -test { + faultsim_test_result {0 {}} +} + +#------------------------------------------------------------------------- +# +# 5.2.* OOM while running a query that includes synonyms and matchinfo(). +# +# 5.3.* OOM while running a query that returns a row containing instances +# of more than 4 synonyms for a single term. +# +proc mit {blob} { + set scan(littleEndian) i* + set scan(bigEndian) I* + binary scan $blob $scan($::tcl_platform(byteOrder)) r + return $r +} +proc tcl_tokenize {tflags text} { + foreach {w iStart iEnd} [fts5_tokenize_split $text] { + sqlite3_fts5_token $w $iStart $iEnd + if {$tflags=="query" && [string length $w]==1} { + for {set i 2} {$i < 7} {incr i} { + sqlite3_fts5_token -colo [string repeat $w $i] $iStart $iEnd + } + } + } +} +proc tcl_create {args} { return "tcl_tokenize" } +reset_db +sqlite3_fts5_create_tokenizer db tcl tcl_create +db func mit mit +sqlite3_fts5_register_matchinfo db +do_test 5.0 { + execsql { CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=tcl) } + execsql { INSERT INTO t1(t1, rank) VALUES('pgsz', 32) } + foreach {rowid text} { + 1 {aaaa cc b aaaaa cc aa} + 2 {aa aa bb a bbb} + 3 {bb aaaaa aaaaa b aaaa aaaaa} + 4 {aa a b aaaa aa} + 5 {aa b ccc aaaaa cc} + 6 {aa aaaaa bbbb cc aaa} + 7 {aaaaa aa aa ccccc bb} + 8 {ccc bbbbb ccccc bbb c} + 9 {cccccc bbbb a aaa cccc c} + + 20 {ddd f ddd eeeee fff ffff eeee ddd fff eeeee dddddd eeee} + 21 {fffff eee dddd fffff dd ee ee eeeee eee eeeeee ee dd e} + 22 {fffff d eeee dddd fffff dddddd ffff ddddd eeeee ee eee dddd ddddd} + 23 {ddddd fff ddd eeeee ffff eeee ddd ff ff ffffff eeeeee dddd ffffff} + 24 {eee dd ee dddd dddd eeeeee e eee fff ffff} + 25 {ddddd ffffff dddddd fff ddd ddddd ddd f eeee fff dddd f} + 26 {f ffff fff fff eeeeee dddd d dddddd ddddd eee ff eeeee} + 27 {eee fff dddddd eeeee eeeee dddd ddddd ffff f eeeee eee dddddd ddddd d} + 28 {dd ddddd d ddd d fff d dddd ee dddd ee ddd dddddd dddddd} + 29 {eeee dddd ee dddd eeee dddd dd fffff f ddd eeeee ddd ee} + 30 {ff ffffff eeeeee eeeee eee ffffff ff ffff f fffff eeeee} + 31 {fffff eeeeee dddd eeee eeee eeeeee eee fffff d ddddd ffffff ffff dddddd} + 32 {dddddd fffff ee eeeeee eeee ee fff dddd fff eeee ffffff eeeeee ffffff} + 33 {ddddd eeee dd ffff dddddd fff eeee ddddd ffff eeee ddd} + 34 {ee dddd ddddd dddddd eeee eeeeee f dd ee dddddd ffffff} + 35 {ee dddd dd eeeeee ddddd eee d eeeeee dddddd eee dddd fffff} + 36 {eee ffffff ffffff e fffff eeeee ff dddddd dddddd fff} + 37 {eeeee fffff dddddd dddd ffffff fff f dd ee dd dd eeeee} + 38 {eeeeee ee d ff eeeeee eeeeee eee eeeee ee ffffff dddd eeee dddddd ee} + 39 {eeeeee ddd fffff e dddd ee eee eee ffffff ee f d dddd} + 40 {ffffff dddddd eee ee ffffff eee eeee ddddd ee eeeeee f} + 41 {ddd ddd fff fffff ee fffff f fff ddddd fffff} + 42 {dddd ee ff d f ffffff fff ffffff ff dd dddddd f eeee} + 43 {d dd fff fffff d f fff e dddd ee ee} + 44 {ff ffff eee ddd d dd ffff dddd d eeee d eeeeee} + 45 {eeee f eeeee ee e ffff f ddd e fff} + 46 {ffff d ffff eeee ffff eeeee f ffff ddddd eee} + 47 {dd dd dddddd ddddd fffff dddddd ddd ddddd eeeeee ffff eeee eee ee} + 48 {ffff ffff e dddd ffffff dd dd dddd f fffff} + 49 {ffffff d dddddd ffff eeeee f ffff ffff d dd fffff eeeee} + + 50 {x e} + } { + execsql { INSERT INTO t1(rowid, a) VALUES($rowid, $text) } + } +} {} + +set res [list {*}{ + 1 {3 24 8 2 12 6} + 5 {2 24 8 2 12 6} + 6 {3 24 8 1 12 6} + 7 {3 24 8 1 12 6} + 9 {2 24 8 3 12 6} +}] +do_execsql_test 5.1.1 { + SELECT rowid, mit(matchinfo(t1, 'x')) FROM t1 WHERE t1 MATCH 'a AND c' +} $res +do_execsql_test 5.1.2 { + SELECT count(*) FROM t1 WHERE t1 MATCH 'd e f' +} 29 + +faultsim_save_and_close +do_faultsim_test 5.2 -faults oom* -prep { + faultsim_restore_and_reopen + sqlite3_fts5_create_tokenizer db tcl tcl_create + sqlite3_fts5_register_matchinfo db + db func mit mit +} -body { + db eval { + SELECT rowid, mit(matchinfo(t1, 'x')) FROM t1 WHERE t1 MATCH 'a AND c' + } +} -test { + faultsim_test_result [list 0 $::res] +} + +do_faultsim_test 5.3 -faults oom* -prep { + faultsim_restore_and_reopen + sqlite3_fts5_create_tokenizer db tcl tcl_create +} -body { + db eval { + SELECT count(*) FROM t1 WHERE t1 MATCH 'd AND e AND f' + } +} -test { + faultsim_test_result {0 29} +} + +do_faultsim_test 5.4 -faults oom* -prep { + faultsim_restore_and_reopen + sqlite3_fts5_create_tokenizer db tcl tcl_create +} -body { + db eval { + SELECT count(*) FROM t1 WHERE t1 MATCH 'x + e' + } +} -test { + faultsim_test_result {0 1} +} + +#------------------------------------------------------------------------- +catch { db close } +breakpoint +do_faultsim_test 6 -faults oom* -prep { + sqlite_orig db test.db + sqlite3_db_config_lookaside db 0 0 0 +} -test { + faultsim_test_result {0 {}} {1 {initialization of fts5 failed: }} + if {$testrc==0} { + db eval { CREATE VIRTUAL TABLE temp.t1 USING fts5(x) } + } + db close +} +finish_test + diff --git a/ext/fts5/test/fts5fault7.test b/ext/fts5/test/fts5fault7.test new file mode 100644 index 0000000..a35b19a --- /dev/null +++ b/ext/fts5/test/fts5fault7.test @@ -0,0 +1,119 @@ +# 2015 September 3 +# +# 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 is focused on OOM errors. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +source $testdir/malloc_common.tcl +set testprefix fts5fault7 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +if 1 { + +#------------------------------------------------------------------------- +# Test fault-injection on a query that uses xColumnSize() on columnsize=0 +# table. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize=0); + INSERT INTO t1 VALUES('a b c d e f g'); + INSERT INTO t1 VALUES('a b c d'); + INSERT INTO t1 VALUES('a b c d e f g h i j'); +} + + +fts5_aux_test_functions db +do_faultsim_test 1 -faults oom* -body { + execsql { SELECT fts5_test_columnsize(t1) FROM t1 WHERE t1 MATCH 'b' } +} -test { + faultsim_test_result {0 {7 4 10}} {1 SQLITE_NOMEM} +} + +} + +#------------------------------------------------------------------------- +# Test fault-injection when a segment is promoted. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t2 USING fts5(a); + INSERT INTO t2(t2, rank) VALUES('automerge', 0); + INSERT INTO t2(t2, rank) VALUES('crisismerge', 4); + INSERT INTO t2(t2, rank) VALUES('pgsz', 40); + + INSERT INTO t2 VALUES('a b c'); + INSERT INTO t2 VALUES('d e f'); + INSERT INTO t2 VALUES('f e d'); + INSERT INTO t2 VALUES('c b a'); + + INSERT INTO t2 VALUES('a b c'); + INSERT INTO t2 VALUES('d e f'); + INSERT INTO t2 VALUES('f e d'); + INSERT INTO t2 VALUES('c b a'); +} {} + +faultsim_save_and_close +do_faultsim_test 1 -faults oom-t* -prep { + faultsim_restore_and_reopen + db eval { + BEGIN; + INSERT INTO t2 VALUES('c d c g g f'); + INSERT INTO t2 VALUES('c d g b f d'); + INSERT INTO t2 VALUES('c c f d e d'); + INSERT INTO t2 VALUES('e a f c e f'); + INSERT INTO t2 VALUES('c g f b b d'); + INSERT INTO t2 VALUES('d a g a b b'); + INSERT INTO t2 VALUES('e f a b c e'); + INSERT INTO t2 VALUES('e c a g c d'); + INSERT INTO t2 VALUES('g b d d e b'); + INSERT INTO t2 VALUES('e a d a e d'); + } +} -body { + db eval COMMIT +} -test { + faultsim_test_result {0 {}} +} + +#------------------------------------------------------------------------- +# Test fault-injection when a segment is promoted. +# +reset_db +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE xy USING fts5(x); + INSERT INTO xy(rowid, x) VALUES(1, '1 2 3'); + INSERT INTO xy(rowid, x) VALUES(2, '2 3 4'); + INSERT INTO xy(rowid, x) VALUES(3, '3 4 5'); +} +faultsim_save_and_close + +do_faultsim_test 2.1 -faults oom-* -prep { + faultsim_restore_and_reopen +} -body { + db eval { UPDATE OR REPLACE xy SET rowid=3 WHERE rowid = 2 } +} -test { + faultsim_test_result {0 {}} +} + +# Test fault-injection when an empty expression is parsed. +# +do_faultsim_test 2.2 -faults oom-* -body { + db eval { SELECT * FROM xy('""') } +} -test { + faultsim_test_result {0 {}} +} + +finish_test + diff --git a/ext/fts5/test/fts5fault8.test b/ext/fts5/test/fts5fault8.test new file mode 100644 index 0000000..ae58494 --- /dev/null +++ b/ext/fts5/test/fts5fault8.test @@ -0,0 +1,60 @@ +# 2015 September 3 +# +# 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 is focused on OOM errors. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +source $testdir/malloc_common.tcl +set testprefix fts5fault8 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + + fts5_aux_test_functions db + do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%); + INSERT INTO t1 VALUES('a b c d', '1 2 3 4'); + INSERT INTO t1 VALUES('a b a b', NULL); + INSERT INTO t1 VALUES(NULL, '1 2 1 2'); + } + + do_faultsim_test 1 -faults oom-* -body { + execsql { + SELECT rowid, fts5_test_poslist(t1) FROM t1 WHERE t1 MATCH 'b OR 2' + } + } -test { + faultsim_test_result {0 {1 {0.0.1 1.1.1} 2 {0.0.1 0.0.3} 3 {1.1.1 1.1.3}}} \ + {1 SQLITE_NOMEM} + } + + do_faultsim_test 2 -faults oom-* -body { + execsql { INSERT INTO t1(t1) VALUES('integrity-check') } + } -test { + faultsim_test_result {0 {}} {1 SQLITE_NOMEM} + } + + if {[detail_is_none]==0} { + do_faultsim_test 3 -faults oom-* -body { + execsql { SELECT rowid FROM t1('b:2') } + } -test { + faultsim_test_result {0 {1 3}} {1 SQLITE_NOMEM} + } + } +} ;# foreach_detail_mode... + +finish_test + diff --git a/ext/fts5/test/fts5fault9.test b/ext/fts5/test/fts5fault9.test new file mode 100644 index 0000000..908a91d --- /dev/null +++ b/ext/fts5/test/fts5fault9.test @@ -0,0 +1,156 @@ +# 2015 September 3 +# +# 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 is focused on OOM errors. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +source $testdir/malloc_common.tcl +set testprefix fts5fault9 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + +fts5_aux_test_functions db + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + WITH seq(s) AS ( SELECT 1 UNION ALL SELECT s+1 FROM seq WHERE s<50) + INSERT INTO t1 SELECT 'x x x y y y', 'a b c d e f' FROM seq; +} + +do_faultsim_test 1 -faults oom-* -body { + execsql { SELECT count(*) FROM t1('x AND y') } +} -test { + faultsim_test_result {0 50} +} + +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE t2 USING fts5(a, b, detail=%DETAIL%); + INSERT INTO t2(t2, rank) VALUES('pgsz', 32); + INSERT INTO t2 VALUES('abc cba', 'cba abc'); + INSERT INTO t2 VALUES('abc cba', 'cba abc'); + INSERT INTO t2 VALUES('abc cba', 'cba abc'); + + INSERT INTO t2 VALUES('axy cyx', 'cyx axy'); + INSERT INTO t2 VALUES('axy cyx', 'cyx axy'); + INSERT INTO t2 VALUES('axy cyx', 'cyx axy'); +} + +do_faultsim_test 2 -faults oom-* -body { + execsql { SELECT count(*) FROM t2('a* AND c*') } +} -test { + faultsim_test_result {0 6} +} + + +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE t3 USING fts5(a, detail=%DETAIL%); + INSERT INTO t3 VALUES('a x x a x a a a'); + INSERT INTO t3 VALUES('x a a x a x x x'); +} + +do_faultsim_test 3.1 -faults oom-* -body { + execsql { SELECT highlight(t3, 0, '[', ']') FROM t3('a') } +} -test { + faultsim_test_result {0 {{[a] x x [a] x [a] [a] [a]} {x [a] [a] x [a] x x x}}} +} + +do_faultsim_test 3.2 -faults oom-t* -body { + execsql { SELECT fts5_test_poslist2(t3) FROM t3('x') } +} -test { + faultsim_test_result \ + {0 {{0.0.1 0.0.2 0.0.4} {0.0.0 0.0.3 0.0.5 0.0.6 0.0.7}}} \ + {1 SQLITE_NOMEM} +} + +#------------------------------------------------------------------------- +# Test OOM injection with the xPhraseFirstColumn() API and a tokenizer +# uses query synonyms. +# +fts5_tclnum_register db +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE t4 USING fts5(x, y, z, detail=%DETAIL%, tokenize=tclnum); + INSERT INTO t4 VALUES('one two three', '1 2 3', 'i ii iii'); + INSERT INTO t4 VALUES('1 2 3', 'i ii iii', 'one two three'); + INSERT INTO t4 VALUES('i ii iii', 'one two three', 'i ii iii'); + + INSERT INTO t4 VALUES('a1 a2 a3', 'a4 a5 a6', 'a7 a8 a9'); + INSERT INTO t4 VALUES('b1 b2 b3', 'b4 b5 b6', 'b7 b8 b9'); + INSERT INTO t4 VALUES('c1 c2 c3', 'c4 c5 c6', 'c7 c8 c9'); +} + +do_faultsim_test 4.1 -faults oom-t* -body { + execsql { SELECT rowid, fts5_test_collist(t4) FROM t4('2') } +} -test { + faultsim_test_result \ + {0 {1 {0.0 0.1 0.2} 2 {0.0 0.1 0.2} 3 {0.0 0.1 0.2}}} {1 SQLITE_NOMEM} +} + +do_faultsim_test 4.2 -faults oom-t* -body { + execsql { SELECT rowid, fts5_test_collist(t4) FROM t4('a5 OR b5 OR c5') } +} -test { + faultsim_test_result \ + {0 {4 {0.0 0.1 0.2} 5 {1.0 1.1 1.2} 6 {2.0 2.1 2.2}}} {1 SQLITE_NOMEM} +} + + +#------------------------------------------------------------------------- +# An OOM within an "ORDER BY rank" query. +# +db func rnddoc fts5_rnddoc +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE xx USING fts5(x, y, detail=%DETAIL%); + INSERT INTO xx VALUES ('def', 'abc ' || rnddoc(10)); + INSERT INTO xx VALUES ('def', 'abc abc' || rnddoc(9)); + INSERT INTO xx VALUES ('def', 'abc abc abc' || rnddoc(8)); +} {} +faultsim_save_and_close + +do_faultsim_test 5 -faults oom-* -prep { + faultsim_restore_and_reopen + execsql { SELECT * FROM xx } +} -body { + execsql { SELECT rowid FROM xx('abc AND def') ORDER BY rank } +} -test { + faultsim_test_result [list 0 {3 2 1}] +} + +set doc [string repeat "xyz " 500] +do_execsql_test 6.0 { + CREATE VIRTUAL TABLE yy USING fts5(y, detail=%DETAIL%); + INSERT INTO yy(yy, rank) VALUES('pgsz', 64); + INSERT INTO yy VALUES ($doc); + INSERT INTO yy VALUES ('1 2 3'); + INSERT INTO yy VALUES ('xyz'); + UPDATE yy SET y = y WHERE rowid = 1; + UPDATE yy SET y = y WHERE rowid = 1; + UPDATE yy SET y = y WHERE rowid = 1; + UPDATE yy SET y = y WHERE rowid = 1; +} {} + +do_faultsim_test 6 -faults oom-* -body { + execsql { SELECT rowid FROM yy('xyz') } +} -test { + faultsim_test_result [list 0 {1 3}] +} + + +} ;# foreach_detail_mode... + +finish_test + diff --git a/ext/fts5/test/fts5faultA.test b/ext/fts5/test/fts5faultA.test new file mode 100644 index 0000000..817ccb4 --- /dev/null +++ b/ext/fts5/test/fts5faultA.test @@ -0,0 +1,64 @@ +# 2016 February 2 +# +# 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 is focused on OOM errors. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +source $testdir/malloc_common.tcl +set testprefix fts5faultA + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + do_execsql_test 1.0 { + CREATE VIRTUAL TABLE o1 USING fts5(a, detail=%DETAIL%); + INSERT INTO o1(o1, rank) VALUES('pgsz', 32); + + WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<300 ) + INSERT INTO o1 SELECT 'A B C' FROM s; + + INSERT INTO o1 VALUES('A X C'); + + WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<300 ) + INSERT INTO o1 SELECT 'A B C' FROM s; + } + + do_faultsim_test 1 -faults oom* -prep { + sqlite3 db test.db + } -body { + execsql { SELECT rowid FROM o1('a NOT b') } + } -test { + faultsim_test_result {0 301} + } +} + +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE o2 USING fts5(a); + + INSERT INTO o2 VALUES('A B C'); + WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<300 ) + INSERT INTO o2 SELECT group_concat('A B C ') FROM s; +} + +do_faultsim_test 2 -faults oom* -prep { + sqlite3 db test.db +} -body { + execsql { SELECT rowid FROM o2('a+b+c NOT xyz') } +} -test { + faultsim_test_result {0 {1 2}} +} +finish_test + diff --git a/ext/fts5/test/fts5full.test b/ext/fts5/test/fts5full.test new file mode 100644 index 0000000..c640f56 --- /dev/null +++ b/ext/fts5/test/fts5full.test @@ -0,0 +1,43 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Test that SQLITE_FULL is returned if the FTS5 table cannot find a free +# segid to use. In practice this can only really happen when automerge and +# crisismerge are both disabled. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5full + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE x8 USING fts5(i); + INSERT INTO x8(x8, rank) VALUES('automerge', 0); + INSERT INTO x8(x8, rank) VALUES('crisismerge', 100000); +} + +db func rnddoc fts5_rnddoc +do_test 1.1 { + list [catch { + for {set i 0} {$i < 2500} {incr i} { + execsql { INSERT INTO x8 VALUES( rnddoc(5) ); } + } + } msg] $msg +} {1 {database or disk is full}} + + +finish_test + diff --git a/ext/fts5/test/fts5hash.test b/ext/fts5/test/fts5hash.test new file mode 100644 index 0000000..f3952d6 --- /dev/null +++ b/ext/fts5/test/fts5hash.test @@ -0,0 +1,133 @@ +# 2015 April 21 +# +# 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. +# +#*********************************************************************** +# +# The tests in this file are focused on the code in fts5_hash.c. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5hash + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +#------------------------------------------------------------------------- +# Return a list of tokens (a vocabulary) that all share the same hash +# key value. This can be used to test hash collisions. +# +proc build_vocab1 {args} { + + set O(-nslot) 1024 + set O(-nword) 20 + set O(-hash) 88 + set O(-prefix) "" + + if {[llength $args] % 2} { error "bad args" } + array set O2 $args + foreach {k v} $args { + if {[info exists O($k)]==0} { error "bad option: $k" } + set O($k) $v + } + + set L [list] + while {[llength $L] < $O(-nword)} { + set t "$O(-prefix)[random_token]" + set h [sqlite3_fts5_token_hash $O(-nslot) $t] + if {$O(-hash)==$h} { lappend L $t } + } + return $L +} + +proc random_token {} { + set map [list 0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j] + set iVal [expr int(rand() * 2000000)] + return [string map $map $iVal] +} + +proc random_doc {vocab nWord} { + set doc "" + set nVocab [llength $vocab] + for {set i 0} {$i<$nWord} {incr i} { + set j [expr {int(rand() * $nVocab)}] + lappend doc [lindex $vocab $j] + } + return $doc +} + +foreach_detail_mode $testprefix { + + set vocab [build_vocab1] + db func r random_doc + + do_execsql_test 1.0 { + CREATE VIRTUAL TABLE eee USING fts5(e, ee, detail=%DETAIL%); + BEGIN; + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100) + INSERT INTO eee SELECT r($vocab, 5), r($vocab, 7) FROM ii; + INSERT INTO eee(eee) VALUES('integrity-check'); + COMMIT; + INSERT INTO eee(eee) VALUES('integrity-check'); + } + + set hash [sqlite3_fts5_token_hash 1024 xyz] + set vocab [build_vocab1 -prefix xyz -hash $hash] + lappend vocab xyz + + do_execsql_test 1.1 { + CREATE VIRTUAL TABLE vocab USING fts5vocab(eee, 'row'); + BEGIN; + } + do_test 1.2 { + for {set i 1} {$i <= 100} {incr i} { + execsql { INSERT INTO eee VALUES( r($vocab, 5), r($vocab, 7) ) } + } + } {} + + do_test 1.3 { + db eval { SELECT term, doc FROM vocab } { + set nRow [db one {SELECT count(*) FROM eee WHERE eee MATCH $term}] + if {$nRow != $doc} { + error "term=$term fts5vocab=$doc cnt=$nRow" + } + } + set {} {} + } {} + + do_execsql_test 1.4 { + COMMIT; + INSERT INTO eee(eee) VALUES('integrity-check'); + } + + #----------------------------------------------------------------------- + # Add a small and very large token with the same hash value to an + # empty table. At one point this would provoke an asan error. + # + do_test 2.0 { + set big [string repeat 12345 40] + set hash [sqlite3_fts5_token_hash 1024 $big] + while {1} { + set small [random_token] + if {[sqlite3_fts5_token_hash 1024 $small]==$hash} break + } + + execsql { CREATE VIRTUAL TABLE t2 USING fts5(x, detail=%DETAIL%) } +breakpoint + execsql { + INSERT INTO t2 VALUES($small || ' ' || $big); + } + } {} + +} ;# foreach_detail_mode + +finish_test + diff --git a/ext/fts5/test/fts5integrity.test b/ext/fts5/test/fts5integrity.test new file mode 100644 index 0000000..37ca933 --- /dev/null +++ b/ext/fts5/test/fts5integrity.test @@ -0,0 +1,213 @@ +# 2015 Jan 13 +# +# 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 contains tests focused on the integrity-check procedure. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5integrity + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE xx USING fts5(x); + INSERT INTO xx VALUES('term'); +} +do_execsql_test 1.1 { + INSERT INTO xx(xx) VALUES('integrity-check'); +} + +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE yy USING fts5(x, prefix=1); + INSERT INTO yy VALUES('term'); +} +do_execsql_test 2.1 { + INSERT INTO yy(yy) VALUES('integrity-check'); +} + +#-------------------------------------------------------------------- +# +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE zz USING fts5(z); + INSERT INTO zz(zz, rank) VALUES('pgsz', 32); + INSERT INTO zz VALUES('b b b b b b b b b b b b b b'); + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz SELECT z FROM zz; + INSERT INTO zz(zz) VALUES('optimize'); +} + +do_execsql_test 3.1 { INSERT INTO zz(zz) VALUES('integrity-check'); } + +#-------------------------------------------------------------------- +# Mess around with a docsize record. And the averages record. Then +# check that integrity-check picks it up. +# +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE aa USING fts5(zz); + INSERT INTO aa(zz) VALUES('a b c d e'); + INSERT INTO aa(zz) VALUES('a b c d'); + INSERT INTO aa(zz) VALUES('a b c'); + INSERT INTO aa(zz) VALUES('a b'); + INSERT INTO aa(zz) VALUES('a'); + SELECT length(sz) FROM aa_docsize; +} {1 1 1 1 1} +do_execsql_test 4.1 { + INSERT INTO aa(aa) VALUES('integrity-check'); +} + +do_catchsql_test 4.2 { + BEGIN; + UPDATE aa_docsize SET sz = X'44' WHERE rowid = 3; + INSERT INTO aa(aa) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +do_catchsql_test 4.3 { + ROLLBACK; + BEGIN; + UPDATE aa_data SET block = X'44' WHERE rowid = 1; + INSERT INTO aa(aa) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +do_catchsql_test 4.4 { + ROLLBACK; + BEGIN; + INSERT INTO aa_docsize VALUES(23, X'04'); + INSERT INTO aa(aa) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +do_catchsql_test 4.5 { + ROLLBACK; + BEGIN; + INSERT INTO aa_docsize VALUES(23, X'00'); + INSERT INTO aa_content VALUES(23, ''); + INSERT INTO aa(aa) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM zz_data} {puts $r} +#exit + +execsql { ROLLBACK } + + +#------------------------------------------------------------------------- +# Test that integrity-check works on a reasonably large db with many +# different terms. + +# Document generator command. +proc rnddoc {n} { + set doc [list] + for {set i 0} {$i<$n} {incr i} { + lappend doc [format %.5d [expr int(rand()*10000)]] + } + return $doc +} +db func rnddoc rnddoc + +expr srand(0) +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE gg USING fts5(a, prefix="1,2,3"); + INSERT INTO gg(gg, rank) VALUES('pgsz', 256); + INSERT INTO gg VALUES(rnddoc(20)); + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; + INSERT INTO gg SELECT rnddoc(20) FROM gg; +} + +do_execsql_test 5.1 { + INSERT INTO gg(gg) VALUES('integrity-check'); +} + +do_execsql_test 5.2 { + INSERT INTO gg(gg) VALUES('optimize'); +} + +do_execsql_test 5.3 { + INSERT INTO gg(gg) VALUES('integrity-check'); +} + +do_test 5.4.1 { + set ok 0 + for {set i 0} {$i < 10000} {incr i} { + set T [format %.5d $i] + set res [db eval { SELECT rowid FROM gg($T) ORDER BY rowid ASC }] + set res2 [db eval { SELECT rowid FROM gg($T) ORDER BY rowid DESC }] + if {$res == [lsort -integer $res2]} { incr ok } + } + set ok +} {10000} + +do_test 5.4.2 { + set ok 0 + for {set i 0} {$i < 100} {incr i} { + set T "[format %.3d $i]*" + set res [db eval { SELECT rowid FROM gg($T) ORDER BY rowid ASC }] + set res2 [db eval { SELECT rowid FROM gg($T) ORDER BY rowid DESC }] + if {$res == [lsort -integer $res2]} { incr ok } + } + set ok +} {100} + +#------------------------------------------------------------------------- +# Similar to 5.*. +# +foreach {tn pgsz} { + 1 32 + 2 36 + 3 40 + 4 44 + 5 48 +} { + do_execsql_test 6.$tn.1 { + DROP TABLE IF EXISTS hh; + CREATE VIRTUAL TABLE hh USING fts5(y); + INSERT INTO hh(hh, rank) VALUES('pgsz', $pgsz); + + WITH s(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<999) + INSERT INTO hh SELECT printf("%.3d%.3d%.3d %.3d%.3d%.3d",i,i,i,i+1,i+1,i+1) + FROM s; + + WITH s(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<999) + INSERT INTO hh SELECT printf("%.3d%.3d%.3d %.3d%.3d%.3d",i,i,i,i+1,i+1,i+1) + FROM s; + + INSERT INTO hh(hh) VALUES('optimize'); + } + + do_test 6.$tn.2 { + set ok 0 + for {set i 0} {$i < 1000} {incr i} { + set T [format %.3d%.3d%.3d $i $i $i] + set res [db eval { SELECT rowid FROM hh($T) ORDER BY rowid ASC }] + set res2 [db eval { SELECT rowid FROM hh($T) ORDER BY rowid DESC }] + if {$res == [lsort -integer $res2]} { incr ok } + } + set ok + } {1000} +} + +finish_test + diff --git a/ext/fts5/test/fts5matchinfo.test b/ext/fts5/test/fts5matchinfo.test new file mode 100644 index 0000000..06f4550 --- /dev/null +++ b/ext/fts5/test/fts5matchinfo.test @@ -0,0 +1,471 @@ +# 2015 August 05 +# +# 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. +# +#*********************************************************************** +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5matchinfo + +# If SQLITE_ENABLE_FTS5 is not defined, omit this file. +ifcapable !fts5 { finish_test ; return } + +foreach_detail_mode $testprefix { + +proc mit {blob} { + set scan(littleEndian) i* + set scan(bigEndian) I* + binary scan $blob $scan($::tcl_platform(byteOrder)) r + return $r +} +db func mit mit + +sqlite3_fts5_register_matchinfo db + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(content, detail=%DETAIL%); +} + +do_execsql_test 1.1 { + INSERT INTO t1(content) VALUES('I wandered lonely as a cloud'); + INSERT INTO t1(content) VALUES('That floats on high o''er vales and hills,'); + INSERT INTO t1(content) VALUES('When all at once I saw a crowd,'); + INSERT INTO t1(content) VALUES('A host, of golden daffodils,'); + SELECT mit(matchinfo(t1)) FROM t1 WHERE t1 MATCH 'I'; +} {{1 1 1 2 2} {1 1 1 2 2}} + +# Now create an FTS4 table that does not specify matchinfo=fts3. +# +do_execsql_test 1.2 { + CREATE VIRTUAL TABLE t2 USING fts5(content, detail=%DETAIL%); + INSERT INTO t2 SELECT * FROM t1; + SELECT mit(matchinfo(t2)) FROM t2 WHERE t2 MATCH 'I'; +} {{1 1 1 2 2} {1 1 1 2 2}} + + +#-------------------------------------------------------------------------- +# Proc [do_matchinfo_test] is used to test the FTSX matchinfo() function. +# +# The first argument - $tn - is a test identifier. This may be either a +# full identifier (i.e. "fts3matchinfo-1.1") or, if global var $testprefix +# is set, just the numeric component (i.e. "1.1"). +# +# The second argument is the name of an FTSX table. The third is the +# full text of a WHERE/MATCH expression to query the table for +# (i.e. "t1 MATCH 'abc'"). The final argument - $results - should be a +# key-value list (serialized array) with matchinfo() format specifiers +# as keys, and the results of executing the statement: +# +# SELECT matchinfo($tbl, '$key') FROM $tbl WHERE $expr +# +# For example: +# +# CREATE VIRTUAL TABLE t1 USING fts4; +# INSERT INTO t1 VALUES('abc'); +# INSERT INTO t1 VALUES('def'); +# INSERT INTO t1 VALUES('abc abc'); +# +# do_matchinfo_test 1.1 t1 "t1 MATCH 'abc'" { +# n {3 3} +# p {1 1} +# c {1 1} +# x {{1 3 2} {2 3 2}} +# } +# +# If the $results list contains keys mapped to "-" instead of a matchinfo() +# result, then this command computes the expected results based on other +# mappings to test the matchinfo() function. For example, the command above +# could be changed to: +# +# do_matchinfo_test 1.1 t1 "t1 MATCH 'abc'" { +# n {3 3} p {1 1} c {1 1} x {{1 3 2} {2 3 2}} +# pcx - +# } +# +# And this command would compute the expected results for matchinfo(t1, 'pcx') +# based on the results of matchinfo(t1, 'p'), matchinfo(t1, 'c') and +# matchinfo(t1, 'x') in order to test 'pcx'. +# +proc do_matchinfo_test {tn tbl expr results} { + + foreach {fmt res} $results { + if {$res == "-"} continue + set resarray($fmt) $res + } + + set nRow 0 + foreach {fmt res} [array get resarray] { + if {[llength $res]>$nRow} { set nRow [llength $res] } + } + + # Construct expected results for any formats for which the caller + # supplied result is "-". + # + foreach {fmt res} $results { + if {$res == "-"} { + set res [list] + for {set iRow 0} {$iRow<$nRow} {incr iRow} { + set rowres [list] + foreach c [split $fmt ""] { + set rowres [concat $rowres [lindex $resarray($c) $iRow]] + } + lappend res $rowres + } + set resarray($fmt) $res + } + } + + # Test each matchinfo() request individually. + # + foreach {fmt res} [array get resarray] { + set sql "SELECT mit(matchinfo($tbl, '$fmt')) FROM $tbl WHERE $expr" + do_execsql_test $tn.$fmt $sql [normalize2 $res] + } + + # Test them all executed together (multiple invocations of matchinfo()). + # + set exprlist [list] + foreach {format res} [array get resarray] { + lappend exprlist "mit(matchinfo($tbl, '$format'))" + } + set allres [list] + for {set iRow 0} {$iRow<$nRow} {incr iRow} { + foreach {format res} [array get resarray] { + lappend allres [lindex $res $iRow] + } + } + set sql "SELECT [join $exprlist ,] FROM $tbl WHERE $expr" + do_execsql_test $tn.multi $sql [normalize2 $allres] +} +proc normalize2 {list_of_lists} { + set res [list] + foreach elem $list_of_lists { + lappend res [list {*}$elem] + } + return $res +} + +# Similar to [do_matchinfo_test], except that this is a no-op if the FTS5 +# mode is not detail=full. +# +proc do_matchinfo_p_test {tn tbl expr results} { + if {[detail_is_full]} { + uplevel [list do_matchinfo_test $tn $tbl $expr $results] + } +} + +do_execsql_test 4.1.0 { + CREATE VIRTUAL TABLE t4 USING fts5(x, y, detail=%DETAIL%); + INSERT INTO t4 VALUES('a b c d e', 'f g h i j'); + INSERT INTO t4 VALUES('f g h i j', 'a b c d e'); +} + +do_matchinfo_test 4.1.1 t4 {t4 MATCH 'a b c'} { + s {{3 0} {0 3}} +} + +do_matchinfo_test 4.1.1 t4 {t4 MATCH 'a b c'} { + p {3 3} + x { + {1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1} + {0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1} + } +} + +do_matchinfo_test 4.1.1 t4 {t4 MATCH 'a b c'} { + p {3 3} + c {2 2} + x { + {1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1} + {0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1} + } + n {2 2} + l {{5 5} {5 5}} + a {{5 5} {5 5}} + + s {{3 0} {0 3}} + + xxxxxxxxxxxxxxxxxx - pcx - xpc - ccc - pppxpcpcx - laxnpc - + xpxsscplax - +} + +do_matchinfo_p_test 4.1.2 t4 {t4 MATCH '"g h i"'} { + p {1 1} + c {2 2} + x { + {0 1 1 1 1 1} + {1 1 1 0 1 1} + } + n {2 2} + l {{5 5} {5 5}} + a {{5 5} {5 5}} + + s {{0 1} {1 0}} + + xxxxxxxxxxxxxxxxxx - pcx - xpc - ccc - pppxpcpcx - laxnpc - + sxsxs - +} + +do_matchinfo_test 4.1.3 t4 {t4 MATCH 'a b'} { s {{2 0} {0 2}} } +do_matchinfo_p_test 4.1.4 t4 {t4 MATCH '"a b" c'} { s {{2 0} {0 2}} } +do_matchinfo_p_test 4.1.5 t4 {t4 MATCH 'a "b c"'} { s {{2 0} {0 2}} } +do_matchinfo_test 4.1.6 t4 {t4 MATCH 'd d'} { s {{1 0} {0 1}} } +do_matchinfo_test 4.1.7 t4 {t4 MATCH 'f OR abcd'} { + x { + {0 1 1 1 1 1 0 0 0 0 0 0} + {1 1 1 0 1 1 0 0 0 0 0 0} + } +} +do_matchinfo_test 4.1.8 t4 {t4 MATCH 'f NOT abcd'} { + x { + {0 1 1 1 1 1 0 0 0 0 0 0} + {1 1 1 0 1 1 0 0 0 0 0 0} + } +} + +do_execsql_test 4.2.0 { + CREATE VIRTUAL TABLE t5 USING fts5(content, detail=%DETAIL%); + INSERT INTO t5 VALUES('a a a a a'); + INSERT INTO t5 VALUES('a b a b a'); + INSERT INTO t5 VALUES('c b c b c'); + INSERT INTO t5 VALUES('x x x x x'); +} +do_matchinfo_test 4.2.1 t5 {t5 MATCH 'a a'} { + x {{5 8 2 5 8 2} {3 8 2 3 8 2}} + s {2 1} +} +do_matchinfo_test 4.2.2 t5 {t5 MATCH 'a b'} { s {2} } +do_matchinfo_test 4.2.3 t5 {t5 MATCH 'a b a'} { s {3} } +do_matchinfo_test 4.2.4 t5 {t5 MATCH 'a a a'} { s {3 1} } +do_matchinfo_p_test 4.2.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} } +do_matchinfo_test 4.2.6 t5 {t5 MATCH 'a OR b'} { s {1 2 1} } + +do_execsql_test 4.3.0 "INSERT INTO t5 VALUES('x y [string repeat {b } 50000]')"; + +# It used to be that the second 'a' token would be deferred. That doesn't +# work any longer. +if 0 { + do_matchinfo_test 4.3.1 t5 {t5 MATCH 'a a'} { + x {{5 8 2 5 5 5} {3 8 2 3 5 5}} + s {2 1} + } +} + +do_matchinfo_test 4.3.2 t5 {t5 MATCH 'a b'} { s {2} } +do_matchinfo_test 4.3.3 t5 {t5 MATCH 'a b a'} { s {3} } +do_matchinfo_test 4.3.4 t5 {t5 MATCH 'a a a'} { s {3 1} } +do_matchinfo_p_test 4.3.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} } +do_matchinfo_test 4.3.6 t5 {t5 MATCH 'a OR b'} { s {1 2 1 1} } + +do_execsql_test 4.4.0.1 { INSERT INTO t5(t5) VALUES('optimize') } + +do_matchinfo_test 4.4.2 t5 {t5 MATCH 'a b'} { s {2} } +do_matchinfo_test 4.4.1 t5 {t5 MATCH 'a a'} { s {2 1} } +do_matchinfo_test 4.4.2 t5 {t5 MATCH 'a b'} { s {2} } +do_matchinfo_test 4.4.3 t5 {t5 MATCH 'a b a'} { s {3} } +do_matchinfo_test 4.4.4 t5 {t5 MATCH 'a a a'} { s {3 1} } +do_matchinfo_p_test 4.4.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} } + +do_execsql_test 4.5.0 { + CREATE VIRTUAL TABLE t6 USING fts5(a, b, c, detail=%DETAIL%); + INSERT INTO t6 VALUES('a', 'b', 'c'); +} +do_matchinfo_test 4.5.1 t6 {t6 MATCH 'a b c'} { s {{1 1 1}} } + + +#------------------------------------------------------------------------- +# Test the outcome of matchinfo() when used within a query that does not +# use the full-text index (i.e. lookup by rowid or full-table scan). +# +do_execsql_test 7.1 { + CREATE VIRTUAL TABLE t10 USING fts5(content, detail=%DETAIL%); + INSERT INTO t10 VALUES('first record'); + INSERT INTO t10 VALUES('second record'); +} +do_execsql_test 7.2 { + SELECT typeof(matchinfo(t10)), length(matchinfo(t10)) FROM t10; +} {blob 8 blob 8} +do_execsql_test 7.3 { + SELECT typeof(matchinfo(t10)), length(matchinfo(t10)) FROM t10 WHERE rowid=1; +} {blob 8} +do_execsql_test 7.4 { + SELECT typeof(matchinfo(t10)), length(matchinfo(t10)) + FROM t10 WHERE t10 MATCH 'record' +} {blob 20 blob 20} + +#------------------------------------------------------------------------- +# Test a special case - matchinfo('nxa') with many zero length documents. +# Special because "x" internally uses a statement used by both "n" and "a". +# This was causing a problem at one point in the obscure case where the +# total number of bytes of data stored in an fts3 table was greater than +# the number of rows. i.e. when the following query returns true: +# +# SELECT sum(length(content)) < count(*) FROM fts4table; +# +do_execsql_test 8.1 { + CREATE VIRTUAL TABLE t11 USING fts5(content, detail=%DETAIL%); + INSERT INTO t11(t11, rank) VALUES('pgsz', 32); + INSERT INTO t11 VALUES('quitealongstringoftext'); + INSERT INTO t11 VALUES('anotherquitealongstringoftext'); + INSERT INTO t11 VALUES('athirdlongstringoftext'); + INSERT INTO t11 VALUES('andonemoreforgoodluck'); +} +do_test 8.2 { + for {set i 0} {$i < 200} {incr i} { + execsql { INSERT INTO t11 VALUES('') } + } + execsql { INSERT INTO t11(t11) VALUES('optimize') } +} {} +do_execsql_test 8.3 { + SELECT mit(matchinfo(t11, 'nxa')) FROM t11 WHERE t11 MATCH 'a*' +} {{204 1 3 3 0} {204 1 3 3 0} {204 1 3 3 0}} + +#------------------------------------------------------------------------- + +if {[detail_is_full]} { + do_execsql_test 9.1 { + CREATE VIRTUAL TABLE t12 USING fts5(content, detail=%DETAIL%); + INSERT INTO t12 VALUES('a b c d'); + SELECT mit(matchinfo(t12,'x')) FROM t12 WHERE t12 MATCH 'NEAR(a d, 1) OR a'; + } {{0 1 1 0 1 1 1 1 1}} + do_execsql_test 9.2 { + INSERT INTO t12 VALUES('a d c d'); + SELECT mit(matchinfo(t12,'x')) FROM t12 WHERE t12 MATCH 'NEAR(a d, 1) OR a'; + } { + {0 2 2 0 3 2 1 2 2} {1 2 2 1 3 2 1 2 2} + } + do_execsql_test 9.3 { + INSERT INTO t12 VALUES('a d d a'); + SELECT mit(matchinfo(t12,'x')) FROM t12 WHERE t12 MATCH 'NEAR(a d, 1) OR a'; + } { + {0 4 3 0 5 3 1 4 3} {1 4 3 1 5 3 1 4 3} {2 4 3 2 5 3 2 4 3} + } +} + +#--------------------------------------------------------------------------- +# Test for a memory leak +# +do_execsql_test 10.1 { + DROP TABLE t10; + CREATE VIRTUAL TABLE t10 USING fts5(idx, value, detail=%DETAIL%); + INSERT INTO t10 values (1, 'one'),(2, 'two'),(3, 'three'); + SELECT t10.rowid, t10.* + FROM t10 + JOIN (SELECT 1 AS idx UNION SELECT 2 UNION SELECT 3) AS x + WHERE t10 MATCH x.idx + AND matchinfo(t10) not null + GROUP BY t10.rowid + ORDER BY 1; +} {1 1 one 2 2 two 3 3 three} + +#--------------------------------------------------------------------------- +# Test the 'y' matchinfo flag +# +reset_db +sqlite3_fts5_register_matchinfo db +do_execsql_test 11.0 { + CREATE VIRTUAL TABLE tt USING fts5(x, y, detail=%DETAIL%); + INSERT INTO tt VALUES('c d a c d d', 'e a g b d a'); -- 1 + INSERT INTO tt VALUES('c c g a e b', 'c g d g e c'); -- 2 + INSERT INTO tt VALUES('b e f d e g', 'b a c b c g'); -- 3 + INSERT INTO tt VALUES('a c f f g d', 'd b f d e g'); -- 4 + INSERT INTO tt VALUES('g a c f c f', 'd g g b c c'); -- 5 + INSERT INTO tt VALUES('g a c e b b', 'd b f b g g'); -- 6 + INSERT INTO tt VALUES('f d a a f c', 'e e a d c f'); -- 7 + INSERT INTO tt VALUES('a c b b g f', 'a b a e d f'); -- 8 + INSERT INTO tt VALUES('b a f e c c', 'f d b b a b'); -- 9 + INSERT INTO tt VALUES('f d c e a c', 'f a f a a f'); -- 10 +} + +db func mit mit +foreach {tn expr res} { + 1 "a" { + 1 {1 2} 2 {1 0} 3 {0 1} 4 {1 0} 5 {1 0} + 6 {1 0} 7 {2 1} 8 {1 2} 9 {1 1} 10 {1 3} + } + + 2 "b" { + 1 {0 1} 2 {1 0} 3 {1 2} 4 {0 1} 5 {0 1} + 6 {2 2} 8 {2 1} 9 {1 3} + } + + 3 "y:a" { + 1 {0 2} 3 {0 1} + 7 {0 1} 8 {0 2} 9 {0 1} 10 {0 3} + } + + 4 "x:a" { + 1 {1 0} 2 {1 0} 4 {1 0} 5 {1 0} + 6 {1 0} 7 {2 0} 8 {1 0} 9 {1 0} 10 {1 0} + } + + 5 "a OR b" { + 1 {1 2 0 1} 2 {1 0 1 0} 3 {0 1 1 2} 4 {1 0 0 1} 5 {1 0 0 1} + 6 {1 0 2 2} 7 {2 1 0 0} 8 {1 2 2 1} 9 {1 1 1 3} 10 {1 3 0 0} + } + + 6 "a AND b" { + 1 {1 2 0 1} 2 {1 0 1 0} 3 {0 1 1 2} 4 {1 0 0 1} 5 {1 0 0 1} + 6 {1 0 2 2} 8 {1 2 2 1} 9 {1 1 1 3} + } + + 7 "a OR (a AND b)" { + 1 {1 2 1 2 0 1} 2 {1 0 1 0 1 0} 3 {0 1 0 1 1 2} 4 {1 0 1 0 0 1} + 5 {1 0 1 0 0 1} 6 {1 0 1 0 2 2} 7 {2 1 0 0 0 0} 8 {1 2 1 2 2 1} + 9 {1 1 1 1 1 3} 10 {1 3 0 0 0 0} + } + +} { + + if {[string match *:* $expr] && [detail_is_none]} continue + do_execsql_test 11.1.$tn.1 { + SELECT rowid, mit(matchinfo(tt, 'y')) FROM tt WHERE tt MATCH $expr + } $res + + set r2 [list] + foreach {rowid L} $res { + lappend r2 $rowid + set M [list] + foreach {a b} $L { + lappend M [expr ($a ? 1 : 0) + ($b ? 2 : 0)] + } + lappend r2 $M + } + + do_execsql_test 11.1.$tn.2 { + SELECT rowid, mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH $expr + } $r2 + + do_execsql_test 11.1.$tn.2 { + SELECT rowid, mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH $expr + } $r2 +} + +#--------------------------------------------------------------------------- +# Test the 'b' matchinfo flag +# +reset_db +sqlite3_fts5_register_matchinfo db +db func mit mit + +do_test 12.0 { + set cols [list] + for {set i 0} {$i < 50} {incr i} { lappend cols "c$i" } + execsql "CREATE VIRTUAL TABLE tt USING fts5([join $cols ,], detail=%DETAIL%)" +} {} + +do_execsql_test 12.1 { + INSERT INTO tt (rowid, c4, c45) VALUES(1, 'abc', 'abc'); + SELECT mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH 'abc'; +} [list [list [expr 1<<4] [expr 1<<(45-32)]]] + +} ;# foreach_detail_mode + +finish_test + diff --git a/ext/fts5/test/fts5merge.test b/ext/fts5/test/fts5merge.test new file mode 100644 index 0000000..9dd1ecd --- /dev/null +++ b/ext/fts5/test/fts5merge.test @@ -0,0 +1,194 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Test that focus on incremental merges of segments. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5merge + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +db func repeat [list string repeat] + +#------------------------------------------------------------------------- +# Create an fts index so that: +# +# * the index consists of two top-level segments +# * each segment contains records related to $nRowPerSeg rows +# * all rows consist of tokens "x" and "y" only. +# +# Then run ('merge', 1) until everything is completely merged. +# +proc do_merge1_test {testname nRowPerSeg} { + set ::nRowPerSeg [expr $nRowPerSeg] + do_execsql_test $testname.0 { + DROP TABLE IF EXISTS x8; + CREATE VIRTUAL TABLE x8 USING fts5(i); + INSERT INTO x8(x8, rank) VALUES('pgsz', 32); + + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg) + INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii; + + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg) + INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii; + + INSERT INTO x8(x8, rank) VALUES('automerge', 2); + } + + for {set tn 1} {[lindex [fts5_level_segs x8] 0]>0} {incr tn} { + do_execsql_test $testname.$tn { + INSERT INTO x8(x8, rank) VALUES('merge', 1); + INSERT INTO x8(x8) VALUES('integrity-check'); + } + if {$tn>5} break + } + + do_test $testname.x [list expr "$tn < 5"] 1 +} + +do_merge1_test 1.1 1 +do_merge1_test 1.2 2 +do_merge1_test 1.3 3 +do_merge1_test 1.4 4 +do_merge1_test 1.5 10 +do_merge1_test 1.6 20 +do_merge1_test 1.7 100 + +#------------------------------------------------------------------------- +# +proc do_merge2_test {testname nRow} { + db func rnddoc fts5_rnddoc + + do_execsql_test $testname.0 { + DROP TABLE IF EXISTS x8; + CREATE VIRTUAL TABLE x8 USING fts5(i); + INSERT INTO x8(x8, rank) VALUES('pgsz', 32); + } + + set ::nRow $nRow + do_test $testname.1 { + for {set i 0} {$i < $::nRow} {incr i} { + execsql { INSERT INTO x8 VALUES( rnddoc(($i%16) + 5) ) } + while {[not_merged x8]} { + execsql { + INSERT INTO x8(x8, rank) VALUES('automerge', 2); + INSERT INTO x8(x8, rank) VALUES('merge', 1); + INSERT INTO x8(x8, rank) VALUES('automerge', 16); + INSERT INTO x8(x8) VALUES('integrity-check'); + } + } + } + } {} +} +proc not_merged {tbl} { + set segs [fts5_level_segs $tbl] + foreach s $segs { if {$s>1} { return 1 } } + return 0 +} + +do_merge2_test 2.1 5 +do_merge2_test 2.2 10 +do_merge2_test 2.3 20 + +#------------------------------------------------------------------------- +# Test that an auto-merge will complete any merge that has already been +# started, even if the number of input segments is less than the current +# value of the 'automerge' configuration parameter. +# +db func rnddoc fts5_rnddoc + +do_execsql_test 3.1 { + DROP TABLE IF EXISTS x8; + CREATE VIRTUAL TABLE x8 USING fts5(i); + INSERT INTO x8(x8, rank) VALUES('pgsz', 32); + INSERT INTO x8 VALUES(rnddoc(100)); + INSERT INTO x8 VALUES(rnddoc(100)); +} +do_test 3.2 { + execsql { + INSERT INTO x8(x8, rank) VALUES('automerge', 4); + INSERT INTO x8(x8, rank) VALUES('merge', 1); + } + fts5_level_segs x8 +} {2} + +do_test 3.3 { + execsql { + INSERT INTO x8(x8, rank) VALUES('automerge', 2); + INSERT INTO x8(x8, rank) VALUES('merge', 1); + } + fts5_level_segs x8 +} {2 1} + +do_test 3.4 { + execsql { INSERT INTO x8(x8, rank) VALUES('automerge', 4) } + while {[not_merged x8]} { + execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1) } + } + fts5_level_segs x8 +} {0 1} + +#------------------------------------------------------------------------- +# +proc mydoc {} { + set x [lindex {a b c d e f g h i j} [expr int(rand()*10)]] + return [string repeat "$x " 30] +} +db func mydoc mydoc + +proc mycount {} { + set res [list] + foreach x {a b c d e f g h i j} { + lappend res [db one {SELECT count(*) FROM x8 WHERE x8 MATCH $x}] + } + set res +} + + #1 32 +foreach {tn pgsz} { + 2 1000 +} { + do_execsql_test 4.$tn.1 { + DROP TABLE IF EXISTS x8; + CREATE VIRTUAL TABLE x8 USING fts5(i); + INSERT INTO x8(x8, rank) VALUES('pgsz', $pgsz); + } + + do_execsql_test 4.$tn.2 { + INSERT INTO x8(x8, rank) VALUES('merge', 1); + } + + do_execsql_test 4.$tn.3 { + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100) + INSERT INTO x8 SELECT mydoc() FROM ii; + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100) + INSERT INTO x8 SELECT mydoc() FROM ii; + INSERT INTO x8(x8, rank) VALUES('automerge', 2); + } + + set expect [mycount] + for {set i 0} {$i < 20} {incr i} { + do_test 4.$tn.4.$i { + execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1); } + mycount + } $expect + break + } +# db eval {SELECT fts5_decode(rowid, block) AS r FROM x8_data} { puts $r } +} + +finish_test + diff --git a/ext/fts5/test/fts5merge2.test b/ext/fts5/test/fts5merge2.test new file mode 100644 index 0000000..87dbf14 --- /dev/null +++ b/ext/fts5/test/fts5merge2.test @@ -0,0 +1,59 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Test that focus on incremental merges of segments. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5merge + +proc dump_structure {} { + db eval {SELECT fts5_decode(id, block) AS t FROM t1_data WHERE id=10} { + foreach lvl [lrange $t 1 end] { + set seg [string repeat . [expr [llength $lvl]-2]] + puts "[lrange $lvl 0 1] $seg" + } + } +} + +foreach_detail_mode $testprefix { + +if {[detail_is_none]==0} continue + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + INSERT INTO t1(t1, rank) VALUES('crisismerge', 2); + INSERT INTO t1 VALUES('1 2 3 4'); +} + +expr srand(0) +db func rnddoc fts5_rnddoc +do_test 1.1 { + for {set i 0} {$i < 100} {incr i} { + execsql { + BEGIN; + DELETE FROM t1 WHERE rowid = 1; + INSERT INTO t1(rowid, x) VALUES(1, '1 2 3 4'); + INSERT INTO t1 VALUES(rnddoc(10)); + COMMIT; + } + } +} {} + +do_execsql_test 1.2 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} + +} + +finish_test + diff --git a/ext/fts5/test/fts5near.test b/ext/fts5/test/fts5near.test new file mode 100644 index 0000000..b4ae205 --- /dev/null +++ b/ext/fts5/test/fts5near.test @@ -0,0 +1,71 @@ +# 2014 Jan 08 +# +# 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. +# +#*********************************************************************** +# +# Tests focused on the NEAR operator. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5near + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +proc do_near_test {tn doc near res} { + uplevel [list do_execsql_test $tn " + DELETE FROM t1; + INSERT INTO t1 VALUES('$doc'); + SELECT count(*) FROM t1 WHERE t1 MATCH '$near'; + " $res] +} + +execsql { + CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = "ascii tokenchars '.'") +} + +do_near_test 1.1 ". . a . . . b . ." { NEAR(a b, 5) } 1 +do_near_test 1.2 ". . a . . . b . ." { NEAR(a b, 4) } 1 +do_near_test 1.3 ". . a . . . b . ." { NEAR(a b, 3) } 1 +do_near_test 1.4 ". . a . . . b . ." { NEAR(a b, 2) } 0 + +do_near_test 1.5 ". . a . . . b . ." { NEAR(b a, 5) } 1 +do_near_test 1.6 ". . a . . . b . ." { NEAR(b a, 4) } 1 +do_near_test 1.7 ". . a . . . b . ." { NEAR(b a, 3) } 1 +do_near_test 1.8 ". . a . . . b . ." { NEAR(b a, 2) } 0 + +do_near_test 1.9 ". a b . . . c . ." { NEAR("a b" c, 3) } 1 +do_near_test 1.10 ". a b . . . c . ." { NEAR("a b" c, 2) } 0 +do_near_test 1.11 ". a b . . . c . ." { NEAR(c "a b", 3) } 1 +do_near_test 1.12 ". a b . . . c . ." { NEAR(c "a b", 2) } 0 + +do_near_test 1.13 ". a b . . . c d ." { NEAR(a+b c+d, 3) } 1 +do_near_test 1.14 ". a b . . . c d ." { NEAR(a+b c+d, 2) } 0 +do_near_test 1.15 ". a b . . . c d ." { NEAR(c+d a+b, 3) } 1 +do_near_test 1.16 ". a b . . . c d ." { NEAR(c+d a+b, 2) } 0 + +do_near_test 1.17 ". a b . . . c d ." { NEAR(a b c d, 5) } 1 +do_near_test 1.18 ". a b . . . c d ." { NEAR(a b c d, 4) } 0 +do_near_test 1.19 ". a b . . . c d ." { NEAR(a+b c d, 4) } 1 + +do_near_test 1.20 "a b c d e f g h i" { NEAR(b+c a+b+c+d i, 5) } 1 +do_near_test 1.21 "a b c d e f g h i" { NEAR(b+c a+b+c+d i, 4) } 0 + +do_near_test 1.22 "a b c d e f g h i" { NEAR(a+b+c+d i b+c, 5) } 1 +do_near_test 1.23 "a b c d e f g h i" { NEAR(a+b+c+d i b+c, 4) } 0 + +do_near_test 1.24 "a b c d e f g h i" { NEAR(i a+b+c+d b+c, 5) } 1 +do_near_test 1.25 "a b c d e f g h i" { NEAR(i a+b+c+d b+c, 4) } 0 + + +finish_test + diff --git a/ext/fts5/test/fts5onepass.test b/ext/fts5/test/fts5onepass.test new file mode 100644 index 0000000..a614b78 --- /dev/null +++ b/ext/fts5/test/fts5onepass.test @@ -0,0 +1,181 @@ +# 2015 Sep 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. +# +#************************************************************************* +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5onepass + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE ft USING fts5(content); + INSERT INTO ft(rowid, content) VALUES(1, '1 2 3'); + INSERT INTO ft(rowid, content) VALUES(2, '4 5 6'); + INSERT INTO ft(rowid, content) VALUES(3, '7 8 9'); +} + +#------------------------------------------------------------------------- +# Check that UPDATE and DELETE statements that feature "WHERE rowid=?" or +# or "WHERE rowid=?" clauses do not use statement journals. But that other +# DELETE and UPDATE statements do. +# +# Note: "MATCH ? AND rowid=?" does use a statement journal. +# +foreach {tn sql uses} { + 1.1 { DELETE FROM ft } 1 + 1.2 { DELETE FROM ft WHERE rowid=? } 0 + 1.3 { DELETE FROM ft WHERE rowid=? } 0 + 1.4 { DELETE FROM ft WHERE ft MATCH '1' } 1 + 1.5 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 1 + 1.6 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 1 + + 2.1 { UPDATE ft SET content='a b c' } 1 + 2.2 { UPDATE ft SET content='a b c' WHERE rowid=? } 0 + 2.3 { UPDATE ft SET content='a b c' WHERE rowid=? } 0 + 2.4 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' } 1 + 2.5 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 1 + 2.6 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 1 +} { + do_test 1.$tn { sql_uses_stmt db $sql } $uses +} + +#------------------------------------------------------------------------- +# Check that putting a "DELETE/UPDATE ... WHERE rowid=?" statement in a +# trigger program does not prevent the VM from using a statement +# transaction. Even if the calling statement cannot hit a constraint. +# +do_execsql_test 2.0 { + CREATE TABLE t1(x); + + CREATE TRIGGER t1_ai AFTER INSERT ON t1 BEGIN + DELETE FROM ft WHERE rowid=new.x; + END; + + CREATE TRIGGER t1_ad AFTER DELETE ON t1 BEGIN + UPDATE ft SET content = 'a b c' WHERE rowid=old.x; + END; + + CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 BEGIN + DELETE FROM ft WHERE rowid=old.x; + END; +} + +foreach {tn sql uses} { + 1 { INSERT INTO t1 VALUES(1) } 1 + 2 { DELETE FROM t1 WHERE x=4 } 1 + 3 { UPDATE t1 SET x=10 WHERE x=11 } 1 +} { + do_test 2.$tn { sql_uses_stmt db $sql } $uses +} + +#------------------------------------------------------------------------- +# Test that an "UPDATE ... WHERE rowid=?" works and does not corrupt the +# index when it strikes a constraint. Both inside and outside a +# transaction. +# +foreach {tn tcl1 tcl2} { + 1 {} {} + + 2 { + execsql BEGIN + } { + if {[sqlite3_get_autocommit db]==1} { error "transaction rolled back!" } + execsql COMMIT + } +} { + + do_execsql_test 3.$tn.0 { + DROP TABLE IF EXISTS ft2; + CREATE VIRTUAL TABLE ft2 USING fts5(content); + INSERT INTO ft2(rowid, content) VALUES(1, 'a b c'); + INSERT INTO ft2(rowid, content) VALUES(2, 'a b d'); + INSERT INTO ft2(rowid, content) VALUES(3, 'a b e'); + } + + eval $tcl1 + foreach {tn2 sql content} { + 1 { UPDATE ft2 SET rowid=2 WHERE rowid=1 } + { 1 {a b c} 2 {a b d} 3 {a b e} } + + 2 { + INSERT INTO ft2(rowid, content) VALUES(4, 'a b f'); + UPDATE ft2 SET rowid=5 WHERE rowid=4; + UPDATE ft2 SET rowid=3 WHERE rowid=5; + } { 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } + + 3 { + UPDATE ft2 SET rowid=3 WHERE rowid=4; -- matches 0 rows + UPDATE ft2 SET rowid=2 WHERE rowid=3; + } { 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } + + 4 { + INSERT INTO ft2(rowid, content) VALUES(4, 'a b g'); + UPDATE ft2 SET rowid=-1 WHERE rowid=4; + UPDATE ft2 SET rowid=3 WHERE rowid=-1; + } {-1 {a b g} 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } + + 5 { + DELETE FROM ft2 WHERE rowid=451; + DELETE FROM ft2 WHERE rowid=-1; + UPDATE ft2 SET rowid = 2 WHERE rowid = 1; + } {1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} } + } { + do_catchsql_test 3.$tn.$tn2.a $sql {1 {constraint failed}} + do_execsql_test 3.$tn.$tn2.b { SELECT rowid, content FROM ft2 } $content + + do_execsql_test 3.$tn.$tn2.c { + INSERT INTO ft2(ft2) VALUES('integrity-check'); + } + } + eval $tcl2 +} + +#------------------------------------------------------------------------- +# Check that DELETE and UPDATE operations can be done without flushing +# the in-memory hash table to disk. +# +reset_db +do_execsql_test 4.1.1 { + CREATE VIRTUAL TABLE ttt USING fts5(x); + BEGIN; + INSERT INTO ttt(rowid, x) VALUES(1, 'a b c'); + INSERT INTO ttt(rowid, x) VALUES(2, 'a b c'); + INSERT INTO ttt(rowid, x) VALUES(3, 'a b c'); + COMMIT +} +do_test 4.1.2 { fts5_level_segs ttt } {1} + +do_execsql_test 4.2.1 { + BEGIN; + DELETE FROM ttt WHERE rowid=1; + DELETE FROM ttt WHERE rowid=3; + INSERT INTO ttt(rowid, x) VALUES(4, 'd e f'); + INSERT INTO ttt(rowid, x) VALUES(5, 'd e f'); + COMMIT; +} {} +do_test 4.2.2 { fts5_level_segs ttt } {2} + + +do_execsql_test 4.3.1 { + BEGIN; + UPDATE ttt SET x = 'd e f' WHERE rowid = 2; + UPDATE ttt SET x = 'A B C' WHERE rowid = 4; + INSERT INTO ttt(rowid, x) VALUES(6, 'd e f'); + COMMIT; +} {} +do_test 4.2.2 { fts5_level_segs ttt } {3} + +finish_test + diff --git a/ext/fts5/test/fts5optimize.test b/ext/fts5/test/fts5optimize.test new file mode 100644 index 0000000..984af8c --- /dev/null +++ b/ext/fts5/test/fts5optimize.test @@ -0,0 +1,66 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5optimize + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +proc rnddoc {nWord} { + set vocab {a b c d e f g h i j k l m n o p q r s t u v w x y z} + set nVocab [llength $vocab] + set ret [list] + for {set i 0} {$i < $nWord} {incr i} { + lappend ret [lindex $vocab [expr {int(rand() * $nVocab)}]] + } + return $ret +} + + +foreach {tn nStep} { + 1 2 + 2 10 + 3 50 + 4 500 +} { +if {$tn!=4} continue + reset_db + db func rnddoc rnddoc + do_execsql_test 1.$tn.1 { + CREATE VIRTUAL TABLE t1 USING fts5(x, y); + } + do_test 1.$tn.2 { + for {set i 0} {$i < $nStep} {incr i} { + execsql { INSERT INTO t1 VALUES( rnddoc(5), rnddoc(5) ) } + } + } {} + + do_execsql_test 1.$tn.3 { + INSERT INTO t1(t1) VALUES('integrity-check'); + } + + do_execsql_test 1.$tn.4 { + INSERT INTO t1(t1) VALUES('optimize'); + } + + do_execsql_test 1.$tn.5 { + INSERT INTO t1(t1) VALUES('integrity-check'); + } +} + +finish_test + diff --git a/ext/fts5/test/fts5phrase.test b/ext/fts5/test/fts5phrase.test new file mode 100644 index 0000000..6dac684 --- /dev/null +++ b/ext/fts5/test/fts5phrase.test @@ -0,0 +1,119 @@ +# 2014 Jan 08 +# +# 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. +# +#*********************************************************************** +# +# Tests focused on phrase queries. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5phrase + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t3 USING fts5(a, b, c); + INSERT INTO t3 VALUES('d e a', 'd i j j f', 'i j i e b f h'); -- 1 + INSERT INTO t3 VALUES('g a e', 'f g i g a', 'h d g i g h c'); -- 2 + INSERT INTO t3 VALUES('e a d', 'e i h a f', 'c e h i f b i'); -- 3 + INSERT INTO t3 VALUES('a g c', 'd j d j c', 'c d f j i g j'); -- 4 + INSERT INTO t3 VALUES('b c b', 'j g c d f', 'j c j d g f b'); -- 5 + INSERT INTO t3 VALUES('j a d', 'e b i h h', 'c c f g d i d'); -- 6 + INSERT INTO t3 VALUES('a d f', 'h g i i i', 'e a g c i f b'); -- 7 + INSERT INTO t3 VALUES('g f d', 'f c g b j', 'b b h h h j j'); -- 8 + INSERT INTO t3 VALUES('f h g', 'c j f g j', 'd h d f e b h'); -- 9 + INSERT INTO t3 VALUES('f h d', 'c i a d b', 'g b j b a d e'); -- 10 + INSERT INTO t3 VALUES('j h h', 'j i h a g', 'd e i e a g j'); -- 11 + INSERT INTO t3 VALUES('a b e', 'h g a g c', 'h c a a d e g'); -- 12 + INSERT INTO t3 VALUES('a j g', 'i h i f i', 'a g h j g i b'); -- 13 + INSERT INTO t3 VALUES('j h e', 'f e d i e', 'i d c f e d c'); -- 14 + INSERT INTO t3 VALUES('d j d', 'd b i a c', 'g d h i d b e'); -- 15 + INSERT INTO t3 VALUES('h j e', 'e b b c f', 'j a f g h d j'); -- 16 + INSERT INTO t3 VALUES('c b j', 'c a b a i', 'h f i d a d c'); -- 17 + INSERT INTO t3 VALUES('e e d', 'i d f c c', 'g i d a f e a'); -- 18 + INSERT INTO t3 VALUES('e i g', 'e a b i h', 'i f d d a d f'); -- 19 + INSERT INTO t3 VALUES('h g f', 'b h h j d', 'i f d e g j a'); -- 20 + INSERT INTO t3 VALUES('e h f', 'j c b c f', 'j a j g h a c'); -- 21 + INSERT INTO t3 VALUES('d c h', 'b g i c e', 'i i c d e h i'); -- 22 + INSERT INTO t3 VALUES('a h i', 'a g d f f', 'e f i i b b h'); -- 23 + INSERT INTO t3 VALUES('d d g', 'c c b c g', 'g c h e b c e'); -- 24 + INSERT INTO t3 VALUES('a b b', 'b f a d i', 'd a h a b c i'); -- 25 + INSERT INTO t3 VALUES('a f d', 'a j e a h', 'j i h j a i f'); -- 26 + INSERT INTO t3 VALUES('d j d', 'h a d i a', 'h h f j h g a'); -- 27 + INSERT INTO t3 VALUES('g a e', 'd g f a g', 'i d b c g g j'); -- 28 + INSERT INTO t3 VALUES('j e h', 'g h j h g', 'd a e j a a h'); -- 29 + INSERT INTO t3 VALUES('e j e', 'g e j g c', 'f c e b e e a'); -- 30 + INSERT INTO t3 VALUES('h f f', 'i j g e c', 'j j f c a i j'); -- 31 + INSERT INTO t3 VALUES('a g c', 'c g d b i', 'g h c b a a f'); -- 32 + INSERT INTO t3 VALUES('c h i', 'j d h e e', 'a h i d c c j'); -- 33 + INSERT INTO t3 VALUES('d a c', 'e d d b j', 'c e b b h i h'); -- 34 + INSERT INTO t3 VALUES('d f h', 'c a f c c', 'j b b c c j f'); -- 35 + INSERT INTO t3 VALUES('b g h', 'g c c c f', 'c g c f h e e'); -- 36 + INSERT INTO t3 VALUES('f e a', 'b h f j h', 'j g h f d g f'); -- 37 + INSERT INTO t3 VALUES('h f a', 'a e i j g', 'f d a f d f c'); -- 38 + INSERT INTO t3 VALUES('f i c', 'f i i i i', 'e c f d h j f'); -- 39 + INSERT INTO t3 VALUES('h h d', 'd i e d i', 'd f e i a h a'); -- 40 + INSERT INTO t3 VALUES('f g c', 'd a f c h', 'b b g j c e g'); -- 41 + INSERT INTO t3 VALUES('h i h', 'h d j d e', 'e d b b i e g'); -- 42 + INSERT INTO t3 VALUES('b h i', 'j e i d a', 'j j h e e c a'); -- 43 + INSERT INTO t3 VALUES('g i g', 'f c c f d', 'a c i c a d a'); -- 44 + INSERT INTO t3 VALUES('c c f', 'a b j d b', 'c a e g f e c'); -- 45 + INSERT INTO t3 VALUES('d h j', 'g c b j d', 'e a h f h j g'); -- 46 + INSERT INTO t3 VALUES('a a d', 'j e j a i', 'i d c f f f b'); -- 47 + INSERT INTO t3 VALUES('b g j', 'e c i h f', 'd d h b g a d'); -- 48 + INSERT INTO t3 VALUES('c i a', 'a c c c c', 'e h i e h i e'); -- 49 + INSERT INTO t3 VALUES('f f c', 'f f b i i', 'f f a j e c i'); -- 50 +} + +proc pmatch {col expr} { + return [expr {[string first $expr $col]>=0}] +} +db func pmatch pmatch + +foreach {tn cols tokens} { + 1 a "c c" + 2 b "c c" + 3 c "c c" + 4 {a b c} "c c" + 5 {a b c} "b h" + 6 {a b} "b h" + 7 {a c} "b h" + 8 {c a} "b h" + 9 {c} "i e" + 10 {b} "i e" + 11 {a} "i e" +} { + set fts "{$cols}:[join $tokens +]" + set where [list] + foreach c $cols { lappend where "pmatch($c, '$tokens')" } + set where [join $where " OR "] + + set res [db eval "SELECT rowid FROM t3 WHERE $where"] + do_execsql_test "1.$tn.$fts->([llength $res] rows)" { + SELECT rowid FROM t3($fts) + } $res +} + +do_execsql_test 2.0 { + SELECT rowid, + highlight(t3, 0, '*', '*'), + highlight(t3, 1, '*', '*'), + highlight(t3, 2, '*', '*') + FROM t3('a:f+f') +} { + 31 {h *f f*} {i j g e c} {j j f c a i j} + 50 {*f f* c} {f f b i i} {f f a j e c i} +} + +finish_test + diff --git a/ext/fts5/test/fts5plan.test b/ext/fts5/test/fts5plan.test new file mode 100644 index 0000000..d7f5fd6 --- /dev/null +++ b/ext/fts5/test/fts5plan.test @@ -0,0 +1,67 @@ +# 2014 Dec 20 +# +# 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 focuses on testing the planner (xBestIndex function). +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5plan + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE TABLE t1(x, y); + CREATE VIRTUAL TABLE f1 USING fts5(ff); +} + +do_eqp_test 1.1 { + SELECT * FROM t1, f1 WHERE f1 MATCH t1.x +} { + 0 0 0 {SCAN TABLE t1} + 0 1 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 1:} +} + +do_eqp_test 1.2 { + SELECT * FROM t1, f1 WHERE f1 > t1.x +} { + 0 0 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 0:} + 0 1 0 {SCAN TABLE t1} +} + +do_eqp_test 1.3 { + SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff +} { + 0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 1:} + 0 0 0 {USE TEMP B-TREE FOR ORDER BY} +} + +do_eqp_test 1.4 { + SELECT * FROM f1 ORDER BY rank +} { + 0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 0:} + 0 0 0 {USE TEMP B-TREE FOR ORDER BY} +} + +do_eqp_test 1.5 { + SELECT * FROM f1 WHERE rank MATCH ? +} { + 0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 2:} +} + + + + +finish_test + diff --git a/ext/fts5/test/fts5porter.test b/ext/fts5/test/fts5porter.test new file mode 100644 index 0000000..2535eb7 --- /dev/null +++ b/ext/fts5/test/fts5porter.test @@ -0,0 +1,11806 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Tests focusing on the fts5 porter stemmer implementation. +# +# http://tartarus.org/martin/PorterStemmer/ +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5porter + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +set test_vocab { + a a aaron aaron + abaissiez abaissiez abandon abandon + abandoned abandon abase abas + abash abash abate abat + abated abat abatement abat + abatements abat abates abat + abbess abbess abbey abbei + abbeys abbei abbominable abbomin + abbot abbot abbots abbot + abbreviated abbrevi abed ab + abel abel aberga aberga + abergavenny abergavenni abet abet + abetting abet abhominable abhomin + abhor abhor abhorr abhorr + abhorred abhor abhorring abhor + abhors abhor abhorson abhorson + abide abid abides abid + abilities abil ability abil + abject abject abjectly abjectli + abjects abject abjur abjur + abjure abjur able abl + abler abler aboard aboard + abode abod aboded abod + abodements abod aboding abod + abominable abomin abominably abomin + abominations abomin abortive abort + abortives abort abound abound + abounding abound about about + above abov abr abr + abraham abraham abram abram + abreast abreast abridg abridg + abridge abridg abridged abridg + abridgment abridg abroach abroach + abroad abroad abrogate abrog + abrook abrook abrupt abrupt + abruption abrupt abruptly abruptli + absence absenc absent absent + absey absei absolute absolut + absolutely absolut absolv absolv + absolver absolv abstains abstain + abstemious abstemi abstinence abstin + abstract abstract absurd absurd + absyrtus absyrtu abundance abund + abundant abund abundantly abundantli + abus abu abuse abus + abused abus abuser abus + abuses abus abusing abus + abutting abut aby abi + abysm abysm ac ac + academe academ academes academ + accent accent accents accent + accept accept acceptable accept + acceptance accept accepted accept + accepts accept access access + accessary accessari accessible access + accidence accid accident accid + accidental accident accidentally accident + accidents accid accite accit + accited accit accites accit + acclamations acclam accommodate accommod + accommodated accommod accommodation accommod + accommodations accommod accommodo accommodo + accompanied accompani accompany accompani + accompanying accompani accomplices accomplic + accomplish accomplish accomplished accomplish + accomplishing accomplish accomplishment accomplish + accompt accompt accord accord + accordant accord accorded accord + accordeth accordeth according accord + accordingly accordingli accords accord + accost accost accosted accost + account account accountant account + accounted account accounts account + accoutred accoutr accoutrement accoutr + accoutrements accoutr accrue accru + accumulate accumul accumulated accumul + accumulation accumul accurs accur + accursed accurs accurst accurst + accus accu accusation accus + accusations accus accusative accus + accusativo accusativo accuse accus + accused accus accuser accus + accusers accus accuses accus + accuseth accuseth accusing accus + accustom accustom accustomed accustom + ace ac acerb acerb + ache ach acheron acheron + aches ach achiev achiev + achieve achiev achieved achiev + achievement achiev achievements achiev + achiever achiev achieves achiev + achieving achiev achilles achil + aching ach achitophel achitophel + acknowledg acknowledg acknowledge acknowledg + acknowledged acknowledg acknowledgment acknowledg + acknown acknown acold acold + aconitum aconitum acordo acordo + acorn acorn acquaint acquaint + acquaintance acquaint acquainted acquaint + acquaints acquaint acquir acquir + acquire acquir acquisition acquisit + acquit acquit acquittance acquitt + acquittances acquitt acquitted acquit + acre acr acres acr + across across act act + actaeon actaeon acted act + acting act action action + actions action actium actium + active activ actively activ + activity activ actor actor + actors actor acts act + actual actual acture actur + acute acut acutely acut + ad ad adage adag + adallas adalla adam adam + adamant adam add add + added ad adder adder + adders adder addeth addeth + addict addict addicted addict + addiction addict adding ad + addition addit additions addit + addle addl address address + addressing address addrest addrest + adds add adhere adher + adheres adher adieu adieu + adieus adieu adjacent adjac + adjoin adjoin adjoining adjoin + adjourn adjourn adjudg adjudg + adjudged adjudg adjunct adjunct + administer administ administration administr + admir admir admirable admir + admiral admir admiration admir + admire admir admired admir + admirer admir admiring admir + admiringly admiringli admission admiss + admit admit admits admit + admittance admitt admitted admit + admitting admit admonish admonish + admonishing admonish admonishment admonish + admonishments admonish admonition admonit + ado ado adonis adoni + adopt adopt adopted adopt + adoptedly adoptedli adoption adopt + adoptious adopti adopts adopt + ador ador adoration ador + adorations ador adore ador + adorer ador adores ador + adorest adorest adoreth adoreth + adoring ador adorn adorn + adorned adorn adornings adorn + adornment adorn adorns adorn + adown adown adramadio adramadio + adrian adrian adriana adriana + adriano adriano adriatic adriat + adsum adsum adulation adul + adulterate adulter adulterates adulter + adulterers adulter adulteress adulteress + adulteries adulteri adulterous adulter + adultery adulteri adultress adultress + advanc advanc advance advanc + advanced advanc advancement advanc + advancements advanc advances advanc + advancing advanc advantage advantag + advantageable advantag advantaged advantag + advantageous advantag advantages advantag + advantaging advantag advent advent + adventur adventur adventure adventur + adventures adventur adventuring adventur + adventurous adventur adventurously adventur + adversaries adversari adversary adversari + adverse advers adversely advers + adversities advers adversity advers + advertis adverti advertise advertis + advertised advertis advertisement advertis + advertising advertis advice advic + advis advi advise advis + advised advis advisedly advisedli + advises advis advisings advis + advocate advoc advocation advoc + aeacida aeacida aeacides aeacid + aedile aedil aediles aedil + aegeon aegeon aegion aegion + aegles aegl aemelia aemelia + aemilia aemilia aemilius aemiliu + aeneas aenea aeolus aeolu + aer aer aerial aerial + aery aeri aesculapius aesculapiu + aeson aeson aesop aesop + aetna aetna afar afar + afear afear afeard afeard + affability affabl affable affabl + affair affair affaire affair + affairs affair affect affect + affectation affect affectations affect + affected affect affectedly affectedli + affecteth affecteth affecting affect + affection affect affectionate affection + affectionately affection affections affect + affects affect affeer affeer + affianc affianc affiance affianc + affianced affianc affied affi + affin affin affined affin + affinity affin affirm affirm + affirmation affirm affirmatives affirm + afflict afflict afflicted afflict + affliction afflict afflictions afflict + afflicts afflict afford afford + affordeth affordeth affords afford + affray affrai affright affright + affrighted affright affrights affright + affront affront affronted affront + affy affi afield afield + afire afir afloat afloat + afoot afoot afore afor + aforehand aforehand aforesaid aforesaid + afraid afraid afresh afresh + afric afric africa africa + african african afront afront + after after afternoon afternoon + afterward afterward afterwards afterward + ag ag again again + against against agamemmon agamemmon + agamemnon agamemnon agate agat + agaz agaz age ag + aged ag agenor agenor + agent agent agents agent + ages ag aggravate aggrav + aggrief aggrief agile agil + agincourt agincourt agitation agit + aglet aglet agnize agniz + ago ago agone agon + agony agoni agree agre + agreed agre agreeing agre + agreement agreement agrees agre + agrippa agrippa aground aground + ague agu aguecheek aguecheek + agued agu agueface aguefac + agues agu ah ah + aha aha ahungry ahungri + ai ai aialvolio aialvolio + aiaria aiaria aid aid + aidance aidanc aidant aidant + aided aid aiding aid + aidless aidless aids aid + ail ail aim aim + aimed aim aimest aimest + aiming aim aims aim + ainsi ainsi aio aio + air air aired air + airless airless airs air + airy airi ajax ajax + akilling akil al al + alabaster alabast alack alack + alacrity alacr alarbus alarbu + alarm alarm alarms alarm + alarum alarum alarums alarum + alas ala alb alb + alban alban albans alban + albany albani albeit albeit + albion albion alchemist alchemist + alchemy alchemi alcibiades alcibiad + alcides alcid alder alder + alderman alderman aldermen aldermen + ale al alecto alecto + alehouse alehous alehouses alehous + alencon alencon alengon alengon + aleppo aleppo ales al + alewife alewif alexander alexand + alexanders alexand alexandria alexandria + alexandrian alexandrian alexas alexa + alias alia alice alic + alien alien aliena aliena + alight alight alighted alight + alights alight aliis alii + alike alik alisander alisand + alive aliv all all + alla alla allay allai + allayed allai allaying allai + allayment allay allayments allay + allays allai allegation alleg + allegations alleg allege alleg + alleged alleg allegiance allegi + allegiant allegi alley allei + alleys allei allhallowmas allhallowma + alliance allianc allicholy allicholi + allied alli allies alli + alligant allig alligator allig + allons allon allot allot + allots allot allotted allot + allottery allotteri allow allow + allowance allow allowed allow + allowing allow allows allow + allur allur allure allur + allurement allur alluring allur + allusion allus ally alli + allycholly allycholli almain almain + almanac almanac almanack almanack + almanacs almanac almighty almighti + almond almond almost almost + alms alm almsman almsman + aloes alo aloft aloft + alone alon along along + alonso alonso aloof aloof + aloud aloud alphabet alphabet + alphabetical alphabet alphonso alphonso + alps alp already alreadi + also also alt alt + altar altar altars altar + alter alter alteration alter + altered alter alters alter + althaea althaea although although + altitude altitud altogether altogeth + alton alton alway alwai + always alwai am am + amaimon amaimon amain amain + amaking amak amamon amamon + amaz amaz amaze amaz + amazed amaz amazedly amazedli + amazedness amazed amazement amaz + amazes amaz amazeth amazeth + amazing amaz amazon amazon + amazonian amazonian amazons amazon + ambassador ambassador ambassadors ambassador + amber amber ambiguides ambiguid + ambiguities ambigu ambiguous ambigu + ambition ambit ambitions ambit + ambitious ambiti ambitiously ambiti + amble ambl ambled ambl + ambles ambl ambling ambl + ambo ambo ambuscadoes ambuscado + ambush ambush amen amen + amend amend amended amend + amendment amend amends amend + amerce amerc america america + ames am amiable amiabl + amid amid amidst amidst + amiens amien amis ami + amiss amiss amities amiti + amity amiti amnipotent amnipot + among among amongst amongst + amorous amor amorously amor + amort amort amount amount + amounts amount amour amour + amphimacus amphimacu ample ampl + ampler ampler amplest amplest + amplified amplifi amplify amplifi + amply ampli ampthill ampthil + amurath amurath amyntas amynta + an an anatomiz anatomiz + anatomize anatom anatomy anatomi + ancestor ancestor ancestors ancestor + ancestry ancestri anchises anchis + anchor anchor anchorage anchorag + anchored anchor anchoring anchor + anchors anchor anchovies anchovi + ancient ancient ancientry ancientri + ancients ancient ancus ancu + and and andirons andiron + andpholus andpholu andren andren + andrew andrew andromache andromach + andronici andronici andronicus andronicu + anew anew ang ang + angel angel angelica angelica + angelical angel angelo angelo + angels angel anger anger + angerly angerli angers anger + anges ang angiers angier + angl angl anglais anglai + angle angl angler angler + angleterre angleterr angliae anglia + angling angl anglish anglish + angrily angrili angry angri + anguish anguish angus angu + animal anim animals anim + animis animi anjou anjou + ankle ankl anna anna + annals annal anne ann + annex annex annexed annex + annexions annexion annexment annex + annothanize annothan announces announc + annoy annoi annoyance annoy + annoying annoi annual annual + anoint anoint anointed anoint + anon anon another anoth + anselmo anselmo answer answer + answerable answer answered answer + answerest answerest answering answer + answers answer ant ant + ante ant antenor antenor + antenorides antenorid anteroom anteroom + anthem anthem anthems anthem + anthony anthoni anthropophagi anthropophagi + anthropophaginian anthropophaginian antiates antiat + antic antic anticipate anticip + anticipates anticip anticipatest anticipatest + anticipating anticip anticipation anticip + antick antick anticly anticli + antics antic antidote antidot + antidotes antidot antigonus antigonu + antiopa antiopa antipathy antipathi + antipholus antipholu antipholuses antipholus + antipodes antipod antiquary antiquari + antique antiqu antiquity antiqu + antium antium antoniad antoniad + antonio antonio antonius antoniu + antony antoni antres antr + anvil anvil any ani + anybody anybodi anyone anyon + anything anyth anywhere anywher + ap ap apace apac + apart apart apartment apart + apartments apart ape ap + apemantus apemantu apennines apennin + apes ap apiece apiec + apish apish apollinem apollinem + apollo apollo apollodorus apollodoru + apology apolog apoplex apoplex + apoplexy apoplexi apostle apostl + apostles apostl apostrophas apostropha + apoth apoth apothecary apothecari + appal appal appall appal + appalled appal appals appal + apparel apparel apparell apparel + apparelled apparel apparent appar + apparently appar apparition apparit + apparitions apparit appeach appeach + appeal appeal appeals appeal + appear appear appearance appear + appeared appear appeareth appeareth + appearing appear appears appear + appeas appea appease appeas + appeased appeas appelant appel + appele appel appelee appele + appeles appel appelez appelez + appellant appel appellants appel + appelons appelon appendix appendix + apperil apperil appertain appertain + appertaining appertain appertainings appertain + appertains appertain appertinent appertin + appertinents appertin appetite appetit + appetites appetit applaud applaud + applauded applaud applauding applaud + applause applaus applauses applaus + apple appl apples appl + appletart appletart appliance applianc + appliances applianc applications applic + applied appli applies appli + apply appli applying appli + appoint appoint appointed appoint + appointment appoint appointments appoint + appoints appoint apprehend apprehend + apprehended apprehend apprehends apprehend + apprehension apprehens apprehensions apprehens + apprehensive apprehens apprendre apprendr + apprenne apprenn apprenticehood apprenticehood + appris appri approach approach + approachers approach approaches approach + approacheth approacheth approaching approach + approbation approb approof approof + appropriation appropri approv approv + approve approv approved approv + approvers approv approves approv + appurtenance appurten appurtenances appurten + apricocks apricock april april + apron apron aprons apron + apt apt apter apter + aptest aptest aptly aptli + aptness apt aqua aqua + aquilon aquilon aquitaine aquitain + arabia arabia arabian arabian + araise arais arbitrate arbitr + arbitrating arbitr arbitrator arbitr + arbitrement arbitr arbors arbor + arbour arbour arc arc + arch arch archbishop archbishop + archbishopric archbishopr archdeacon archdeacon + arched arch archelaus archelau + archer archer archers archer + archery archeri archibald archibald + archidamus archidamu architect architect + arcu arcu arde ard + arden arden ardent ardent + ardour ardour are ar + argal argal argier argier + argo argo argosies argosi + argosy argosi argu argu + argue argu argued argu + argues argu arguing argu + argument argument arguments argument + argus argu ariachne ariachn + ariadne ariadn ariel ariel + aries ari aright aright + arinado arinado arinies arini + arion arion arise aris + arises aris ariseth ariseth + arising aris aristode aristod + aristotle aristotl arithmetic arithmet + arithmetician arithmetician ark ark + arm arm arma arma + armado armado armadoes armado + armagnac armagnac arme arm + armed arm armenia armenia + armies armi armigero armigero + arming arm armipotent armipot + armor armor armour armour + armourer armour armourers armour + armours armour armoury armouri + arms arm army armi + arn arn aroint aroint + arose aros arouse arous + aroused arous arragon arragon + arraign arraign arraigned arraign + arraigning arraign arraignment arraign + arrant arrant arras arra + array arrai arrearages arrearag + arrest arrest arrested arrest + arrests arrest arriv arriv + arrival arriv arrivance arriv + arrive arriv arrived arriv + arrives arriv arriving arriv + arrogance arrog arrogancy arrog + arrogant arrog arrow arrow + arrows arrow art art + artemidorus artemidoru arteries arteri + arthur arthur article articl + articles articl articulate articul + artificer artific artificial artifici + artillery artilleri artire artir + artist artist artists artist + artless artless artois artoi + arts art artus artu + arviragus arviragu as as + asaph asaph ascanius ascaniu + ascend ascend ascended ascend + ascendeth ascendeth ascends ascend + ascension ascens ascent ascent + ascribe ascrib ascribes ascrib + ash ash asham asham + ashamed asham asher asher + ashes ash ashford ashford + ashore ashor ashouting ashout + ashy ashi asia asia + aside asid ask ask + askance askanc asked ask + asker asker asketh asketh + asking ask asks ask + aslant aslant asleep asleep + asmath asmath asp asp + aspect aspect aspects aspect + aspen aspen aspersion aspers + aspic aspic aspicious aspici + aspics aspic aspir aspir + aspiration aspir aspire aspir + aspiring aspir asquint asquint + ass ass assail assail + assailable assail assailant assail + assailants assail assailed assail + assaileth assaileth assailing assail + assails assail assassination assassin + assault assault assaulted assault + assaults assault assay assai + assaying assai assays assai + assemblance assembl assemble assembl + assembled assembl assemblies assembl + assembly assembl assent assent + asses ass assez assez + assign assign assigned assign + assigns assign assinico assinico + assist assist assistance assist + assistances assist assistant assist + assistants assist assisted assist + assisting assist associate associ + associated associ associates associ + assuage assuag assubjugate assubjug + assum assum assume assum + assumes assum assumption assumpt + assur assur assurance assur + assure assur assured assur + assuredly assuredli assures assur + assyrian assyrian astonish astonish + astonished astonish astraea astraea + astray astrai astrea astrea + astronomer astronom astronomers astronom + astronomical astronom astronomy astronomi + asunder asund at at + atalanta atalanta ate at + ates at athenian athenian + athenians athenian athens athen + athol athol athversary athversari + athwart athwart atlas atla + atomies atomi atomy atomi + atone aton atonement aton + atonements aton atropos atropo + attach attach attached attach + attachment attach attain attain + attainder attaind attains attain + attaint attaint attainted attaint + attainture attaintur attempt attempt + attemptable attempt attempted attempt + attempting attempt attempts attempt + attend attend attendance attend + attendant attend attendants attend + attended attend attendents attend + attendeth attendeth attending attend + attends attend attent attent + attention attent attentive attent + attentivenes attentiven attest attest + attested attest attir attir + attire attir attired attir + attires attir attorney attornei + attorneyed attornei attorneys attornei + attorneyship attorneyship attract attract + attraction attract attractive attract + attracts attract attribute attribut + attributed attribut attributes attribut + attribution attribut attributive attribut + atwain atwain au au + aubrey aubrei auburn auburn + aucun aucun audacious audaci + audaciously audaci audacity audac + audible audibl audience audienc + audis audi audit audit + auditor auditor auditors auditor + auditory auditori audre audr + audrey audrei aufidius aufidiu + aufidiuses aufidius auger auger + aught aught augment augment + augmentation augment augmented augment + augmenting augment augurer augur + augurers augur augures augur + auguring augur augurs augur + augury auguri august august + augustus augustu auld auld + aumerle aumerl aunchient aunchient + aunt aunt aunts aunt + auricular auricular aurora aurora + auspicious auspici aussi aussi + austere auster austerely auster + austereness auster austerity auster + austria austria aut aut + authentic authent author author + authorities author authority author + authorized author authorizing author + authors author autolycus autolycu + autre autr autumn autumn + auvergne auvergn avail avail + avails avail avarice avaric + avaricious avarici avaunt avaunt + ave av aveng aveng + avenge aveng avenged aveng + averring aver avert avert + aves av avez avez + avis avi avoid avoid + avoided avoid avoiding avoid + avoids avoid avoirdupois avoirdupoi + avouch avouch avouched avouch + avouches avouch avouchment avouch + avow avow aw aw + await await awaits await + awak awak awake awak + awaked awak awaken awaken + awakened awaken awakens awaken + awakes awak awaking awak + award award awards award + awasy awasi away awai + awe aw aweary aweari + aweless aweless awful aw + awhile awhil awkward awkward + awl awl awooing awoo + awork awork awry awri + axe ax axle axl + axletree axletre ay ay + aye ay ayez ayez + ayli ayli azur azur + azure azur b b + ba ba baa baa + babbl babbl babble babbl + babbling babbl babe babe + babes babe babies babi + baboon baboon baboons baboon + baby babi babylon babylon + bacare bacar bacchanals bacchan + bacchus bacchu bach bach + bachelor bachelor bachelors bachelor + back back backbite backbit + backbitten backbitten backing back + backs back backward backward + backwardly backwardli backwards backward + bacon bacon bacons bacon + bad bad bade bade + badge badg badged badg + badges badg badly badli + badness bad baes bae + baffl baffl baffle baffl + baffled baffl bag bag + baggage baggag bagot bagot + bagpipe bagpip bags bag + bail bail bailiff bailiff + baillez baillez baily baili + baisant baisant baisees baise + baiser baiser bait bait + baited bait baiting bait + baitings bait baits bait + bajazet bajazet bak bak + bake bake baked bake + baker baker bakers baker + bakes bake baking bake + bal bal balanc balanc + balance balanc balcony balconi + bald bald baldrick baldrick + bale bale baleful bale + balk balk ball ball + ballad ballad ballads ballad + ballast ballast ballasting ballast + ballet ballet ballow ballow + balls ball balm balm + balms balm balmy balmi + balsam balsam balsamum balsamum + balth balth balthasar balthasar + balthazar balthazar bames bame + ban ban banbury banburi + band band bandied bandi + banding band bandit bandit + banditti banditti banditto banditto + bands band bandy bandi + bandying bandi bane bane + banes bane bang bang + bangor bangor banish banish + banished banish banishers banish + banishment banish banister banist + bank bank bankrout bankrout + bankrupt bankrupt bankrupts bankrupt + banks bank banner banner + bannerets banneret banners banner + banning ban banns bann + banquet banquet banqueted banquet + banqueting banquet banquets banquet + banquo banquo bans ban + baptism baptism baptista baptista + baptiz baptiz bar bar + barbarian barbarian barbarians barbarian + barbarism barbar barbarous barbar + barbary barbari barbason barbason + barbed barb barber barber + barbermonger barbermong bard bard + bardolph bardolph bards bard + bare bare bared bare + barefac barefac barefaced barefac + barefoot barefoot bareheaded barehead + barely bare bareness bare + barful bar bargain bargain + bargains bargain barge barg + bargulus bargulu baring bare + bark bark barking bark + barkloughly barkloughli barks bark + barky barki barley barlei + barm barm barn barn + barnacles barnacl barnardine barnardin + barne barn barnes barn + barnet barnet barns barn + baron baron barons baron + barony baroni barr barr + barrabas barraba barrel barrel + barrels barrel barren barren + barrenly barrenli barrenness barren + barricado barricado barricadoes barricado + barrow barrow bars bar + barson barson barter barter + bartholomew bartholomew bas ba + basan basan base base + baseless baseless basely base + baseness base baser baser + bases base basest basest + bashful bash bashfulness bash + basilisco basilisco basilisk basilisk + basilisks basilisk basimecu basimecu + basin basin basingstoke basingstok + basins basin basis basi + bask bask basket basket + baskets basket bass bass + bassanio bassanio basset basset + bassianus bassianu basta basta + bastard bastard bastardizing bastard + bastardly bastardli bastards bastard + bastardy bastardi basted bast + bastes bast bastinado bastinado + basting bast bat bat + batailles batail batch batch + bate bate bated bate + bates bate bath bath + bathe bath bathed bath + bathing bath baths bath + bating bate batler batler + bats bat batt batt + battalia battalia battalions battalion + batten batten batter batter + battering batter batters batter + battery batteri battle battl + battled battl battlefield battlefield + battlements battlement battles battl + batty batti bauble baubl + baubles baubl baubling baubl + baulk baulk bavin bavin + bawcock bawcock bawd bawd + bawdry bawdri bawds bawd + bawdy bawdi bawl bawl + bawling bawl bay bai + baying bai baynard baynard + bayonne bayonn bays bai + be be beach beach + beached beach beachy beachi + beacon beacon bead bead + beaded bead beadle beadl + beadles beadl beads bead + beadsmen beadsmen beagle beagl + beagles beagl beak beak + beaks beak beam beam + beamed beam beams beam + bean bean beans bean + bear bear beard beard + bearded beard beardless beardless + beards beard bearer bearer + bearers bearer bearest bearest + beareth beareth bearing bear + bears bear beast beast + beastliest beastliest beastliness beastli + beastly beastli beasts beast + beat beat beated beat + beaten beaten beating beat + beatrice beatric beats beat + beau beau beaufort beaufort + beaumond beaumond beaumont beaumont + beauteous beauteou beautied beauti + beauties beauti beautified beautifi + beautiful beauti beautify beautifi + beauty beauti beaver beaver + beavers beaver became becam + because becaus bechanc bechanc + bechance bechanc bechanced bechanc + beck beck beckon beckon + beckons beckon becks beck + becom becom become becom + becomed becom becomes becom + becoming becom becomings becom + bed bed bedabbled bedabbl + bedash bedash bedaub bedaub + bedazzled bedazzl bedchamber bedchamb + bedclothes bedcloth bedded bed + bedeck bedeck bedecking bedeck + bedew bedew bedfellow bedfellow + bedfellows bedfellow bedford bedford + bedlam bedlam bedrench bedrench + bedrid bedrid beds bed + bedtime bedtim bedward bedward + bee bee beef beef + beefs beef beehives beehiv + been been beer beer + bees bee beest beest + beetle beetl beetles beetl + beeves beev befall befal + befallen befallen befalls befal + befell befel befits befit + befitted befit befitting befit + befor befor before befor + beforehand beforehand befortune befortun + befriend befriend befriended befriend + befriends befriend beg beg + began began beget beget + begets beget begetting beget + begg begg beggar beggar + beggared beggar beggarly beggarli + beggarman beggarman beggars beggar + beggary beggari begging beg + begin begin beginners beginn + beginning begin beginnings begin + begins begin begnawn begnawn + begone begon begot begot + begotten begotten begrimed begrim + begs beg beguil beguil + beguile beguil beguiled beguil + beguiles beguil beguiling beguil + begun begun behalf behalf + behalfs behalf behav behav + behaved behav behavedst behavedst + behavior behavior behaviors behavior + behaviour behaviour behaviours behaviour + behead behead beheaded behead + beheld beheld behest behest + behests behest behind behind + behold behold beholder behold + beholders behold beholdest beholdest + beholding behold beholds behold + behoof behoof behooffull behoofful + behooves behoov behove behov + behoves behov behowls behowl + being be bel bel + belarius belariu belch belch + belching belch beldam beldam + beldame beldam beldams beldam + belee bele belgia belgia + belie beli belied beli + belief belief beliest beliest + believ believ believe believ + believed believ believes believ + believest believest believing believ + belike belik bell bell + bellario bellario belle bell + bellied belli bellies belli + bellman bellman bellona bellona + bellow bellow bellowed bellow + bellowing bellow bellows bellow + bells bell belly belli + bellyful belly belman belman + belmont belmont belock belock + belong belong belonging belong + belongings belong belongs belong + belov belov beloved belov + beloving belov below below + belt belt belzebub belzebub + bemadding bemad bemet bemet + bemete bemet bemoan bemoan + bemoaned bemoan bemock bemock + bemoil bemoil bemonster bemonst + ben ben bench bench + bencher bencher benches bench + bend bend bended bend + bending bend bends bend + bene bene beneath beneath + benedicite benedicit benedick benedick + benediction benedict benedictus benedictu + benefactors benefactor benefice benefic + beneficial benefici benefit benefit + benefited benefit benefits benefit + benetted benet benevolence benevol + benevolences benevol benied beni + benison benison bennet bennet + bent bent bentii bentii + bentivolii bentivolii bents bent + benumbed benumb benvolio benvolio + bepaint bepaint bepray beprai + bequeath bequeath bequeathed bequeath + bequeathing bequeath bequest bequest + ber ber berard berard + berattle berattl beray berai + bere bere bereave bereav + bereaved bereav bereaves bereav + bereft bereft bergamo bergamo + bergomask bergomask berhym berhym + berhyme berhym berkeley berkelei + bermoothes bermooth bernardo bernardo + berod berod berowne berown + berri berri berries berri + berrord berrord berry berri + bertram bertram berwick berwick + bescreen bescreen beseech beseech + beseeched beseech beseechers beseech + beseeching beseech beseek beseek + beseem beseem beseemeth beseemeth + beseeming beseem beseems beseem + beset beset beshrew beshrew + beside besid besides besid + besieg besieg besiege besieg + besieged besieg beslubber beslubb + besmear besmear besmeared besmear + besmirch besmirch besom besom + besort besort besotted besot + bespake bespak bespeak bespeak + bespice bespic bespoke bespok + bespotted bespot bess bess + bessy bessi best best + bestained bestain bested best + bestial bestial bestir bestir + bestirr bestirr bestow bestow + bestowed bestow bestowing bestow + bestows bestow bestraught bestraught + bestrew bestrew bestrid bestrid + bestride bestrid bestrides bestrid + bet bet betake betak + beteem beteem bethink bethink + bethought bethought bethrothed bethroth + bethump bethump betid betid + betide betid betideth betideth + betime betim betimes betim + betoken betoken betook betook + betossed betoss betray betrai + betrayed betrai betraying betrai + betrays betrai betrims betrim + betroth betroth betrothed betroth + betroths betroth bett bett + betted bet better better + bettered better bettering better + betters better betting bet + bettre bettr between between + betwixt betwixt bevel bevel + beverage beverag bevis bevi + bevy bevi bewail bewail + bewailed bewail bewailing bewail + bewails bewail beware bewar + bewasted bewast beweep beweep + bewept bewept bewet bewet + bewhored bewhor bewitch bewitch + bewitched bewitch bewitchment bewitch + bewray bewrai beyond beyond + bezonian bezonian bezonians bezonian + bianca bianca bianco bianco + bias bia bibble bibbl + bickerings bicker bid bid + bidden bidden bidding bid + biddings bid biddy biddi + bide bide bides bide + biding bide bids bid + bien bien bier bier + bifold bifold big big + bigamy bigami biggen biggen + bigger bigger bigness big + bigot bigot bilberry bilberri + bilbo bilbo bilboes bilbo + bilbow bilbow bill bill + billeted billet billets billet + billiards billiard billing bill + billow billow billows billow + bills bill bin bin + bind bind bindeth bindeth + binding bind binds bind + biondello biondello birch birch + bird bird birding bird + birdlime birdlim birds bird + birnam birnam birth birth + birthday birthdai birthdom birthdom + birthplace birthplac birthright birthright + birthrights birthright births birth + bis bi biscuit biscuit + bishop bishop bishops bishop + bisson bisson bit bit + bitch bitch bite bite + biter biter bites bite + biting bite bits bit + bitt bitt bitten bitten + bitter bitter bitterest bitterest + bitterly bitterli bitterness bitter + blab blab blabb blabb + blabbing blab blabs blab + black black blackamoor blackamoor + blackamoors blackamoor blackberries blackberri + blackberry blackberri blacker blacker + blackest blackest blackfriars blackfriar + blackheath blackheath blackmere blackmer + blackness black blacks black + bladder bladder bladders bladder + blade blade bladed blade + blades blade blains blain + blam blam blame blame + blamed blame blameful blame + blameless blameless blames blame + blanc blanc blanca blanca + blanch blanch blank blank + blanket blanket blanks blank + blaspheme blasphem blaspheming blasphem + blasphemous blasphem blasphemy blasphemi + blast blast blasted blast + blasting blast blastments blastment + blasts blast blaz blaz + blaze blaze blazes blaze + blazing blaze blazon blazon + blazoned blazon blazoning blazon + bleach bleach bleaching bleach + bleak bleak blear blear + bleared blear bleat bleat + bleated bleat bleats bleat + bled bled bleed bleed + bleedest bleedest bleedeth bleedeth + bleeding bleed bleeds bleed + blemish blemish blemishes blemish + blench blench blenches blench + blend blend blended blend + blent blent bless bless + blessed bless blessedly blessedli + blessedness blessed blesses bless + blesseth blesseth blessing bless + blessings bless blest blest + blew blew blind blind + blinded blind blindfold blindfold + blinding blind blindly blindli + blindness blind blinds blind + blink blink blinking blink + bliss bliss blist blist + blister blister blisters blister + blithe blith blithild blithild + bloat bloat block block + blockish blockish blocks block + blois bloi blood blood + blooded blood bloodhound bloodhound + bloodied bloodi bloodier bloodier + bloodiest bloodiest bloodily bloodili + bloodless bloodless bloods blood + bloodshed bloodsh bloodshedding bloodshed + bloodstained bloodstain bloody bloodi + bloom bloom blooms bloom + blossom blossom blossoming blossom + blossoms blossom blot blot + blots blot blotted blot + blotting blot blount blount + blow blow blowed blow + blowers blower blowest blowest + blowing blow blown blown + blows blow blowse blows + blubb blubb blubber blubber + blubbering blubber blue blue + bluecaps bluecap bluest bluest + blunt blunt blunted blunt + blunter blunter bluntest bluntest + blunting blunt bluntly bluntli + bluntness blunt blunts blunt + blur blur blurr blurr + blurs blur blush blush + blushes blush blushest blushest + blushing blush blust blust + bluster bluster blusterer bluster + blusters bluster bo bo + boar boar board board + boarded board boarding board + boards board boarish boarish + boars boar boast boast + boasted boast boastful boast + boasting boast boasts boast + boat boat boats boat + boatswain boatswain bob bob + bobb bobb boblibindo boblibindo + bobtail bobtail bocchus bocchu + bode bode boded bode + bodements bodement bodes bode + bodg bodg bodied bodi + bodies bodi bodiless bodiless + bodily bodili boding bode + bodkin bodkin body bodi + bodykins bodykin bog bog + boggle boggl boggler boggler + bogs bog bohemia bohemia + bohemian bohemian bohun bohun + boil boil boiling boil + boils boil boist boist + boisterous boister boisterously boister + boitier boitier bold bold + bolden bolden bolder bolder + boldest boldest boldly boldli + boldness bold bolds bold + bolingbroke bolingbrok bolster bolster + bolt bolt bolted bolt + bolter bolter bolters bolter + bolting bolt bolts bolt + bombard bombard bombards bombard + bombast bombast bon bon + bona bona bond bond + bondage bondag bonded bond + bondmaid bondmaid bondman bondman + bondmen bondmen bonds bond + bondslave bondslav bone bone + boneless boneless bones bone + bonfire bonfir bonfires bonfir + bonjour bonjour bonne bonn + bonnet bonnet bonneted bonnet + bonny bonni bonos bono + bonto bonto bonville bonvil + bood bood book book + bookish bookish books book + boon boon boor boor + boorish boorish boors boor + boot boot booted boot + booties booti bootless bootless + boots boot booty booti + bor bor bora bora + borachio borachio bordeaux bordeaux + border border bordered border + borderers border borders border + bore bore boreas borea + bores bore boring bore + born born borne born + borough borough boroughs borough + borrow borrow borrowed borrow + borrower borrow borrowing borrow + borrows borrow bosko bosko + boskos bosko bosky boski + bosom bosom bosoms bosom + boson boson boss boss + bosworth bosworth botch botch + botcher botcher botches botch + botchy botchi both both + bots bot bottle bottl + bottled bottl bottles bottl + bottom bottom bottomless bottomless + bottoms bottom bouciqualt bouciqualt + bouge boug bough bough + boughs bough bought bought + bounce bounc bouncing bounc + bound bound bounded bound + bounden bounden boundeth boundeth + bounding bound boundless boundless + bounds bound bounteous bounteou + bounteously bounteous bounties bounti + bountiful bounti bountifully bountifulli + bounty bounti bourbier bourbier + bourbon bourbon bourchier bourchier + bourdeaux bourdeaux bourn bourn + bout bout bouts bout + bove bove bow bow + bowcase bowcas bowed bow + bowels bowel bower bower + bowing bow bowl bowl + bowler bowler bowling bowl + bowls bowl bows bow + bowsprit bowsprit bowstring bowstr + box box boxes box + boy boi boyet boyet + boyish boyish boys boi + brabant brabant brabantio brabantio + brabble brabbl brabbler brabbler + brac brac brace brace + bracelet bracelet bracelets bracelet + brach brach bracy braci + brag brag bragg bragg + braggardism braggard braggards braggard + braggart braggart braggarts braggart + bragged brag bragging brag + bragless bragless brags brag + braid braid braided braid + brain brain brained brain + brainford brainford brainish brainish + brainless brainless brains brain + brainsick brainsick brainsickly brainsickli + brake brake brakenbury brakenburi + brakes brake brambles brambl + bran bran branch branch + branches branch branchless branchless + brand brand branded brand + brandish brandish brandon brandon + brands brand bras bra + brass brass brassy brassi + brat brat brats brat + brav brav brave brave + braved brave bravely brave + braver braver bravery braveri + braves brave bravest bravest + braving brave brawl brawl + brawler brawler brawling brawl + brawls brawl brawn brawn + brawns brawn bray brai + braying brai braz braz + brazen brazen brazier brazier + breach breach breaches breach + bread bread breadth breadth + break break breaker breaker + breakfast breakfast breaking break + breaks break breast breast + breasted breast breasting breast + breastplate breastplat breasts breast + breath breath breathe breath + breathed breath breather breather + breathers breather breathes breath + breathest breathest breathing breath + breathless breathless breaths breath + brecknock brecknock bred bred + breech breech breeches breech + breeching breech breed breed + breeder breeder breeders breeder + breeding breed breeds breed + breese brees breeze breez + breff breff bretagne bretagn + brethen brethen bretheren bretheren + brethren brethren brevis brevi + brevity breviti brew brew + brewage brewag brewer brewer + brewers brewer brewing brew + brews brew briareus briareu + briars briar brib brib + bribe bribe briber briber + bribes bribe brick brick + bricklayer bricklay bricks brick + bridal bridal bride bride + bridegroom bridegroom bridegrooms bridegroom + brides bride bridge bridg + bridgenorth bridgenorth bridges bridg + bridget bridget bridle bridl + bridled bridl brief brief + briefer briefer briefest briefest + briefly briefli briefness brief + brier brier briers brier + brigandine brigandin bright bright + brighten brighten brightest brightest + brightly brightli brightness bright + brim brim brimful brim + brims brim brimstone brimston + brinded brind brine brine + bring bring bringer bringer + bringeth bringeth bringing bring + bringings bring brings bring + brinish brinish brink brink + brisk brisk brisky briski + bristle bristl bristled bristl + bristly bristli bristol bristol + bristow bristow britain britain + britaine britain britaines britain + british british briton briton + britons briton brittany brittani + brittle brittl broach broach + broached broach broad broad + broader broader broadsides broadsid + brocas broca brock brock + brogues brogu broil broil + broiling broil broils broil + broke broke broken broken + brokenly brokenli broker broker + brokers broker brokes broke + broking broke brooch brooch + brooches brooch brood brood + brooded brood brooding brood + brook brook brooks brook + broom broom broomstaff broomstaff + broth broth brothel brothel + brother brother brotherhood brotherhood + brotherhoods brotherhood brotherly brotherli + brothers brother broths broth + brought brought brow brow + brown brown browner browner + brownist brownist browny browni + brows brow browse brows + browsing brows bruis brui + bruise bruis bruised bruis + bruises bruis bruising bruis + bruit bruit bruited bruit + brundusium brundusium brunt brunt + brush brush brushes brush + brute brute brutish brutish + brutus brutu bubble bubbl + bubbles bubbl bubbling bubbl + bubukles bubukl buck buck + bucket bucket buckets bucket + bucking buck buckingham buckingham + buckle buckl buckled buckl + buckler buckler bucklers buckler + bucklersbury bucklersburi buckles buckl + buckram buckram bucks buck + bud bud budded bud + budding bud budge budg + budger budger budget budget + buds bud buff buff + buffet buffet buffeting buffet + buffets buffet bug bug + bugbear bugbear bugle bugl + bugs bug build build + builded build buildeth buildeth + building build buildings build + builds build built built + bulk bulk bulks bulk + bull bull bullcalf bullcalf + bullen bullen bullens bullen + bullet bullet bullets bullet + bullocks bullock bulls bull + bully bulli bulmer bulmer + bulwark bulwark bulwarks bulwark + bum bum bumbast bumbast + bump bump bumper bumper + bums bum bunch bunch + bunches bunch bundle bundl + bung bung bunghole bunghol + bungle bungl bunting bunt + buoy buoi bur bur + burbolt burbolt burd burd + burden burden burdened burden + burdening burden burdenous burden + burdens burden burgh burgh + burgher burgher burghers burgher + burglary burglari burgomasters burgomast + burgonet burgonet burgundy burgundi + burial burial buried buri + burier burier buriest buriest + burly burli burn burn + burned burn burnet burnet + burneth burneth burning burn + burnish burnish burns burn + burnt burnt burr burr + burrows burrow burs bur + burst burst bursting burst + bursts burst burthen burthen + burthens burthen burton burton + bury buri burying buri + bush bush bushels bushel + bushes bush bushy bushi + busied busi busily busili + busines busin business busi + businesses busi buskin buskin + busky buski buss buss + busses buss bussing buss + bustle bustl bustling bustl + busy busi but but + butcheed butche butcher butcher + butchered butcher butcheries butcheri + butcherly butcherli butchers butcher + butchery butcheri butler butler + butt butt butter butter + buttered butter butterflies butterfli + butterfly butterfli butterwoman butterwoman + buttery butteri buttock buttock + buttocks buttock button button + buttonhole buttonhol buttons button + buttress buttress buttry buttri + butts butt buxom buxom + buy bui buyer buyer + buying bui buys bui + buzz buzz buzzard buzzard + buzzards buzzard buzzers buzzer + buzzing buzz by by + bye bye byzantium byzantium + c c ca ca + cabbage cabbag cabileros cabilero + cabin cabin cabins cabin + cable cabl cables cabl + cackling cackl cacodemon cacodemon + caddis caddi caddisses caddiss + cade cade cadence cadenc + cadent cadent cades cade + cadmus cadmu caduceus caduceu + cadwal cadwal cadwallader cadwallad + caelius caeliu caelo caelo + caesar caesar caesarion caesarion + caesars caesar cage cage + caged cage cagion cagion + cain cain caithness caith + caitiff caitiff caitiffs caitiff + caius caiu cak cak + cake cake cakes cake + calaber calab calais calai + calamities calam calamity calam + calchas calcha calculate calcul + calen calen calendar calendar + calendars calendar calf calf + caliban caliban calibans caliban + calipolis calipoli cality caliti + caliver caliv call call + callat callat called call + callet callet calling call + calls call calm calm + calmest calmest calmly calmli + calmness calm calms calm + calpurnia calpurnia calumniate calumni + calumniating calumni calumnious calumni + calumny calumni calve calv + calved calv calves calv + calveskins calveskin calydon calydon + cam cam cambio cambio + cambria cambria cambric cambric + cambrics cambric cambridge cambridg + cambyses cambys came came + camel camel camelot camelot + camels camel camest camest + camillo camillo camlet camlet + camomile camomil camp camp + campeius campeiu camping camp + camps camp can can + canakin canakin canaries canari + canary canari cancel cancel + cancell cancel cancelled cancel + cancelling cancel cancels cancel + cancer cancer candidatus candidatu + candied candi candle candl + candles candl candlesticks candlestick + candy candi canidius canidiu + cank cank canker canker + cankerblossom cankerblossom cankers canker + cannibally cannib cannibals cannib + cannon cannon cannoneer cannon + cannons cannon cannot cannot + canon canon canoniz canoniz + canonize canon canonized canon + canons canon canopied canopi + canopies canopi canopy canopi + canst canst canstick canstick + canterbury canterburi cantle cantl + cantons canton canus canu + canvas canva canvass canvass + canzonet canzonet cap cap + capability capabl capable capabl + capacities capac capacity capac + caparison caparison capdv capdv + cape cape capel capel + capels capel caper caper + capers caper capet capet + caphis caphi capilet capilet + capitaine capitain capital capit + capite capit capitol capitol + capitulate capitul capocchia capocchia + capon capon capons capon + capp capp cappadocia cappadocia + capriccio capriccio capricious caprici + caps cap capt capt + captain captain captains captain + captainship captainship captious captiou + captivate captiv captivated captiv + captivates captiv captive captiv + captives captiv captivity captiv + captum captum capucius capuciu + capulet capulet capulets capulet + car car carack carack + caracks carack carat carat + caraways carawai carbonado carbonado + carbuncle carbuncl carbuncled carbuncl + carbuncles carbuncl carcanet carcanet + carcase carcas carcases carcas + carcass carcass carcasses carcass + card card cardecue cardecu + carded card carders carder + cardinal cardin cardinally cardin + cardinals cardin cardmaker cardmak + cards card carduus carduu + care care cared care + career career careers career + careful care carefully carefulli + careless careless carelessly carelessli + carelessness careless cares care + caret caret cargo cargo + carl carl carlisle carlisl + carlot carlot carman carman + carmen carmen carnal carnal + carnally carnal carnarvonshire carnarvonshir + carnation carnat carnations carnat + carol carol carous carou + carouse carous caroused carous + carouses carous carousing carous + carp carp carpenter carpent + carper carper carpet carpet + carpets carpet carping carp + carriage carriag carriages carriag + carried carri carrier carrier + carriers carrier carries carri + carrion carrion carrions carrion + carry carri carrying carri + cars car cart cart + carters carter carthage carthag + carts cart carv carv + carve carv carved carv + carver carver carves carv + carving carv cas ca + casa casa casaer casaer + casca casca case case + casement casement casements casement + cases case cash cash + cashier cashier casing case + cask cask casket casket + casketed casket caskets casket + casque casqu casques casqu + cassado cassado cassandra cassandra + cassibelan cassibelan cassio cassio + cassius cassiu cassocks cassock + cast cast castalion castalion + castaway castawai castaways castawai + casted cast caster caster + castigate castig castigation castig + castile castil castiliano castiliano + casting cast castle castl + castles castl casts cast + casual casual casually casual + casualties casualti casualty casualti + cat cat cataian cataian + catalogue catalogu cataplasm cataplasm + cataracts cataract catarrhs catarrh + catastrophe catastroph catch catch + catcher catcher catches catch + catching catch cate cate + catechising catechis catechism catech + catechize catech cater cater + caterpillars caterpillar caters cater + caterwauling caterwaul cates cate + catesby catesbi cathedral cathedr + catlike catlik catling catl + catlings catl cato cato + cats cat cattle cattl + caucasus caucasu caudle caudl + cauf cauf caught caught + cauldron cauldron caus cau + cause caus caused caus + causeless causeless causer causer + causes caus causest causest + causeth causeth cautel cautel + cautelous cautel cautels cautel + cauterizing cauter caution caution + cautions caution cavaleiro cavaleiro + cavalery cavaleri cavaliers cavali + cave cave cavern cavern + caverns cavern caves cave + caveto caveto caviary caviari + cavil cavil cavilling cavil + cawdor cawdor cawdron cawdron + cawing caw ce ce + ceas cea cease ceas + ceases ceas ceaseth ceaseth + cedar cedar cedars cedar + cedius cediu celebrate celebr + celebrated celebr celebrates celebr + celebration celebr celerity celer + celestial celesti celia celia + cell cell cellar cellar + cellarage cellarag celsa celsa + cement cement censer censer + censor censor censorinus censorinu + censur censur censure censur + censured censur censurers censur + censures censur censuring censur + centaur centaur centaurs centaur + centre centr cents cent + centuries centuri centurion centurion + centurions centurion century centuri + cerberus cerberu cerecloth cerecloth + cerements cerement ceremonial ceremoni + ceremonies ceremoni ceremonious ceremoni + ceremoniously ceremoni ceremony ceremoni + ceres cere cerns cern + certain certain certainer certain + certainly certainli certainties certainti + certainty certainti certes cert + certificate certif certified certifi + certifies certifi certify certifi + ces ce cesario cesario + cess cess cesse cess + cestern cestern cetera cetera + cette cett chaces chace + chaf chaf chafe chafe + chafed chafe chafes chafe + chaff chaff chaffless chaffless + chafing chafe chain chain + chains chain chair chair + chairs chair chalic chalic + chalice chalic chalices chalic + chalk chalk chalks chalk + chalky chalki challeng challeng + challenge challeng challenged challeng + challenger challeng challengers challeng + challenges challeng cham cham + chamber chamber chamberers chamber + chamberlain chamberlain chamberlains chamberlain + chambermaid chambermaid chambermaids chambermaid + chambers chamber chameleon chameleon + champ champ champagne champagn + champain champain champains champain + champion champion champions champion + chanc chanc chance chanc + chanced chanc chancellor chancellor + chances chanc chandler chandler + chang chang change chang + changeable changeabl changed chang + changeful chang changeling changel + changelings changel changer changer + changes chang changest changest + changing chang channel channel + channels channel chanson chanson + chant chant chanticleer chanticl + chanting chant chantries chantri + chantry chantri chants chant + chaos chao chap chap + chape chape chapel chapel + chapeless chapeless chapels chapel + chaplain chaplain chaplains chaplain + chapless chapless chaplet chaplet + chapmen chapmen chaps chap + chapter chapter character charact + charactered charact characterless characterless + characters charact charactery characteri + characts charact charbon charbon + chare chare chares chare + charg charg charge charg + charged charg chargeful charg + charges charg chargeth chargeth + charging charg chariest chariest + chariness chari charing chare + chariot chariot chariots chariot + charitable charit charitably charit + charities chariti charity chariti + charlemain charlemain charles charl + charm charm charmed charm + charmer charmer charmeth charmeth + charmian charmian charming charm + charmingly charmingli charms charm + charneco charneco charnel charnel + charolois charoloi charon charon + charter charter charters charter + chartreux chartreux chary chari + charybdis charybdi chas cha + chase chase chased chase + chaser chaser chaseth chaseth + chasing chase chaste chast + chastely chast chastis chasti + chastise chastis chastised chastis + chastisement chastis chastity chastiti + chat chat chatham chatham + chatillon chatillon chats chat + chatt chatt chattels chattel + chatter chatter chattering chatter + chattles chattl chaud chaud + chaunted chaunt chaw chaw + chawdron chawdron che che + cheap cheap cheapen cheapen + cheaper cheaper cheapest cheapest + cheaply cheapli cheapside cheapsid + cheat cheat cheated cheat + cheater cheater cheaters cheater + cheating cheat cheats cheat + check check checked check + checker checker checking check + checks check cheek cheek + cheeks cheek cheer cheer + cheered cheer cheerer cheerer + cheerful cheer cheerfully cheerfulli + cheering cheer cheerless cheerless + cheerly cheerli cheers cheer + cheese chees chequer chequer + cher cher cherish cherish + cherished cherish cherisher cherish + cherishes cherish cherishing cherish + cherries cherri cherry cherri + cherrypit cherrypit chertsey chertsei + cherub cherub cherubims cherubim + cherubin cherubin cherubins cherubin + cheshu cheshu chess chess + chest chest chester chester + chestnut chestnut chestnuts chestnut + chests chest chetas cheta + chev chev cheval cheval + chevalier chevali chevaliers chevali + cheveril cheveril chew chew + chewed chew chewet chewet + chewing chew chez chez + chi chi chick chick + chicken chicken chickens chicken + chicurmurco chicurmurco chid chid + chidden chidden chide chide + chiders chider chides chide + chiding chide chief chief + chiefest chiefest chiefly chiefli + chien chien child child + childed child childeric childer + childhood childhood childhoods childhood + childing child childish childish + childishness childish childlike childlik + childness child children children + chill chill chilling chill + chime chime chimes chime + chimney chimnei chimneypiece chimneypiec + chimneys chimnei chimurcho chimurcho + chin chin china china + chine chine chines chine + chink chink chinks chink + chins chin chipp chipp + chipper chipper chips chip + chiron chiron chirping chirp + chirrah chirrah chirurgeonly chirurgeonli + chisel chisel chitopher chitoph + chivalrous chivalr chivalry chivalri + choice choic choicely choic + choicest choicest choir choir + choirs choir chok chok + choke choke choked choke + chokes choke choking choke + choler choler choleric choler + cholers choler chollors chollor + choose choos chooser chooser + chooses choos chooseth chooseth + choosing choos chop chop + chopine chopin choplogic choplog + chopp chopp chopped chop + chopping chop choppy choppi + chops chop chopt chopt + chor chor choristers chorist + chorus choru chose chose + chosen chosen chough chough + choughs chough chrish chrish + christ christ christen christen + christendom christendom christendoms christendom + christening christen christenings christen + christian christian christianlike christianlik + christians christian christmas christma + christom christom christopher christoph + christophero christophero chronicle chronicl + chronicled chronicl chronicler chronicl + chroniclers chronicl chronicles chronicl + chrysolite chrysolit chuck chuck + chucks chuck chud chud + chuffs chuff church church + churches church churchman churchman + churchmen churchmen churchyard churchyard + churchyards churchyard churl churl + churlish churlish churlishly churlishli + churls churl churn churn + chus chu cicatrice cicatric + cicatrices cicatric cicely cice + cicero cicero ciceter cicet + ciel ciel ciitzens ciitzen + cilicia cilicia cimber cimber + cimmerian cimmerian cinable cinabl + cincture cinctur cinders cinder + cine cine cinna cinna + cinque cinqu cipher cipher + ciphers cipher circa circa + circe circ circle circl + circled circl circlets circlet + circling circl circuit circuit + circum circum circumcised circumcis + circumference circumfer circummur circummur + circumscrib circumscrib circumscribed circumscrib + circumscription circumscript circumspect circumspect + circumstance circumst circumstanced circumstanc + circumstances circumst circumstantial circumstanti + circumvent circumv circumvention circumvent + cistern cistern citadel citadel + cital cital cite cite + cited cite cites cite + cities citi citing cite + citizen citizen citizens citizen + cittern cittern city citi + civet civet civil civil + civility civil civilly civilli + clack clack clad clad + claim claim claiming claim + claims claim clamb clamb + clamber clamber clammer clammer + clamor clamor clamorous clamor + clamors clamor clamour clamour + clamours clamour clang clang + clangor clangor clap clap + clapp clapp clapped clap + clapper clapper clapping clap + claps clap clare clare + clarence clarenc claret claret + claribel claribel clasp clasp + clasps clasp clatter clatter + claud claud claudio claudio + claudius claudiu clause claus + claw claw clawed claw + clawing claw claws claw + clay clai clays clai + clean clean cleanliest cleanliest + cleanly cleanli cleans clean + cleanse cleans cleansing cleans + clear clear clearer clearer + clearest clearest clearly clearli + clearness clear clears clear + cleave cleav cleaving cleav + clef clef cleft cleft + cleitus cleitu clemency clemenc + clement clement cleomenes cleomen + cleopatpa cleopatpa cleopatra cleopatra + clepeth clepeth clept clept + clerestories clerestori clergy clergi + clergyman clergyman clergymen clergymen + clerk clerk clerkly clerkli + clerks clerk clew clew + client client clients client + cliff cliff clifford clifford + cliffords clifford cliffs cliff + clifton clifton climate climat + climature climatur climb climb + climbed climb climber climber + climbeth climbeth climbing climb + climbs climb clime clime + cling cling clink clink + clinking clink clinquant clinquant + clip clip clipp clipp + clipper clipper clippeth clippeth + clipping clip clipt clipt + clitus clitu clo clo + cloak cloak cloakbag cloakbag + cloaks cloak clock clock + clocks clock clod clod + cloddy cloddi clodpole clodpol + clog clog clogging clog + clogs clog cloister cloister + cloistress cloistress cloquence cloquenc + clos clo close close + closed close closely close + closeness close closer closer + closes close closest closest + closet closet closing close + closure closur cloten cloten + clotens cloten cloth cloth + clothair clothair clotharius clothariu + clothe cloth clothes cloth + clothier clothier clothiers clothier + clothing cloth cloths cloth + clotpoles clotpol clotpoll clotpol + cloud cloud clouded cloud + cloudiness cloudi clouds cloud + cloudy cloudi clout clout + clouted clout clouts clout + cloven cloven clover clover + cloves clove clovest clovest + clowder clowder clown clown + clownish clownish clowns clown + cloy cloi cloyed cloi + cloying cloi cloyless cloyless + cloyment cloyment cloys cloi + club club clubs club + cluck cluck clung clung + clust clust clusters cluster + clutch clutch clyster clyster + cneius cneiu cnemies cnemi + co co coach coach + coaches coach coachmakers coachmak + coact coact coactive coactiv + coagulate coagul coal coal + coals coal coarse coars + coarsely coars coast coast + coasting coast coasts coast + coat coat coated coat + coats coat cobble cobbl + cobbled cobbl cobbler cobbler + cobham cobham cobloaf cobloaf + cobweb cobweb cobwebs cobweb + cock cock cockatrice cockatric + cockatrices cockatric cockle cockl + cockled cockl cockney cocknei + cockpit cockpit cocks cock + cocksure cocksur coctus coctu + cocytus cocytu cod cod + codding cod codling codl + codpiece codpiec codpieces codpiec + cods cod coelestibus coelestibu + coesar coesar coeur coeur + coffer coffer coffers coffer + coffin coffin coffins coffin + cog cog cogging cog + cogitation cogit cogitations cogit + cognition cognit cognizance cogniz + cogscomb cogscomb cohabitants cohabit + coher coher cohere coher + coherence coher coherent coher + cohorts cohort coif coif + coign coign coil coil + coin coin coinage coinag + coiner coiner coining coin + coins coin col col + colbrand colbrand colchos colcho + cold cold colder colder + coldest coldest coldly coldli + coldness cold coldspur coldspur + colebrook colebrook colic colic + collar collar collars collar + collateral collater colleagued colleagu + collect collect collected collect + collection collect college colleg + colleges colleg collied colli + collier collier colliers collier + collop collop collusion collus + colme colm colmekill colmekil + coloquintida coloquintida color color + colors color colossus colossu + colour colour colourable colour + coloured colour colouring colour + colours colour colt colt + colted colt colts colt + columbine columbin columbines columbin + colville colvil com com + comagene comagen comart comart + comb comb combat combat + combatant combat combatants combat + combated combat combating combat + combin combin combinate combin + combination combin combine combin + combined combin combless combless + combustion combust come come + comedian comedian comedians comedian + comedy comedi comeliness comeli + comely come comer comer + comers comer comes come + comest comest comet comet + cometh cometh comets comet + comfect comfect comfit comfit + comfits comfit comfort comfort + comfortable comfort comforted comfort + comforter comfort comforting comfort + comfortless comfortless comforts comfort + comic comic comical comic + coming come comings come + cominius cominiu comma comma + command command commande command + commanded command commander command + commanders command commanding command + commandment command commandments command + commands command comme comm + commenc commenc commence commenc + commenced commenc commencement commenc + commences commenc commencing commenc + commend commend commendable commend + commendation commend commendations commend + commended commend commending commend + commends commend comment comment + commentaries commentari commenting comment + comments comment commerce commerc + commingled commingl commiseration commiser + commission commiss commissioners commission + commissions commiss commit commit + commits commit committ committ + committed commit committing commit + commix commix commixed commix + commixtion commixt commixture commixtur + commodious commodi commodities commod + commodity commod common common + commonalty commonalti commoner common + commoners common commonly commonli + commons common commonweal commonw + commonwealth commonwealth commotion commot + commotions commot commune commun + communicat communicat communicate commun + communication commun communities commun + community commun comonty comonti + compact compact companies compani + companion companion companions companion + companionship companionship company compani + compar compar comparative compar + compare compar compared compar + comparing compar comparison comparison + comparisons comparison compartner compartn + compass compass compasses compass + compassing compass compassion compass + compassionate compassion compeers compeer + compel compel compell compel + compelled compel compelling compel + compels compel compensation compens + competence compet competency compet + competent compet competitor competitor + competitors competitor compil compil + compile compil compiled compil + complain complain complainer complain + complainest complainest complaining complain + complainings complain complains complain + complaint complaint complaints complaint + complement complement complements complement + complete complet complexion complexion + complexioned complexion complexions complexion + complices complic complies compli + compliment compliment complimental compliment + compliments compliment complot complot + complots complot complotted complot + comply compli compos compo + compose compos composed compos + composition composit compost compost + composture compostur composure composur + compound compound compounded compound + compounds compound comprehend comprehend + comprehended comprehend comprehends comprehend + compremises compremis compris compri + comprising compris compromis compromi + compromise compromis compt compt + comptible comptibl comptrollers comptrol + compulsatory compulsatori compulsion compuls + compulsive compuls compunctious compuncti + computation comput comrade comrad + comrades comrad comutual comutu + con con concave concav + concavities concav conceal conceal + concealed conceal concealing conceal + concealment conceal concealments conceal + conceals conceal conceit conceit + conceited conceit conceitless conceitless + conceits conceit conceiv conceiv + conceive conceiv conceived conceiv + conceives conceiv conceiving conceiv + conception concept conceptions concept + conceptious concepti concern concern + concernancy concern concerneth concerneth + concerning concern concernings concern + concerns concern conclave conclav + conclud conclud conclude conclud + concluded conclud concludes conclud + concluding conclud conclusion conclus + conclusions conclus concolinel concolinel + concord concord concubine concubin + concupiscible concupisc concupy concupi + concur concur concurring concur + concurs concur condemn condemn + condemnation condemn condemned condemn + condemning condemn condemns condemn + condescend condescend condign condign + condition condit conditionally condition + conditions condit condole condol + condolement condol condoling condol + conduce conduc conduct conduct + conducted conduct conducting conduct + conductor conductor conduit conduit + conduits conduit conected conect + coney conei confection confect + confectionary confectionari confections confect + confederacy confederaci confederate confeder + confederates confeder confer confer + conference confer conferr conferr + conferring confer confess confess + confessed confess confesses confess + confesseth confesseth confessing confess + confession confess confessions confess + confessor confessor confidence confid + confident confid confidently confid + confin confin confine confin + confined confin confineless confineless + confiners confin confines confin + confining confin confirm confirm + confirmation confirm confirmations confirm + confirmed confirm confirmer confirm + confirmers confirm confirming confirm + confirmities confirm confirms confirm + confiscate confisc confiscated confisc + confiscation confisc confixed confix + conflict conflict conflicting conflict + conflicts conflict confluence confluenc + conflux conflux conform conform + conformable conform confound confound + confounded confound confounding confound + confounds confound confront confront + confronted confront confus confu + confused confus confusedly confusedli + confusion confus confusions confus + confutation confut confutes confut + congeal congeal congealed congeal + congealment congeal congee conge + conger conger congest congest + congied congi congratulate congratul + congreeing congre congreeted congreet + congregate congreg congregated congreg + congregation congreg congregations congreg + congruent congruent congruing congru + conies coni conjectural conjectur + conjecture conjectur conjectures conjectur + conjoin conjoin conjoined conjoin + conjoins conjoin conjointly conjointli + conjunct conjunct conjunction conjunct + conjunctive conjunct conjur conjur + conjuration conjur conjurations conjur + conjure conjur conjured conjur + conjurer conjur conjurers conjur + conjures conjur conjuring conjur + conjuro conjuro conn conn + connected connect connive conniv + conqu conqu conquer conquer + conquered conquer conquering conquer + conqueror conqueror conquerors conqueror + conquers conquer conquest conquest + conquests conquest conquring conqur + conrade conrad cons con + consanguineous consanguin consanguinity consanguin + conscienc conscienc conscience conscienc + consciences conscienc conscionable conscion + consecrate consecr consecrated consecr + consecrations consecr consent consent + consented consent consenting consent + consents consent consequence consequ + consequences consequ consequently consequ + conserve conserv conserved conserv + conserves conserv consider consid + considerance consider considerate consider + consideration consider considerations consider + considered consid considering consid + considerings consid considers consid + consign consign consigning consign + consist consist consisteth consisteth + consisting consist consistory consistori + consists consist consolate consol + consolation consol consonancy conson + consonant conson consort consort + consorted consort consortest consortest + conspectuities conspectu conspir conspir + conspiracy conspiraci conspirant conspir + conspirator conspir conspirators conspir + conspire conspir conspired conspir + conspirers conspir conspires conspir + conspiring conspir constable constabl + constables constabl constance constanc + constancies constanc constancy constanc + constant constant constantine constantin + constantinople constantinopl constantly constantli + constellation constel constitution constitut + constrain constrain constrained constrain + constraineth constraineth constrains constrain + constraint constraint constring constr + construction construct construe constru + consul consul consuls consul + consulship consulship consulships consulship + consult consult consulting consult + consults consult consum consum + consume consum consumed consum + consumes consum consuming consum + consummate consumm consummation consumm + consumption consumpt consumptions consumpt + contagion contagion contagious contagi + contain contain containing contain + contains contain contaminate contamin + contaminated contamin contemn contemn + contemned contemn contemning contemn + contemns contemn contemplate contempl + contemplation contempl contemplative contempl + contempt contempt contemptible contempt + contempts contempt contemptuous contemptu + contemptuously contemptu contend contend + contended contend contending contend + contendon contendon content content + contenta contenta contented content + contenteth contenteth contention content + contentious contenti contentless contentless + contento contento contents content + contest contest contestation contest + continence contin continency contin + continent contin continents contin + continu continu continual continu + continually continu continuance continu + continuantly continuantli continuate continu + continue continu continued continu + continuer continu continues continu + continuing continu contract contract + contracted contract contracting contract + contraction contract contradict contradict + contradicted contradict contradiction contradict + contradicts contradict contraries contrari + contrarieties contrarieti contrariety contrarieti + contrarious contrari contrariously contrari + contrary contrari contre contr + contribution contribut contributors contributor + contrite contrit contriv contriv + contrive contriv contrived contriv + contriver contriv contrives contriv + contriving contriv control control + controll control controller control + controlling control controlment control + controls control controversy controversi + contumelious contumeli contumeliously contumeli + contumely contum contusions contus + convenience conveni conveniences conveni + conveniency conveni convenient conveni + conveniently conveni convented convent + conventicles conventicl convents convent + convers conver conversant convers + conversation convers conversations convers + converse convers conversed convers + converses convers conversing convers + conversion convers convert convert + converted convert convertest convertest + converting convert convertite convertit + convertites convertit converts convert + convey convei conveyance convey + conveyances convey conveyers convey + conveying convei convict convict + convicted convict convince convinc + convinced convinc convinces convinc + convive conviv convocation convoc + convoy convoi convulsions convuls + cony coni cook cook + cookery cookeri cooks cook + cool cool cooled cool + cooling cool cools cool + coop coop coops coop + cop cop copatain copatain + cope cope cophetua cophetua + copied copi copies copi + copious copiou copper copper + copperspur copperspur coppice coppic + copulation copul copulatives copul + copy copi cor cor + coragio coragio coral coral + coram coram corambus corambu + coranto coranto corantos coranto + corbo corbo cord cord + corded cord cordelia cordelia + cordial cordial cordis cordi + cords cord core core + corin corin corinth corinth + corinthian corinthian coriolanus coriolanu + corioli corioli cork cork + corky corki cormorant cormor + corn corn cornelia cornelia + cornelius corneliu corner corner + corners corner cornerstone cornerston + cornets cornet cornish cornish + corns corn cornuto cornuto + cornwall cornwal corollary corollari + coronal coron coronation coron + coronet coronet coronets coronet + corporal corpor corporals corpor + corporate corpor corpse corps + corpulent corpul correct correct + corrected correct correcting correct + correction correct correctioner correction + corrects correct correspondence correspond + correspondent correspond corresponding correspond + corresponsive correspons corrigible corrig + corrival corriv corrivals corriv + corroborate corrobor corrosive corros + corrupt corrupt corrupted corrupt + corrupter corrupt corrupters corrupt + corruptible corrupt corruptibly corrupt + corrupting corrupt corruption corrupt + corruptly corruptli corrupts corrupt + corse cors corses cors + corslet corslet cosmo cosmo + cost cost costard costard + costermongers costermong costlier costlier + costly costli costs cost + cot cot cote cote + coted cote cotsall cotsal + cotsole cotsol cotswold cotswold + cottage cottag cottages cottag + cotus cotu couch couch + couched couch couching couch + couchings couch coude coud + cough cough coughing cough + could could couldst couldst + coulter coulter council council + councillor councillor councils council + counsel counsel counsell counsel + counsellor counsellor counsellors counsellor + counselor counselor counselors counselor + counsels counsel count count + counted count countenanc countenanc + countenance counten countenances counten + counter counter counterchange counterchang + countercheck countercheck counterfeit counterfeit + counterfeited counterfeit counterfeiting counterfeit + counterfeitly counterfeitli counterfeits counterfeit + countermand countermand countermands countermand + countermines countermin counterpart counterpart + counterpoints counterpoint counterpois counterpoi + counterpoise counterpois counters counter + countervail countervail countess countess + countesses countess counties counti + counting count countless countless + countries countri countrv countrv + country countri countryman countryman + countrymen countrymen counts count + county counti couper couper + couple coupl coupled coupl + couplement couplement couples coupl + couplet couplet couplets couplet + cour cour courage courag + courageous courag courageously courag + courages courag courier courier + couriers courier couronne couronn + cours cour course cours + coursed cours courser courser + coursers courser courses cours + coursing cours court court + courted court courteous courteou + courteously courteous courtesan courtesan + courtesies courtesi courtesy courtesi + courtezan courtezan courtezans courtezan + courtier courtier courtiers courtier + courtlike courtlik courtly courtli + courtney courtnei courts court + courtship courtship cousin cousin + cousins cousin couterfeit couterfeit + coutume coutum covenant coven + covenants coven covent covent + coventry coventri cover cover + covered cover covering cover + coverlet coverlet covers cover + covert covert covertly covertli + coverture covertur covet covet + coveted covet coveting covet + covetings covet covetous covet + covetously covet covetousness covet + covets covet cow cow + coward coward cowarded coward + cowardice cowardic cowardly cowardli + cowards coward cowardship cowardship + cowish cowish cowl cowl + cowslip cowslip cowslips cowslip + cox cox coxcomb coxcomb + coxcombs coxcomb coy coi + coystrill coystril coz coz + cozen cozen cozenage cozenag + cozened cozen cozener cozen + cozeners cozen cozening cozen + coziers cozier crab crab + crabbed crab crabs crab + crack crack cracked crack + cracker cracker crackers cracker + cracking crack cracks crack + cradle cradl cradled cradl + cradles cradl craft craft + crafted craft craftied crafti + craftier craftier craftily craftili + crafts craft craftsmen craftsmen + crafty crafti cram cram + cramm cramm cramp cramp + cramps cramp crams cram + cranking crank cranks crank + cranmer cranmer crannied cranni + crannies cranni cranny cranni + crants crant crare crare + crash crash crassus crassu + crav crav crave crave + craved crave craven craven + cravens craven craves crave + craveth craveth craving crave + crawl crawl crawling crawl + crawls crawl craz craz + crazed craze crazy crazi + creaking creak cream cream + create creat created creat + creates creat creating creat + creation creation creator creator + creature creatur creatures creatur + credence credenc credent credent + credible credibl credit credit + creditor creditor creditors creditor + credo credo credulity credul + credulous credul creed creed + creek creek creeks creek + creep creep creeping creep + creeps creep crept crept + crescent crescent crescive cresciv + cressets cresset cressid cressid + cressida cressida cressids cressid + cressy cressi crest crest + crested crest crestfall crestfal + crestless crestless crests crest + cretan cretan crete crete + crevice crevic crew crew + crews crew crib crib + cribb cribb cribs crib + cricket cricket crickets cricket + cried cri criedst criedst + crier crier cries cri + criest criest crieth crieth + crime crime crimeful crime + crimeless crimeless crimes crime + criminal crimin crimson crimson + cringe cring cripple crippl + crisp crisp crisped crisp + crispian crispian crispianus crispianu + crispin crispin critic critic + critical critic critics critic + croak croak croaking croak + croaks croak crocodile crocodil + cromer cromer cromwell cromwel + crone crone crook crook + crookback crookback crooked crook + crooking crook crop crop + cropp cropp crosby crosbi + cross cross crossed cross + crosses cross crossest crossest + crossing cross crossings cross + crossly crossli crossness cross + crost crost crotchets crotchet + crouch crouch crouching crouch + crow crow crowd crowd + crowded crowd crowding crowd + crowds crowd crowflowers crowflow + crowing crow crowkeeper crowkeep + crown crown crowned crown + crowner crowner crownet crownet + crownets crownet crowning crown + crowns crown crows crow + crudy crudi cruel cruel + cruell cruell crueller crueller + cruelly cruelli cruels cruel + cruelty cruelti crum crum + crumble crumbl crumbs crumb + crupper crupper crusadoes crusado + crush crush crushed crush + crushest crushest crushing crush + crust crust crusts crust + crusty crusti crutch crutch + crutches crutch cry cry + crying cry crystal crystal + crystalline crystallin crystals crystal + cub cub cubbert cubbert + cubiculo cubiculo cubit cubit + cubs cub cuckold cuckold + cuckoldly cuckoldli cuckolds cuckold + cuckoo cuckoo cucullus cucullu + cudgel cudgel cudgeled cudgel + cudgell cudgel cudgelling cudgel + cudgels cudgel cue cue + cues cue cuff cuff + cuffs cuff cuique cuiqu + cull cull culling cull + cullion cullion cullionly cullionli + cullions cullion culpable culpabl + culverin culverin cum cum + cumber cumber cumberland cumberland + cunning cun cunningly cunningli + cunnings cun cuore cuor + cup cup cupbearer cupbear + cupboarding cupboard cupid cupid + cupids cupid cuppele cuppel + cups cup cur cur + curan curan curate curat + curb curb curbed curb + curbing curb curbs curb + curd curd curdied curdi + curds curd cure cure + cured cure cureless cureless + curer curer cures cure + curfew curfew curing cure + curio curio curiosity curios + curious curiou curiously curious + curl curl curled curl + curling curl curls curl + currance curranc currants currant + current current currents current + currish currish curry curri + curs cur curse curs + cursed curs curses curs + cursies cursi cursing curs + cursorary cursorari curst curst + curster curster curstest curstest + curstness curst cursy cursi + curtail curtail curtain curtain + curtains curtain curtal curtal + curtis curti curtle curtl + curtsied curtsi curtsies curtsi + curtsy curtsi curvet curvet + curvets curvet cushes cush + cushion cushion cushions cushion + custalorum custalorum custard custard + custody custodi custom custom + customary customari customed custom + customer custom customers custom + customs custom custure custur + cut cut cutler cutler + cutpurse cutpurs cutpurses cutpurs + cuts cut cutter cutter + cutting cut cuttle cuttl + cxsar cxsar cyclops cyclop + cydnus cydnu cygnet cygnet + cygnets cygnet cym cym + cymbals cymbal cymbeline cymbelin + cyme cyme cynic cynic + cynthia cynthia cypress cypress + cypriot cypriot cyprus cypru + cyrus cyru cytherea cytherea + d d dabbled dabbl + dace dace dad dad + daedalus daedalu daemon daemon + daff daff daffed daf + daffest daffest daffodils daffodil + dagger dagger daggers dagger + dagonet dagonet daily daili + daintier daintier dainties dainti + daintiest daintiest daintily daintili + daintiness dainti daintry daintri + dainty dainti daisied daisi + daisies daisi daisy daisi + dale dale dalliance dallianc + dallied dalli dallies dalli + dally dalli dallying dalli + dalmatians dalmatian dam dam + damage damag damascus damascu + damask damask damasked damask + dame dame dames dame + damm damm damn damn + damnable damnabl damnably damnabl + damnation damnat damned damn + damns damn damoiselle damoisel + damon damon damosella damosella + damp damp dams dam + damsel damsel damsons damson + dan dan danc danc + dance danc dancer dancer + dances danc dancing danc + dandle dandl dandy dandi + dane dane dang dang + danger danger dangerous danger + dangerously danger dangers danger + dangling dangl daniel daniel + danish danish dank dank + dankish dankish danskers dansker + daphne daphn dappled dappl + dapples dappl dar dar + dardan dardan dardanian dardanian + dardanius dardaniu dare dare + dared dare dareful dare + dares dare darest darest + daring dare darius dariu + dark dark darken darken + darkening darken darkens darken + darker darker darkest darkest + darkling darkl darkly darkli + darkness dark darling darl + darlings darl darnel darnel + darraign darraign dart dart + darted dart darter darter + dartford dartford darting dart + darts dart dash dash + dashes dash dashing dash + dastard dastard dastards dastard + dat dat datchet datchet + date date dated date + dateless dateless dates date + daub daub daughter daughter + daughters daughter daunt daunt + daunted daunt dauntless dauntless + dauphin dauphin daventry daventri + davy davi daw daw + dawn dawn dawning dawn + daws daw day dai + daylight daylight days dai + dazzle dazzl dazzled dazzl + dazzling dazzl de de + dead dead deadly deadli + deaf deaf deafing deaf + deafness deaf deafs deaf + deal deal dealer dealer + dealers dealer dealest dealest + dealing deal dealings deal + deals deal dealt dealt + dean dean deanery deaneri + dear dear dearer dearer + dearest dearest dearly dearli + dearness dear dears dear + dearth dearth dearths dearth + death death deathbed deathb + deathful death deaths death + deathsman deathsman deathsmen deathsmen + debarred debar debase debas + debate debat debated debat + debatement debat debateth debateth + debating debat debauch debauch + debile debil debility debil + debitor debitor debonair debonair + deborah deborah debosh debosh + debt debt debted debt + debtor debtor debtors debtor + debts debt debuty debuti + decay decai decayed decai + decayer decay decaying decai + decays decai deceas decea + decease deceas deceased deceas + deceit deceit deceitful deceit + deceits deceit deceiv deceiv + deceivable deceiv deceive deceiv + deceived deceiv deceiver deceiv + deceivers deceiv deceives deceiv + deceivest deceivest deceiveth deceiveth + deceiving deceiv december decemb + decent decent deceptious decepti + decerns decern decide decid + decides decid decimation decim + decipher deciph deciphers deciph + decision decis decius deciu + deck deck decking deck + decks deck deckt deckt + declare declar declares declar + declension declens declensions declens + declin declin decline declin + declined declin declines declin + declining declin decoct decoct + decorum decorum decreas decrea + decrease decreas decreasing decreas + decree decre decreed decre + decrees decre decrepit decrepit + dedicate dedic dedicated dedic + dedicates dedic dedication dedic + deed deed deedless deedless + deeds deed deem deem + deemed deem deep deep + deeper deeper deepest deepest + deeply deepli deeps deep + deepvow deepvow deer deer + deesse deess defac defac + deface defac defaced defac + defacer defac defacers defac + defacing defac defam defam + default default defeat defeat + defeated defeat defeats defeat + defeatures defeatur defect defect + defective defect defects defect + defence defenc defences defenc + defend defend defendant defend + defended defend defender defend + defenders defend defending defend + defends defend defense defens + defensible defens defensive defens + defer defer deferr deferr + defiance defianc deficient defici + defied defi defies defi + defil defil defile defil + defiler defil defiles defil + defiling defil define defin + definement defin definite definit + definitive definit definitively definit + deflow deflow deflower deflow + deflowered deflow deform deform + deformed deform deformities deform + deformity deform deftly deftli + defunct defunct defunction defunct + defuse defus defy defi + defying defi degenerate degener + degraded degrad degree degre + degrees degre deified deifi + deifying deifi deign deign + deigned deign deiphobus deiphobu + deities deiti deity deiti + deja deja deject deject + dejected deject delabreth delabreth + delay delai delayed delai + delaying delai delays delai + delectable delect deliberate deliber + delicate delic delicates delic + delicious delici deliciousness delici + delight delight delighted delight + delightful delight delights delight + delinquents delinqu deliv deliv + deliver deliv deliverance deliver + delivered deliv delivering deliv + delivers deliv delivery deliveri + delphos delpho deluded delud + deluding delud deluge delug + delve delv delver delver + delves delv demand demand + demanded demand demanding demand + demands demand demean demean + demeanor demeanor demeanour demeanour + demerits demerit demesnes demesn + demetrius demetriu demi demi + demigod demigod demise demis + demoiselles demoisel demon demon + demonstrable demonstr demonstrate demonstr + demonstrated demonstr demonstrating demonstr + demonstration demonstr demonstrative demonstr + demure demur demurely demur + demuring demur den den + denay denai deni deni + denial denial denials denial + denied deni denier denier + denies deni deniest deniest + denis deni denmark denmark + dennis denni denny denni + denote denot denoted denot + denotement denot denounc denounc + denounce denounc denouncing denounc + dens den denunciation denunci + deny deni denying deni + deo deo depart depart + departed depart departest departest + departing depart departure departur + depeche depech depend depend + dependant depend dependants depend + depended depend dependence depend + dependences depend dependency depend + dependent depend dependents depend + depender depend depending depend + depends depend deplore deplor + deploring deplor depopulate depopul + depos depo depose depos + deposed depos deposing depos + depositaries depositari deprav deprav + depravation deprav deprave deprav + depraved deprav depraves deprav + depress depress depriv depriv + deprive depriv depth depth + depths depth deputation deput + depute deput deputed deput + deputies deputi deputing deput + deputy deputi deracinate deracin + derby derbi dercetas derceta + dere dere derides derid + derision deris deriv deriv + derivation deriv derivative deriv + derive deriv derived deriv + derives deriv derogate derog + derogately derog derogation derog + des de desartless desartless + descant descant descend descend + descended descend descending descend + descends descend descension descens + descent descent descents descent + describe describ described describ + describes describ descried descri + description descript descriptions descript + descry descri desdemon desdemon + desdemona desdemona desert desert + deserts desert deserv deserv + deserve deserv deserved deserv + deservedly deservedli deserver deserv + deservers deserv deserves deserv + deservest deservest deserving deserv + deservings deserv design design + designment design designments design + designs design desir desir + desire desir desired desir + desirers desir desires desir + desirest desirest desiring desir + desirous desir desist desist + desk desk desolate desol + desolation desol desp desp + despair despair despairing despair + despairs despair despatch despatch + desperate desper desperately desper + desperation desper despis despi + despise despis despised despis + despiser despis despiseth despiseth + despising despis despite despit + despiteful despit despoiled despoil + dest dest destin destin + destined destin destinies destini + destiny destini destitute destitut + destroy destroi destroyed destroi + destroyer destroy destroyers destroy + destroying destroi destroys destroi + destruction destruct destructions destruct + det det detain detain + detains detain detect detect + detected detect detecting detect + detection detect detector detector + detects detect detention detent + determin determin determinate determin + determination determin determinations determin + determine determin determined determin + determines determin detest detest + detestable detest detested detest + detesting detest detests detest + detract detract detraction detract + detractions detract deucalion deucalion + deuce deuc deum deum + deux deux devant devant + devesting devest device devic + devices devic devil devil + devilish devilish devils devil + devis devi devise devis + devised devis devises devis + devising devis devoid devoid + devonshire devonshir devote devot + devoted devot devotion devot + devour devour devoured devour + devourers devour devouring devour + devours devour devout devout + devoutly devoutli dew dew + dewberries dewberri dewdrops dewdrop + dewlap dewlap dewlapp dewlapp + dews dew dewy dewi + dexter dexter dexteriously dexteri + dexterity dexter di di + diable diabl diablo diablo + diadem diadem dial dial + dialect dialect dialogue dialogu + dialogued dialogu dials dial + diameter diamet diamond diamond + diamonds diamond dian dian + diana diana diaper diaper + dibble dibbl dic dic + dice dice dicers dicer + dich dich dick dick + dickens dicken dickon dickon + dicky dicki dictator dictat + diction diction dictynna dictynna + did did diddle diddl + didest didest dido dido + didst didst die die + died di diedst diedst + dies di diest diest + diet diet dieted diet + dieter dieter dieu dieu + diff diff differ differ + difference differ differences differ + differency differ different differ + differing differ differs differ + difficile difficil difficult difficult + difficulties difficulti difficulty difficulti + diffidence diffid diffidences diffid + diffus diffu diffused diffus + diffusest diffusest dig dig + digest digest digested digest + digestion digest digestions digest + digg digg digging dig + dighton dighton dignified dignifi + dignifies dignifi dignify dignifi + dignities digniti dignity digniti + digress digress digressing digress + digression digress digs dig + digt digt dilate dilat + dilated dilat dilations dilat + dilatory dilatori dild dild + dildos dildo dilemma dilemma + dilemmas dilemma diligence dilig + diligent dilig diluculo diluculo + dim dim dimension dimens + dimensions dimens diminish diminish + diminishing diminish diminution diminut + diminutive diminut diminutives diminut + dimm dimm dimmed dim + dimming dim dimpled dimpl + dimples dimpl dims dim + din din dine dine + dined dine diner diner + dines dine ding ding + dining dine dinner dinner + dinners dinner dinnertime dinnertim + dint dint diomed diom + diomede diomed diomedes diomed + dion dion dip dip + dipp dipp dipping dip + dips dip dir dir + dire dire direct direct + directed direct directing direct + direction direct directions direct + directitude directitud directive direct + directly directli directs direct + direful dire direness dire + direst direst dirge dirg + dirges dirg dirt dirt + dirty dirti dis di + disability disabl disable disabl + disabled disabl disabling disabl + disadvantage disadvantag disagree disagre + disallow disallow disanimates disanim + disannul disannul disannuls disannul + disappointed disappoint disarm disarm + disarmed disarm disarmeth disarmeth + disarms disarm disaster disast + disasters disast disastrous disastr + disbench disbench disbranch disbranch + disburdened disburden disburs disbur + disburse disburs disbursed disburs + discandy discandi discandying discandi + discard discard discarded discard + discase discas discased discas + discern discern discerner discern + discerning discern discernings discern + discerns discern discharg discharg + discharge discharg discharged discharg + discharging discharg discipled discipl + disciples discipl disciplin disciplin + discipline disciplin disciplined disciplin + disciplines disciplin disclaim disclaim + disclaiming disclaim disclaims disclaim + disclos disclo disclose disclos + disclosed disclos discloses disclos + discolour discolour discoloured discolour + discolours discolour discomfit discomfit + discomfited discomfit discomfiture discomfitur + discomfort discomfort discomfortable discomfort + discommend discommend disconsolate disconsol + discontent discont discontented discont + discontentedly discontentedli discontenting discont + discontents discont discontinue discontinu + discontinued discontinu discord discord + discordant discord discords discord + discourse discours discoursed discours + discourser discours discourses discours + discoursive discours discourtesy discourtesi + discov discov discover discov + discovered discov discoverers discover + discoveries discoveri discovering discov + discovers discov discovery discoveri + discredit discredit discredited discredit + discredits discredit discreet discreet + discreetly discreetli discretion discret + discretions discret discuss discuss + disdain disdain disdained disdain + disdaineth disdaineth disdainful disdain + disdainfully disdainfulli disdaining disdain + disdains disdain disdnguish disdnguish + diseas disea disease diseas + diseased diseas diseases diseas + disedg disedg disembark disembark + disfigure disfigur disfigured disfigur + disfurnish disfurnish disgorge disgorg + disgrac disgrac disgrace disgrac + disgraced disgrac disgraceful disgrac + disgraces disgrac disgracing disgrac + disgracious disgraci disguis disgui + disguise disguis disguised disguis + disguiser disguis disguises disguis + disguising disguis dish dish + dishabited dishabit dishclout dishclout + dishearten dishearten disheartens dishearten + dishes dish dishonest dishonest + dishonestly dishonestli dishonesty dishonesti + dishonor dishonor dishonorable dishonor + dishonors dishonor dishonour dishonour + dishonourable dishonour dishonoured dishonour + dishonours dishonour disinherit disinherit + disinherited disinherit disjoin disjoin + disjoining disjoin disjoins disjoin + disjoint disjoint disjunction disjunct + dislik dislik dislike dislik + disliken disliken dislikes dislik + dislimns dislimn dislocate disloc + dislodg dislodg disloyal disloy + disloyalty disloyalti dismal dismal + dismantle dismantl dismantled dismantl + dismask dismask dismay dismai + dismayed dismai dismemb dismemb + dismember dismemb dismes dism + dismiss dismiss dismissed dismiss + dismissing dismiss dismission dismiss + dismount dismount dismounted dismount + disnatur disnatur disobedience disobedi + disobedient disobedi disobey disobei + disobeys disobei disorb disorb + disorder disord disordered disord + disorderly disorderli disorders disord + disparage disparag disparagement disparag + disparagements disparag dispark dispark + dispatch dispatch dispensation dispens + dispense dispens dispenses dispens + dispers disper disperse dispers + dispersed dispers dispersedly dispersedli + dispersing dispers dispiteous dispit + displac displac displace displac + displaced displac displant displant + displanting displant display displai + displayed displai displeas displea + displease displeas displeased displeas + displeasing displeas displeasure displeasur + displeasures displeasur disponge dispong + disport disport disports disport + dispos dispo dispose dispos + disposed dispos disposer dispos + disposing dispos disposition disposit + dispositions disposit dispossess dispossess + dispossessing dispossess disprais disprai + dispraise disprais dispraising disprais + dispraisingly dispraisingli dispropertied disproperti + disproportion disproport disproportioned disproport + disprov disprov disprove disprov + disproved disprov dispursed dispurs + disputable disput disputation disput + disputations disput dispute disput + disputed disput disputes disput + disputing disput disquantity disquant + disquiet disquiet disquietly disquietli + disrelish disrelish disrobe disrob + disseat disseat dissemble dissembl + dissembled dissembl dissembler dissembl + dissemblers dissembl dissembling dissembl + dissembly dissembl dissension dissens + dissensions dissens dissentious dissenti + dissever dissev dissipation dissip + dissolute dissolut dissolutely dissolut + dissolution dissolut dissolutions dissolut + dissolv dissolv dissolve dissolv + dissolved dissolv dissolves dissolv + dissuade dissuad dissuaded dissuad + distaff distaff distaffs distaff + distain distain distains distain + distance distanc distant distant + distaste distast distasted distast + distasteful distast distemp distemp + distemper distemp distemperature distemperatur + distemperatures distemperatur distempered distemp + distempering distemp distil distil + distill distil distillation distil + distilled distil distills distil + distilment distil distinct distinct + distinction distinct distinctly distinctli + distingue distingu distinguish distinguish + distinguishes distinguish distinguishment distinguish + distract distract distracted distract + distractedly distractedli distraction distract + distractions distract distracts distract + distrain distrain distraught distraught + distress distress distressed distress + distresses distress distressful distress + distribute distribut distributed distribut + distribution distribut distrust distrust + distrustful distrust disturb disturb + disturbed disturb disturbers disturb + disturbing disturb disunite disunit + disvalued disvalu disvouch disvouch + dit dit ditch ditch + ditchers ditcher ditches ditch + dites dite ditties ditti + ditty ditti diurnal diurnal + div div dive dive + diver diver divers diver + diversely divers diversity divers + divert divert diverted divert + diverts divert dives dive + divest divest dividable divid + dividant divid divide divid + divided divid divides divid + divideth divideth divin divin + divination divin divine divin + divinely divin divineness divin + diviner divin divines divin + divinest divinest divining divin + divinity divin division divis + divisions divis divorc divorc + divorce divorc divorced divorc + divorcement divorc divorcing divorc + divulg divulg divulge divulg + divulged divulg divulging divulg + dizy dizi dizzy dizzi + do do doating doat + dobbin dobbin dock dock + docks dock doct doct + doctor doctor doctors doctor + doctrine doctrin document document + dodge dodg doe doe + doer doer doers doer + does doe doest doest + doff doff dog dog + dogberry dogberri dogfish dogfish + dogg dogg dogged dog + dogs dog doigts doigt + doing do doings do + doit doit doits doit + dolabella dolabella dole dole + doleful dole doll doll + dollar dollar dollars dollar + dolor dolor dolorous dolor + dolour dolour dolours dolour + dolphin dolphin dolt dolt + dolts dolt domestic domest + domestics domest dominance domin + dominations domin dominator domin + domine domin domineer domin + domineering domin dominical domin + dominion dominion dominions dominion + domitius domitiu dommelton dommelton + don don donalbain donalbain + donation donat donc donc + doncaster doncast done done + dong dong donn donn + donne donn donner donner + donnerai donnerai doom doom + doomsday doomsdai door door + doorkeeper doorkeep doors door + dorcas dorca doreus doreu + doricles doricl dormouse dormous + dorothy dorothi dorset dorset + dorsetshire dorsetshir dost dost + dotage dotag dotant dotant + dotard dotard dotards dotard + dote dote doted dote + doters doter dotes dote + doteth doteth doth doth + doting dote double doubl + doubled doubl doubleness doubl + doubler doubler doublet doublet + doublets doublet doubling doubl + doubly doubli doubt doubt + doubted doubt doubtful doubt + doubtfully doubtfulli doubting doubt + doubtless doubtless doubts doubt + doug doug dough dough + doughty doughti doughy doughi + douglas dougla dout dout + doute dout douts dout + dove dove dovehouse dovehous + dover dover doves dove + dow dow dowager dowag + dowdy dowdi dower dower + dowerless dowerless dowers dower + dowlas dowla dowle dowl + down down downfall downfal + downright downright downs down + downstairs downstair downtrod downtrod + downward downward downwards downward + downy downi dowries dowri + dowry dowri dowsabel dowsabel + doxy doxi dozed doze + dozen dozen dozens dozen + dozy dozi drab drab + drabbing drab drabs drab + drachma drachma drachmas drachma + draff draff drag drag + dragg dragg dragged drag + dragging drag dragon dragon + dragonish dragonish dragons dragon + drain drain drained drain + drains drain drake drake + dram dram dramatis dramati + drank drank draught draught + draughts draught drave drave + draw draw drawbridge drawbridg + drawer drawer drawers drawer + draweth draweth drawing draw + drawling drawl drawn drawn + draws draw drayman drayman + draymen draymen dread dread + dreaded dread dreadful dread + dreadfully dreadfulli dreading dread + dreads dread dream dream + dreamer dreamer dreamers dreamer + dreaming dream dreams dream + dreamt dreamt drearning drearn + dreary dreari dreg dreg + dregs dreg drench drench + drenched drench dress dress + dressed dress dresser dresser + dressing dress dressings dress + drest drest drew drew + dribbling dribbl dried dri + drier drier dries dri + drift drift drily drili + drink drink drinketh drinketh + drinking drink drinkings drink + drinks drink driv driv + drive drive drivelling drivel + driven driven drives drive + driveth driveth driving drive + drizzle drizzl drizzled drizzl + drizzles drizzl droit droit + drollery drolleri dromio dromio + dromios dromio drone drone + drones drone droop droop + droopeth droopeth drooping droop + droops droop drop drop + dropheir dropheir droplets droplet + dropp dropp dropper dropper + droppeth droppeth dropping drop + droppings drop drops drop + dropsied dropsi dropsies dropsi + dropsy dropsi dropt dropt + dross dross drossy drossi + drought drought drove drove + droven droven drovier drovier + drown drown drowned drown + drowning drown drowns drown + drows drow drowse drows + drowsily drowsili drowsiness drowsi + drowsy drowsi drudge drudg + drudgery drudgeri drudges drudg + drug drug drugg drugg + drugs drug drum drum + drumble drumbl drummer drummer + drumming drum drums drum + drunk drunk drunkard drunkard + drunkards drunkard drunken drunken + drunkenly drunkenli drunkenness drunken + dry dry dryness dryness + dst dst du du + dub dub dubb dubb + ducat ducat ducats ducat + ducdame ducdam duchess duchess + duchies duchi duchy duchi + duck duck ducking duck + ducks duck dudgeon dudgeon + due due duellist duellist + duello duello duer duer + dues due duff duff + dug dug dugs dug + duke duke dukedom dukedom + dukedoms dukedom dukes duke + dulcet dulcet dulche dulch + dull dull dullard dullard + duller duller dullest dullest + dulling dull dullness dull + dulls dull dully dulli + dulness dul duly duli + dumain dumain dumb dumb + dumbe dumb dumbly dumbl + dumbness dumb dump dump + dumps dump dun dun + duncan duncan dung dung + dungeon dungeon dungeons dungeon + dunghill dunghil dunghills dunghil + dungy dungi dunnest dunnest + dunsinane dunsinan dunsmore dunsmor + dunstable dunstabl dupp dupp + durance duranc during dure + durst durst dusky duski + dust dust dusted dust + dusty dusti dutch dutch + dutchman dutchman duteous duteou + duties duti dutiful duti + duty duti dwarf dwarf + dwarfish dwarfish dwell dwell + dwellers dweller dwelling dwell + dwells dwell dwelt dwelt + dwindle dwindl dy dy + dye dye dyed dy + dyer dyer dying dy + e e each each + eager eager eagerly eagerli + eagerness eager eagle eagl + eagles eagl eaning ean + eanlings eanl ear ear + earing ear earl earl + earldom earldom earlier earlier + earliest earliest earliness earli + earls earl early earli + earn earn earned earn + earnest earnest earnestly earnestli + earnestness earnest earns earn + ears ear earth earth + earthen earthen earthlier earthlier + earthly earthli earthquake earthquak + earthquakes earthquak earthy earthi + eas ea ease eas + eased eas easeful eas + eases eas easier easier + easiest easiest easiliest easiliest + easily easili easiness easi + easing eas east east + eastcheap eastcheap easter easter + eastern eastern eastward eastward + easy easi eat eat + eaten eaten eater eater + eaters eater eating eat + eats eat eaux eaux + eaves eav ebb ebb + ebbing eb ebbs ebb + ebon ebon ebony eboni + ebrew ebrew ecce ecc + echapper echapp echo echo + echoes echo eclips eclip + eclipse eclips eclipses eclips + ecolier ecoli ecoutez ecoutez + ecstacy ecstaci ecstasies ecstasi + ecstasy ecstasi ecus ecu + eden eden edg edg + edgar edgar edge edg + edged edg edgeless edgeless + edges edg edict edict + edicts edict edifice edific + edifices edific edified edifi + edifies edifi edition edit + edm edm edmund edmund + edmunds edmund edmundsbury edmundsburi + educate educ educated educ + education educ edward edward + eel eel eels eel + effect effect effected effect + effectless effectless effects effect + effectual effectu effectually effectu + effeminate effemin effigies effigi + effus effu effuse effus + effusion effus eftest eftest + egal egal egally egal + eget eget egeus egeu + egg egg eggs egg + eggshell eggshel eglamour eglamour + eglantine eglantin egma egma + ego ego egregious egregi + egregiously egregi egress egress + egypt egypt egyptian egyptian + egyptians egyptian eie eie + eight eight eighteen eighteen + eighth eighth eightpenny eightpenni + eighty eighti eisel eisel + either either eject eject + eke ek el el + elbe elb elbow elbow + elbows elbow eld eld + elder elder elders elder + eldest eldest eleanor eleanor + elect elect elected elect + election elect elegancy eleg + elegies elegi element element + elements element elephant eleph + elephants eleph elevated elev + eleven eleven eleventh eleventh + elf elf elflocks elflock + eliads eliad elinor elinor + elizabeth elizabeth ell ell + elle ell ellen ellen + elm elm eloquence eloqu + eloquent eloqu else els + elsewhere elsewher elsinore elsinor + eltham eltham elves elv + elvish elvish ely eli + elysium elysium em em + emballing embal embalm embalm + embalms embalm embark embark + embarked embark embarquements embarqu + embassade embassad embassage embassag + embassies embassi embassy embassi + embattailed embattail embattl embattl + embattle embattl embay embai + embellished embellish embers ember + emblaze emblaz emblem emblem + emblems emblem embodied embodi + embold embold emboldens embolden + emboss emboss embossed emboss + embounded embound embowel embowel + embowell embowel embrac embrac + embrace embrac embraced embrac + embracement embrac embracements embrac + embraces embrac embracing embrac + embrasures embrasur embroider embroid + embroidery embroideri emhracing emhrac + emilia emilia eminence emin + eminent emin eminently emin + emmanuel emmanuel emnity emniti + empale empal emperal emper + emperess emperess emperial emperi + emperor emperor empery emperi + emphasis emphasi empire empir + empirics empir empiricutic empiricut + empleached empleach employ emploi + employed emploi employer employ + employment employ employments employ + empoison empoison empress empress + emptied empti emptier emptier + empties empti emptiness empti + empty empti emptying empti + emulate emul emulation emul + emulations emul emulator emul + emulous emul en en + enact enact enacted enact + enacts enact enactures enactur + enamell enamel enamelled enamel + enamour enamour enamoured enamour + enanmour enanmour encamp encamp + encamped encamp encave encav + enceladus enceladu enchaf enchaf + enchafed enchaf enchant enchant + enchanted enchant enchanting enchant + enchantingly enchantingli enchantment enchant + enchantress enchantress enchants enchant + enchas encha encircle encircl + encircled encircl enclos enclo + enclose enclos enclosed enclos + encloses enclos encloseth encloseth + enclosing enclos enclouded encloud + encompass encompass encompassed encompass + encompasseth encompasseth encompassment encompass + encore encor encorporal encorpor + encount encount encounter encount + encountered encount encounters encount + encourage encourag encouraged encourag + encouragement encourag encrimsoned encrimson + encroaching encroach encumb encumb + end end endamage endamag + endamagement endamag endanger endang + endart endart endear endear + endeared endear endeavour endeavour + endeavours endeavour ended end + ender ender ending end + endings end endite endit + endless endless endow endow + endowed endow endowments endow + endows endow ends end + endu endu endue endu + endur endur endurance endur + endure endur endured endur + endures endur enduring endur + endymion endymion eneas enea + enemies enemi enemy enemi + enernies enerni enew enew + enfeebled enfeebl enfeebles enfeebl + enfeoff enfeoff enfetter enfett + enfoldings enfold enforc enforc + enforce enforc enforced enforc + enforcedly enforcedli enforcement enforc + enforces enforc enforcest enforcest + enfranched enfranch enfranchis enfranchi + enfranchise enfranchis enfranchised enfranchis + enfranchisement enfranchis enfreed enfre + enfreedoming enfreedom engag engag + engage engag engaged engag + engagements engag engaging engag + engaol engaol engend engend + engender engend engenders engend + engilds engild engine engin + engineer engin enginer engin + engines engin engirt engirt + england england english english + englishman englishman englishmen englishmen + engluts englut englutted englut + engraffed engraf engraft engraft + engrafted engraft engrav engrav + engrave engrav engross engross + engrossed engross engrossest engrossest + engrossing engross engrossments engross + enguard enguard enigma enigma + enigmatical enigmat enjoin enjoin + enjoined enjoin enjoy enjoi + enjoyed enjoi enjoyer enjoy + enjoying enjoi enjoys enjoi + enkindle enkindl enkindled enkindl + enlard enlard enlarg enlarg + enlarge enlarg enlarged enlarg + enlargement enlarg enlargeth enlargeth + enlighten enlighten enlink enlink + enmesh enmesh enmities enmiti + enmity enmiti ennoble ennobl + ennobled ennobl enobarb enobarb + enobarbus enobarbu enon enon + enormity enorm enormous enorm + enough enough enow enow + enpatron enpatron enpierced enpierc + enquir enquir enquire enquir + enquired enquir enrag enrag + enrage enrag enraged enrag + enrages enrag enrank enrank + enrapt enrapt enrich enrich + enriched enrich enriches enrich + enridged enridg enrings enr + enrob enrob enrobe enrob + enroll enrol enrolled enrol + enrooted enroot enrounded enround + enschedul enschedul ensconce ensconc + ensconcing ensconc enseamed enseam + ensear ensear enseigne enseign + enseignez enseignez ensemble ensembl + enshelter enshelt enshielded enshield + enshrines enshrin ensign ensign + ensigns ensign enskied enski + ensman ensman ensnare ensnar + ensnared ensnar ensnareth ensnareth + ensteep ensteep ensu ensu + ensue ensu ensued ensu + ensues ensu ensuing ensu + enswathed enswath ent ent + entail entail entame entam + entangled entangl entangles entangl + entendre entendr enter enter + entered enter entering enter + enterprise enterpris enterprises enterpris + enters enter entertain entertain + entertained entertain entertainer entertain + entertaining entertain entertainment entertain + entertainments entertain enthrall enthral + enthralled enthral enthron enthron + enthroned enthron entice entic + enticements entic enticing entic + entire entir entirely entir + entitle entitl entitled entitl + entitling entitl entomb entomb + entombed entomb entrails entrail + entrance entranc entrances entranc + entrap entrap entrapp entrapp + entre entr entreat entreat + entreated entreat entreaties entreati + entreating entreat entreatments entreat + entreats entreat entreaty entreati + entrench entrench entry entri + entwist entwist envelop envelop + envenom envenom envenomed envenom + envenoms envenom envied envi + envies envi envious enviou + enviously envious environ environ + environed environ envoy envoi + envy envi envying envi + enwheel enwheel enwombed enwomb + enwraps enwrap ephesian ephesian + ephesians ephesian ephesus ephesu + epicure epicur epicurean epicurean + epicures epicur epicurism epicur + epicurus epicuru epidamnum epidamnum + epidaurus epidauru epigram epigram + epilepsy epilepsi epileptic epilept + epilogue epilogu epilogues epilogu + epistles epistl epistrophus epistrophu + epitaph epitaph epitaphs epitaph + epithet epithet epitheton epitheton + epithets epithet epitome epitom + equal equal equalities equal + equality equal equall equal + equally equal equalness equal + equals equal equinoctial equinocti + equinox equinox equipage equipag + equity equiti equivocal equivoc + equivocate equivoc equivocates equivoc + equivocation equivoc equivocator equivoc + er er erbear erbear + erbearing erbear erbears erbear + erbeat erbeat erblows erblow + erboard erboard erborne erborn + ercame ercam ercast ercast + ercharg ercharg ercharged ercharg + ercharging ercharg ercles ercl + ercome ercom ercover ercov + ercrows ercrow erdoing erdo + ere er erebus erebu + erect erect erected erect + erecting erect erection erect + erects erect erewhile erewhil + erflourish erflourish erflow erflow + erflowing erflow erflows erflow + erfraught erfraught erga erga + ergalled ergal erglanced erglanc + ergo ergo ergone ergon + ergrow ergrow ergrown ergrown + ergrowth ergrowth erhang erhang + erhanging erhang erhasty erhasti + erhear erhear erheard erheard + eringoes eringo erjoy erjoi + erleap erleap erleaps erleap + erleavens erleaven erlook erlook + erlooking erlook ermaster ermast + ermengare ermengar ermount ermount + ern ern ernight ernight + eros ero erpaid erpaid + erparted erpart erpast erpast + erpays erpai erpeer erpeer + erperch erperch erpicturing erpictur + erpingham erpingham erposting erpost + erpow erpow erpress erpress + erpressed erpress err err + errand errand errands errand + errant errant errate errat + erraught erraught erreaches erreach + erred er errest errest + erring er erroneous erron + error error errors error + errs err errule errul + errun errun erset erset + ershade ershad ershades ershad + ershine ershin ershot ershot + ersized ersiz erskip erskip + erslips erslip erspreads erspread + erst erst erstare erstar + erstep erstep erstunk erstunk + ersway erswai ersways erswai + erswell erswel erta erta + ertake ertak erteemed erteem + erthrow erthrow erthrown erthrown + erthrows erthrow ertook ertook + ertop ertop ertopping ertop + ertrip ertrip erturn erturn + erudition erudit eruption erupt + eruptions erupt ervalues ervalu + erwalk erwalk erwatch erwatch + erween erween erweens erween + erweigh erweigh erweighs erweigh + erwhelm erwhelm erwhelmed erwhelm + erworn erworn es es + escalus escalu escap escap + escape escap escaped escap + escapes escap eschew eschew + escoted escot esill esil + especial especi especially especi + esperance esper espials espial + espied espi espies espi + espous espou espouse espous + espy espi esquire esquir + esquires esquir essay essai + essays essai essence essenc + essential essenti essentially essenti + esses ess essex essex + est est establish establish + established establish estate estat + estates estat esteem esteem + esteemed esteem esteemeth esteemeth + esteeming esteem esteems esteem + estimable estim estimate estim + estimation estim estimations estim + estime estim estranged estrang + estridge estridg estridges estridg + et et etc etc + etceteras etcetera ete et + eternal etern eternally etern + eterne etern eternity etern + eterniz eterniz etes et + ethiop ethiop ethiope ethiop + ethiopes ethiop ethiopian ethiopian + etna etna eton eton + etre etr eunuch eunuch + eunuchs eunuch euphrates euphrat + euphronius euphroniu euriphile euriphil + europa europa europe europ + ev ev evade evad + evades evad evans evan + evasion evas evasions evas + eve ev even even + evening even evenly evenli + event event eventful event + events event ever ever + everlasting everlast everlastingly everlastingli + evermore evermor every everi + everyone everyon everything everyth + everywhere everywher evidence evid + evidences evid evident evid + evil evil evilly evilli + evils evil evitate evit + ewe ew ewer ewer + ewers ewer ewes ew + exact exact exacted exact + exactest exactest exacting exact + exaction exact exactions exact + exactly exactli exacts exact + exalt exalt exalted exalt + examin examin examination examin + examinations examin examine examin + examined examin examines examin + exampl exampl example exampl + exampled exampl examples exampl + exasperate exasper exasperates exasper + exceed exce exceeded exceed + exceedeth exceedeth exceeding exceed + exceedingly exceedingli exceeds exce + excel excel excelled excel + excellence excel excellencies excel + excellency excel excellent excel + excellently excel excelling excel + excels excel except except + excepted except excepting except + exception except exceptions except + exceptless exceptless excess excess + excessive excess exchang exchang + exchange exchang exchanged exchang + exchequer exchequ exchequers exchequ + excite excit excited excit + excitements excit excites excit + exclaim exclaim exclaims exclaim + exclamation exclam exclamations exclam + excludes exclud excommunicate excommun + excommunication excommun excrement excrement + excrements excrement excursion excurs + excursions excurs excus excu + excusable excus excuse excus + excused excus excuses excus + excusez excusez excusing excus + execrable execr execrations execr + execute execut executed execut + executing execut execution execut + executioner execution executioners execution + executor executor executors executor + exempt exempt exempted exempt + exequies exequi exercise exercis + exercises exercis exeter exet + exeunt exeunt exhal exhal + exhalation exhal exhalations exhal + exhale exhal exhales exhal + exhaust exhaust exhibit exhibit + exhibiters exhibit exhibition exhibit + exhort exhort exhortation exhort + exigent exig exil exil + exile exil exiled exil + exion exion exist exist + exists exist exit exit + exits exit exorciser exorcis + exorcisms exorc exorcist exorcist + expect expect expectance expect + expectancy expect expectation expect + expectations expect expected expect + expecters expect expecting expect + expects expect expedience expedi + expedient expedi expediently expedi + expedition expedit expeditious expediti + expel expel expell expel + expelling expel expels expel + expend expend expense expens + expenses expens experienc experienc + experience experi experiences experi + experiment experi experimental experiment + experiments experi expert expert + expertness expert expiate expiat + expiation expiat expir expir + expiration expir expire expir + expired expir expires expir + expiring expir explication explic + exploit exploit exploits exploit + expos expo expose expos + exposing expos exposition exposit + expositor expositor expostulate expostul + expostulation expostul exposture expostur + exposure exposur expound expound + expounded expound express express + expressed express expresseth expresseth + expressing express expressive express + expressly expressli expressure expressur + expuls expul expulsion expuls + exquisite exquisit exsufflicate exsuffl + extant extant extemporal extempor + extemporally extempor extempore extempor + extend extend extended extend + extends extend extent extent + extenuate extenu extenuated extenu + extenuates extenu extenuation extenu + exterior exterior exteriorly exteriorli + exteriors exterior extermin extermin + extern extern external extern + extinct extinct extincted extinct + extincture extinctur extinguish extinguish + extirp extirp extirpate extirp + extirped extirp extol extol + extoll extol extolment extol + exton exton extort extort + extorted extort extortion extort + extortions extort extra extra + extract extract extracted extract + extracting extract extraordinarily extraordinarili + extraordinary extraordinari extraught extraught + extravagancy extravag extravagant extravag + extreme extrem extremely extrem + extremes extrem extremest extremest + extremities extrem extremity extrem + exuent exuent exult exult + exultation exult ey ey + eyas eya eyases eyas + eye ey eyeball eyebal + eyeballs eyebal eyebrow eyebrow + eyebrows eyebrow eyed ei + eyeless eyeless eyelid eyelid + eyelids eyelid eyes ey + eyesight eyesight eyestrings eyestr + eying ei eyne eyn + eyrie eyri fa fa + fabian fabian fable fabl + fables fabl fabric fabric + fabulous fabul fac fac + face face faced face + facere facer faces face + faciant faciant facile facil + facility facil facinerious facineri + facing face facit facit + fact fact faction faction + factionary factionari factions faction + factious factiou factor factor + factors factor faculties faculti + faculty faculti fade fade + faded fade fadeth fadeth + fadge fadg fading fade + fadings fade fadom fadom + fadoms fadom fagot fagot + fagots fagot fail fail + failing fail fails fail + fain fain faint faint + fainted faint fainter fainter + fainting faint faintly faintli + faintness faint faints faint + fair fair fairer fairer + fairest fairest fairies fairi + fairing fair fairings fair + fairly fairli fairness fair + fairs fair fairwell fairwel + fairy fairi fais fai + fait fait faites fait + faith faith faithful faith + faithfull faithful faithfully faithfulli + faithless faithless faiths faith + faitors faitor fal fal + falchion falchion falcon falcon + falconbridge falconbridg falconer falcon + falconers falcon fall fall + fallacy fallaci fallen fallen + falleth falleth falliable falliabl + fallible fallibl falling fall + fallow fallow fallows fallow + falls fall fally falli + falorous falor false fals + falsehood falsehood falsely fals + falseness fals falser falser + falsify falsifi falsing fals + falstaff falstaff falstaffs falstaff + falter falter fam fam + fame fame famed fame + familiar familiar familiarity familiar + familiarly familiarli familiars familiar + family famili famine famin + famish famish famished famish + famous famou famoused famous + famously famous fan fan + fanatical fanat fancies fanci + fancy fanci fane fane + fanes fane fang fang + fangled fangl fangless fangless + fangs fang fann fann + fanning fan fans fan + fantasied fantasi fantasies fantasi + fantastic fantast fantastical fantast + fantastically fantast fantasticoes fantastico + fantasy fantasi fap fap + far far farborough farborough + farced farc fardel fardel + fardels fardel fare fare + fares fare farewell farewel + farewells farewel fariner farin + faring fare farm farm + farmer farmer farmhouse farmhous + farms farm farre farr + farrow farrow farther farther + farthest farthest farthing farth + farthingale farthingal farthingales farthingal + farthings farth fartuous fartuou + fas fa fashion fashion + fashionable fashion fashioning fashion + fashions fashion fast fast + fasted fast fasten fasten + fastened fasten faster faster + fastest fastest fasting fast + fastly fastli fastolfe fastolf + fasts fast fat fat + fatal fatal fatally fatal + fate fate fated fate + fates fate father father + fathered father fatherless fatherless + fatherly fatherli fathers father + fathom fathom fathomless fathomless + fathoms fathom fatigate fatig + fatness fat fats fat + fatted fat fatter fatter + fattest fattest fatting fat + fatuus fatuu fauconbridge fauconbridg + faulconbridge faulconbridg fault fault + faultiness faulti faultless faultless + faults fault faulty faulti + fausse fauss fauste faust + faustuses faustus faut faut + favor favor favorable favor + favorably favor favors favor + favour favour favourable favour + favoured favour favouredly favouredli + favourer favour favourers favour + favouring favour favourite favourit + favourites favourit favours favour + favout favout fawn fawn + fawneth fawneth fawning fawn + fawns fawn fay fai + fe fe fealty fealti + fear fear feared fear + fearest fearest fearful fear + fearfull fearful fearfully fearfulli + fearfulness fear fearing fear + fearless fearless fears fear + feast feast feasted feast + feasting feast feasts feast + feat feat feated feat + feater feater feather feather + feathered feather feathers feather + featly featli feats feat + featur featur feature featur + featured featur featureless featureless + features featur february februari + fecks feck fed fed + fedary fedari federary federari + fee fee feeble feebl + feebled feebl feebleness feebl + feebling feebl feebly feebli + feed feed feeder feeder + feeders feeder feedeth feedeth + feeding feed feeds feed + feel feel feeler feeler + feeling feel feelingly feelingli + feels feel fees fee + feet feet fehemently fehement + feign feign feigned feign + feigning feign feil feil + feith feith felicitate felicit + felicity felic fell fell + fellest fellest fellies felli + fellow fellow fellowly fellowli + fellows fellow fellowship fellowship + fellowships fellowship fells fell + felon felon felonious feloni + felony feloni felt felt + female femal females femal + feminine feminin fen fen + fenc fenc fence fenc + fencer fencer fencing fenc + fends fend fennel fennel + fenny fenni fens fen + fenton fenton fer fer + ferdinand ferdinand fere fere + fernseed fernse ferrara ferrara + ferrers ferrer ferret ferret + ferry ferri ferryman ferryman + fertile fertil fertility fertil + fervency fervenc fervour fervour + fery feri fest fest + feste fest fester fester + festinate festin festinately festin + festival festiv festivals festiv + fet fet fetch fetch + fetches fetch fetching fetch + fetlock fetlock fetlocks fetlock + fett fett fetter fetter + fettering fetter fetters fetter + fettle fettl feu feu + feud feud fever fever + feverous fever fevers fever + few few fewer fewer + fewest fewest fewness few + fickle fickl fickleness fickl + fico fico fiction fiction + fiddle fiddl fiddler fiddler + fiddlestick fiddlestick fidele fidel + fidelicet fidelicet fidelity fidel + fidius fidiu fie fie + field field fielded field + fields field fiend fiend + fiends fiend fierce fierc + fiercely fierc fierceness fierc + fiery fieri fife fife + fifes fife fifteen fifteen + fifteens fifteen fifteenth fifteenth + fifth fifth fifty fifti + fiftyfold fiftyfold fig fig + fight fight fighter fighter + fightest fightest fighteth fighteth + fighting fight fights fight + figo figo figs fig + figur figur figure figur + figured figur figures figur + figuring figur fike fike + fil fil filberts filbert + filch filch filches filch + filching filch file file + filed file files file + filial filial filius filiu + fill fill filled fill + fillet fillet filling fill + fillip fillip fills fill + filly filli film film + fils fil filth filth + filths filth filthy filthi + fin fin finally final + finch finch find find + finder finder findeth findeth + finding find findings find + finds find fine fine + fineless fineless finely fine + finem finem fineness fine + finer finer fines fine + finest finest fing fing + finger finger fingering finger + fingers finger fingre fingr + fingres fingr finical finic + finish finish finished finish + finisher finish finless finless + finn finn fins fin + finsbury finsburi fir fir + firago firago fire fire + firebrand firebrand firebrands firebrand + fired fire fires fire + firework firework fireworks firework + firing fire firk firk + firm firm firmament firmament + firmly firmli firmness firm + first first firstlings firstl + fish fish fisher fisher + fishermen fishermen fishers fisher + fishes fish fishified fishifi + fishmonger fishmong fishpond fishpond + fisnomy fisnomi fist fist + fisting fist fists fist + fistula fistula fit fit + fitchew fitchew fitful fit + fitly fitli fitment fitment + fitness fit fits fit + fitted fit fitter fitter + fittest fittest fitteth fitteth + fitting fit fitzwater fitzwat + five five fivepence fivep + fives five fix fix + fixed fix fixes fix + fixeth fixeth fixing fix + fixture fixtur fl fl + flag flag flagging flag + flagon flagon flagons flagon + flags flag flail flail + flakes flake flaky flaki + flam flam flame flame + flamen flamen flamens flamen + flames flame flaming flame + flaminius flaminiu flanders flander + flannel flannel flap flap + flaring flare flash flash + flashes flash flashing flash + flask flask flat flat + flatly flatli flatness flat + flats flat flatt flatt + flatter flatter flattered flatter + flatterer flatter flatterers flatter + flatterest flatterest flatteries flatteri + flattering flatter flatters flatter + flattery flatteri flaunts flaunt + flavio flavio flavius flaviu + flaw flaw flaws flaw + flax flax flaxen flaxen + flay flai flaying flai + flea flea fleance fleanc + fleas flea flecked fleck + fled fled fledge fledg + flee flee fleec fleec + fleece fleec fleeces fleec + fleer fleer fleering fleer + fleers fleer fleet fleet + fleeter fleeter fleeting fleet + fleming fleme flemish flemish + flesh flesh fleshes flesh + fleshly fleshli fleshment fleshment + fleshmonger fleshmong flew flew + flexible flexibl flexure flexur + flibbertigibbet flibbertigibbet flickering flicker + flidge flidg fliers flier + flies fli flieth flieth + flight flight flights flight + flighty flighti flinch flinch + fling fling flint flint + flints flint flinty flinti + flirt flirt float float + floated float floating float + flock flock flocks flock + flood flood floodgates floodgat + floods flood floor floor + flora flora florence florenc + florentine florentin florentines florentin + florentius florentiu florizel florizel + flote flote floulish floulish + flour flour flourish flourish + flourishes flourish flourisheth flourisheth + flourishing flourish flout flout + flouted flout flouting flout + flouts flout flow flow + flowed flow flower flower + flowerets floweret flowers flower + flowing flow flown flown + flows flow fluellen fluellen + fluent fluent flung flung + flush flush flushing flush + fluster fluster flute flute + flutes flute flutter flutter + flux flux fluxive fluxiv + fly fly flying fly + fo fo foal foal + foals foal foam foam + foamed foam foaming foam + foams foam foamy foami + fob fob focative foc + fodder fodder foe foe + foeman foeman foemen foemen + foes foe fog fog + foggy foggi fogs fog + foh foh foi foi + foil foil foiled foil + foils foil foin foin + foining foin foins foin + fois foi foison foison + foisons foison foist foist + foix foix fold fold + folded fold folds fold + folio folio folk folk + folks folk follies folli + follow follow followed follow + follower follow followers follow + followest followest following follow + follows follow folly folli + fond fond fonder fonder + fondly fondli fondness fond + font font fontibell fontibel + food food fool fool + fooleries fooleri foolery fooleri + foolhardy foolhardi fooling fool + foolish foolish foolishly foolishli + foolishness foolish fools fool + foot foot football footbal + footboy footboi footboys footboi + footed foot footfall footfal + footing foot footman footman + footmen footmen footpath footpath + footsteps footstep footstool footstool + fopp fopp fopped fop + foppery fopperi foppish foppish + fops fop for for + forage forag foragers forag + forbade forbad forbear forbear + forbearance forbear forbears forbear + forbid forbid forbidden forbidden + forbiddenly forbiddenli forbids forbid + forbod forbod forborne forborn + forc forc force forc + forced forc forceful forc + forceless forceless forces forc + forcible forcibl forcibly forcibl + forcing forc ford ford + fordid fordid fordo fordo + fordoes fordo fordone fordon + fore fore forecast forecast + forefather forefath forefathers forefath + forefinger forefing forego forego + foregone foregon forehand forehand + forehead forehead foreheads forehead + forehorse forehors foreign foreign + foreigner foreign foreigners foreign + foreknowing foreknow foreknowledge foreknowledg + foremost foremost forenamed forenam + forenoon forenoon forerun forerun + forerunner forerunn forerunning forerun + foreruns forerun foresaid foresaid + foresaw foresaw foresay foresai + foresee forese foreseeing forese + foresees forese foreshow foreshow + foreskirt foreskirt forespent foresp + forest forest forestall forestal + forestalled forestal forester forest + foresters forest forests forest + foretell foretel foretelling foretel + foretells foretel forethink forethink + forethought forethought foretold foretold + forever forev foreward foreward + forewarn forewarn forewarned forewarn + forewarning forewarn forfeit forfeit + forfeited forfeit forfeiters forfeit + forfeiting forfeit forfeits forfeit + forfeiture forfeitur forfeitures forfeitur + forfend forfend forfended forfend + forg forg forgave forgav + forge forg forged forg + forgeries forgeri forgery forgeri + forges forg forget forget + forgetful forget forgetfulness forget + forgetive forget forgets forget + forgetting forget forgive forgiv + forgiven forgiven forgiveness forgiv + forgo forgo forgoing forgo + forgone forgon forgot forgot + forgotten forgotten fork fork + forked fork forks fork + forlorn forlorn form form + formal formal formally formal + formed form former former + formerly formerli formless formless + forms form fornication fornic + fornications fornic fornicatress fornicatress + forres forr forrest forrest + forsake forsak forsaken forsaken + forsaketh forsaketh forslow forslow + forsook forsook forsooth forsooth + forspent forspent forspoke forspok + forswear forswear forswearing forswear + forswore forswor forsworn forsworn + fort fort forted fort + forth forth forthcoming forthcom + forthlight forthlight forthright forthright + forthwith forthwith fortification fortif + fortifications fortif fortified fortifi + fortifies fortifi fortify fortifi + fortinbras fortinbra fortitude fortitud + fortnight fortnight fortress fortress + fortresses fortress forts fort + fortun fortun fortuna fortuna + fortunate fortun fortunately fortun + fortune fortun fortuned fortun + fortunes fortun fortward fortward + forty forti forum forum + forward forward forwarding forward + forwardness forward forwards forward + forwearied forweari fosset fosset + fost fost foster foster + fostered foster fought fought + foughten foughten foul foul + fouler fouler foulest foulest + foully foulli foulness foul + found found foundation foundat + foundations foundat founded found + founder founder fount fount + fountain fountain fountains fountain + founts fount four four + fourscore fourscor fourteen fourteen + fourth fourth foutra foutra + fowl fowl fowler fowler + fowling fowl fowls fowl + fox fox foxes fox + foxship foxship fracted fract + fraction fraction fractions fraction + fragile fragil fragment fragment + fragments fragment fragrant fragrant + frail frail frailer frailer + frailties frailti frailty frailti + fram fram frame frame + framed frame frames frame + frampold frampold fran fran + francais francai france franc + frances franc franchise franchis + franchised franchis franchisement franchis + franchises franchis franciae francia + francis franci francisca francisca + franciscan franciscan francisco francisco + frank frank franker franker + frankfort frankfort franklin franklin + franklins franklin frankly frankli + frankness frank frantic frantic + franticly franticli frateretto frateretto + fratrum fratrum fraud fraud + fraudful fraud fraught fraught + fraughtage fraughtag fraughting fraught + fray frai frays frai + freckl freckl freckled freckl + freckles freckl frederick frederick + free free freed freed + freedom freedom freedoms freedom + freehearted freeheart freelier freelier + freely freeli freeman freeman + freemen freemen freeness freeness + freer freer frees free + freestone freeston freetown freetown + freeze freez freezes freez + freezing freez freezings freez + french french frenchman frenchman + frenchmen frenchmen frenchwoman frenchwoman + frenzy frenzi frequent frequent + frequents frequent fresh fresh + fresher fresher freshes fresh + freshest freshest freshly freshli + freshness fresh fret fret + fretful fret frets fret + fretted fret fretten fretten + fretting fret friar friar + friars friar friday fridai + fridays fridai friend friend + friended friend friending friend + friendless friendless friendliness friendli + friendly friendli friends friend + friendship friendship friendships friendship + frieze friez fright fright + frighted fright frightened frighten + frightful fright frighting fright + frights fright fringe fring + fringed fring frippery fripperi + frisk frisk fritters fritter + frivolous frivol fro fro + frock frock frog frog + frogmore frogmor froissart froissart + frolic frolic from from + front front fronted front + frontier frontier frontiers frontier + fronting front frontlet frontlet + fronts front frost frost + frosts frost frosty frosti + froth froth froward froward + frown frown frowning frown + frowningly frowningli frowns frown + froze froze frozen frozen + fructify fructifi frugal frugal + fruit fruit fruiterer fruiter + fruitful fruit fruitfully fruitfulli + fruitfulness fruit fruition fruition + fruitless fruitless fruits fruit + frush frush frustrate frustrat + frutify frutifi fry fry + fubb fubb fuel fuel + fugitive fugit fulfil fulfil + fulfill fulfil fulfilling fulfil + fulfils fulfil full full + fullam fullam fuller fuller + fullers fuller fullest fullest + fullness full fully fulli + fulness ful fulsome fulsom + fulvia fulvia fum fum + fumble fumbl fumbles fumbl + fumblest fumblest fumbling fumbl + fume fume fumes fume + fuming fume fumiter fumit + fumitory fumitori fun fun + function function functions function + fundamental fundament funeral funer + funerals funer fur fur + furbish furbish furies furi + furious furiou furlongs furlong + furnace furnac furnaces furnac + furnish furnish furnished furnish + furnishings furnish furniture furnitur + furnival furniv furor furor + furr furr furrow furrow + furrowed furrow furrows furrow + furth furth further further + furtherance further furtherer further + furthermore furthermor furthest furthest + fury furi furze furz + furzes furz fust fust + fustian fustian fustilarian fustilarian + fusty fusti fut fut + future futur futurity futur + g g gabble gabbl + gaberdine gaberdin gabriel gabriel + gad gad gadding gad + gads gad gadshill gadshil + gag gag gage gage + gaged gage gagg gagg + gaging gage gagne gagn + gain gain gained gain + gainer gainer gaingiving gaingiv + gains gain gainsaid gainsaid + gainsay gainsai gainsaying gainsai + gainsays gainsai gainst gainst + gait gait gaited gait + galathe galath gale gale + galen galen gales gale + gall gall gallant gallant + gallantly gallantli gallantry gallantri + gallants gallant galled gall + gallery galleri galley gallei + galleys gallei gallia gallia + gallian gallian galliard galliard + galliasses galliass gallimaufry gallimaufri + galling gall gallons gallon + gallop gallop galloping gallop + gallops gallop gallow gallow + galloway gallowai gallowglasses gallowglass + gallows gallow gallowses gallows + galls gall gallus gallu + gam gam gambol gambol + gambold gambold gambols gambol + gamboys gamboi game game + gamers gamer games game + gamesome gamesom gamester gamest + gaming game gammon gammon + gamut gamut gan gan + gangren gangren ganymede ganymed + gaol gaol gaoler gaoler + gaolers gaoler gaols gaol + gap gap gape gape + gapes gape gaping gape + gar gar garb garb + garbage garbag garboils garboil + garcon garcon gard gard + garde gard garden garden + gardener garden gardeners garden + gardens garden gardez gardez + gardiner gardin gardon gardon + gargantua gargantua gargrave gargrav + garish garish garland garland + garlands garland garlic garlic + garment garment garments garment + garmet garmet garner garner + garners garner garnish garnish + garnished garnish garret garret + garrison garrison garrisons garrison + gart gart garter garter + garterd garterd gartering garter + garters garter gascony gasconi + gash gash gashes gash + gaskins gaskin gasp gasp + gasping gasp gasted gast + gastness gast gat gat + gate gate gated gate + gates gate gath gath + gather gather gathered gather + gathering gather gathers gather + gatories gatori gatory gatori + gaud gaud gaudeo gaudeo + gaudy gaudi gauge gaug + gaul gaul gaultree gaultre + gaunt gaunt gauntlet gauntlet + gauntlets gauntlet gav gav + gave gave gavest gavest + gawded gawd gawds gawd + gawsey gawsei gay gai + gayness gay gaz gaz + gaze gaze gazed gaze + gazer gazer gazers gazer + gazes gaze gazeth gazeth + gazing gaze gear gear + geck geck geese gees + geffrey geffrei geld geld + gelded geld gelding geld + gelida gelida gelidus gelidu + gelt gelt gem gem + geminy gemini gems gem + gen gen gender gender + genders gender general gener + generally gener generals gener + generation gener generations gener + generative gener generosity generos + generous gener genitive genit + genitivo genitivo genius geniu + gennets gennet genoa genoa + genoux genoux gens gen + gent gent gentilhomme gentilhomm + gentility gentil gentle gentl + gentlefolks gentlefolk gentleman gentleman + gentlemanlike gentlemanlik gentlemen gentlemen + gentleness gentl gentler gentler + gentles gentl gentlest gentlest + gentlewoman gentlewoman gentlewomen gentlewomen + gently gentli gentry gentri + george georg gerard gerard + germaines germain germains germain + german german germane german + germans german germany germani + gertrude gertrud gest gest + gests gest gesture gestur + gestures gestur get get + getrude getrud gets get + getter getter getting get + ghastly ghastli ghost ghost + ghosted ghost ghostly ghostli + ghosts ghost gi gi + giant giant giantess giantess + giantlike giantlik giants giant + gib gib gibber gibber + gibbet gibbet gibbets gibbet + gibe gibe giber giber + gibes gibe gibing gibe + gibingly gibingli giddily giddili + giddiness giddi giddy giddi + gift gift gifts gift + gig gig giglets giglet + giglot giglot gilbert gilbert + gild gild gilded gild + gilding gild gilliams gilliam + gillian gillian gills gill + gillyvors gillyvor gilt gilt + gimmal gimmal gimmers gimmer + gin gin ging ging + ginger ginger gingerbread gingerbread + gingerly gingerli ginn ginn + gins gin gioucestershire gioucestershir + gipes gipe gipsies gipsi + gipsy gipsi gird gird + girded gird girdle girdl + girdled girdl girdles girdl + girdling girdl girl girl + girls girl girt girt + girth girth gis gi + giv giv give give + given given giver giver + givers giver gives give + givest givest giveth giveth + giving give givings give + glad glad gladded glad + gladding glad gladly gladli + gladness glad glamis glami + glanc glanc glance glanc + glanced glanc glances glanc + glancing glanc glanders glander + glansdale glansdal glare glare + glares glare glass glass + glasses glass glassy glassi + glaz glaz glazed glaze + gleams gleam glean glean + gleaned glean gleaning glean + gleeful gleeful gleek gleek + gleeking gleek gleeks gleek + glend glend glendower glendow + glib glib glide glide + glided glide glides glide + glideth glideth gliding glide + glimmer glimmer glimmering glimmer + glimmers glimmer glimpse glimps + glimpses glimps glist glist + glistening glisten glister glister + glistering glister glisters glister + glitt glitt glittering glitter + globe globe globes globe + glooming gloom gloomy gloomi + glories glori glorified glorifi + glorify glorifi glorious gloriou + gloriously glorious glory glori + glose glose gloss gloss + glosses gloss glou glou + glouceste gloucest gloucester gloucest + gloucestershire gloucestershir glove glove + glover glover gloves glove + glow glow glowed glow + glowing glow glowworm glowworm + gloz gloz gloze gloze + glozes gloze glu glu + glue glue glued glu + glues glue glut glut + glutt glutt glutted glut + glutton glutton gluttoning glutton + gluttony gluttoni gnarled gnarl + gnarling gnarl gnat gnat + gnats gnat gnaw gnaw + gnawing gnaw gnawn gnawn + gnaws gnaw go go + goad goad goaded goad + goads goad goal goal + goat goat goatish goatish + goats goat gobbets gobbet + gobbo gobbo goblet goblet + goblets goblet goblin goblin + goblins goblin god god + godded god godden godden + goddess goddess goddesses goddess + goddild goddild godfather godfath + godfathers godfath godhead godhead + godlike godlik godliness godli + godly godli godmother godmoth + gods god godson godson + goer goer goers goer + goes goe goest goest + goeth goeth goffe goff + gogs gog going go + gold gold golden golden + goldenly goldenli goldsmith goldsmith + goldsmiths goldsmith golgotha golgotha + goliases golias goliath goliath + gon gon gondola gondola + gondolier gondoli gone gone + goneril goneril gong gong + gonzago gonzago gonzalo gonzalo + good good goodfellow goodfellow + goodlier goodlier goodliest goodliest + goodly goodli goodman goodman + goodness good goodnight goodnight + goodrig goodrig goods good + goodwife goodwif goodwill goodwil + goodwin goodwin goodwins goodwin + goodyear goodyear goodyears goodyear + goose goos gooseberry gooseberri + goosequills goosequil goot goot + gor gor gorbellied gorbelli + gorboduc gorboduc gordian gordian + gore gore gored gore + gorg gorg gorge gorg + gorgeous gorgeou gorget gorget + gorging gorg gorgon gorgon + gormandize gormand gormandizing gormand + gory gori gosling gosl + gospel gospel gospels gospel + goss goss gossamer gossam + gossip gossip gossiping gossip + gossiplike gossiplik gossips gossip + got got goth goth + goths goth gotten gotten + gourd gourd gout gout + gouts gout gouty gouti + govern govern governance govern + governed govern governess gover + government govern governor governor + governors governor governs govern + gower gower gown gown + gowns gown grac grac + grace grace graced grace + graceful grace gracefully gracefulli + graceless graceless graces grace + gracing grace gracious graciou + graciously gracious gradation gradat + graff graff graffing graf + graft graft grafted graft + grafters grafter grain grain + grained grain grains grain + gramercies gramerci gramercy gramerci + grammar grammar grand grand + grandam grandam grandame grandam + grandchild grandchild grande grand + grandeur grandeur grandfather grandfath + grandjurors grandjuror grandmother grandmoth + grandpre grandpr grandsir grandsir + grandsire grandsir grandsires grandsir + grange grang grant grant + granted grant granting grant + grants grant grape grape + grapes grape grapple grappl + grapples grappl grappling grappl + grasp grasp grasped grasp + grasps grasp grass grass + grasshoppers grasshopp grassy grassi + grate grate grated grate + grateful grate grates grate + gratiano gratiano gratify gratifi + gratii gratii gratillity gratil + grating grate gratis grati + gratitude gratitud gratulate gratul + grav grav grave grave + gravediggers gravedigg gravel gravel + graveless graveless gravell gravel + gravely grave graven graven + graveness grave graver graver + graves grave gravest gravest + gravestone graveston gravities graviti + gravity graviti gravy gravi + gray grai graymalkin graymalkin + graz graz graze graze + grazed graze grazing graze + grease greas greases greas + greasily greasili greasy greasi + great great greater greater + greatest greatest greatly greatli + greatness great grecian grecian + grecians grecian gree gree + greece greec greed greed + greedily greedili greediness greedi + greedy greedi greeing gree + greek greek greekish greekish + greeks greek green green + greener greener greenly greenli + greens green greensleeves greensleev + greenwich greenwich greenwood greenwood + greet greet greeted greet + greeting greet greetings greet + greets greet greg greg + gregory gregori gremio gremio + grew grew grey grei + greybeard greybeard greybeards greybeard + greyhound greyhound greyhounds greyhound + grief grief griefs grief + griev griev grievance grievanc + grievances grievanc grieve griev + grieved griev grieves griev + grievest grievest grieving griev + grievingly grievingli grievous grievou + grievously grievous griffin griffin + griffith griffith grim grim + grime grime grimly grimli + grin grin grind grind + grinding grind grindstone grindston + grinning grin grip grip + gripe gripe gripes gripe + griping gripe grise grise + grisly grisli grissel grissel + grize grize grizzle grizzl + grizzled grizzl groan groan + groaning groan groans groan + groat groat groats groat + groin groin groom groom + grooms groom grop grop + groping grope gros gro + gross gross grosser grosser + grossly grossli grossness gross + ground ground grounded ground + groundlings groundl grounds ground + grove grove grovel grovel + grovelling grovel groves grove + grow grow groweth groweth + growing grow grown grown + grows grow growth growth + grub grub grubb grubb + grubs grub grudge grudg + grudged grudg grudges grudg + grudging grudg gruel gruel + grumble grumbl grumblest grumblest + grumbling grumbl grumblings grumbl + grumio grumio grund grund + grunt grunt gualtier gualtier + guard guard guardage guardag + guardant guardant guarded guard + guardian guardian guardians guardian + guards guard guardsman guardsman + gud gud gudgeon gudgeon + guerdon guerdon guerra guerra + guess guess guesses guess + guessingly guessingli guest guest + guests guest guiana guiana + guichard guichard guide guid + guided guid guider guider + guiderius guideriu guides guid + guiding guid guidon guidon + guienne guienn guil guil + guildenstern guildenstern guilders guilder + guildford guildford guildhall guildhal + guile guil guiled guil + guileful guil guilfords guilford + guilt guilt guiltian guiltian + guiltier guiltier guiltily guiltili + guiltiness guilti guiltless guiltless + guilts guilt guilty guilti + guinea guinea guinever guinev + guise guis gul gul + gules gule gulf gulf + gulfs gulf gull gull + gulls gull gum gum + gumm gumm gums gum + gun gun gunner gunner + gunpowder gunpowd guns gun + gurnet gurnet gurney gurnei + gust gust gusts gust + gusty gusti guts gut + gutter gutter guy gui + guynes guyn guysors guysor + gypsy gypsi gyve gyve + gyved gyve gyves gyve + h h ha ha + haberdasher haberdash habiliment habili + habiliments habili habit habit + habitation habit habited habit + habits habit habitude habitud + hack hack hacket hacket + hackney hacknei hacks hack + had had hadst hadst + haec haec haeres haer + hag hag hagar hagar + haggard haggard haggards haggard + haggish haggish haggled haggl + hags hag hail hail + hailed hail hailstone hailston + hailstones hailston hair hair + hairless hairless hairs hair + hairy hairi hal hal + halberd halberd halberds halberd + halcyon halcyon hale hale + haled hale hales hale + half half halfcan halfcan + halfpence halfpenc halfpenny halfpenni + halfpennyworth halfpennyworth halfway halfwai + halidom halidom hall hall + halloa halloa halloing hallo + hallond hallond halloo halloo + hallooing halloo hallow hallow + hallowed hallow hallowmas hallowma + hallown hallown hals hal + halt halt halter halter + halters halter halting halt + halts halt halves halv + ham ham hames hame + hamlet hamlet hammer hammer + hammered hammer hammering hammer + hammers hammer hamper hamper + hampton hampton hams ham + hamstring hamstr hand hand + handed hand handful hand + handicraft handicraft handicraftsmen handicraftsmen + handing hand handiwork handiwork + handkercher handkerch handkerchers handkerch + handkerchief handkerchief handle handl + handled handl handles handl + handless handless handlest handlest + handling handl handmaid handmaid + handmaids handmaid hands hand + handsaw handsaw handsome handsom + handsomely handsom handsomeness handsom + handwriting handwrit handy handi + hang hang hanged hang + hangers hanger hangeth hangeth + hanging hang hangings hang + hangman hangman hangmen hangmen + hangs hang hannibal hannib + hap hap hapless hapless + haply hapli happ happ + happen happen happened happen + happier happier happies happi + happiest happiest happily happili + happiness happi happy happi + haps hap harbinger harbing + harbingers harbing harbor harbor + harbour harbour harbourage harbourag + harbouring harbour harbours harbour + harcourt harcourt hard hard + harder harder hardest hardest + hardiest hardiest hardiment hardiment + hardiness hardi hardly hardli + hardness hard hardocks hardock + hardy hardi hare hare + harelip harelip hares hare + harfleur harfleur hark hark + harlot harlot harlotry harlotri + harlots harlot harm harm + harmed harm harmful harm + harming harm harmless harmless + harmonious harmoni harmony harmoni + harms harm harness har + harp harp harper harper + harpier harpier harping harp + harpy harpi harried harri + harrow harrow harrows harrow + harry harri harsh harsh + harshly harshli harshness harsh + hart hart harts hart + harum harum harvest harvest + has ha hast hast + haste hast hasted hast + hasten hasten hastes hast + hastily hastili hasting hast + hastings hast hasty hasti + hat hat hatch hatch + hatches hatch hatchet hatchet + hatching hatch hatchment hatchment + hate hate hated hate + hateful hate hater hater + haters hater hates hate + hateth hateth hatfield hatfield + hath hath hating hate + hatred hatr hats hat + haud haud hauf hauf + haught haught haughtiness haughti + haughty haughti haunch haunch + haunches haunch haunt haunt + haunted haunt haunting haunt + haunts haunt hautboy hautboi + hautboys hautboi have have + haven haven havens haven + haver haver having have + havings have havior havior + haviour haviour havoc havoc + hawk hawk hawking hawk + hawks hawk hawthorn hawthorn + hawthorns hawthorn hay hai + hazard hazard hazarded hazard + hazards hazard hazel hazel + hazelnut hazelnut he he + head head headborough headborough + headed head headier headier + heading head headland headland + headless headless headlong headlong + heads head headsman headsman + headstrong headstrong heady headi + heal heal healed heal + healing heal heals heal + health health healthful health + healths health healthsome healthsom + healthy healthi heap heap + heaping heap heaps heap + hear hear heard heard + hearer hearer hearers hearer + hearest hearest heareth heareth + hearing hear hearings hear + heark heark hearken hearken + hearkens hearken hears hear + hearsay hearsai hearse hears + hearsed hears hearst hearst + heart heart heartache heartach + heartbreak heartbreak heartbreaking heartbreak + hearted heart hearten hearten + hearth hearth hearths hearth + heartily heartili heartiness hearti + heartless heartless heartlings heartl + heartly heartli hearts heart + heartsick heartsick heartstrings heartstr + hearty hearti heat heat + heated heat heath heath + heathen heathen heathenish heathenish + heating heat heats heat + heauties heauti heav heav + heave heav heaved heav + heaven heaven heavenly heavenli + heavens heaven heaves heav + heavier heavier heaviest heaviest + heavily heavili heaviness heavi + heaving heav heavings heav + heavy heavi hebona hebona + hebrew hebrew hecate hecat + hectic hectic hector hector + hectors hector hecuba hecuba + hedg hedg hedge hedg + hedgehog hedgehog hedgehogs hedgehog + hedges hedg heed heed + heeded heed heedful heed + heedfull heedful heedfully heedfulli + heedless heedless heel heel + heels heel hefted heft + hefts heft heifer heifer + heifers heifer heigh heigh + height height heighten heighten + heinous heinou heinously heinous + heir heir heiress heiress + heirless heirless heirs heir + held held helen helen + helena helena helenus helenu + helias helia helicons helicon + hell hell hellespont hellespont + hellfire hellfir hellish hellish + helm helm helmed helm + helmet helmet helmets helmet + helms helm help help + helper helper helpers helper + helpful help helping help + helpless helpless helps help + helter helter hem hem + heme heme hemlock hemlock + hemm hemm hemp hemp + hempen hempen hems hem + hen hen hence henc + henceforth henceforth henceforward henceforward + henchman henchman henri henri + henricus henricu henry henri + hens hen hent hent + henton henton her her + herald herald heraldry heraldri + heralds herald herb herb + herbert herbert herblets herblet + herbs herb herculean herculean + hercules hercul herd herd + herds herd herdsman herdsman + herdsmen herdsmen here here + hereabout hereabout hereabouts hereabout + hereafter hereaft hereby herebi + hereditary hereditari hereford hereford + herefordshire herefordshir herein herein + hereof hereof heresies heresi + heresy heresi heretic heret + heretics heret hereto hereto + hereupon hereupon heritage heritag + heritier heriti hermes herm + hermia hermia hermione hermion + hermit hermit hermitage hermitag + hermits hermit herne hern + hero hero herod herod + herods herod heroes hero + heroic heroic heroical heroic + herring her herrings her + hers her herself herself + hesperides hesperid hesperus hesperu + hest hest hests hest + heure heur heureux heureux + hew hew hewgh hewgh + hewing hew hewn hewn + hews hew hey hei + heyday heydai hibocrates hibocr + hic hic hiccups hiccup + hick hick hid hid + hidden hidden hide hide + hideous hideou hideously hideous + hideousness hideous hides hide + hidest hidest hiding hide + hie hie hied hi + hiems hiem hies hi + hig hig high high + higher higher highest highest + highly highli highmost highmost + highness high hight hight + highway highwai highways highwai + hilding hild hildings hild + hill hill hillo hillo + hilloa hilloa hills hill + hilt hilt hilts hilt + hily hili him him + himself himself hinc hinc + hinckley hincklei hind hind + hinder hinder hindered hinder + hinders hinder hindmost hindmost + hinds hind hing hing + hinge hing hinges hing + hint hint hip hip + hipp hipp hipparchus hipparchu + hippolyta hippolyta hips hip + hir hir hire hire + hired hire hiren hiren + hirtius hirtiu his hi + hisperia hisperia hiss hiss + hisses hiss hissing hiss + hist hist historical histor + history histori hit hit + hither hither hitherto hitherto + hitherward hitherward hitherwards hitherward + hits hit hitting hit + hive hive hives hive + hizzing hizz ho ho + hoa hoa hoar hoar + hoard hoard hoarded hoard + hoarding hoard hoars hoar + hoarse hoars hoary hoari + hob hob hobbididence hobbidid + hobby hobbi hobbyhorse hobbyhors + hobgoblin hobgoblin hobnails hobnail + hoc hoc hod hod + hodge hodg hog hog + hogs hog hogshead hogshead + hogsheads hogshead hois hoi + hoise hois hoist hoist + hoisted hoist hoists hoist + holborn holborn hold hold + holden holden holder holder + holdeth holdeth holdfast holdfast + holding hold holds hold + hole hole holes hole + holidam holidam holidame holidam + holiday holidai holidays holidai + holier holier holiest holiest + holily holili holiness holi + holla holla holland holland + hollander holland hollanders holland + holloa holloa holloaing holloa + hollow hollow hollowly hollowli + hollowness hollow holly holli + holmedon holmedon holofernes holofern + holp holp holy holi + homage homag homager homag + home home homely home + homes home homespuns homespun + homeward homeward homewards homeward + homicide homicid homicides homicid + homily homili hominem hominem + hommes homm homo homo + honest honest honester honest + honestest honestest honestly honestli + honesty honesti honey honei + honeycomb honeycomb honeying honei + honeyless honeyless honeysuckle honeysuckl + honeysuckles honeysuckl honi honi + honneur honneur honor honor + honorable honor honorably honor + honorato honorato honorificabilitudinitatibus honorificabilitudinitatibu + honors honor honour honour + honourable honour honourably honour + honoured honour honourest honourest + honourible honour honouring honour + honours honour hoo hoo + hood hood hooded hood + hoodman hoodman hoods hood + hoodwink hoodwink hoof hoof + hoofs hoof hook hook + hooking hook hooks hook + hoop hoop hoops hoop + hoot hoot hooted hoot + hooting hoot hoots hoot + hop hop hope hope + hopeful hope hopeless hopeless + hopes hope hopest hopest + hoping hope hopkins hopkin + hoppedance hopped hor hor + horace horac horatio horatio + horizon horizon horn horn + hornbook hornbook horned horn + horner horner horning horn + hornpipes hornpip horns horn + horologe horolog horrible horribl + horribly horribl horrid horrid + horrider horrid horridly horridli + horror horror horrors horror + hors hor horse hors + horseback horseback horsed hors + horsehairs horsehair horseman horseman + horsemanship horsemanship horsemen horsemen + horses hors horseway horsewai + horsing hors hortensio hortensio + hortensius hortensiu horum horum + hose hose hospitable hospit + hospital hospit hospitality hospit + host host hostage hostag + hostages hostag hostess hostess + hostile hostil hostility hostil + hostilius hostiliu hosts host + hot hot hotly hotli + hotspur hotspur hotter hotter + hottest hottest hound hound + hounds hound hour hour + hourly hourli hours hour + hous hou house hous + household household householder household + householders household households household + housekeeper housekeep housekeepers housekeep + housekeeping housekeep houseless houseless + houses hous housewife housewif + housewifery housewiferi housewives housew + hovel hovel hover hover + hovered hover hovering hover + hovers hover how how + howbeit howbeit howe how + howeer howeer however howev + howl howl howled howl + howlet howlet howling howl + howls howl howsoe howso + howsoever howsoev howsome howsom + hoxes hox hoy hoi + hoyday hoydai hubert hubert + huddled huddl huddling huddl + hue hue hued hu + hues hue hug hug + huge huge hugely huge + hugeness huge hugg hugg + hugger hugger hugh hugh + hugs hug hujus huju + hulk hulk hulks hulk + hull hull hulling hull + hullo hullo hum hum + human human humane human + humanely human humanity human + humble humbl humbled humbl + humbleness humbl humbler humbler + humbles humbl humblest humblest + humbling humbl humbly humbl + hume hume humh humh + humidity humid humility humil + humming hum humor humor + humorous humor humors humor + humour humour humourists humourist + humours humour humphrey humphrei + humphry humphri hums hum + hundred hundr hundreds hundr + hundredth hundredth hung hung + hungarian hungarian hungary hungari + hunger hunger hungerford hungerford + hungerly hungerli hungry hungri + hunt hunt hunted hunt + hunter hunter hunters hunter + hunteth hunteth hunting hunt + huntington huntington huntress huntress + hunts hunt huntsman huntsman + huntsmen huntsmen hurdle hurdl + hurl hurl hurling hurl + hurls hurl hurly hurli + hurlyburly hurlyburli hurricano hurricano + hurricanoes hurricano hurried hurri + hurries hurri hurry hurri + hurt hurt hurting hurt + hurtled hurtl hurtless hurtless + hurtling hurtl hurts hurt + husband husband husbanded husband + husbandless husbandless husbandry husbandri + husbands husband hush hush + hushes hush husht husht + husks husk huswife huswif + huswifes huswif hutch hutch + hybla hybla hydra hydra + hyen hyen hymen hymen + hymenaeus hymenaeu hymn hymn + hymns hymn hyperboles hyperbol + hyperbolical hyperbol hyperion hyperion + hypocrisy hypocrisi hypocrite hypocrit + hypocrites hypocrit hyrcan hyrcan + hyrcania hyrcania hyrcanian hyrcanian + hyssop hyssop hysterica hysterica + i i iachimo iachimo + iaculis iaculi iago iago + iament iament ibat ibat + icarus icaru ice ic + iceland iceland ici ici + icicle icicl icicles icicl + icy ici idea idea + ideas idea idem idem + iden iden ides id + idiot idiot idiots idiot + idle idl idleness idl + idles idl idly idli + idol idol idolatrous idolatr + idolatry idolatri ield ield + if if ifs if + ignis igni ignoble ignobl + ignobly ignobl ignominious ignomini + ignominy ignomini ignomy ignomi + ignorance ignor ignorant ignor + ii ii iii iii + iiii iiii il il + ilbow ilbow ild ild + ilion ilion ilium ilium + ill ill illegitimate illegitim + illiterate illiter illness ill + illo illo ills ill + illume illum illumin illumin + illuminate illumin illumineth illumineth + illusion illus illusions illus + illustrate illustr illustrated illustr + illustrious illustri illyria illyria + illyrian illyrian ils il + im im image imag + imagery imageri images imag + imagin imagin imaginary imaginari + imagination imagin imaginations imagin + imagine imagin imagining imagin + imaginings imagin imbar imbar + imbecility imbecil imbrue imbru + imitari imitari imitate imit + imitated imit imitation imit + imitations imit immaculate immacul + immanity imman immask immask + immaterial immateri immediacy immediaci + immediate immedi immediately immedi + imminence immin imminent immin + immoderate immoder immoderately immoder + immodest immodest immoment immoment + immortal immort immortaliz immortaliz + immortally immort immur immur + immured immur immures immur + imogen imogen imp imp + impaint impaint impair impair + impairing impair impale impal + impaled impal impanelled impanel + impart impart imparted impart + impartial imparti impartment impart + imparts impart impasted impast + impatience impati impatient impati + impatiently impati impawn impawn + impeach impeach impeached impeach + impeachment impeach impeachments impeach + impedes imped impediment impedi + impediments impedi impenetrable impenetr + imperator imper imperceiverant imperceiver + imperfect imperfect imperfection imperfect + imperfections imperfect imperfectly imperfectli + imperial imperi imperious imperi + imperiously imperi impertinency impertin + impertinent impertin impeticos impetico + impetuosity impetuos impetuous impetu + impieties impieti impiety impieti + impious impiou implacable implac + implements implement implies impli + implor implor implorators implor + implore implor implored implor + imploring implor impon impon + import import importance import + importancy import important import + importantly importantli imported import + importeth importeth importing import + importless importless imports import + importun importun importunacy importunaci + importunate importun importune importun + importunes importun importunity importun + impos impo impose impos + imposed impos imposition imposit + impositions imposit impossibilities imposs + impossibility imposs impossible imposs + imposthume imposthum impostor impostor + impostors impostor impotence impot + impotent impot impounded impound + impregnable impregn imprese impres + impress impress impressed impress + impressest impressest impression impress + impressure impressur imprimendum imprimendum + imprimis imprimi imprint imprint + imprinted imprint imprison imprison + imprisoned imprison imprisoning imprison + imprisonment imprison improbable improb + improper improp improve improv + improvident improvid impudence impud + impudency impud impudent impud + impudently impud impudique impudiqu + impugn impugn impugns impugn + impure impur imputation imput + impute imput in in + inaccessible inaccess inaidable inaid + inaudible inaud inauspicious inauspici + incaged incag incantations incant + incapable incap incardinate incardin + incarnadine incarnadin incarnate incarn + incarnation incarn incens incen + incense incens incensed incens + incensement incens incenses incens + incensing incens incertain incertain + incertainties incertainti incertainty incertainti + incessant incess incessantly incessantli + incest incest incestuous incestu + inch inch incharitable incharit + inches inch incidency incid + incident incid incision incis + incite incit incites incit + incivil incivil incivility incivil + inclin inclin inclinable inclin + inclination inclin incline inclin + inclined inclin inclines inclin + inclining inclin inclips inclip + include includ included includ + includes includ inclusive inclus + incomparable incompar incomprehensible incomprehens + inconsiderate inconsider inconstancy inconst + inconstant inconst incontinency incontin + incontinent incontin incontinently incontin + inconvenience inconveni inconveniences inconveni + inconvenient inconveni incony inconi + incorporate incorpor incorps incorp + incorrect incorrect increas increa + increase increas increases increas + increaseth increaseth increasing increas + incredible incred incredulous incredul + incur incur incurable incur + incurr incurr incurred incur + incursions incurs ind ind + inde ind indebted indebt + indeed inde indent indent + indented indent indenture indentur + indentures indentur index index + indexes index india india + indian indian indict indict + indicted indict indictment indict + indies indi indifferency indiffer + indifferent indiffer indifferently indiffer + indigent indig indigest indigest + indigested indigest indign indign + indignation indign indignations indign + indigne indign indignities indign + indignity indign indirect indirect + indirection indirect indirections indirect + indirectly indirectli indiscreet indiscreet + indiscretion indiscret indispos indispo + indisposition indisposit indissoluble indissolubl + indistinct indistinct indistinguish indistinguish + indistinguishable indistinguish indited indit + individable individ indrench indrench + indu indu indubitate indubit + induc induc induce induc + induced induc inducement induc + induction induct inductions induct + indue indu indued indu + indues indu indulgence indulg + indulgences indulg indulgent indulg + indurance indur industrious industri + industriously industri industry industri + inequality inequ inestimable inestim + inevitable inevit inexecrable inexecr + inexorable inexor inexplicable inexplic + infallible infal infallibly infal + infamonize infamon infamous infam + infamy infami infancy infanc + infant infant infants infant + infect infect infected infect + infecting infect infection infect + infections infect infectious infecti + infectiously infecti infects infect + infer infer inference infer + inferior inferior inferiors inferior + infernal infern inferr inferr + inferreth inferreth inferring infer + infest infest infidel infidel + infidels infidel infinite infinit + infinitely infinit infinitive infinit + infirm infirm infirmities infirm + infirmity infirm infixed infix + infixing infix inflam inflam + inflame inflam inflaming inflam + inflammation inflamm inflict inflict + infliction inflict influence influenc + influences influenc infold infold + inform inform informal inform + information inform informations inform + informed inform informer inform + informs inform infortunate infortun + infring infr infringe infring + infringed infring infus infu + infuse infus infused infus + infusing infus infusion infus + ingener ingen ingenious ingeni + ingeniously ingeni inglorious inglori + ingots ingot ingraffed ingraf + ingraft ingraft ingrate ingrat + ingrated ingrat ingrateful ingrat + ingratitude ingratitud ingratitudes ingratitud + ingredient ingredi ingredients ingredi + ingross ingross inhabit inhabit + inhabitable inhabit inhabitants inhabit + inhabited inhabit inhabits inhabit + inhearse inhears inhearsed inhears + inherent inher inherit inherit + inheritance inherit inherited inherit + inheriting inherit inheritor inheritor + inheritors inheritor inheritrix inheritrix + inherits inherit inhibited inhibit + inhibition inhibit inhoop inhoop + inhuman inhuman iniquities iniqu + iniquity iniqu initiate initi + injointed injoint injunction injunct + injunctions injunct injur injur + injure injur injurer injur + injuries injuri injurious injuri + injury injuri injustice injustic + ink ink inkhorn inkhorn + inkle inkl inkles inkl + inkling inkl inky inki + inlaid inlaid inland inland + inlay inlai inly inli + inmost inmost inn inn + inner inner innkeeper innkeep + innocence innoc innocency innoc + innocent innoc innocents innoc + innovation innov innovator innov + inns inn innumerable innumer + inoculate inocul inordinate inordin + inprimis inprimi inquir inquir + inquire inquir inquiry inquiri + inquisition inquisit inquisitive inquisit + inroads inroad insane insan + insanie insani insatiate insati + insconce insconc inscrib inscrib + inscription inscript inscriptions inscript + inscroll inscrol inscrutable inscrut + insculp insculp insculpture insculptur + insensible insens inseparable insepar + inseparate insepar insert insert + inserted insert inset inset + inshell inshel inshipp inshipp + inside insid insinewed insinew + insinuate insinu insinuateth insinuateth + insinuating insinu insinuation insinu + insisted insist insisting insist + insisture insistur insociable insoci + insolence insol insolent insol + insomuch insomuch inspir inspir + inspiration inspir inspirations inspir + inspire inspir inspired inspir + install instal installed instal + instalment instal instance instanc + instances instanc instant instant + instantly instantli instate instat + instead instead insteeped insteep + instigate instig instigated instig + instigation instig instigations instig + instigator instig instinct instinct + instinctively instinct institute institut + institutions institut instruct instruct + instructed instruct instruction instruct + instructions instruct instructs instruct + instrument instrument instrumental instrument + instruments instrument insubstantial insubstanti + insufficience insuffici insufficiency insuffici + insult insult insulted insult + insulting insult insultment insult + insults insult insupportable insupport + insuppressive insuppress insurrection insurrect + insurrections insurrect int int + integer integ integritas integrita + integrity integr intellect intellect + intellects intellect intellectual intellectu + intelligence intellig intelligencer intelligenc + intelligencing intelligenc intelligent intellig + intelligis intelligi intelligo intelligo + intemperance intemper intemperate intemper + intend intend intended intend + intendeth intendeth intending intend + intendment intend intends intend + intenible inten intent intent + intention intent intentively intent + intents intent inter inter + intercept intercept intercepted intercept + intercepter intercept interception intercept + intercepts intercept intercession intercess + intercessors intercessor interchained interchain + interchang interchang interchange interchang + interchangeably interchang interchangement interchang + interchanging interchang interdiction interdict + interest interest interim interim + interims interim interior interior + interjections interject interjoin interjoin + interlude interlud intermingle intermingl + intermission intermiss intermissive intermiss + intermit intermit intermix intermix + intermixed intermix interpose interpos + interposer interpos interposes interpos + interpret interpret interpretation interpret + interpreted interpret interpreter interpret + interpreters interpret interprets interpret + interr interr interred inter + interrogatories interrogatori interrupt interrupt + interrupted interrupt interrupter interrupt + interruptest interruptest interruption interrupt + interrupts interrupt intertissued intertissu + intervallums intervallum interview interview + intestate intest intestine intestin + intil intil intimate intim + intimation intim intitled intitl + intituled intitul into into + intolerable intoler intoxicates intox + intreasured intreasur intreat intreat + intrench intrench intrenchant intrench + intricate intric intrinse intrins + intrinsicate intrins intrude intrud + intruder intrud intruding intrud + intrusion intrus inundation inund + inure inur inurn inurn + invade invad invades invad + invasion invas invasive invas + invectively invect invectives invect + inveigled inveigl invent invent + invented invent invention invent + inventions invent inventor inventor + inventorially inventori inventoried inventori + inventors inventor inventory inventori + inverness inver invert invert + invest invest invested invest + investing invest investments invest + inveterate inveter invincible invinc + inviolable inviol invised invis + invisible invis invitation invit + invite invit invited invit + invites invit inviting invit + invitis inviti invocate invoc + invocation invoc invoke invok + invoked invok invulnerable invulner + inward inward inwardly inwardli + inwardness inward inwards inward + ionia ionia ionian ionian + ipse ips ipswich ipswich + ira ira irae ira + iras ira ire ir + ireful ir ireland ireland + iris iri irish irish + irishman irishman irishmen irishmen + irks irk irksome irksom + iron iron irons iron + irreconcil irreconcil irrecoverable irrecover + irregular irregular irregulous irregul + irreligious irreligi irremovable irremov + irreparable irrepar irresolute irresolut + irrevocable irrevoc is is + isabel isabel isabella isabella + isbel isbel isbels isbel + iscariot iscariot ise is + ish ish isidore isidor + isis isi island island + islander island islanders island + islands island isle isl + isles isl israel israel + issu issu issue issu + issued issu issueless issueless + issues issu issuing issu + ist ist ista ista + it it italian italian + italy itali itch itch + itches itch itching itch + item item items item + iteration iter ithaca ithaca + its it itself itself + itshall itshal iv iv + ivory ivori ivy ivi + iwis iwi ix ix + j j jacet jacet + jack jack jackanapes jackanap + jacks jack jacksauce jacksauc + jackslave jackslav jacob jacob + jade jade jaded jade + jades jade jail jail + jakes jake jamany jamani + james jame jamy jami + jane jane jangled jangl + jangling jangl january januari + janus janu japhet japhet + jaquenetta jaquenetta jaques jaqu + jar jar jarring jar + jars jar jarteer jarteer + jasons jason jaunce jaunc + jauncing jaunc jaundice jaundic + jaundies jaundi jaw jaw + jawbone jawbon jaws jaw + jay jai jays jai + jc jc je je + jealous jealou jealousies jealousi + jealousy jealousi jeer jeer + jeering jeer jelly jelli + jenny jenni jeopardy jeopardi + jephtha jephtha jephthah jephthah + jerkin jerkin jerkins jerkin + jerks jerk jeronimy jeronimi + jerusalem jerusalem jeshu jeshu + jesses jess jessica jessica + jest jest jested jest + jester jester jesters jester + jesting jest jests jest + jesu jesu jesus jesu + jet jet jets jet + jew jew jewel jewel + jeweller jewel jewels jewel + jewess jewess jewish jewish + jewry jewri jews jew + jezebel jezebel jig jig + jigging jig jill jill + jills jill jingling jingl + joan joan job job + jockey jockei jocund jocund + jog jog jogging jog + john john johns john + join join joinder joinder + joined join joiner joiner + joineth joineth joins join + joint joint jointed joint + jointing joint jointly jointli + jointress jointress joints joint + jointure jointur jollity jolliti + jolly jolli jolt jolt + joltheads jolthead jordan jordan + joseph joseph joshua joshua + jot jot jour jour + jourdain jourdain journal journal + journey journei journeying journei + journeyman journeyman journeymen journeymen + journeys journei jove jove + jovem jovem jovial jovial + jowl jowl jowls jowl + joy joi joyed joi + joyful joy joyfully joyfulli + joyless joyless joyous joyou + joys joi juan juan + jud jud judas juda + judases judas jude jude + judg judg judge judg + judged judg judgement judgement + judges judg judgest judgest + judging judg judgment judgment + judgments judgment judicious judici + jug jug juggle juggl + juggled juggl juggler juggler + jugglers juggler juggling juggl + jugs jug juice juic + juiced juic jul jul + jule jule julia julia + juliet juliet julietta julietta + julio julio julius juliu + july juli jump jump + jumpeth jumpeth jumping jump + jumps jump june june + junes june junior junior + junius juniu junkets junket + juno juno jupiter jupit + jure jure jurement jurement + jurisdiction jurisdict juror juror + jurors juror jury juri + jurymen jurymen just just + justeius justeiu justest justest + justice justic justicer justic + justicers justic justices justic + justification justif justified justifi + justify justifi justle justl + justled justl justles justl + justling justl justly justli + justness just justs just + jutting jut jutty jutti + juvenal juven kam kam + kate kate kated kate + kates kate katharine katharin + katherina katherina katherine katherin + kecksies kecksi keech keech + keel keel keels keel + keen keen keenness keen + keep keep keepdown keepdown + keeper keeper keepers keeper + keepest keepest keeping keep + keeps keep keiser keiser + ken ken kendal kendal + kennel kennel kent kent + kentish kentish kentishman kentishman + kentishmen kentishmen kept kept + kerchief kerchief kerely kere + kern kern kernal kernal + kernel kernel kernels kernel + kerns kern kersey kersei + kettle kettl kettledrum kettledrum + kettledrums kettledrum key kei + keys kei kibe kibe + kibes kibe kick kick + kicked kick kickshaws kickshaw + kickshawses kickshaws kicky kicki + kid kid kidney kidnei + kikely kike kildare kildar + kill kill killed kill + killer killer killeth killeth + killing kill killingworth killingworth + kills kill kiln kiln + kimbolton kimbolton kin kin + kind kind kinder kinder + kindest kindest kindle kindl + kindled kindl kindless kindless + kindlier kindlier kindling kindl + kindly kindli kindness kind + kindnesses kind kindred kindr + kindreds kindr kinds kind + kine kine king king + kingdom kingdom kingdoms kingdom + kingly kingli kings king + kinred kinr kins kin + kinsman kinsman kinsmen kinsmen + kinswoman kinswoman kirtle kirtl + kirtles kirtl kiss kiss + kissed kiss kisses kiss + kissing kiss kitchen kitchen + kitchens kitchen kite kite + kites kite kitten kitten + kj kj kl kl + klll klll knack knack + knacks knack knapp knapp + knav knav knave knave + knaveries knaveri knavery knaveri + knaves knave knavish knavish + knead knead kneaded knead + kneading knead knee knee + kneel kneel kneeling kneel + kneels kneel knees knee + knell knell knew knew + knewest knewest knife knife + knight knight knighted knight + knighthood knighthood knighthoods knighthood + knightly knightli knights knight + knit knit knits knit + knitters knitter knitteth knitteth + knives knive knobs knob + knock knock knocking knock + knocks knock knog knog + knoll knoll knot knot + knots knot knotted knot + knotty knotti know know + knower knower knowest knowest + knowing know knowingly knowingli + knowings know knowledge knowledg + known known knows know + l l la la + laban laban label label + labell label labienus labienu + labio labio labor labor + laboring labor labors labor + labour labour laboured labour + labourer labour labourers labour + labouring labour labours labour + laboursome laboursom labras labra + labyrinth labyrinth lac lac + lace lace laced lace + lacedaemon lacedaemon laces lace + lacies laci lack lack + lackbeard lackbeard lacked lack + lackey lackei lackeying lackei + lackeys lackei lacking lack + lacks lack lad lad + ladder ladder ladders ladder + lade lade laden laden + ladies ladi lading lade + lads lad lady ladi + ladybird ladybird ladyship ladyship + ladyships ladyship laer laer + laertes laert lafeu lafeu + lag lag lagging lag + laid laid lain lain + laissez laissez lake lake + lakes lake lakin lakin + lam lam lamb lamb + lambert lambert lambkin lambkin + lambkins lambkin lambs lamb + lame lame lamely lame + lameness lame lament lament + lamentable lament lamentably lament + lamentation lament lamentations lament + lamented lament lamenting lament + lamentings lament laments lament + lames lame laming lame + lammas lamma lammastide lammastid + lamound lamound lamp lamp + lampass lampass lamps lamp + lanc lanc lancaster lancast + lance lanc lances lanc + lanceth lanceth lanch lanch + land land landed land + landing land landless landless + landlord landlord landmen landmen + lands land lane lane + lanes lane langage langag + langley langlei langton langton + language languag languageless languageless + languages languag langues langu + languish languish languished languish + languishes languish languishing languish + languishings languish languishment languish + languor languor lank lank + lantern lantern lanterns lantern + lanthorn lanthorn lap lap + lapis lapi lapland lapland + lapp lapp laps lap + lapse laps lapsed laps + lapsing laps lapwing lapw + laquais laquai larded lard + larder larder larding lard + lards lard large larg + largely larg largeness larg + larger larger largess largess + largest largest lark lark + larks lark larron larron + lartius lartiu larum larum + larums larum las la + lascivious lascivi lash lash + lass lass lasses lass + last last lasted last + lasting last lastly lastli + lasts last latch latch + latches latch late late + lated late lately late + later later latest latest + lath lath latin latin + latten latten latter latter + lattice lattic laud laud + laudable laudabl laudis laudi + laugh laugh laughable laughabl + laughed laugh laugher laugher + laughest laughest laughing laugh + laughs laugh laughter laughter + launce launc launcelot launcelot + launces launc launch launch + laund laund laundress laundress + laundry laundri laur laur + laura laura laurel laurel + laurels laurel laurence laurenc + laus lau lavache lavach + lave lave lavee lave + lavender lavend lavina lavina + lavinia lavinia lavish lavish + lavishly lavishli lavolt lavolt + lavoltas lavolta law law + lawful law lawfully lawfulli + lawless lawless lawlessly lawlessli + lawn lawn lawns lawn + lawrence lawrenc laws law + lawyer lawyer lawyers lawyer + lay lai layer layer + layest layest laying lai + lays lai lazar lazar + lazars lazar lazarus lazaru + lazy lazi lc lc + ld ld ldst ldst + le le lead lead + leaden leaden leader leader + leaders leader leadest leadest + leading lead leads lead + leaf leaf leagu leagu + league leagu leagued leagu + leaguer leaguer leagues leagu + leah leah leak leak + leaky leaki lean lean + leander leander leaner leaner + leaning lean leanness lean + leans lean leap leap + leaped leap leaping leap + leaps leap leapt leapt + lear lear learn learn + learned learn learnedly learnedli + learning learn learnings learn + learns learn learnt learnt + leas lea lease leas + leases leas leash leash + leasing leas least least + leather leather leathern leathern + leav leav leave leav + leaven leaven leavening leaven + leaver leaver leaves leav + leaving leav leavy leavi + lecher lecher lecherous lecher + lechers lecher lechery lecheri + lecon lecon lecture lectur + lectures lectur led led + leda leda leech leech + leeches leech leek leek + leeks leek leer leer + leers leer lees lee + leese lees leet leet + leets leet left left + leg leg legacies legaci + legacy legaci legate legat + legatine legatin lege lege + legerity leger leges lege + legg legg legion legion + legions legion legitimate legitim + legitimation legitim legs leg + leicester leicest leicestershire leicestershir + leiger leiger leigers leiger + leisure leisur leisurely leisur + leisures leisur leman leman + lemon lemon lena lena + lend lend lender lender + lending lend lendings lend + lends lend length length + lengthen lengthen lengthens lengthen + lengths length lenity leniti + lennox lennox lent lent + lenten lenten lentus lentu + leo leo leon leon + leonardo leonardo leonati leonati + leonato leonato leonatus leonatu + leontes leont leopard leopard + leopards leopard leper leper + leperous leper lepidus lepidu + leprosy leprosi lequel lequel + lers ler les le + less less lessen lessen + lessens lessen lesser lesser + lesson lesson lessoned lesson + lessons lesson lest lest + lestrake lestrak let let + lethargied lethargi lethargies lethargi + lethargy lethargi lethe leth + lets let lett lett + letter letter letters letter + letting let lettuce lettuc + leur leur leve leve + level level levell level + levelled level levels level + leven leven levers lever + leviathan leviathan leviathans leviathan + levied levi levies levi + levity leviti levy levi + levying levi lewd lewd + lewdly lewdli lewdness lewd + lewdsters lewdster lewis lewi + liable liabl liar liar + liars liar libbard libbard + libelling libel libels libel + liberal liber liberality liber + liberte libert liberties liberti + libertine libertin libertines libertin + liberty liberti library librari + libya libya licence licenc + licens licen license licens + licentious licenti lichas licha + licio licio lick lick + licked lick licker licker + lictors lictor lid lid + lids lid lie lie + lied li lief lief + liefest liefest liege lieg + liegeman liegeman liegemen liegemen + lien lien lies li + liest liest lieth lieth + lieu lieu lieutenant lieuten + lieutenantry lieutenantri lieutenants lieuten + lieve liev life life + lifeblood lifeblood lifeless lifeless + lifelings lifel lift lift + lifted lift lifter lifter + lifteth lifteth lifting lift + lifts lift lig lig + ligarius ligariu liggens liggen + light light lighted light + lighten lighten lightens lighten + lighter lighter lightest lightest + lightly lightli lightness light + lightning lightn lightnings lightn + lights light lik lik + like like liked like + likeliest likeliest likelihood likelihood + likelihoods likelihood likely like + likeness like liker liker + likes like likest likest + likewise likewis liking like + likings like lilies lili + lily lili lim lim + limander limand limb limb + limbeck limbeck limbecks limbeck + limber limber limbo limbo + limbs limb lime lime + limed lime limehouse limehous + limekilns limekiln limit limit + limitation limit limited limit + limits limit limn limn + limp limp limping limp + limps limp lin lin + lincoln lincoln lincolnshire lincolnshir + line line lineal lineal + lineally lineal lineament lineament + lineaments lineament lined line + linen linen linens linen + lines line ling ling + lingare lingar linger linger + lingered linger lingers linger + linguist linguist lining line + link link links link + linsey linsei linstock linstock + linta linta lion lion + lionel lionel lioness lioness + lions lion lip lip + lipp lipp lips lip + lipsbury lipsburi liquid liquid + liquor liquor liquorish liquorish + liquors liquor lirra lirra + lisbon lisbon lisp lisp + lisping lisp list list + listen listen listening listen + lists list literatured literatur + lither lither litter litter + little littl littlest littlest + liv liv live live + lived live livelier liveli + livelihood livelihood livelong livelong + lively live liver liver + liveries liveri livers liver + livery liveri lives live + livest livest liveth liveth + livia livia living live + livings live lizard lizard + lizards lizard ll ll + lll lll llous llou + lnd lnd lo lo + loa loa loach loach + load load loaden loaden + loading load loads load + loaf loaf loam loam + loan loan loath loath + loathe loath loathed loath + loather loather loathes loath + loathing loath loathly loathli + loathness loath loathsome loathsom + loathsomeness loathsom loathsomest loathsomest + loaves loav lob lob + lobbies lobbi lobby lobbi + local local lochaber lochab + lock lock locked lock + locking lock lockram lockram + locks lock locusts locust + lode lode lodg lodg + lodge lodg lodged lodg + lodgers lodger lodges lodg + lodging lodg lodgings lodg + lodovico lodovico lodowick lodowick + lofty lofti log log + logger logger loggerhead loggerhead + loggerheads loggerhead loggets logget + logic logic logs log + loins loin loiter loiter + loiterer loiter loiterers loiter + loitering loiter lolling loll + lolls loll lombardy lombardi + london london londoners london + lone lone loneliness loneli + lonely lone long long + longaville longavil longboat longboat + longed long longer longer + longest longest longeth longeth + longing long longings long + longly longli longs long + longtail longtail loo loo + loof loof look look + looked look looker looker + lookers looker lookest lookest + looking look looks look + loon loon loop loop + loos loo loose loos + loosed loos loosely loos + loosen loosen loosing loos + lop lop lopp lopp + loquitur loquitur lord lord + lorded lord lording lord + lordings lord lordliness lordli + lordly lordli lords lord + lordship lordship lordships lordship + lorenzo lorenzo lorn lorn + lorraine lorrain lorship lorship + los lo lose lose + loser loser losers loser + loses lose losest losest + loseth loseth losing lose + loss loss losses loss + lost lost lot lot + lots lot lott lott + lottery lotteri loud loud + louder louder loudly loudli + lour lour loureth loureth + louring lour louse lous + louses lous lousy lousi + lout lout louted lout + louts lout louvre louvr + lov lov love love + loved love lovedst lovedst + lovel lovel lovelier loveli + loveliness loveli lovell lovel + lovely love lover lover + lovered lover lovers lover + loves love lovest lovest + loveth loveth loving love + lovingly lovingli low low + lowe low lower lower + lowest lowest lowing low + lowliness lowli lowly lowli + lown lown lowness low + loyal loyal loyally loyal + loyalties loyalti loyalty loyalti + lozel lozel lt lt + lubber lubber lubberly lubberli + luc luc luccicos luccico + luce luce lucentio lucentio + luces luce lucetta lucetta + luciana luciana lucianus lucianu + lucifer lucif lucifier lucifi + lucilius luciliu lucina lucina + lucio lucio lucius luciu + luck luck luckier luckier + luckiest luckiest luckily luckili + luckless luckless lucky lucki + lucre lucr lucrece lucrec + lucretia lucretia lucullius luculliu + lucullus lucullu lucy luci + lud lud ludlow ludlow + lug lug lugg lugg + luggage luggag luke luke + lukewarm lukewarm lull lull + lulla lulla lullaby lullabi + lulls lull lumbert lumbert + lump lump lumpish lumpish + luna luna lunacies lunaci + lunacy lunaci lunatic lunat + lunatics lunat lunes lune + lungs lung lupercal luperc + lurch lurch lure lure + lurk lurk lurketh lurketh + lurking lurk lurks lurk + luscious lusciou lush lush + lust lust lusted lust + luster luster lustful lust + lustier lustier lustiest lustiest + lustig lustig lustihood lustihood + lustily lustili lustre lustr + lustrous lustrou lusts lust + lusty lusti lute lute + lutes lute lutestring lutestr + lutheran lutheran luxurious luxuri + luxuriously luxuri luxury luxuri + ly ly lycaonia lycaonia + lycurguses lycurgus lydia lydia + lye lye lyen lyen + lying ly lym lym + lymoges lymog lynn lynn + lysander lysand m m + ma ma maan maan + mab mab macbeth macbeth + maccabaeus maccabaeu macdonwald macdonwald + macduff macduff mace mace + macedon macedon maces mace + machiavel machiavel machination machin + machinations machin machine machin + mack mack macmorris macmorri + maculate macul maculation macul + mad mad madam madam + madame madam madams madam + madcap madcap madded mad + madding mad made made + madeira madeira madly madli + madman madman madmen madmen + madness mad madonna madonna + madrigals madrig mads mad + maecenas maecena maggot maggot + maggots maggot magic magic + magical magic magician magician + magistrate magistr magistrates magistr + magnanimity magnanim magnanimous magnanim + magni magni magnifi magnifi + magnificence magnific magnificent magnific + magnifico magnifico magnificoes magnifico + magnus magnu mahomet mahomet + mahu mahu maid maid + maiden maiden maidenhead maidenhead + maidenheads maidenhead maidenhood maidenhood + maidenhoods maidenhood maidenliest maidenliest + maidenly maidenli maidens maiden + maidhood maidhood maids maid + mail mail mailed mail + mails mail maim maim + maimed maim maims maim + main main maincourse maincours + maine main mainly mainli + mainmast mainmast mains main + maintain maintain maintained maintain + maintains maintain maintenance mainten + mais mai maison maison + majestas majesta majestee majeste + majestic majest majestical majest + majestically majest majesties majesti + majesty majesti major major + majority major mak mak + make make makeless makeless + maker maker makers maker + makes make makest makest + maketh maketh making make + makings make mal mal + mala mala maladies maladi + malady maladi malapert malapert + malcolm malcolm malcontent malcont + malcontents malcont male male + maledictions maledict malefactions malefact + malefactor malefactor malefactors malefactor + males male malevolence malevol + malevolent malevol malhecho malhecho + malice malic malicious malici + maliciously malici malign malign + malignancy malign malignant malign + malignantly malignantli malkin malkin + mall mall mallard mallard + mallet mallet mallows mallow + malmsey malmsei malt malt + maltworms maltworm malvolio malvolio + mamillius mamilliu mammering mammer + mammet mammet mammets mammet + mammock mammock man man + manacle manacl manacles manacl + manage manag managed manag + manager manag managing manag + manakin manakin manchus manchu + mandate mandat mandragora mandragora + mandrake mandrak mandrakes mandrak + mane mane manent manent + manes mane manet manet + manfully manfulli mangle mangl + mangled mangl mangles mangl + mangling mangl mangy mangi + manhood manhood manhoods manhood + manifest manifest manifested manifest + manifests manifest manifold manifold + manifoldly manifoldli manka manka + mankind mankind manlike manlik + manly manli mann mann + manna manna manner manner + mannerly mannerli manners manner + manningtree manningtre mannish mannish + manor manor manors manor + mans man mansion mansion + mansionry mansionri mansions mansion + manslaughter manslaught mantle mantl + mantled mantl mantles mantl + mantua mantua mantuan mantuan + manual manual manure manur + manured manur manus manu + many mani map map + mapp mapp maps map + mar mar marble marbl + marbled marbl marcade marcad + marcellus marcellu march march + marches march marcheth marcheth + marching march marchioness marchio + marchpane marchpan marcians marcian + marcius marciu marcus marcu + mardian mardian mare mare + mares mare marg marg + margarelon margarelon margaret margaret + marge marg margent margent + margery margeri maria maria + marian marian mariana mariana + maries mari marigold marigold + mariner marin mariners marin + maritime maritim marjoram marjoram + mark mark marked mark + market market marketable market + marketplace marketplac markets market + marking mark markman markman + marks mark marl marl + marle marl marmoset marmoset + marquess marquess marquis marqui + marr marr marriage marriag + marriages marriag married marri + marries marri marring mar + marrow marrow marrowless marrowless + marrows marrow marry marri + marrying marri mars mar + marseilles marseil marsh marsh + marshal marshal marshalsea marshalsea + marshalship marshalship mart mart + marted mart martem martem + martext martext martial martial + martin martin martino martino + martius martiu martlemas martlema + martlet martlet marts mart + martyr martyr martyrs martyr + marullus marullu marv marv + marvel marvel marvell marvel + marvellous marvel marvellously marvel + marvels marvel mary mari + mas ma masculine masculin + masham masham mask mask + masked mask masker masker + maskers masker masking mask + masks mask mason mason + masonry masonri masons mason + masque masqu masquers masquer + masques masqu masquing masqu + mass mass massacre massacr + massacres massacr masses mass + massy massi mast mast + mastcr mastcr master master + masterdom masterdom masterest masterest + masterless masterless masterly masterli + masterpiece masterpiec masters master + mastership mastership mastic mastic + mastiff mastiff mastiffs mastiff + masts mast match match + matches match matcheth matcheth + matching match matchless matchless + mate mate mated mate + mater mater material materi + mates mate mathematics mathemat + matin matin matron matron + matrons matron matter matter + matters matter matthew matthew + mattock mattock mattress mattress + mature matur maturity matur + maud maud maudlin maudlin + maugre maugr maul maul + maund maund mauri mauri + mauritania mauritania mauvais mauvai + maw maw maws maw + maxim maxim may mai + mayday maydai mayest mayest + mayor mayor maypole maypol + mayst mayst maz maz + maze maze mazed maze + mazes maze mazzard mazzard + me me meacock meacock + mead mead meadow meadow + meadows meadow meads mead + meagre meagr meal meal + meals meal mealy meali + mean mean meanders meander + meaner meaner meanest meanest + meaneth meaneth meaning mean + meanings mean meanly meanli + means mean meant meant + meantime meantim meanwhile meanwhil + measles measl measur measur + measurable measur measure measur + measured measur measureless measureless + measures measur measuring measur + meat meat meats meat + mechanic mechan mechanical mechan + mechanicals mechan mechanics mechan + mechante mechant med med + medal medal meddle meddl + meddler meddler meddling meddl + mede mede medea medea + media media mediation mediat + mediators mediat medice medic + medicinal medicin medicine medicin + medicines medicin meditate medit + meditates medit meditating medit + meditation medit meditations medit + mediterranean mediterranean mediterraneum mediterraneum + medlar medlar medlars medlar + meed meed meeds meed + meek meek meekly meekli + meekness meek meet meet + meeter meeter meetest meetest + meeting meet meetings meet + meetly meetli meetness meet + meets meet meg meg + mehercle mehercl meilleur meilleur + meiny meini meisen meisen + melancholies melancholi melancholy melancholi + melford melford mell mell + mellifluous melliflu mellow mellow + mellowing mellow melodious melodi + melody melodi melt melt + melted melt melteth melteth + melting melt melts melt + melun melun member member + members member memento memento + memorable memor memorandums memorandum + memorial memori memorials memori + memories memori memoriz memoriz + memorize memor memory memori + memphis memphi men men + menac menac menace menac + menaces menac menaphon menaphon + menas mena mend mend + mended mend mender mender + mending mend mends mend + menecrates menecr menelaus menelau + menenius meneniu mental mental + menteith menteith mention mention + mentis menti menton menton + mephostophilus mephostophilu mer mer + mercatante mercatant mercatio mercatio + mercenaries mercenari mercenary mercenari + mercer mercer merchandise merchandis + merchandized merchand merchant merchant + merchants merchant mercies merci + merciful merci mercifully mercifulli + merciless merciless mercurial mercuri + mercuries mercuri mercury mercuri + mercutio mercutio mercy merci + mere mere mered mere + merely mere merest merest + meridian meridian merit merit + merited merit meritorious meritori + merits merit merlin merlin + mermaid mermaid mermaids mermaid + merops merop merrier merrier + merriest merriest merrily merrili + merriman merriman merriment merriment + merriments merriment merriness merri + merry merri mervailous mervail + mes me mesh mesh + meshes mesh mesopotamia mesopotamia + mess mess message messag + messages messag messala messala + messaline messalin messenger messeng + messengers messeng messes mess + messina messina met met + metal metal metals metal + metamorphis metamorphi metamorphoses metamorphos + metaphor metaphor metaphysical metaphys + metaphysics metaphys mete mete + metellus metellu meteor meteor + meteors meteor meteyard meteyard + metheglin metheglin metheglins metheglin + methink methink methinks methink + method method methods method + methought methought methoughts methought + metre metr metres metr + metropolis metropoli mette mett + mettle mettl mettled mettl + meus meu mew mew + mewed mew mewling mewl + mexico mexico mi mi + mice mice michael michael + michaelmas michaelma micher micher + miching mich mickle mickl + microcosm microcosm mid mid + midas mida middest middest + middle middl middleham middleham + midnight midnight midriff midriff + midst midst midsummer midsumm + midway midwai midwife midwif + midwives midwiv mienne mienn + might might mightful might + mightier mightier mightiest mightiest + mightily mightili mightiness mighti + mightst mightst mighty mighti + milan milan milch milch + mild mild milder milder + mildest mildest mildew mildew + mildews mildew mildly mildli + mildness mild mile mile + miles mile milford milford + militarist militarist military militari + milk milk milking milk + milkmaid milkmaid milks milk + milksops milksop milky milki + mill mill mille mill + miller miller milliner millin + million million millioned million + millions million mills mill + millstones millston milo milo + mimic mimic minc minc + mince minc minces minc + mincing minc mind mind + minded mind minding mind + mindless mindless minds mind + mine mine mineral miner + minerals miner minerva minerva + mines mine mingle mingl + mingled mingl mingling mingl + minikin minikin minim minim + minime minim minimo minimo + minimus minimu mining mine + minion minion minions minion + minist minist minister minist + ministers minist ministration ministr + minnow minnow minnows minnow + minola minola minority minor + minos mino minotaurs minotaur + minstrel minstrel minstrels minstrel + minstrelsy minstrelsi mint mint + mints mint minute minut + minutely minut minutes minut + minx minx mio mio + mir mir mirable mirabl + miracle miracl miracles miracl + miraculous miracul miranda miranda + mire mire mirror mirror + mirrors mirror mirth mirth + mirthful mirth miry miri + mis mi misadventur misadventur + misadventure misadventur misanthropos misanthropo + misapplied misappli misbecame misbecam + misbecom misbecom misbecome misbecom + misbegot misbegot misbegotten misbegotten + misbeliever misbeliev misbelieving misbeliev + misbhav misbhav miscall miscal + miscalled miscal miscarried miscarri + miscarries miscarri miscarry miscarri + miscarrying miscarri mischance mischanc + mischances mischanc mischief mischief + mischiefs mischief mischievous mischiev + misconceived misconceiv misconst misconst + misconster misconst misconstruction misconstruct + misconstrued misconstru misconstrues misconstru + miscreant miscreant miscreate miscreat + misdeed misde misdeeds misde + misdemean misdemean misdemeanours misdemeanour + misdoubt misdoubt misdoubteth misdoubteth + misdoubts misdoubt misenum misenum + miser miser miserable miser + miserably miser misericorde misericord + miseries miseri misers miser + misery miseri misfortune misfortun + misfortunes misfortun misgive misgiv + misgives misgiv misgiving misgiv + misgoverned misgovern misgovernment misgovern + misgraffed misgraf misguide misguid + mishap mishap mishaps mishap + misheard misheard misinterpret misinterpret + mislead mislead misleader mislead + misleaders mislead misleading mislead + misled misl mislike mislik + misord misord misplac misplac + misplaced misplac misplaces misplac + mispris mispri misprised mispris + misprision mispris misprizing mispriz + misproud misproud misquote misquot + misreport misreport miss miss + missed miss misses miss + misshap misshap misshapen misshapen + missheathed missheath missing miss + missingly missingli missions mission + missive missiv missives missiv + misspoke misspok mist mist + mista mista mistak mistak + mistake mistak mistaken mistaken + mistakes mistak mistaketh mistaketh + mistaking mistak mistakings mistak + mistemp mistemp mistempered mistemp + misterm misterm mistful mist + misthink misthink misthought misthought + mistletoe mistleto mistook mistook + mistreadings mistread mistress mistress + mistresses mistress mistresss mistresss + mistriship mistriship mistrust mistrust + mistrusted mistrust mistrustful mistrust + mistrusting mistrust mists mist + misty misti misus misu + misuse misus misused misus + misuses misus mites mite + mithridates mithrid mitigate mitig + mitigation mitig mix mix + mixed mix mixture mixtur + mixtures mixtur mm mm + mnd mnd moan moan + moans moan moat moat + moated moat mobled mobl + mock mock mockable mockabl + mocker mocker mockeries mockeri + mockers mocker mockery mockeri + mocking mock mocks mock + mockvater mockvat mockwater mockwat + model model modena modena + moderate moder moderately moder + moderation moder modern modern + modest modest modesties modesti + modestly modestli modesty modesti + modicums modicum modo modo + module modul moe moe + moi moi moiety moieti + moist moist moisten moisten + moisture moistur moldwarp moldwarp + mole mole molehill molehil + moles mole molest molest + molestation molest mollification mollif + mollis molli molten molten + molto molto mome mome + moment moment momentary momentari + moming mome mon mon + monachum monachum monarch monarch + monarchies monarchi monarchize monarch + monarcho monarcho monarchs monarch + monarchy monarchi monast monast + monastery monasteri monastic monast + monday mondai monde mond + money monei moneys monei + mong mong monger monger + mongers monger monging mong + mongrel mongrel mongrels mongrel + mongst mongst monk monk + monkey monkei monkeys monkei + monks monk monmouth monmouth + monopoly monopoli mons mon + monsieur monsieur monsieurs monsieur + monster monster monsters monster + monstrous monstrou monstrously monstrous + monstrousness monstrous monstruosity monstruos + montacute montacut montage montag + montague montagu montagues montagu + montano montano montant montant + montez montez montferrat montferrat + montgomery montgomeri month month + monthly monthli months month + montjoy montjoi monument monument + monumental monument monuments monument + mood mood moods mood + moody moodi moon moon + moonbeams moonbeam moonish moonish + moonlight moonlight moons moon + moonshine moonshin moonshines moonshin + moor moor moorfields moorfield + moors moor moorship moorship + mop mop mope mope + moping mope mopping mop + mopsa mopsa moral moral + moraler moral morality moral + moralize moral mordake mordak + more more moreover moreov + mores more morgan morgan + mori mori morisco morisco + morn morn morning morn + mornings morn morocco morocco + morris morri morrow morrow + morrows morrow morsel morsel + morsels morsel mort mort + mortal mortal mortality mortal + mortally mortal mortals mortal + mortar mortar mortgaged mortgag + mortified mortifi mortifying mortifi + mortimer mortim mortimers mortim + mortis morti mortise mortis + morton morton mose mose + moss moss mossgrown mossgrown + most most mote mote + moth moth mother mother + mothers mother moths moth + motion motion motionless motionless + motions motion motive motiv + motives motiv motley motlei + mots mot mought mought + mould mould moulded mould + mouldeth mouldeth moulds mould + mouldy mouldi moult moult + moulten moulten mounch mounch + mounseur mounseur mounsieur mounsieur + mount mount mountain mountain + mountaineer mountain mountaineers mountain + mountainous mountain mountains mountain + mountant mountant mountanto mountanto + mountebank mountebank mountebanks mountebank + mounted mount mounteth mounteth + mounting mount mounts mount + mourn mourn mourned mourn + mourner mourner mourners mourner + mournful mourn mournfully mournfulli + mourning mourn mourningly mourningli + mournings mourn mourns mourn + mous mou mouse mous + mousetrap mousetrap mousing mous + mouth mouth mouthed mouth + mouths mouth mov mov + movables movabl move move + moveable moveabl moveables moveabl + moved move mover mover + movers mover moves move + moveth moveth moving move + movingly movingli movousus movousu + mow mow mowbray mowbrai + mower mower mowing mow + mows mow moy moi + moys moi moyses moys + mrs mr much much + muck muck mud mud + mudded mud muddied muddi + muddy muddi muffins muffin + muffl muffl muffle muffl + muffled muffl muffler muffler + muffling muffl mugger mugger + mugs mug mulberries mulberri + mulberry mulberri mule mule + mules mule muleteers mulet + mulier mulier mulieres mulier + muliteus muliteu mull mull + mulmutius mulmutiu multiplied multipli + multiply multipli multiplying multipli + multipotent multipot multitude multitud + multitudes multitud multitudinous multitudin + mum mum mumble mumbl + mumbling mumbl mummers mummer + mummy mummi mun mun + munch munch muniments muniment + munition munit murd murd + murder murder murdered murder + murderer murder murderers murder + murdering murder murderous murder + murders murder mure mure + murk murk murkiest murkiest + murky murki murmur murmur + murmurers murmur murmuring murmur + murrain murrain murray murrai + murrion murrion murther murther + murtherer murther murtherers murther + murthering murther murtherous murther + murthers murther mus mu + muscadel muscadel muscovites muscovit + muscovits muscovit muscovy muscovi + muse muse muses muse + mush mush mushrooms mushroom + music music musical music + musician musician musicians musician + musics music musing muse + musings muse musk musk + musket musket muskets musket + muskos musko muss muss + mussel mussel mussels mussel + must must mustachio mustachio + mustard mustard mustardseed mustardse + muster muster mustering muster + musters muster musty musti + mutability mutabl mutable mutabl + mutation mutat mutations mutat + mute mute mutes mute + mutest mutest mutine mutin + mutineer mutin mutineers mutin + mutines mutin mutinies mutini + mutinous mutin mutiny mutini + mutius mutiu mutter mutter + muttered mutter mutton mutton + muttons mutton mutual mutual + mutualities mutual mutually mutual + muzzl muzzl muzzle muzzl + muzzled muzzl mv mv + mww mww my my + mynheers mynheer myrmidon myrmidon + myrmidons myrmidon myrtle myrtl + myself myself myst myst + mysteries mysteri mystery mysteri + n n nag nag + nage nage nags nag + naiads naiad nail nail + nails nail nak nak + naked nake nakedness naked + nal nal nam nam + name name named name + nameless nameless namely name + names name namest namest + naming name nan nan + nance nanc nap nap + nape nape napes nape + napkin napkin napkins napkin + naples napl napless napless + napping nap naps nap + narbon narbon narcissus narcissu + narines narin narrow narrow + narrowly narrowli naso naso + nasty nasti nathaniel nathaniel + natifs natif nation nation + nations nation native nativ + nativity nativ natur natur + natural natur naturalize natur + naturally natur nature natur + natured natur natures natur + natus natu naught naught + naughtily naughtili naughty naughti + navarre navarr nave nave + navel navel navigation navig + navy navi nay nai + nayward nayward nayword nayword + nazarite nazarit ne ne + neaf neaf neamnoins neamnoin + neanmoins neanmoin neapolitan neapolitan + neapolitans neapolitan near near + nearer nearer nearest nearest + nearly nearli nearness near + neat neat neatly neatli + neb neb nebour nebour + nebuchadnezzar nebuchadnezzar nec nec + necessaries necessari necessarily necessarili + necessary necessari necessitied necess + necessities necess necessity necess + neck neck necklace necklac + necks neck nectar nectar + ned ned nedar nedar + need need needed need + needer needer needful need + needfull needful needing need + needle needl needles needl + needless needless needly needli + needs need needy needi + neer neer neeze neez + nefas nefa negation negat + negative neg negatives neg + neglect neglect neglected neglect + neglecting neglect neglectingly neglectingli + neglection neglect negligence neglig + negligent neglig negotiate negoti + negotiations negoti negro negro + neigh neigh neighbors neighbor + neighbour neighbour neighbourhood neighbourhood + neighbouring neighbour neighbourly neighbourli + neighbours neighbour neighing neigh + neighs neigh neither neither + nell nell nemean nemean + nemesis nemesi neoptolemus neoptolemu + nephew nephew nephews nephew + neptune neptun ner ner + nereides nereid nerissa nerissa + nero nero neroes nero + ners ner nerve nerv + nerves nerv nervii nervii + nervy nervi nessus nessu + nest nest nestor nestor + nests nest net net + nether nether netherlands netherland + nets net nettle nettl + nettled nettl nettles nettl + neuter neuter neutral neutral + nev nev never never + nevil nevil nevils nevil + new new newborn newborn + newer newer newest newest + newgate newgat newly newli + newness new news new + newsmongers newsmong newt newt + newts newt next next + nibbling nibbl nicanor nicanor + nice nice nicely nice + niceness nice nicer nicer + nicety niceti nicholas nichola + nick nick nickname nicknam + nicks nick niece niec + nieces niec niggard niggard + niggarding niggard niggardly niggardli + nigh nigh night night + nightcap nightcap nightcaps nightcap + nighted night nightgown nightgown + nightingale nightingal nightingales nightingal + nightly nightli nightmare nightmar + nights night nightwork nightwork + nihil nihil nile nile + nill nill nilus nilu + nimble nimbl nimbleness nimbl + nimbler nimbler nimbly nimbl + nine nine nineteen nineteen + ning ning ningly ningli + ninny ninni ninth ninth + ninus ninu niobe niob + niobes niob nip nip + nipp nipp nipping nip + nipple nippl nips nip + nit nit nly nly + nnight nnight nnights nnight + no no noah noah + nob nob nobility nobil + nobis nobi noble nobl + nobleman nobleman noblemen noblemen + nobleness nobl nobler nobler + nobles nobl noblesse nobless + noblest noblest nobly nobli + nobody nobodi noces noce + nod nod nodded nod + nodding nod noddle noddl + noddles noddl noddy noddi + nods nod noes noe + nointed noint nois noi + noise nois noiseless noiseless + noisemaker noisemak noises nois + noisome noisom nole nole + nominate nomin nominated nomin + nomination nomin nominativo nominativo + non non nonage nonag + nonce nonc none none + nonino nonino nonny nonni + nonpareil nonpareil nonsuits nonsuit + nony noni nook nook + nooks nook noon noon + noonday noondai noontide noontid + nor nor norbery norberi + norfolk norfolk norman norman + normandy normandi normans norman + north north northampton northampton + northamptonshire northamptonshir northerly northerli + northern northern northgate northgat + northumberland northumberland northumberlands northumberland + northward northward norway norwai + norways norwai norwegian norwegian + norweyan norweyan nos no + nose nose nosegays nosegai + noseless noseless noses nose + noster noster nostra nostra + nostril nostril nostrils nostril + not not notable notabl + notably notabl notary notari + notch notch note note + notebook notebook noted note + notedly notedli notes note + notest notest noteworthy noteworthi + nothing noth nothings noth + notice notic notify notifi + noting note notion notion + notorious notori notoriously notori + notre notr notwithstanding notwithstand + nought nought noun noun + nouns noun nourish nourish + nourished nourish nourisher nourish + nourishes nourish nourisheth nourisheth + nourishing nourish nourishment nourish + nous nou novel novel + novelties novelti novelty novelti + noverbs noverb novi novi + novice novic novices novic + novum novum now now + nowhere nowher noyance noyanc + ns ns nt nt + nubibus nubibu numa numa + numb numb number number + numbered number numbering number + numberless numberless numbers number + numbness numb nun nun + nuncio nuncio nuncle nuncl + nunnery nunneri nuns nun + nuntius nuntiu nuptial nuptial + nurs nur nurse nurs + nursed nurs nurser nurser + nursery nurseri nurses nurs + nurseth nurseth nursh nursh + nursing nurs nurtur nurtur + nurture nurtur nut nut + nuthook nuthook nutmeg nutmeg + nutmegs nutmeg nutriment nutriment + nuts nut nutshell nutshel + ny ny nym nym + nymph nymph nymphs nymph + o o oak oak + oaken oaken oaks oak + oared oar oars oar + oatcake oatcak oaten oaten + oath oath oathable oathabl + oaths oath oats oat + ob ob obduracy obduraci + obdurate obdur obedience obedi + obedient obedi obeisance obeis + oberon oberon obey obei + obeyed obei obeying obei + obeys obei obidicut obidicut + object object objected object + objections object objects object + oblation oblat oblations oblat + obligation oblig obligations oblig + obliged oblig oblique obliqu + oblivion oblivion oblivious oblivi + obloquy obloqui obscene obscen + obscenely obscen obscur obscur + obscure obscur obscured obscur + obscurely obscur obscures obscur + obscuring obscur obscurity obscur + obsequies obsequi obsequious obsequi + obsequiously obsequi observ observ + observance observ observances observ + observancy observ observant observ + observants observ observation observ + observe observ observed observ + observer observ observers observ + observing observ observingly observingli + obsque obsqu obstacle obstacl + obstacles obstacl obstinacy obstinaci + obstinate obstin obstinately obstin + obstruct obstruct obstruction obstruct + obstructions obstruct obtain obtain + obtained obtain obtaining obtain + occasion occas occasions occas + occident occid occidental occident + occulted occult occupat occupat + occupation occup occupations occup + occupied occupi occupies occupi + occupy occupi occurrence occurr + occurrences occurr occurrents occurr + ocean ocean oceans ocean + octavia octavia octavius octaviu + ocular ocular od od + odd odd oddest oddest + oddly oddli odds odd + ode od odes od + odious odiou odoriferous odorifer + odorous odor odour odour + odours odour ods od + oeillades oeillad oes oe + oeuvres oeuvr of of + ofephesus ofephesu off off + offal offal offence offenc + offenceful offenc offences offenc + offend offend offended offend + offendendo offendendo offender offend + offenders offend offendeth offendeth + offending offend offendress offendress + offends offend offense offens + offenseless offenseless offenses offens + offensive offens offer offer + offered offer offering offer + offerings offer offers offer + offert offert offic offic + office offic officed offic + officer offic officers offic + offices offic official offici + officious offici offspring offspr + oft oft often often + oftener often oftentimes oftentim + oh oh oil oil + oils oil oily oili + old old oldcastle oldcastl + olden olden older older + oldest oldest oldness old + olive oliv oliver oliv + olivers oliv olives oliv + olivia olivia olympian olympian + olympus olympu oman oman + omans oman omen omen + ominous omin omission omiss + omit omit omittance omitt + omitted omit omitting omit + omne omn omnes omn + omnipotent omnipot on on + once onc one on + ones on oneyers oney + ongles ongl onion onion + onions onion only onli + onset onset onward onward + onwards onward oo oo + ooze ooz oozes ooz + oozy oozi op op + opal opal ope op + open open opener open + opening open openly openli + openness open opens open + operant oper operate oper + operation oper operations oper + operative oper opes op + oph oph ophelia ophelia + opinion opinion opinions opinion + opportune opportun opportunities opportun + opportunity opportun oppos oppo + oppose oppos opposed oppos + opposeless opposeless opposer oppos + opposers oppos opposes oppos + opposing oppos opposite opposit + opposites opposit opposition opposit + oppositions opposit oppress oppress + oppressed oppress oppresses oppress + oppresseth oppresseth oppressing oppress + oppression oppress oppressor oppressor + opprest opprest opprobriously opprobri + oppugnancy oppugn opulency opul + opulent opul or or + oracle oracl oracles oracl + orange orang oration orat + orator orat orators orat + oratory oratori orb orb + orbed orb orbs orb + orchard orchard orchards orchard + ord ord ordain ordain + ordained ordain ordaining ordain + order order ordered order + ordering order orderless orderless + orderly orderli orders order + ordinance ordin ordinant ordin + ordinaries ordinari ordinary ordinari + ordnance ordnanc ords ord + ordure ordur ore or + organ organ organs organ + orgillous orgil orient orient + orifex orifex origin origin + original origin orisons orison + ork ork orlando orlando + orld orld orleans orlean + ornament ornament ornaments ornament + orodes orod orphan orphan + orphans orphan orpheus orpheu + orsino orsino ort ort + orthography orthographi orts ort + oscorbidulchos oscorbidulcho osier osier + osiers osier osprey osprei + osr osr osric osric + ossa ossa ost ost + ostent ostent ostentare ostentar + ostentation ostent ostents ostent + ostler ostler ostlers ostler + ostrich ostrich osw osw + oswald oswald othello othello + other other othergates otherg + others other otherwhere otherwher + otherwhiles otherwhil otherwise otherwis + otter otter ottoman ottoman + ottomites ottomit oublie oubli + ouches ouch ought ought + oui oui ounce ounc + ounces ounc ouphes ouph + our our ours our + ourself ourself ourselves ourselv + ousel ousel out out + outbids outbid outbrave outbrav + outbraves outbrav outbreak outbreak + outcast outcast outcries outcri + outcry outcri outdar outdar + outdare outdar outdares outdar + outdone outdon outfac outfac + outface outfac outfaced outfac + outfacing outfac outfly outfli + outfrown outfrown outgo outgo + outgoes outgo outgrown outgrown + outjest outjest outlaw outlaw + outlawry outlawri outlaws outlaw + outliv outliv outlive outliv + outlives outliv outliving outliv + outlook outlook outlustres outlustr + outpriz outpriz outrage outrag + outrageous outrag outrages outrag + outran outran outright outright + outroar outroar outrun outrun + outrunning outrun outruns outrun + outscold outscold outscorn outscorn + outsell outsel outsells outsel + outside outsid outsides outsid + outspeaks outspeak outsport outsport + outstare outstar outstay outstai + outstood outstood outstretch outstretch + outstretched outstretch outstrike outstrik + outstrip outstrip outstripped outstrip + outswear outswear outvenoms outvenom + outward outward outwardly outwardli + outwards outward outwear outwear + outweighs outweigh outwent outwent + outworn outworn outworths outworth + oven oven over over + overawe overaw overbear overbear + overblown overblown overboard overboard + overbold overbold overborne overborn + overbulk overbulk overbuys overbui + overcame overcam overcast overcast + overcharg overcharg overcharged overcharg + overcome overcom overcomes overcom + overdone overdon overearnest overearnest + overfar overfar overflow overflow + overflown overflown overglance overgl + overgo overgo overgone overgon + overgorg overgorg overgrown overgrown + overhead overhead overhear overhear + overheard overheard overhold overhold + overjoyed overjoi overkind overkind + overland overland overleather overleath + overlive overl overlook overlook + overlooking overlook overlooks overlook + overmaster overmast overmounting overmount + overmuch overmuch overpass overpass + overpeer overp overpeering overp + overplus overplu overrul overrul + overrun overrun overscutch overscutch + overset overset overshades overshad + overshine overshin overshines overshin + overshot overshot oversights oversight + overspread overspread overstain overstain + overswear overswear overt overt + overta overta overtake overtak + overtaketh overtaketh overthrow overthrow + overthrown overthrown overthrows overthrow + overtook overtook overtopp overtopp + overture overtur overturn overturn + overwatch overwatch overween overween + overweening overween overweigh overweigh + overwhelm overwhelm overwhelming overwhelm + overworn overworn ovid ovid + ovidius ovidiu ow ow + owe ow owed ow + owedst owedst owen owen + owes ow owest owest + oweth oweth owing ow + owl owl owls owl + own own owner owner + owners owner owning own + owns own owy owi + ox ox oxen oxen + oxford oxford oxfordshire oxfordshir + oxlips oxlip oyes oy + oyster oyster p p + pabble pabbl pabylon pabylon + pac pac pace pace + paced pace paces pace + pacified pacifi pacify pacifi + pacing pace pack pack + packet packet packets packet + packhorses packhors packing pack + packings pack packs pack + packthread packthread pacorus pacoru + paction paction pad pad + paddle paddl paddling paddl + paddock paddock padua padua + pagan pagan pagans pagan + page page pageant pageant + pageants pageant pages page + pah pah paid paid + pail pail pailfuls pail + pails pail pain pain + pained pain painful pain + painfully painfulli pains pain + paint paint painted paint + painter painter painting paint + paintings paint paints paint + pair pair paired pair + pairs pair pajock pajock + pal pal palabras palabra + palace palac palaces palac + palamedes palamed palate palat + palates palat palatine palatin + palating palat pale pale + paled pale paleness pale + paler paler pales pale + palestine palestin palfrey palfrei + palfreys palfrei palisadoes palisado + pall pall pallabris pallabri + pallas palla pallets pallet + palm palm palmer palmer + palmers palmer palms palm + palmy palmi palpable palpabl + palsied palsi palsies palsi + palsy palsi palt palt + palter palter paltry paltri + paly pali pamp pamp + pamper pamper pamphlets pamphlet + pan pan pancackes pancack + pancake pancak pancakes pancak + pandar pandar pandars pandar + pandarus pandaru pander pander + panderly panderli panders pander + pandulph pandulph panel panel + pang pang panging pang + pangs pang pannier pannier + pannonians pannonian pansa pansa + pansies pansi pant pant + pantaloon pantaloon panted pant + pantheon pantheon panther panther + panthino panthino panting pant + pantingly pantingli pantler pantler + pantry pantri pants pant + pap pap papal papal + paper paper papers paper + paphlagonia paphlagonia paphos papho + papist papist paps pap + par par parable parabl + paracelsus paracelsu paradise paradis + paradox paradox paradoxes paradox + paragon paragon paragons paragon + parallel parallel parallels parallel + paramour paramour paramours paramour + parapets parapet paraquito paraquito + parasite parasit parasites parasit + parca parca parcel parcel + parcell parcel parcels parcel + parch parch parched parch + parching parch parchment parchment + pard pard pardon pardon + pardona pardona pardoned pardon + pardoner pardon pardoning pardon + pardonne pardonn pardonner pardonn + pardonnez pardonnez pardons pardon + pare pare pared pare + parel parel parent parent + parentage parentag parents parent + parfect parfect paring pare + parings pare paris pari + parish parish parishioners parishion + parisians parisian paritors paritor + park park parks park + parle parl parler parler + parles parl parley parlei + parlez parlez parliament parliament + parlors parlor parlour parlour + parlous parlou parmacity parmac + parolles parol parricide parricid + parricides parricid parrot parrot + parrots parrot parsley parslei + parson parson part part + partake partak partaken partaken + partaker partak partakers partak + parted part parthia parthia + parthian parthian parthians parthian + parti parti partial partial + partialize partial partially partial + participate particip participation particip + particle particl particular particular + particularities particular particularize particular + particularly particularli particulars particular + parties parti parting part + partisan partisan partisans partisan + partition partit partizan partizan + partlet partlet partly partli + partner partner partners partner + partridge partridg parts part + party parti pas pa + pash pash pashed pash + pashful pash pass pass + passable passabl passado passado + passage passag passages passag + passant passant passed pass + passenger passeng passengers passeng + passes pass passeth passeth + passing pass passio passio + passion passion passionate passion + passioning passion passions passion + passive passiv passport passport + passy passi past past + paste past pasterns pastern + pasties pasti pastime pastim + pastimes pastim pastoral pastor + pastorals pastor pastors pastor + pastry pastri pasture pastur + pastures pastur pasty pasti + pat pat patay patai + patch patch patchery patcheri + patches patch pate pate + pated pate patent patent + patents patent paternal patern + pates pate path path + pathetical pathet paths path + pathway pathwai pathways pathwai + patience patienc patient patient + patiently patient patients patient + patines patin patrician patrician + patricians patrician patrick patrick + patrimony patrimoni patroclus patroclu + patron patron patronage patronag + patroness patro patrons patron + patrum patrum patter patter + pattern pattern patterns pattern + pattle pattl pauca pauca + paucas pauca paul paul + paulina paulina paunch paunch + paunches paunch pause paus + pauser pauser pauses paus + pausingly pausingli pauvres pauvr + pav pav paved pave + pavement pavement pavilion pavilion + pavilions pavilion pavin pavin + paw paw pawn pawn + pawns pawn paws paw + pax pax pay pai + payest payest paying pai + payment payment payments payment + pays pai paysan paysan + paysans paysan pe pe + peace peac peaceable peaceabl + peaceably peaceabl peaceful peac + peacemakers peacemak peaces peac + peach peach peaches peach + peacock peacock peacocks peacock + peak peak peaking peak + peal peal peals peal + pear pear peard peard + pearl pearl pearls pearl + pears pear peas pea + peasant peasant peasantry peasantri + peasants peasant peascod peascod + pease peas peaseblossom peaseblossom + peat peat peaten peaten + peating peat pebble pebbl + pebbled pebbl pebbles pebbl + peck peck pecks peck + peculiar peculiar pecus pecu + pedant pedant pedantical pedant + pedascule pedascul pede pede + pedestal pedest pedigree pedigre + pedlar pedlar pedlars pedlar + pedro pedro peds ped + peel peel peep peep + peeped peep peeping peep + peeps peep peer peer + peereth peereth peering peer + peerless peerless peers peer + peesel peesel peevish peevish + peevishly peevishli peflur peflur + peg peg pegasus pegasu + pegs peg peise peis + peised peis peize peiz + pelf pelf pelican pelican + pelion pelion pell pell + pella pella pelleted pellet + peloponnesus peloponnesu pelt pelt + pelting pelt pembroke pembrok + pen pen penalties penalti + penalty penalti penance penanc + pence penc pencil pencil + pencill pencil pencils pencil + pendant pendant pendent pendent + pendragon pendragon pendulous pendul + penelope penelop penetrable penetr + penetrate penetr penetrative penetr + penitence penit penitent penit + penitential penitenti penitently penit + penitents penit penker penker + penknife penknif penn penn + penned pen penning pen + pennons pennon penny penni + pennyworth pennyworth pennyworths pennyworth + pens pen pense pens + pension pension pensioners pension + pensive pensiv pensived pensiv + pensively pensiv pent pent + pentecost pentecost penthesilea penthesilea + penthouse penthous penurious penuri + penury penuri peopl peopl + people peopl peopled peopl + peoples peopl pepin pepin + pepper pepper peppercorn peppercorn + peppered pepper per per + peradventure peradventur peradventures peradventur + perceiv perceiv perceive perceiv + perceived perceiv perceives perceiv + perceiveth perceiveth perch perch + perchance perchanc percies perci + percussion percuss percy perci + perdie perdi perdita perdita + perdition perdit perdonato perdonato + perdu perdu perdurable perdur + perdurably perdur perdy perdi + pere pere peregrinate peregrin + peremptorily peremptorili peremptory peremptori + perfect perfect perfected perfect + perfecter perfect perfectest perfectest + perfection perfect perfections perfect + perfectly perfectli perfectness perfect + perfidious perfidi perfidiously perfidi + perforce perforc perform perform + performance perform performances perform + performed perform performer perform + performers perform performing perform + performs perform perfum perfum + perfume perfum perfumed perfum + perfumer perfum perfumes perfum + perge perg perhaps perhap + periapts periapt perigort perigort + perigouna perigouna peril peril + perilous peril perils peril + period period periods period + perish perish perished perish + perishest perishest perisheth perisheth + perishing perish periwig periwig + perjur perjur perjure perjur + perjured perjur perjuries perjuri + perjury perjuri perk perk + perkes perk permafoy permafoi + permanent perman permission permiss + permissive permiss permit permit + permitted permit pernicious pernici + perniciously pernici peroration peror + perpend perpend perpendicular perpendicular + perpendicularly perpendicularli perpetual perpetu + perpetually perpetu perpetuity perpetu + perplex perplex perplexed perplex + perplexity perplex pers per + persecuted persecut persecutions persecut + persecutor persecutor perseus perseu + persever persev perseverance persever + persevers persev persia persia + persian persian persist persist + persisted persist persistency persist + persistive persist persists persist + person person personae persona + personage personag personages personag + personal person personally person + personate person personated person + personates person personating person + persons person perspective perspect + perspectively perspect perspectives perspect + perspicuous perspicu persuade persuad + persuaded persuad persuades persuad + persuading persuad persuasion persuas + persuasions persuas pert pert + pertain pertain pertaining pertain + pertains pertain pertaunt pertaunt + pertinent pertin pertly pertli + perturb perturb perturbation perturb + perturbations perturb perturbed perturb + perus peru perusal perus + peruse perus perused perus + perusing perus perverse pervers + perversely pervers perverseness pervers + pervert pervert perverted pervert + peseech peseech pest pest + pester pester pestiferous pestifer + pestilence pestil pestilent pestil + pet pet petar petar + peter peter petit petit + petition petit petitionary petitionari + petitioner petition petitioners petition + petitions petit peto peto + petrarch petrarch petruchio petruchio + petter petter petticoat petticoat + petticoats petticoat pettiness petti + pettish pettish pettitoes pettito + petty petti peu peu + pew pew pewter pewter + pewterer pewter phaethon phaethon + phaeton phaeton phantasime phantasim + phantasimes phantasim phantasma phantasma + pharamond pharamond pharaoh pharaoh + pharsalia pharsalia pheasant pheasant + pheazar pheazar phebe phebe + phebes phebe pheebus pheebu + pheeze pheez phibbus phibbu + philadelphos philadelpho philario philario + philarmonus philarmonu philemon philemon + philip philip philippan philippan + philippe philipp philippi philippi + phillida phillida philo philo + philomel philomel philomela philomela + philosopher philosoph philosophers philosoph + philosophical philosoph philosophy philosophi + philostrate philostr philotus philotu + phlegmatic phlegmat phoebe phoeb + phoebus phoebu phoenicia phoenicia + phoenicians phoenician phoenix phoenix + phorbus phorbu photinus photinu + phrase phrase phraseless phraseless + phrases phrase phrygia phrygia + phrygian phrygian phrynia phrynia + physic physic physical physic + physician physician physicians physician + physics physic pia pia + pibble pibbl pible pibl + picardy picardi pick pick + pickaxe pickax pickaxes pickax + pickbone pickbon picked pick + pickers picker picking pick + pickle pickl picklock picklock + pickpurse pickpurs picks pick + pickt pickt pickthanks pickthank + pictur pictur picture pictur + pictured pictur pictures pictur + pid pid pie pie + piec piec piece piec + pieces piec piecing piec + pied pi piedness pied + pier pier pierc pierc + pierce pierc pierced pierc + pierces pierc pierceth pierceth + piercing pierc piercy pierci + piers pier pies pi + piety pieti pig pig + pigeon pigeon pigeons pigeon + pight pight pigmy pigmi + pigrogromitus pigrogromitu pike pike + pikes pike pil pil + pilate pilat pilates pilat + pilchers pilcher pile pile + piles pile pilf pilf + pilfering pilfer pilgrim pilgrim + pilgrimage pilgrimag pilgrims pilgrim + pill pill pillage pillag + pillagers pillag pillar pillar + pillars pillar pillicock pillicock + pillory pillori pillow pillow + pillows pillow pills pill + pilot pilot pilots pilot + pimpernell pimpernel pin pin + pinch pinch pinched pinch + pinches pinch pinching pinch + pindarus pindaru pine pine + pined pine pines pine + pinfold pinfold pining pine + pinion pinion pink pink + pinn pinn pinnace pinnac + pins pin pinse pins + pint pint pintpot pintpot + pioned pion pioneers pioneer + pioner pioner pioners pioner + pious piou pip pip + pipe pipe piper piper + pipers piper pipes pipe + piping pipe pippin pippin + pippins pippin pirate pirat + pirates pirat pisa pisa + pisanio pisanio pish pish + pismires pismir piss piss + pissing piss pistol pistol + pistols pistol pit pit + pitch pitch pitched pitch + pitcher pitcher pitchers pitcher + pitchy pitchi piteous piteou + piteously piteous pitfall pitfal + pith pith pithless pithless + pithy pithi pitie piti + pitied piti pities piti + pitiful piti pitifully pitifulli + pitiless pitiless pits pit + pittance pittanc pittie pitti + pittikins pittikin pity piti + pitying piti pius piu + plac plac place place + placed place placentio placentio + places place placeth placeth + placid placid placing place + plack plack placket placket + plackets placket plagu plagu + plague plagu plagued plagu + plagues plagu plaguing plagu + plaguy plagui plain plain + plainer plainer plainest plainest + plaining plain plainings plain + plainly plainli plainness plain + plains plain plainsong plainsong + plaintful plaint plaintiff plaintiff + plaintiffs plaintiff plaints plaint + planched planch planet planet + planetary planetari planets planet + planks plank plant plant + plantage plantag plantagenet plantagenet + plantagenets plantagenet plantain plantain + plantation plantat planted plant + planteth planteth plants plant + plash plash plashy plashi + plast plast plaster plaster + plasterer plaster plat plat + plate plate plated plate + plates plate platform platform + platforms platform plats plat + platted plat plausible plausibl + plausive plausiv plautus plautu + play plai played plai + player player players player + playeth playeth playfellow playfellow + playfellows playfellow playhouse playhous + playing plai plays plai + plea plea pleach pleach + pleached pleach plead plead + pleaded plead pleader pleader + pleaders pleader pleading plead + pleads plead pleas plea + pleasance pleasanc pleasant pleasant + pleasantly pleasantli please pleas + pleased pleas pleaser pleaser + pleasers pleaser pleases pleas + pleasest pleasest pleaseth pleaseth + pleasing pleas pleasure pleasur + pleasures pleasur plebeians plebeian + plebeii plebeii plebs pleb + pledge pledg pledges pledg + pleines plein plenitude plenitud + plenteous plenteou plenteously plenteous + plenties plenti plentiful plenti + plentifully plentifulli plenty plenti + pless pless plessed pless + plessing pless pliant pliant + plied pli plies pli + plight plight plighted plight + plighter plighter plod plod + plodded plod plodders plodder + plodding plod plods plod + plood plood ploody ploodi + plot plot plots plot + plotted plot plotter plotter + plough plough ploughed plough + ploughman ploughman ploughmen ploughmen + plow plow plows plow + pluck pluck plucked pluck + plucker plucker plucking pluck + plucks pluck plue plue + plum plum plume plume + plumed plume plumes plume + plummet plummet plump plump + plumpy plumpi plums plum + plung plung plunge plung + plunged plung plural plural + plurisy plurisi plus plu + pluto pluto plutus plutu + ply ply po po + pocket pocket pocketing pocket + pockets pocket pocky pocki + pody podi poem poem + poesy poesi poet poet + poetical poetic poetry poetri + poets poet poictiers poictier + poinards poinard poins poin + point point pointblank pointblank + pointed point pointing point + points point pois poi + poise pois poising pois + poison poison poisoned poison + poisoner poison poisoning poison + poisonous poison poisons poison + poke poke poking poke + pol pol polack polack + polacks polack poland poland + pold pold pole pole + poleaxe poleax polecat polecat + polecats polecat polemon polemon + poles pole poli poli + policies polici policy polici + polish polish polished polish + politic polit politician politician + politicians politician politicly politicli + polixenes polixen poll poll + polluted pollut pollution pollut + polonius poloniu poltroons poltroon + polusion polus polydamus polydamu + polydore polydor polyxena polyxena + pomander pomand pomegranate pomegran + pomewater pomewat pomfret pomfret + pomgarnet pomgarnet pommel pommel + pomp pomp pompeius pompeiu + pompey pompei pompion pompion + pompous pompou pomps pomp + pond pond ponder ponder + ponderous ponder ponds pond + poniard poniard poniards poniard + pont pont pontic pontic + pontifical pontif ponton ponton + pooh pooh pool pool + poole pool poop poop + poor poor poorer poorer + poorest poorest poorly poorli + pop pop pope pope + popedom popedom popilius popiliu + popingay popingai popish popish + popp popp poppy poppi + pops pop popular popular + popularity popular populous popul + porch porch porches porch + pore pore poring pore + pork pork porn porn + porpentine porpentin porridge porridg + porringer porring port port + portable portabl portage portag + portal portal portance portanc + portcullis portculli portend portend + portends portend portent portent + portentous portent portents portent + porter porter porters porter + portia portia portion portion + portly portli portotartarossa portotartarossa + portrait portrait portraiture portraitur + ports port portugal portug + pose pose posied posi + posies posi position posit + positive posit positively posit + posse poss possess possess + possessed possess possesses possess + possesseth possesseth possessing possess + possession possess possessions possess + possessor possessor posset posset + possets posset possibilities possibl + possibility possibl possible possibl + possibly possibl possitable possit + post post poste post + posted post posterior posterior + posteriors posterior posterity poster + postern postern posterns postern + posters poster posthorse posthors + posthorses posthors posthumus posthumu + posting post postmaster postmast + posts post postscript postscript + posture postur postures postur + posy posi pot pot + potable potabl potations potat + potato potato potatoes potato + potch potch potency potenc + potent potent potentates potent + potential potenti potently potent + potents potent pothecary pothecari + pother pother potion potion + potions potion potpan potpan + pots pot potter potter + potting pot pottle pottl + pouch pouch poulter poulter + poultice poultic poultney poultnei + pouncet pouncet pound pound + pounds pound pour pour + pourest pourest pouring pour + pourquoi pourquoi pours pour + pout pout poverty poverti + pow pow powd powd + powder powder power power + powerful power powerfully powerfulli + powerless powerless powers power + pox pox poys poi + poysam poysam prabbles prabbl + practic practic practice practic + practiced practic practicer practic + practices practic practicing practic + practis practi practisants practis + practise practis practiser practis + practisers practis practises practis + practising practis praeclarissimus praeclarissimu + praemunire praemunir praetor praetor + praetors praetor pragging prag + prague pragu prain prain + prains prain prais prai + praise prais praised prais + praises prais praisest praisest + praiseworthy praiseworthi praising prais + prancing pranc prank prank + pranks prank prat prat + prate prate prated prate + prater prater prating prate + prattle prattl prattler prattler + prattling prattl prave prave + prawls prawl prawns prawn + pray prai prayer prayer + prayers prayer praying prai + prays prai pre pre + preach preach preached preach + preachers preacher preaches preach + preaching preach preachment preachment + pread pread preambulate preambul + precedence preced precedent preced + preceding preced precept precept + preceptial precepti precepts precept + precinct precinct precious preciou + preciously precious precipice precipic + precipitating precipit precipitation precipit + precise precis precisely precis + preciseness precis precisian precisian + precor precor precurse precurs + precursors precursor predeceased predeceas + predecessor predecessor predecessors predecessor + predestinate predestin predicament predica + predict predict prediction predict + predictions predict predominance predomin + predominant predomin predominate predomin + preeches preech preeminence preemin + preface prefac prefer prefer + preferment prefer preferments prefer + preferr preferr preferreth preferreth + preferring prefer prefers prefer + prefiguring prefigur prefix prefix + prefixed prefix preformed preform + pregnancy pregnanc pregnant pregnant + pregnantly pregnantli prejudicates prejud + prejudice prejudic prejudicial prejudici + prelate prelat premeditated premedit + premeditation premedit premised premis + premises premis prenez prenez + prenominate prenomin prentice prentic + prentices prentic preordinance preordin + prepar prepar preparation prepar + preparations prepar prepare prepar + prepared prepar preparedly preparedli + prepares prepar preparing prepar + prepost prepost preposterous preposter + preposterously preposter prerogatifes prerogatif + prerogative prerog prerogatived prerogativ + presage presag presagers presag + presages presag presageth presageth + presaging presag prescience prescienc + prescribe prescrib prescript prescript + prescription prescript prescriptions prescript + prescripts prescript presence presenc + presences presenc present present + presentation present presented present + presenter present presenters present + presenteth presenteth presenting present + presently present presentment present + presents present preserv preserv + preservation preserv preservative preserv + preserve preserv preserved preserv + preserver preserv preservers preserv + preserving preserv president presid + press press pressed press + presser presser presses press + pressing press pressure pressur + pressures pressur prest prest + prester prester presume presum + presumes presum presuming presum + presumption presumpt presumptuous presumptu + presuppos presuppo pret pret + pretence pretenc pretences pretenc + pretend pretend pretended pretend + pretending pretend pretense pretens + pretext pretext pretia pretia + prettier prettier prettiest prettiest + prettily prettili prettiness pretti + pretty pretti prevail prevail + prevailed prevail prevaileth prevaileth + prevailing prevail prevailment prevail + prevails prevail prevent prevent + prevented prevent prevention prevent + preventions prevent prevents prevent + prey prei preyful prey + preys prei priam priam + priami priami priamus priamu + pribbles pribbl price price + prick prick pricked prick + pricket pricket pricking prick + pricks prick pricksong pricksong + pride pride prides pride + pridge pridg prie prie + pried pri prief prief + pries pri priest priest + priesthood priesthood priests priest + prig prig primal primal + prime prime primer primer + primero primero primest primest + primitive primit primo primo + primogenity primogen primrose primros + primroses primros primy primi + prince princ princely princ + princes princ princess princess + principal princip principalities princip + principality princip principle principl + principles principl princox princox + prings pring print print + printed print printing print + printless printless prints print + prioress prioress priories priori + priority prioriti priory priori + priscian priscian prison prison + prisoner prison prisoners prison + prisonment prison prisonnier prisonni + prisons prison pristine pristin + prithe prith prithee prithe + privacy privaci private privat + privately privat privates privat + privilage privilag privileg privileg + privilege privileg privileged privileg + privileges privileg privilegio privilegio + privily privili privity priviti + privy privi priz priz + prize prize prized prize + prizer prizer prizes prize + prizest prizest prizing prize + pro pro probable probabl + probal probal probation probat + proceed proce proceeded proceed + proceeders proceed proceeding proceed + proceedings proceed proceeds proce + process process procession process + proclaim proclaim proclaimed proclaim + proclaimeth proclaimeth proclaims proclaim + proclamation proclam proclamations proclam + proconsul proconsul procrastinate procrastin + procreant procreant procreants procreant + procreation procreat procrus procru + proculeius proculeiu procur procur + procurator procur procure procur + procured procur procures procur + procuring procur prodigal prodig + prodigality prodig prodigally prodig + prodigals prodig prodigies prodigi + prodigious prodigi prodigiously prodigi + prodigy prodigi proditor proditor + produc produc produce produc + produced produc produces produc + producing produc proface profac + profan profan profanation profan + profane profan profaned profan + profanely profan profaneness profan + profaners profan profaning profan + profess profess professed profess + professes profess profession profess + professions profess professors professor + proffer proffer proffered proffer + profferer proffer proffers proffer + proficient profici profit profit + profitable profit profitably profit + profited profit profiting profit + profitless profitless profits profit + profound profound profoundest profoundest + profoundly profoundli progenitors progenitor + progeny progeni progne progn + prognosticate prognost prognostication prognost + progress progress progression progress + prohibit prohibit prohibition prohibit + project project projection project + projects project prolixious prolixi + prolixity prolix prologue prologu + prologues prologu prolong prolong + prolongs prolong promethean promethean + prometheus prometheu promis promi + promise promis promised promis + promises promis promiseth promiseth + promising promis promontory promontori + promotion promot promotions promot + prompt prompt prompted prompt + promptement promptement prompter prompter + prompting prompt prompts prompt + prompture promptur promulgate promulg + prone prone prononcer prononc + prononcez prononcez pronoun pronoun + pronounc pronounc pronounce pronounc + pronounced pronounc pronouncing pronounc + pronouns pronoun proof proof + proofs proof prop prop + propagate propag propagation propag + propend propend propension propens + proper proper properer proper + properly properli propertied properti + properties properti property properti + prophecies propheci prophecy propheci + prophesied prophesi prophesier prophesi + prophesy prophesi prophesying prophesi + prophet prophet prophetess prophetess + prophetic prophet prophetically prophet + prophets prophet propinquity propinqu + propontic propont proportion proport + proportionable proportion proportions proport + propos propo propose propos + proposed propos proposer propos + proposes propos proposing propos + proposition proposit propositions proposit + propounded propound propp propp + propre propr propriety proprieti + props prop propugnation propugn + prorogue prorogu prorogued prorogu + proscription proscript proscriptions proscript + prose prose prosecute prosecut + prosecution prosecut proselytes proselyt + proserpina proserpina prosp prosp + prospect prospect prosper prosper + prosperity prosper prospero prospero + prosperous prosper prosperously prosper + prospers prosper prostitute prostitut + prostrate prostrat protect protect + protected protect protection protect + protector protector protectors protector + protectorship protectorship protectress protectress + protects protect protest protest + protestation protest protestations protest + protested protest protester protest + protesting protest protests protest + proteus proteu protheus protheu + protract protract protractive protract + proud proud prouder prouder + proudest proudest proudlier proudlier + proudly proudli prouds proud + prov prov provand provand + prove prove proved prove + provender provend proverb proverb + proverbs proverb proves prove + proveth proveth provide provid + provided provid providence provid + provident provid providently provid + provider provid provides provid + province provinc provinces provinc + provincial provinci proving prove + provision provis proviso proviso + provocation provoc provok provok + provoke provok provoked provok + provoker provok provokes provok + provoketh provoketh provoking provok + provost provost prowess prowess + prudence prudenc prudent prudent + prun prun prune prune + prunes prune pruning prune + pry pry prying pry + psalm psalm psalmist psalmist + psalms psalm psalteries psalteri + ptolemies ptolemi ptolemy ptolemi + public public publican publican + publication public publicly publicli + publicola publicola publish publish + published publish publisher publish + publishing publish publius publiu + pucelle pucel puck puck + pudder pudder pudding pud + puddings pud puddle puddl + puddled puddl pudency pudenc + pueritia pueritia puff puff + puffing puf puffs puff + pugging pug puis pui + puissance puissanc puissant puissant + puke puke puking puke + pulcher pulcher puling pule + pull pull puller puller + pullet pullet pulling pull + pulls pull pulpit pulpit + pulpiter pulpit pulpits pulpit + pulse puls pulsidge pulsidg + pump pump pumpion pumpion + pumps pump pun pun + punched punch punish punish + punished punish punishes punish + punishment punish punishments punish + punk punk punto punto + puny puni pupil pupil + pupils pupil puppet puppet + puppets puppet puppies puppi + puppy puppi pur pur + purblind purblind purchas purcha + purchase purchas purchased purchas + purchases purchas purchaseth purchaseth + purchasing purchas pure pure + purely pure purer purer + purest purest purg purg + purgation purgat purgative purg + purgatory purgatori purge purg + purged purg purgers purger + purging purg purifies purifi + purifying purifi puritan puritan + purity puriti purlieus purlieu + purple purpl purpled purpl + purples purpl purport purport + purpos purpo purpose purpos + purposed purpos purposely purpos + purposes purpos purposeth purposeth + purposing purpos purr purr + purs pur purse purs + pursents pursent purses purs + pursu pursu pursue pursu + pursued pursu pursuers pursuer + pursues pursu pursuest pursuest + pursueth pursueth pursuing pursu + pursuit pursuit pursuivant pursuiv + pursuivants pursuiv pursy pursi + purus puru purveyor purveyor + push push pushes push + pusillanimity pusillanim put put + putrefy putrefi putrified putrifi + puts put putter putter + putting put puttock puttock + puzzel puzzel puzzle puzzl + puzzled puzzl puzzles puzzl + py py pygmalion pygmalion + pygmies pygmi pygmy pygmi + pyramid pyramid pyramides pyramid + pyramids pyramid pyramis pyrami + pyramises pyramis pyramus pyramu + pyrenean pyrenean pyrrhus pyrrhu + pythagoras pythagora qu qu + quadrangle quadrangl quae quae + quaff quaff quaffing quaf + quagmire quagmir quail quail + quailing quail quails quail + quaint quaint quaintly quaintli + quak quak quake quak + quakes quak qualification qualif + qualified qualifi qualifies qualifi + qualify qualifi qualifying qualifi + qualite qualit qualities qualiti + quality qualiti qualm qualm + qualmish qualmish quam quam + quand quand quando quando + quantities quantiti quantity quantiti + quare quar quarrel quarrel + quarrell quarrel quarreller quarrel + quarrelling quarrel quarrelous quarrel + quarrels quarrel quarrelsome quarrelsom + quarries quarri quarry quarri + quart quart quarter quarter + quartered quarter quartering quarter + quarters quarter quarts quart + quasi quasi quat quat + quatch quatch quay quai + que que quean quean + queas quea queasiness queasi + queasy queasi queen queen + queens queen quell quell + queller queller quench quench + quenched quench quenching quench + quenchless quenchless quern quern + quest quest questant questant + question question questionable question + questioned question questioning question + questionless questionless questions question + questrists questrist quests quest + queubus queubu qui qui + quick quick quicken quicken + quickens quicken quicker quicker + quicklier quicklier quickly quickli + quickness quick quicksand quicksand + quicksands quicksand quicksilverr quicksilverr + quid quid quiddities quidditi + quiddits quiddit quier quier + quiet quiet quieter quieter + quietly quietli quietness quiet + quietus quietu quill quill + quillets quillet quills quill + quilt quilt quinapalus quinapalu + quince quinc quinces quinc + quintain quintain quintessence quintess + quintus quintu quip quip + quips quip quire quir + quiring quir quirk quirk + quirks quirk quis qui + quit quit quite quit + quits quit quittance quittanc + quitted quit quitting quit + quiver quiver quivering quiver + quivers quiver quo quo + quod quod quoifs quoif + quoint quoint quoit quoit + quoits quoit quondam quondam + quoniam quoniam quote quot + quoted quot quotes quot + quoth quoth quotidian quotidian + r r rabbit rabbit + rabble rabbl rabblement rabblement + race race rack rack + rackers racker racket racket + rackets racket racking rack + racks rack radiance radianc + radiant radiant radish radish + rafe rafe raft raft + rag rag rage rage + rages rage rageth rageth + ragg ragg ragged rag + raggedness ragged raging rage + ragozine ragozin rags rag + rah rah rail rail + railed rail railer railer + railest railest raileth raileth + railing rail rails rail + raiment raiment rain rain + rainbow rainbow raineth raineth + raining rain rainold rainold + rains rain rainy raini + rais rai raise rais + raised rais raises rais + raising rais raisins raisin + rak rak rake rake + rakers raker rakes rake + ral ral rald rald + ralph ralph ram ram + rambures rambur ramm ramm + rampallian rampallian rampant rampant + ramping ramp rampir rampir + ramps ramp rams ram + ramsey ramsei ramston ramston + ran ran rance ranc + rancorous rancor rancors rancor + rancour rancour random random + rang rang range rang + ranged rang rangers ranger + ranges rang ranging rang + rank rank ranker ranker + rankest rankest ranking rank + rankle rankl rankly rankli + rankness rank ranks rank + ransack ransack ransacking ransack + ransom ransom ransomed ransom + ransoming ransom ransomless ransomless + ransoms ransom rant rant + ranting rant rap rap + rape rape rapes rape + rapier rapier rapiers rapier + rapine rapin raps rap + rapt rapt rapture raptur + raptures raptur rar rar + rare rare rarely rare + rareness rare rarer rarer + rarest rarest rarities rariti + rarity rariti rascal rascal + rascalliest rascalliest rascally rascal + rascals rascal rased rase + rash rash rasher rasher + rashly rashli rashness rash + rat rat ratcatcher ratcatch + ratcliff ratcliff rate rate + rated rate rately rate + rates rate rather rather + ratherest ratherest ratified ratifi + ratifiers ratifi ratify ratifi + rating rate rational ration + ratolorum ratolorum rats rat + ratsbane ratsban rattle rattl + rattles rattl rattling rattl + rature ratur raught raught + rav rav rave rave + ravel ravel raven raven + ravening raven ravenous raven + ravens raven ravenspurgh ravenspurgh + raves rave ravin ravin + raving rave ravish ravish + ravished ravish ravisher ravish + ravishing ravish ravishments ravish + raw raw rawer rawer + rawly rawli rawness raw + ray rai rayed rai + rays rai raz raz + raze raze razed raze + razes raze razeth razeth + razing raze razor razor + razorable razor razors razor + razure razur re re + reach reach reaches reach + reacheth reacheth reaching reach + read read reader reader + readiest readiest readily readili + readiness readi reading read + readins readin reads read + ready readi real real + really realli realm realm + realms realm reap reap + reapers reaper reaping reap + reaps reap rear rear + rears rear rearward rearward + reason reason reasonable reason + reasonably reason reasoned reason + reasoning reason reasonless reasonless + reasons reason reave reav + rebate rebat rebato rebato + rebeck rebeck rebel rebel + rebell rebel rebelling rebel + rebellion rebellion rebellious rebelli + rebels rebel rebound rebound + rebuk rebuk rebuke rebuk + rebukeable rebuk rebuked rebuk + rebukes rebuk rebus rebu + recall recal recant recant + recantation recant recanter recant + recanting recant receipt receipt + receipts receipt receiv receiv + receive receiv received receiv + receiver receiv receives receiv + receivest receivest receiveth receiveth + receiving receiv receptacle receptacl + rechate rechat reciprocal reciproc + reciprocally reciproc recite recit + recited recit reciterai reciterai + reck reck recking reck + reckless reckless reckon reckon + reckoned reckon reckoning reckon + reckonings reckon recks reck + reclaim reclaim reclaims reclaim + reclusive reclus recognizance recogniz + recognizances recogniz recoil recoil + recoiling recoil recollected recollect + recomforted recomfort recomforture recomfortur + recommend recommend recommended recommend + recommends recommend recompens recompen + recompense recompens reconcil reconcil + reconcile reconcil reconciled reconcil + reconcilement reconcil reconciler reconcil + reconciles reconcil reconciliation reconcili + record record recordation record + recorded record recorder record + recorders record records record + recount recount recounted recount + recounting recount recountments recount + recounts recount recourse recours + recov recov recover recov + recoverable recover recovered recov + recoveries recoveri recovers recov + recovery recoveri recreant recreant + recreants recreant recreate recreat + recreation recreat rectify rectifi + rector rector rectorship rectorship + recure recur recured recur + red red redbreast redbreast + redder redder reddest reddest + rede rede redeem redeem + redeemed redeem redeemer redeem + redeeming redeem redeems redeem + redeliver redeliv redemption redempt + redime redim redness red + redoubled redoubl redoubted redoubt + redound redound redress redress + redressed redress redresses redress + reduce reduc reechy reechi + reed reed reeds reed + reek reek reeking reek + reeks reek reeky reeki + reel reel reeleth reeleth + reeling reel reels reel + refell refel refer refer + reference refer referr referr + referred refer refigured refigur + refin refin refined refin + reflect reflect reflecting reflect + reflection reflect reflex reflex + reform reform reformation reform + reformed reform refractory refractori + refrain refrain refresh refresh + refreshing refresh reft reft + refts reft refuge refug + refus refu refusal refus + refuse refus refused refus + refusest refusest refusing refus + reg reg regal regal + regalia regalia regan regan + regard regard regardance regard + regarded regard regardfully regardfulli + regarding regard regards regard + regenerate regener regent regent + regentship regentship regia regia + regiment regiment regiments regiment + regina regina region region + regions region regist regist + register regist registers regist + regreet regreet regreets regreet + regress regress reguerdon reguerdon + regular regular rehears rehear + rehearsal rehears rehearse rehears + reign reign reigned reign + reignier reignier reigning reign + reigns reign rein rein + reinforc reinforc reinforce reinforc + reinforcement reinforc reins rein + reiterate reiter reject reject + rejected reject rejoic rejoic + rejoice rejoic rejoices rejoic + rejoiceth rejoiceth rejoicing rejoic + rejoicingly rejoicingli rejoindure rejoindur + rejourn rejourn rel rel + relapse relaps relate relat + relates relat relation relat + relations relat relative rel + releas relea release releas + released releas releasing releas + relent relent relenting relent + relents relent reliances relianc + relics relic relief relief + reliev reliev relieve reliev + relieved reliev relieves reliev + relieving reliev religion religion + religions religion religious religi + religiously religi relinquish relinquish + reliques reliqu reliquit reliquit + relish relish relume relum + rely reli relying reli + remain remain remainder remaind + remainders remaind remained remain + remaineth remaineth remaining remain + remains remain remark remark + remarkable remark remediate remedi + remedied remedi remedies remedi + remedy remedi rememb rememb + remember rememb remembered rememb + remembers rememb remembrance remembr + remembrancer remembranc remembrances remembr + remercimens remercimen remiss remiss + remission remiss remissness remiss + remit remit remnant remnant + remnants remnant remonstrance remonstr + remorse remors remorseful remors + remorseless remorseless remote remot + remotion remot remov remov + remove remov removed remov + removedness removed remover remov + removes remov removing remov + remunerate remuner remuneration remuner + rence renc rend rend + render render rendered render + renders render rendezvous rendezv + renegado renegado renege reneg + reneges reneg renew renew + renewed renew renewest renewest + renounce renounc renouncement renounc + renouncing renounc renowmed renowm + renown renown renowned renown + rent rent rents rent + repaid repaid repair repair + repaired repair repairing repair + repairs repair repass repass + repast repast repasture repastur + repay repai repaying repai + repays repai repeal repeal + repealing repeal repeals repeal + repeat repeat repeated repeat + repeating repeat repeats repeat + repel repel repent repent + repentance repent repentant repent + repented repent repenting repent + repents repent repetition repetit + repetitions repetit repin repin + repine repin repining repin + replant replant replenish replenish + replenished replenish replete replet + replication replic replied repli + replies repli repliest repliest + reply repli replying repli + report report reported report + reporter report reportest reportest + reporting report reportingly reportingli + reports report reposal repos + repose repos reposeth reposeth + reposing repos repossess repossess + reprehend reprehend reprehended reprehend + reprehending reprehend represent repres + representing repres reprieve repriev + reprieves repriev reprisal repris + reproach reproach reproaches reproach + reproachful reproach reproachfully reproachfulli + reprobate reprob reprobation reprob + reproof reproof reprov reprov + reprove reprov reproveable reprov + reproves reprov reproving reprov + repugn repugn repugnancy repugn + repugnant repugn repulse repuls + repulsed repuls repurchas repurcha + repured repur reputation reput + repute reput reputed reput + reputeless reputeless reputes reput + reputing reput request request + requested request requesting request + requests request requiem requiem + requir requir require requir + required requir requires requir + requireth requireth requiring requir + requisite requisit requisites requisit + requit requit requital requit + requite requit requited requit + requites requit rer rer + rere rere rers rer + rescu rescu rescue rescu + rescued rescu rescues rescu + rescuing rescu resemblance resembl + resemble resembl resembled resembl + resembles resembl resembleth resembleth + resembling resembl reserv reserv + reservation reserv reserve reserv + reserved reserv reserves reserv + reside resid residence resid + resident resid resides resid + residing resid residue residu + resign resign resignation resign + resist resist resistance resist + resisted resist resisting resist + resists resist resolute resolut + resolutely resolut resolutes resolut + resolution resolut resolv resolv + resolve resolv resolved resolv + resolvedly resolvedli resolves resolv + resolveth resolveth resort resort + resorted resort resounding resound + resounds resound respeaking respeak + respect respect respected respect + respecting respect respective respect + respectively respect respects respect + respice respic respite respit + respites respit responsive respons + respose respos ress ress + rest rest rested rest + resteth resteth restful rest + resting rest restitution restitut + restless restless restor restor + restoration restor restorative restor + restore restor restored restor + restores restor restoring restor + restrain restrain restrained restrain + restraining restrain restrains restrain + restraint restraint rests rest + resty resti resum resum + resume resum resumes resum + resurrections resurrect retail retail + retails retail retain retain + retainers retain retaining retain + retell retel retention retent + retentive retent retinue retinu + retir retir retire retir + retired retir retirement retir + retires retir retiring retir + retold retold retort retort + retorts retort retourne retourn + retract retract retreat retreat + retrograde retrograd rets ret + return return returned return + returnest returnest returneth returneth + returning return returns return + revania revania reveal reveal + reveals reveal revel revel + reveler revel revell revel + reveller revel revellers revel + revelling revel revelry revelri + revels revel reveng reveng + revenge reveng revenged reveng + revengeful reveng revengement reveng + revenger reveng revengers reveng + revenges reveng revenging reveng + revengingly revengingli revenue revenu + revenues revenu reverb reverb + reverberate reverber reverbs reverb + reverenc reverenc reverence rever + reverend reverend reverent rever + reverently rever revers rever + reverse revers reversion revers + reverted revert review review + reviewest reviewest revil revil + revile revil revisits revisit + reviv reviv revive reviv + revives reviv reviving reviv + revok revok revoke revok + revokement revok revolt revolt + revolted revolt revolting revolt + revolts revolt revolution revolut + revolutions revolut revolve revolv + revolving revolv reward reward + rewarded reward rewarder reward + rewarding reward rewards reward + reword reword reworded reword + rex rex rey rei + reynaldo reynaldo rford rford + rful rful rfull rfull + rhapsody rhapsodi rheims rheim + rhenish rhenish rhesus rhesu + rhetoric rhetor rheum rheum + rheumatic rheumat rheums rheum + rheumy rheumi rhinoceros rhinocero + rhodes rhode rhodope rhodop + rhubarb rhubarb rhym rhym + rhyme rhyme rhymers rhymer + rhymes rhyme rhyming rhyme + rialto rialto rib rib + ribald ribald riband riband + ribands riband ribaudred ribaudr + ribb ribb ribbed rib + ribbon ribbon ribbons ribbon + ribs rib rice rice + rich rich richard richard + richer richer riches rich + richest richest richly richli + richmond richmond richmonds richmond + rid rid riddance riddanc + ridden ridden riddle riddl + riddles riddl riddling riddl + ride ride rider rider + riders rider rides ride + ridest ridest rideth rideth + ridge ridg ridges ridg + ridiculous ridicul riding ride + rids rid rien rien + ries ri rifle rifl + rift rift rifted rift + rig rig rigg rigg + riggish riggish right right + righteous righteou righteously righteous + rightful right rightfully rightfulli + rightly rightli rights right + rigol rigol rigorous rigor + rigorously rigor rigour rigour + ril ril rim rim + rin rin rinaldo rinaldo + rind rind ring ring + ringing ring ringleader ringlead + ringlets ringlet rings ring + ringwood ringwood riot riot + rioter rioter rioting riot + riotous riotou riots riot + rip rip ripe ripe + ripely ripe ripen ripen + ripened ripen ripeness ripe + ripening ripen ripens ripen + riper riper ripest ripest + riping ripe ripp ripp + ripping rip rise rise + risen risen rises rise + riseth riseth rish rish + rising rise rite rite + rites rite rivage rivag + rival rival rivality rival + rivall rival rivals rival + rive rive rived rive + rivelled rivel river river + rivers river rivet rivet + riveted rivet rivets rivet + rivo rivo rj rj + rless rless road road + roads road roam roam + roaming roam roan roan + roar roar roared roar + roarers roarer roaring roar + roars roar roast roast + roasted roast rob rob + roba roba robas roba + robb robb robbed rob + robber robber robbers robber + robbery robberi robbing rob + robe robe robed robe + robert robert robes robe + robin robin robs rob + robustious robusti rochester rochest + rochford rochford rock rock + rocks rock rocky rocki + rod rod rode rode + roderigo roderigo rods rod + roe roe roes roe + roger roger rogero rogero + rogue rogu roguery rogueri + rogues rogu roguish roguish + roi roi roisting roist + roll roll rolled roll + rolling roll rolls roll + rom rom romage romag + roman roman romano romano + romanos romano romans roman + rome rome romeo romeo + romish romish rondure rondur + ronyon ronyon rood rood + roof roof roofs roof + rook rook rooks rook + rooky rooki room room + rooms room root root + rooted root rootedly rootedli + rooteth rooteth rooting root + roots root rope rope + ropery roperi ropes rope + roping rope ros ro + rosalind rosalind rosalinda rosalinda + rosalinde rosalind rosaline rosalin + roscius rosciu rose rose + rosed rose rosemary rosemari + rosencrantz rosencrantz roses rose + ross ross rosy rosi + rot rot rote rote + roted rote rother rother + rotherham rotherham rots rot + rotted rot rotten rotten + rottenness rotten rotting rot + rotundity rotund rouen rouen + rough rough rougher rougher + roughest roughest roughly roughli + roughness rough round round + rounded round roundel roundel + rounder rounder roundest roundest + rounding round roundly roundli + rounds round roundure roundur + rous rou rouse rous + roused rous rousillon rousillon + rously rousli roussi roussi + rout rout routed rout + routs rout rove rove + rover rover row row + rowel rowel rowland rowland + rowlands rowland roy roi + royal royal royalize royal + royally royal royalties royalti + royalty royalti roynish roynish + rs rs rt rt + rub rub rubb rubb + rubbing rub rubbish rubbish + rubies rubi rubious rubiou + rubs rub ruby rubi + rud rud rudand rudand + rudder rudder ruddiness ruddi + ruddock ruddock ruddy ruddi + rude rude rudely rude + rudeness rude ruder ruder + rudesby rudesbi rudest rudest + rudiments rudiment rue rue + rued ru ruff ruff + ruffian ruffian ruffians ruffian + ruffle ruffl ruffling ruffl + ruffs ruff rug rug + rugby rugbi rugemount rugemount + rugged rug ruin ruin + ruinate ruinat ruined ruin + ruining ruin ruinous ruinou + ruins ruin rul rul + rule rule ruled rule + ruler ruler rulers ruler + rules rule ruling rule + rumble rumbl ruminaies ruminai + ruminat ruminat ruminate rumin + ruminated rumin ruminates rumin + rumination rumin rumor rumor + rumour rumour rumourer rumour + rumours rumour rump rump + run run runagate runag + runagates runag runaway runawai + runaways runawai rung rung + runn runn runner runner + runners runner running run + runs run rupture ruptur + ruptures ruptur rural rural + rush rush rushes rush + rushing rush rushling rushl + rushy rushi russet russet + russia russia russian russian + russians russian rust rust + rusted rust rustic rustic + rustically rustic rustics rustic + rustle rustl rustling rustl + rusts rust rusty rusti + rut rut ruth ruth + ruthful ruth ruthless ruthless + rutland rutland ruttish ruttish + ry ry rye rye + rything ryth s s + sa sa saba saba + sabbath sabbath sable sabl + sables sabl sack sack + sackbuts sackbut sackcloth sackcloth + sacked sack sackerson sackerson + sacks sack sacrament sacrament + sacred sacr sacrific sacrif + sacrifice sacrific sacrificers sacrific + sacrifices sacrific sacrificial sacrifici + sacrificing sacrif sacrilegious sacrilegi + sacring sacr sad sad + sadder sadder saddest saddest + saddle saddl saddler saddler + saddles saddl sadly sadli + sadness sad saf saf + safe safe safeguard safeguard + safely safe safer safer + safest safest safeties safeti + safety safeti saffron saffron + sag sag sage sage + sagittary sagittari said said + saidst saidst sail sail + sailing sail sailmaker sailmak + sailor sailor sailors sailor + sails sail sain sain + saint saint sainted saint + saintlike saintlik saints saint + saith saith sake sake + sakes sake sala sala + salad salad salamander salamand + salary salari sale sale + salerio salerio salicam salicam + salique saliqu salisbury salisburi + sall sall sallet sallet + sallets sallet sallies salli + sallow sallow sally salli + salmon salmon salmons salmon + salt salt salter salter + saltiers saltier saltness salt + saltpetre saltpetr salutation salut + salutations salut salute salut + saluted salut salutes salut + saluteth saluteth salv salv + salvation salvat salve salv + salving salv same same + samingo samingo samp samp + sampire sampir sample sampl + sampler sampler sampson sampson + samson samson samsons samson + sancta sancta sanctified sanctifi + sanctifies sanctifi sanctify sanctifi + sanctimonies sanctimoni sanctimonious sanctimoni + sanctimony sanctimoni sanctities sanctiti + sanctity sanctiti sanctuarize sanctuar + sanctuary sanctuari sand sand + sandal sandal sandbag sandbag + sanded sand sands sand + sandy sandi sandys sandi + sang sang sanguine sanguin + sanguis sangui sanity saniti + sans san santrailles santrail + sap sap sapient sapient + sapit sapit sapless sapless + sapling sapl sapphire sapphir + sapphires sapphir saracens saracen + sarcenet sarcenet sard sard + sardians sardian sardinia sardinia + sardis sardi sarum sarum + sat sat satan satan + satchel satchel sate sate + sated sate satiate satiat + satiety satieti satin satin + satire satir satirical satir + satis sati satisfaction satisfact + satisfied satisfi satisfies satisfi + satisfy satisfi satisfying satisfi + saturday saturdai saturdays saturdai + saturn saturn saturnine saturnin + saturninus saturninu satyr satyr + satyrs satyr sauc sauc + sauce sauc sauced sauc + saucers saucer sauces sauc + saucily saucili sauciness sauci + saucy sauci sauf sauf + saunder saunder sav sav + savage savag savagely savag + savageness savag savagery savageri + savages savag save save + saved save saves save + saving save saviour saviour + savory savori savour savour + savouring savour savours savour + savoury savouri savoy savoi + saw saw sawed saw + sawest sawest sawn sawn + sawpit sawpit saws saw + sawyer sawyer saxons saxon + saxony saxoni saxton saxton + say sai sayest sayest + saying sai sayings sai + says sai sayst sayst + sblood sblood sc sc + scab scab scabbard scabbard + scabs scab scaffold scaffold + scaffoldage scaffoldag scal scal + scald scald scalded scald + scalding scald scale scale + scaled scale scales scale + scaling scale scall scall + scalp scalp scalps scalp + scaly scali scamble scambl + scambling scambl scamels scamel + scan scan scandal scandal + scandaliz scandaliz scandalous scandal + scandy scandi scann scann + scant scant scanted scant + scanter scanter scanting scant + scantling scantl scants scant + scap scap scape scape + scaped scape scapes scape + scapeth scapeth scar scar + scarce scarc scarcely scarc + scarcity scarciti scare scare + scarecrow scarecrow scarecrows scarecrow + scarf scarf scarfed scarf + scarfs scarf scaring scare + scarlet scarlet scarr scarr + scarre scarr scars scar + scarus scaru scath scath + scathe scath scathful scath + scatt scatt scatter scatter + scattered scatter scattering scatter + scatters scatter scelera scelera + scelerisque scelerisqu scene scene + scenes scene scent scent + scented scent scept scept + scepter scepter sceptre sceptr + sceptred sceptr sceptres sceptr + schedule schedul schedules schedul + scholar scholar scholarly scholarli + scholars scholar school school + schoolboy schoolboi schoolboys schoolboi + schoolfellows schoolfellow schooling school + schoolmaster schoolmast schoolmasters schoolmast + schools school sciatica sciatica + sciaticas sciatica science scienc + sciences scienc scimitar scimitar + scion scion scions scion + scissors scissor scoff scoff + scoffer scoffer scoffing scof + scoffs scoff scoggin scoggin + scold scold scolding scold + scolds scold sconce sconc + scone scone scope scope + scopes scope scorch scorch + scorched scorch score score + scored score scores score + scoring score scorn scorn + scorned scorn scornful scorn + scornfully scornfulli scorning scorn + scorns scorn scorpion scorpion + scorpions scorpion scot scot + scotch scotch scotches scotch + scotland scotland scots scot + scottish scottish scoundrels scoundrel + scour scour scoured scour + scourg scourg scourge scourg + scouring scour scout scout + scouts scout scowl scowl + scrap scrap scrape scrape + scraping scrape scraps scrap + scratch scratch scratches scratch + scratching scratch scream scream + screams scream screech screech + screeching screech screen screen + screens screen screw screw + screws screw scribbl scribbl + scribbled scribbl scribe scribe + scribes scribe scrimers scrimer + scrip scrip scrippage scrippag + scripture scriptur scriptures scriptur + scrivener scriven scroll scroll + scrolls scroll scroop scroop + scrowl scrowl scroyles scroyl + scrubbed scrub scruple scrupl + scruples scrupl scrupulous scrupul + scuffles scuffl scuffling scuffl + scullion scullion sculls scull + scum scum scurril scurril + scurrility scurril scurrilous scurril + scurvy scurvi scuse scuse + scut scut scutcheon scutcheon + scutcheons scutcheon scylla scylla + scythe scyth scythed scyth + scythia scythia scythian scythian + sdeath sdeath se se + sea sea seacoal seacoal + seafaring seafar seal seal + sealed seal sealing seal + seals seal seam seam + seamen seamen seamy seami + seaport seaport sear sear + searce searc search search + searchers searcher searches search + searcheth searcheth searching search + seared sear seas sea + seasick seasick seaside seasid + season season seasoned season + seasons season seat seat + seated seat seats seat + sebastian sebastian second second + secondarily secondarili secondary secondari + seconded second seconds second + secrecy secreci secret secret + secretaries secretari secretary secretari + secretly secretli secrets secret + sect sect sectary sectari + sects sect secundo secundo + secure secur securely secur + securing secur security secur + sedg sedg sedge sedg + sedges sedg sedgy sedgi + sedition sedit seditious sediti + seduc seduc seduce seduc + seduced seduc seducer seduc + seducing seduc see see + seed seed seeded seed + seedness seed seeds seed + seedsman seedsman seein seein + seeing see seek seek + seeking seek seeks seek + seel seel seeling seel + seely seeli seem seem + seemed seem seemers seemer + seemest seemest seemeth seemeth + seeming seem seemingly seemingli + seemly seemli seems seem + seen seen seer seer + sees see seese sees + seest seest seethe seeth + seethes seeth seething seeth + seeting seet segregation segreg + seigneur seigneur seigneurs seigneur + seiz seiz seize seiz + seized seiz seizes seiz + seizeth seizeth seizing seiz + seizure seizur seld seld + seldom seldom select select + seleucus seleucu self self + selfsame selfsam sell sell + seller seller selling sell + sells sell selves selv + semblable semblabl semblably semblabl + semblance semblanc semblances semblanc + semblative sembl semi semi + semicircle semicircl semiramis semirami + semper semper sempronius semproniu + senate senat senator senat + senators senat send send + sender sender sendeth sendeth + sending send sends send + seneca seneca senior senior + seniory seniori senis seni + sennet sennet senoys senoi + sense sens senseless senseless + senses sens sensible sensibl + sensibly sensibl sensual sensual + sensuality sensual sent sent + sentenc sentenc sentence sentenc + sentences sentenc sententious sententi + sentinel sentinel sentinels sentinel + separable separ separate separ + separated separ separates separ + separation separ septentrion septentrion + sepulchre sepulchr sepulchres sepulchr + sepulchring sepulchr sequel sequel + sequence sequenc sequent sequent + sequest sequest sequester sequest + sequestration sequestr sere sere + serenis sereni serge serg + sergeant sergeant serious seriou + seriously serious sermon sermon + sermons sermon serpent serpent + serpentine serpentin serpents serpent + serpigo serpigo serv serv + servant servant servanted servant + servants servant serve serv + served serv server server + serves serv serveth serveth + service servic serviceable servic + services servic servile servil + servility servil servilius serviliu + serving serv servingman servingman + servingmen servingmen serviteur serviteur + servitor servitor servitors servitor + servitude servitud sessa sessa + session session sessions session + sestos sesto set set + setebos setebo sets set + setter setter setting set + settle settl settled settl + settlest settlest settling settl + sev sev seven seven + sevenfold sevenfold sevennight sevennight + seventeen seventeen seventh seventh + seventy seventi sever sever + several sever severally sever + severals sever severe sever + severed sever severely sever + severest severest severing sever + severity sever severn severn + severs sever sew sew + seward seward sewer sewer + sewing sew sex sex + sexes sex sexton sexton + sextus sextu seymour seymour + seyton seyton sfoot sfoot + sh sh shackle shackl + shackles shackl shade shade + shades shade shadow shadow + shadowed shadow shadowing shadow + shadows shadow shadowy shadowi + shady shadi shafalus shafalu + shaft shaft shafts shaft + shag shag shak shak + shake shake shaked shake + shaken shaken shakes shake + shaking shake shales shale + shall shall shallenge shalleng + shallow shallow shallowest shallowest + shallowly shallowli shallows shallow + shalt shalt sham sham + shambles shambl shame shame + shamed shame shameful shame + shamefully shamefulli shameless shameless + shames shame shamest shamest + shaming shame shank shank + shanks shank shap shap + shape shape shaped shape + shapeless shapeless shapen shapen + shapes shape shaping shape + shar shar shard shard + sharded shard shards shard + share share shared share + sharers sharer shares share + sharing share shark shark + sharp sharp sharpen sharpen + sharpened sharpen sharpens sharpen + sharper sharper sharpest sharpest + sharply sharpli sharpness sharp + sharps sharp shatter shatter + shav shav shave shave + shaven shaven shaw shaw + she she sheaf sheaf + sheal sheal shear shear + shearers shearer shearing shear + shearman shearman shears shear + sheath sheath sheathe sheath + sheathed sheath sheathes sheath + sheathing sheath sheaved sheav + sheaves sheav shed shed + shedding shed sheds shed + sheen sheen sheep sheep + sheepcote sheepcot sheepcotes sheepcot + sheeps sheep sheepskins sheepskin + sheer sheer sheet sheet + sheeted sheet sheets sheet + sheffield sheffield shelf shelf + shell shell shells shell + shelt shelt shelter shelter + shelters shelter shelves shelv + shelving shelv shelvy shelvi + shent shent shepherd shepherd + shepherdes shepherd shepherdess shepherdess + shepherdesses shepherdess shepherds shepherd + sher sher sheriff sheriff + sherris sherri shes she + sheweth sheweth shield shield + shielded shield shields shield + shift shift shifted shift + shifting shift shifts shift + shilling shill shillings shill + shin shin shine shine + shines shine shineth shineth + shining shine shins shin + shiny shini ship ship + shipboard shipboard shipman shipman + shipmaster shipmast shipmen shipmen + shipp shipp shipped ship + shipping ship ships ship + shipt shipt shipwreck shipwreck + shipwrecking shipwreck shipwright shipwright + shipwrights shipwright shire shire + shirley shirlei shirt shirt + shirts shirt shive shive + shiver shiver shivering shiver + shivers shiver shoal shoal + shoals shoal shock shock + shocks shock shod shod + shoe shoe shoeing shoe + shoemaker shoemak shoes shoe + shog shog shone shone + shook shook shoon shoon + shoot shoot shooter shooter + shootie shooti shooting shoot + shoots shoot shop shop + shops shop shore shore + shores shore shorn shorn + short short shortcake shortcak + shorten shorten shortened shorten + shortens shorten shorter shorter + shortly shortli shortness short + shot shot shotten shotten + shoughs shough should should + shoulder shoulder shouldering shoulder + shoulders shoulder shouldst shouldst + shout shout shouted shout + shouting shout shouts shout + shov shov shove shove + shovel shovel shovels shovel + show show showed show + shower shower showers shower + showest showest showing show + shown shown shows show + shreds shred shrew shrew + shrewd shrewd shrewdly shrewdli + shrewdness shrewd shrewish shrewish + shrewishly shrewishli shrewishness shrewish + shrews shrew shrewsbury shrewsburi + shriek shriek shrieking shriek + shrieks shriek shrieve shriev + shrift shrift shrill shrill + shriller shriller shrills shrill + shrilly shrilli shrimp shrimp + shrine shrine shrink shrink + shrinking shrink shrinks shrink + shriv shriv shrive shrive + shriver shriver shrives shrive + shriving shrive shroud shroud + shrouded shroud shrouding shroud + shrouds shroud shrove shrove + shrow shrow shrows shrow + shrub shrub shrubs shrub + shrug shrug shrugs shrug + shrunk shrunk shudd shudd + shudders shudder shuffl shuffl + shuffle shuffl shuffled shuffl + shuffling shuffl shun shun + shunless shunless shunn shunn + shunned shun shunning shun + shuns shun shut shut + shuts shut shuttle shuttl + shy shy shylock shylock + si si sibyl sibyl + sibylla sibylla sibyls sibyl + sicil sicil sicilia sicilia + sicilian sicilian sicilius siciliu + sicils sicil sicily sicili + sicinius siciniu sick sick + sicken sicken sickens sicken + sicker sicker sickle sickl + sicklemen sicklemen sicklied sickli + sickliness sickli sickly sickli + sickness sick sicles sicl + sicyon sicyon side side + sided side sides side + siege sieg sieges sieg + sienna sienna sies si + sieve siev sift sift + sifted sift sigeia sigeia + sigh sigh sighed sigh + sighing sigh sighs sigh + sight sight sighted sight + sightless sightless sightly sightli + sights sight sign sign + signal signal signet signet + signieur signieur significant signific + significants signific signified signifi + signifies signifi signify signifi + signifying signifi signior signior + signiories signiori signiors signior + signiory signiori signor signor + signories signori signs sign + signum signum silenc silenc + silence silenc silenced silenc + silencing silenc silent silent + silently silent silius siliu + silk silk silken silken + silkman silkman silks silk + silliest silliest silliness silli + silling sill silly silli + silva silva silver silver + silvered silver silverly silverli + silvia silvia silvius silviu + sima sima simile simil + similes simil simois simoi + simon simon simony simoni + simp simp simpcox simpcox + simple simpl simpleness simpl + simpler simpler simples simpl + simplicity simplic simply simpli + simular simular simulation simul + sin sin since sinc + sincere sincer sincerely sincer + sincerity sincer sinel sinel + sinew sinew sinewed sinew + sinews sinew sinewy sinewi + sinful sin sinfully sinfulli + sing sing singe sing + singeing sing singer singer + singes sing singeth singeth + singing sing single singl + singled singl singleness singl + singly singli sings sing + singular singular singulariter singularit + singularities singular singularity singular + singuled singul sinister sinist + sink sink sinking sink + sinks sink sinn sinn + sinner sinner sinners sinner + sinning sin sinon sinon + sins sin sip sip + sipping sip sir sir + sire sire siren siren + sirrah sirrah sirs sir + sist sist sister sister + sisterhood sisterhood sisterly sisterli + sisters sister sit sit + sith sith sithence sithenc + sits sit sitting sit + situate situat situation situat + situations situat siward siward + six six sixpence sixpenc + sixpences sixpenc sixpenny sixpenni + sixteen sixteen sixth sixth + sixty sixti siz siz + size size sizes size + sizzle sizzl skains skain + skamble skambl skein skein + skelter skelter skies ski + skilful skil skilfully skilfulli + skill skill skilless skilless + skillet skillet skillful skill + skills skill skim skim + skimble skimbl skin skin + skinker skinker skinny skinni + skins skin skip skip + skipp skipp skipper skipper + skipping skip skirmish skirmish + skirmishes skirmish skirr skirr + skirted skirt skirts skirt + skittish skittish skulking skulk + skull skull skulls skull + sky sky skyey skyei + skyish skyish slab slab + slack slack slackly slackli + slackness slack slain slain + slake slake sland sland + slander slander slandered slander + slanderer slander slanderers slander + slandering slander slanderous slander + slanders slander slash slash + slaught slaught slaughter slaughter + slaughtered slaughter slaughterer slaughter + slaughterman slaughterman slaughtermen slaughtermen + slaughterous slaughter slaughters slaughter + slave slave slaver slaver + slavery slaveri slaves slave + slavish slavish slay slai + slayeth slayeth slaying slai + slays slai sleave sleav + sledded sled sleek sleek + sleekly sleekli sleep sleep + sleeper sleeper sleepers sleeper + sleepest sleepest sleeping sleep + sleeps sleep sleepy sleepi + sleeve sleev sleeves sleev + sleid sleid sleided sleid + sleight sleight sleights sleight + slender slender slenderer slender + slenderly slenderli slept slept + slew slew slewest slewest + slice slice slid slid + slide slide slides slide + sliding slide slight slight + slighted slight slightest slightest + slightly slightli slightness slight + slights slight slily slili + slime slime slimy slimi + slings sling slink slink + slip slip slipp slipp + slipper slipper slippers slipper + slippery slipperi slips slip + slish slish slit slit + sliver sliver slobb slobb + slomber slomber slop slop + slope slope slops slop + sloth sloth slothful sloth + slough slough slovenly slovenli + slovenry slovenri slow slow + slower slower slowly slowli + slowness slow slubber slubber + slug slug sluggard sluggard + sluggardiz sluggardiz sluggish sluggish + sluic sluic slumb slumb + slumber slumber slumbers slumber + slumbery slumberi slunk slunk + slut slut sluts slut + sluttery slutteri sluttish sluttish + sluttishness sluttish sly sly + slys sly smack smack + smacking smack smacks smack + small small smaller smaller + smallest smallest smallness small + smalus smalu smart smart + smarting smart smartly smartli + smatch smatch smatter smatter + smear smear smell smell + smelling smell smells smell + smelt smelt smil smil + smile smile smiled smile + smiles smile smilest smilest + smilets smilet smiling smile + smilingly smilingli smirch smirch + smirched smirch smit smit + smite smite smites smite + smith smith smithfield smithfield + smock smock smocks smock + smok smok smoke smoke + smoked smoke smokes smoke + smoking smoke smoky smoki + smooth smooth smoothed smooth + smoothing smooth smoothly smoothli + smoothness smooth smooths smooth + smote smote smoth smoth + smother smother smothered smother + smothering smother smug smug + smulkin smulkin smutch smutch + snaffle snaffl snail snail + snails snail snake snake + snakes snake snaky snaki + snap snap snapp snapp + snapper snapper snar snar + snare snare snares snare + snarl snarl snarleth snarleth + snarling snarl snatch snatch + snatchers snatcher snatches snatch + snatching snatch sneak sneak + sneaking sneak sneap sneap + sneaping sneap sneck sneck + snip snip snipe snipe + snipt snipt snore snore + snores snore snoring snore + snorting snort snout snout + snow snow snowballs snowbal + snowed snow snowy snowi + snuff snuff snuffs snuff + snug snug so so + soak soak soaking soak + soaks soak soar soar + soaring soar soars soar + sob sob sobbing sob + sober sober soberly soberli + sobriety sobrieti sobs sob + sociable sociabl societies societi + society societi socks sock + socrates socrat sod sod + sodden sodden soe soe + soever soever soft soft + soften soften softens soften + softer softer softest softest + softly softli softness soft + soil soil soiled soil + soilure soilur soit soit + sojourn sojourn sol sol + sola sola solace solac + solanio solanio sold sold + soldat soldat solder solder + soldest soldest soldier soldier + soldiers soldier soldiership soldiership + sole sole solely sole + solem solem solemn solemn + solemness solem solemnities solemn + solemnity solemn solemniz solemniz + solemnize solemn solemnized solemn + solemnly solemnli soles sole + solicit solicit solicitation solicit + solicited solicit soliciting solicit + solicitings solicit solicitor solicitor + solicits solicit solid solid + solidares solidar solidity solid + solinus solinu solitary solitari + solomon solomon solon solon + solum solum solus solu + solyman solyman some some + somebody somebodi someone someon + somerset somerset somerville somervil + something someth sometime sometim + sometimes sometim somever somev + somewhat somewhat somewhere somewher + somewhither somewhith somme somm + son son sonance sonanc + song song songs song + sonnet sonnet sonneting sonnet + sonnets sonnet sons son + sont sont sonties sonti + soon soon sooner sooner + soonest soonest sooth sooth + soothe sooth soothers soother + soothing sooth soothsay soothsai + soothsayer soothsay sooty sooti + sop sop sophister sophist + sophisticated sophist sophy sophi + sops sop sorcerer sorcer + sorcerers sorcer sorceress sorceress + sorceries sorceri sorcery sorceri + sore sore sorel sorel + sorely sore sorer sorer + sores sore sorrier sorrier + sorriest sorriest sorrow sorrow + sorrowed sorrow sorrowest sorrowest + sorrowful sorrow sorrowing sorrow + sorrows sorrow sorry sorri + sort sort sortance sortanc + sorted sort sorting sort + sorts sort sossius sossiu + sot sot soto soto + sots sot sottish sottish + soud soud sought sought + soul soul sould sould + soulless soulless souls soul + sound sound sounded sound + sounder sounder soundest soundest + sounding sound soundless soundless + soundly soundli soundness sound + soundpost soundpost sounds sound + sour sour source sourc + sources sourc sourest sourest + sourly sourli sours sour + sous sou souse sous + south south southam southam + southampton southampton southerly southerli + southern southern southward southward + southwark southwark southwell southwel + souviendrai souviendrai sov sov + sovereign sovereign sovereignest sovereignest + sovereignly sovereignli sovereignty sovereignti + sovereignvours sovereignvour sow sow + sowing sow sowl sowl + sowter sowter space space + spaces space spacious spaciou + spade spade spades spade + spain spain spak spak + spake spake spakest spakest + span span spangle spangl + spangled spangl spaniard spaniard + spaniel spaniel spaniels spaniel + spanish spanish spann spann + spans span spar spar + spare spare spares spare + sparing spare sparingly sparingli + spark spark sparkle sparkl + sparkles sparkl sparkling sparkl + sparks spark sparrow sparrow + sparrows sparrow sparta sparta + spartan spartan spavin spavin + spavins spavin spawn spawn + speak speak speaker speaker + speakers speaker speakest speakest + speaketh speaketh speaking speak + speaks speak spear spear + speargrass speargrass spears spear + special special specialities special + specially special specialties specialti + specialty specialti specify specifi + speciously specious spectacle spectacl + spectacled spectacl spectacles spectacl + spectators spectat spectatorship spectatorship + speculation specul speculations specul + speculative specul sped sped + speech speech speeches speech + speechless speechless speed speed + speeded speed speedier speedier + speediest speediest speedily speedili + speediness speedi speeding speed + speeds speed speedy speedi + speens speen spell spell + spelling spell spells spell + spelt spelt spencer spencer + spend spend spendest spendest + spending spend spends spend + spendthrift spendthrift spent spent + sperato sperato sperm sperm + spero spero sperr sperr + spher spher sphere sphere + sphered sphere spheres sphere + spherical spheric sphery spheri + sphinx sphinx spice spice + spiced spice spicery spiceri + spices spice spider spider + spiders spider spied spi + spies spi spieth spieth + spightfully spightfulli spigot spigot + spill spill spilling spill + spills spill spilt spilt + spilth spilth spin spin + spinii spinii spinners spinner + spinster spinster spinsters spinster + spire spire spirit spirit + spirited spirit spiritless spiritless + spirits spirit spiritual spiritu + spiritualty spiritualti spirt spirt + spit spit spital spital + spite spite spited spite + spiteful spite spites spite + spits spit spitted spit + spitting spit splay splai + spleen spleen spleenful spleen + spleens spleen spleeny spleeni + splendour splendour splenitive splenit + splinter splinter splinters splinter + split split splits split + splitted split splitting split + spoil spoil spoils spoil + spok spok spoke spoke + spoken spoken spokes spoke + spokesman spokesman sponge spong + spongy spongi spoon spoon + spoons spoon sport sport + sportful sport sporting sport + sportive sportiv sports sport + spot spot spotless spotless + spots spot spotted spot + spousal spousal spouse spous + spout spout spouting spout + spouts spout sprag sprag + sprang sprang sprat sprat + sprawl sprawl spray sprai + sprays sprai spread spread + spreading spread spreads spread + sprighted spright sprightful spright + sprightly sprightli sprigs sprig + spring spring springe spring + springes spring springeth springeth + springhalt springhalt springing spring + springs spring springtime springtim + sprinkle sprinkl sprinkles sprinkl + sprite sprite sprited sprite + spritely sprite sprites sprite + spriting sprite sprout sprout + spruce spruce sprung sprung + spun spun spur spur + spurio spurio spurn spurn + spurns spurn spurr spurr + spurrer spurrer spurring spur + spurs spur spy spy + spying spy squabble squabbl + squadron squadron squadrons squadron + squand squand squar squar + square squar squarer squarer + squares squar squash squash + squeak squeak squeaking squeak + squeal squeal squealing squeal + squeezes squeez squeezing squeez + squele squel squier squier + squints squint squiny squini + squire squir squires squir + squirrel squirrel st st + stab stab stabb stabb + stabbed stab stabbing stab + stable stabl stableness stabl + stables stabl stablish stablish + stablishment stablish stabs stab + stacks stack staff staff + stafford stafford staffords stafford + staffordshire staffordshir stag stag + stage stage stages stage + stagger stagger staggering stagger + staggers stagger stags stag + staid staid staider staider + stain stain stained stain + staines stain staineth staineth + staining stain stainless stainless + stains stain stair stair + stairs stair stake stake + stakes stake stale stale + staled stale stalk stalk + stalking stalk stalks stalk + stall stall stalling stall + stalls stall stamford stamford + stammer stammer stamp stamp + stamped stamp stamps stamp + stanch stanch stanchless stanchless + stand stand standard standard + standards standard stander stander + standers stander standest standest + standeth standeth standing stand + stands stand staniel staniel + stanley stanlei stanze stanz + stanzo stanzo stanzos stanzo + staple stapl staples stapl + star star stare stare + stared stare stares stare + staring stare starings stare + stark stark starkly starkli + starlight starlight starling starl + starr starr starry starri + stars star start start + started start starting start + startingly startingli startle startl + startles startl starts start + starv starv starve starv + starved starv starvelackey starvelackei + starveling starvel starveth starveth + starving starv state state + statelier stateli stately state + states state statesman statesman + statesmen statesmen statilius statiliu + station station statist statist + statists statist statue statu + statues statu stature statur + statures statur statute statut + statutes statut stave stave + staves stave stay stai + stayed stai stayest stayest + staying stai stays stai + stead stead steaded stead + steadfast steadfast steadier steadier + steads stead steal steal + stealer stealer stealers stealer + stealing steal steals steal + stealth stealth stealthy stealthi + steed steed steeds steed + steel steel steeled steel + steely steeli steep steep + steeped steep steeple steepl + steeples steepl steeps steep + steepy steepi steer steer + steerage steerag steering steer + steers steer stelled stell + stem stem stemming stem + stench stench step step + stepdame stepdam stephano stephano + stephen stephen stepmothers stepmoth + stepp stepp stepping step + steps step sterile steril + sterility steril sterling sterl + stern stern sternage sternag + sterner sterner sternest sternest + sternness stern steterat steterat + stew stew steward steward + stewards steward stewardship stewardship + stewed stew stews stew + stick stick sticking stick + stickler stickler sticks stick + stiff stiff stiffen stiffen + stiffly stiffli stifle stifl + stifled stifl stifles stifl + stigmatic stigmat stigmatical stigmat + stile stile still still + stiller stiller stillest stillest + stillness still stilly stilli + sting sting stinging sting + stingless stingless stings sting + stink stink stinking stink + stinkingly stinkingli stinks stink + stint stint stinted stint + stints stint stir stir + stirr stirr stirred stir + stirrer stirrer stirrers stirrer + stirreth stirreth stirring stir + stirrup stirrup stirrups stirrup + stirs stir stitchery stitcheri + stitches stitch stithied stithi + stithy stithi stoccadoes stoccado + stoccata stoccata stock stock + stockfish stockfish stocking stock + stockings stock stockish stockish + stocks stock stog stog + stogs stog stoics stoic + stokesly stokesli stol stol + stole stole stolen stolen + stolest stolest stomach stomach + stomachers stomach stomaching stomach + stomachs stomach ston ston + stone stone stonecutter stonecutt + stones stone stonish stonish + stony stoni stood stood + stool stool stools stool + stoop stoop stooping stoop + stoops stoop stop stop + stope stope stopp stopp + stopped stop stopping stop + stops stop stor stor + store store storehouse storehous + storehouses storehous stores store + stories stori storm storm + stormed storm storming storm + storms storm stormy stormi + story stori stoup stoup + stoups stoup stout stout + stouter stouter stoutly stoutli + stoutness stout stover stover + stow stow stowage stowag + stowed stow strachy strachi + stragglers straggler straggling straggl + straight straight straightest straightest + straightway straightwai strain strain + strained strain straining strain + strains strain strait strait + straited strait straiter straiter + straitly straitli straitness strait + straits strait strand strand + strange strang strangely strang + strangeness strang stranger stranger + strangers stranger strangest strangest + strangle strangl strangled strangl + strangler strangler strangles strangl + strangling strangl strappado strappado + straps strap stratagem stratagem + stratagems stratagem stratford stratford + strato strato straw straw + strawberries strawberri strawberry strawberri + straws straw strawy strawi + stray strai straying strai + strays strai streak streak + streaks streak stream stream + streamers streamer streaming stream + streams stream streching strech + street street streets street + strength strength strengthen strengthen + strengthened strengthen strengthless strengthless + strengths strength stretch stretch + stretched stretch stretches stretch + stretching stretch strew strew + strewing strew strewings strew + strewments strewment stricken stricken + strict strict stricter stricter + strictest strictest strictly strictli + stricture strictur stride stride + strides stride striding stride + strife strife strifes strife + strik strik strike strike + strikers striker strikes strike + strikest strikest striking strike + string string stringless stringless + strings string strip strip + stripes stripe stripling stripl + striplings stripl stripp stripp + stripping strip striv striv + strive strive strives strive + striving strive strok strok + stroke stroke strokes stroke + strond strond stronds strond + strong strong stronger stronger + strongest strongest strongly strongli + strooke strook strossers strosser + strove strove strown strown + stroy stroi struck struck + strucken strucken struggle struggl + struggles struggl struggling struggl + strumpet strumpet strumpeted strumpet + strumpets strumpet strung strung + strut strut struts strut + strutted strut strutting strut + stubble stubbl stubborn stubborn + stubbornest stubbornest stubbornly stubbornli + stubbornness stubborn stuck stuck + studded stud student student + students student studied studi + studies studi studious studiou + studiously studious studs stud + study studi studying studi + stuff stuff stuffing stuf + stuffs stuff stumble stumbl + stumbled stumbl stumblest stumblest + stumbling stumbl stump stump + stumps stump stung stung + stupefy stupefi stupid stupid + stupified stupifi stuprum stuprum + sturdy sturdi sty sty + styga styga stygian stygian + styl styl style style + styx styx su su + sub sub subcontracted subcontract + subdu subdu subdue subdu + subdued subdu subduements subduement + subdues subdu subduing subdu + subject subject subjected subject + subjection subject subjects subject + submerg submerg submission submiss + submissive submiss submit submit + submits submit submitting submit + suborn suborn subornation suborn + suborned suborn subscrib subscrib + subscribe subscrib subscribed subscrib + subscribes subscrib subscription subscript + subsequent subsequ subsidies subsidi + subsidy subsidi subsist subsist + subsisting subsist substance substanc + substances substanc substantial substanti + substitute substitut substituted substitut + substitutes substitut substitution substitut + subtile subtil subtilly subtilli + subtle subtl subtleties subtleti + subtlety subtleti subtly subtli + subtractors subtractor suburbs suburb + subversion subvers subverts subvert + succedant succed succeed succe + succeeded succeed succeeders succeed + succeeding succeed succeeds succe + success success successantly successantli + successes success successful success + successfully successfulli succession success + successive success successively success + successor successor successors successor + succour succour succours succour + such such suck suck + sucker sucker suckers sucker + sucking suck suckle suckl + sucks suck sudden sudden + suddenly suddenli sue sue + sued su suerly suerli + sues sue sueth sueth + suff suff suffer suffer + sufferance suffer sufferances suffer + suffered suffer suffering suffer + suffers suffer suffic suffic + suffice suffic sufficed suffic + suffices suffic sufficeth sufficeth + sufficiency suffici sufficient suffici + sufficiently suffici sufficing suffic + sufficit sufficit suffigance suffig + suffocate suffoc suffocating suffoc + suffocation suffoc suffolk suffolk + suffrage suffrag suffrages suffrag + sug sug sugar sugar + sugarsop sugarsop suggest suggest + suggested suggest suggesting suggest + suggestion suggest suggestions suggest + suggests suggest suis sui + suit suit suitable suitabl + suited suit suiting suit + suitor suitor suitors suitor + suits suit suivez suivez + sullen sullen sullens sullen + sullied sulli sullies sulli + sully sulli sulph sulph + sulpherous sulpher sulphur sulphur + sulphurous sulphur sultan sultan + sultry sultri sum sum + sumless sumless summ summ + summa summa summary summari + summer summer summers summer + summit summit summon summon + summoners summon summons summon + sumpter sumpter sumptuous sumptuou + sumptuously sumptuous sums sum + sun sun sunbeams sunbeam + sunburning sunburn sunburnt sunburnt + sund sund sunday sundai + sundays sundai sunder sunder + sunders sunder sundry sundri + sung sung sunk sunk + sunken sunken sunny sunni + sunrising sunris suns sun + sunset sunset sunshine sunshin + sup sup super super + superficial superfici superficially superfici + superfluity superflu superfluous superflu + superfluously superflu superflux superflux + superior superior supernal supern + supernatural supernatur superpraise superprais + superscript superscript superscription superscript + superserviceable superservic superstition superstit + superstitious superstiti superstitiously superstiti + supersubtle supersubtl supervise supervis + supervisor supervisor supp supp + supper supper suppers supper + suppertime suppertim supping sup + supplant supplant supple suppl + suppler suppler suppliance supplianc + suppliant suppliant suppliants suppliant + supplicant supplic supplication supplic + supplications supplic supplie suppli + supplied suppli supplies suppli + suppliest suppliest supply suppli + supplyant supplyant supplying suppli + supplyment supplyment support support + supportable support supportance support + supported support supporter support + supporters support supporting support + supportor supportor suppos suppo + supposal suppos suppose suppos + supposed suppos supposes suppos + supposest supposest supposing suppos + supposition supposit suppress suppress + suppressed suppress suppresseth suppresseth + supremacy supremaci supreme suprem + sups sup sur sur + surance suranc surcease surceas + surd surd sure sure + surecard surecard surely sure + surer surer surest surest + sureties sureti surety sureti + surfeit surfeit surfeited surfeit + surfeiter surfeit surfeiting surfeit + surfeits surfeit surge surg + surgeon surgeon surgeons surgeon + surgere surger surgery surgeri + surges surg surly surli + surmis surmi surmise surmis + surmised surmis surmises surmis + surmount surmount surmounted surmount + surmounts surmount surnam surnam + surname surnam surnamed surnam + surpasseth surpasseth surpassing surpass + surplice surplic surplus surplu + surpris surpri surprise surpris + surprised surpris surrender surrend + surrey surrei surreys surrei + survey survei surveyest surveyest + surveying survei surveyor surveyor + surveyors surveyor surveys survei + survive surviv survives surviv + survivor survivor susan susan + suspect suspect suspected suspect + suspecting suspect suspects suspect + suspend suspend suspense suspens + suspicion suspicion suspicions suspicion + suspicious suspici suspiration suspir + suspire suspir sust sust + sustain sustain sustaining sustain + sutler sutler sutton sutton + suum suum swabber swabber + swaddling swaddl swag swag + swagg swagg swagger swagger + swaggerer swagger swaggerers swagger + swaggering swagger swain swain + swains swain swallow swallow + swallowed swallow swallowing swallow + swallows swallow swam swam + swan swan swans swan + sward sward sware sware + swarm swarm swarming swarm + swart swart swarth swarth + swarths swarth swarthy swarthi + swashers swasher swashing swash + swath swath swathing swath + swathling swathl sway swai + swaying swai sways swai + swear swear swearer swearer + swearers swearer swearest swearest + swearing swear swearings swear + swears swear sweat sweat + sweaten sweaten sweating sweat + sweats sweat sweaty sweati + sweep sweep sweepers sweeper + sweeps sweep sweet sweet + sweeten sweeten sweetens sweeten + sweeter sweeter sweetest sweetest + sweetheart sweetheart sweeting sweet + sweetly sweetli sweetmeats sweetmeat + sweetness sweet sweets sweet + swell swell swelling swell + swellings swell swells swell + swelter swelter sweno sweno + swept swept swerve swerv + swerver swerver swerving swerv + swift swift swifter swifter + swiftest swiftest swiftly swiftli + swiftness swift swill swill + swills swill swim swim + swimmer swimmer swimmers swimmer + swimming swim swims swim + swine swine swineherds swineherd + swing swing swinge swing + swinish swinish swinstead swinstead + switches switch swits swit + switzers switzer swol swol + swoll swoll swoln swoln + swoon swoon swooned swoon + swooning swoon swoons swoon + swoop swoop swoopstake swoopstak + swor swor sword sword + sworder sworder swords sword + swore swore sworn sworn + swounded swound swounds swound + swum swum swung swung + sy sy sycamore sycamor + sycorax sycorax sylla sylla + syllable syllabl syllables syllabl + syllogism syllog symbols symbol + sympathise sympathis sympathiz sympathiz + sympathize sympath sympathized sympath + sympathy sympathi synagogue synagogu + synod synod synods synod + syracuse syracus syracusian syracusian + syracusians syracusian syria syria + syrups syrup t t + ta ta taber taber + table tabl tabled tabl + tables tabl tablet tablet + tabor tabor taborer tabor + tabors tabor tabourines tabourin + taciturnity taciturn tack tack + tackle tackl tackled tackl + tackles tackl tackling tackl + tacklings tackl taddle taddl + tadpole tadpol taffeta taffeta + taffety taffeti tag tag + tagrag tagrag tah tah + tail tail tailor tailor + tailors tailor tails tail + taint taint tainted taint + tainting taint taints taint + tainture taintur tak tak + take take taken taken + taker taker takes take + takest takest taketh taketh + taking take tal tal + talbot talbot talbotites talbotit + talbots talbot tale tale + talent talent talents talent + taleporter taleport tales tale + talk talk talked talk + talker talker talkers talker + talkest talkest talking talk + talks talk tall tall + taller taller tallest tallest + tallies talli tallow tallow + tally talli talons talon + tam tam tambourines tambourin + tame tame tamed tame + tamely tame tameness tame + tamer tamer tames tame + taming tame tamora tamora + tamworth tamworth tan tan + tang tang tangle tangl + tangled tangl tank tank + tanlings tanl tann tann + tanned tan tanner tanner + tanquam tanquam tanta tanta + tantaene tantaen tap tap + tape tape taper taper + tapers taper tapestries tapestri + tapestry tapestri taphouse taphous + tapp tapp tapster tapster + tapsters tapster tar tar + tardied tardi tardily tardili + tardiness tardi tardy tardi + tarentum tarentum targe targ + targes targ target target + targets target tarpeian tarpeian + tarquin tarquin tarquins tarquin + tarr tarr tarre tarr + tarriance tarrianc tarried tarri + tarries tarri tarry tarri + tarrying tarri tart tart + tartar tartar tartars tartar + tartly tartli tartness tart + task task tasker tasker + tasking task tasks task + tassel tassel taste tast + tasted tast tastes tast + tasting tast tatt tatt + tatter tatter tattered tatter + tatters tatter tattle tattl + tattling tattl tattlings tattl + taught taught taunt taunt + taunted taunt taunting taunt + tauntingly tauntingli taunts taunt + taurus tauru tavern tavern + taverns tavern tavy tavi + tawdry tawdri tawny tawni + tax tax taxation taxat + taxations taxat taxes tax + taxing tax tc tc + te te teach teach + teacher teacher teachers teacher + teaches teach teachest teachest + teacheth teacheth teaching teach + team team tear tear + tearful tear tearing tear + tears tear tearsheet tearsheet + teat teat tedious tediou + tediously tedious tediousness tedious + teem teem teeming teem + teems teem teen teen + teeth teeth teipsum teipsum + telamon telamon telamonius telamoniu + tell tell teller teller + telling tell tells tell + tellus tellu temp temp + temper temper temperality temper + temperance temper temperate temper + temperately temper tempers temper + tempest tempest tempests tempest + tempestuous tempestu temple templ + temples templ temporal tempor + temporary temporari temporiz temporiz + temporize tempor temporizer tempor + temps temp tempt tempt + temptation temptat temptations temptat + tempted tempt tempter tempter + tempters tempter tempteth tempteth + tempting tempt tempts tempt + ten ten tenable tenabl + tenant tenant tenantius tenantiu + tenantless tenantless tenants tenant + tench tench tend tend + tendance tendanc tended tend + tender tender tendered tender + tenderly tenderli tenderness tender + tenders tender tending tend + tends tend tenedos tenedo + tenement tenement tenements tenement + tenfold tenfold tennis tenni + tenour tenour tenours tenour + tens ten tent tent + tented tent tenth tenth + tenths tenth tents tent + tenure tenur tenures tenur + tercel tercel tereus tereu + term term termagant termag + termed term terminations termin + termless termless terms term + terra terra terrace terrac + terram terram terras terra + terre terr terrene terren + terrestrial terrestri terrible terribl + terribly terribl territories territori + territory territori terror terror + terrors terror tertian tertian + tertio tertio test test + testament testament tested test + tester tester testern testern + testify testifi testimonied testimoni + testimonies testimoni testimony testimoni + testiness testi testril testril + testy testi tetchy tetchi + tether tether tetter tetter + tevil tevil tewksbury tewksburi + text text tgv tgv + th th thaes thae + thames thame than than + thane thane thanes thane + thank thank thanked thank + thankful thank thankfully thankfulli + thankfulness thank thanking thank + thankings thank thankless thankless + thanks thank thanksgiving thanksgiv + thasos thaso that that + thatch thatch thaw thaw + thawing thaw thaws thaw + the the theatre theatr + theban theban thebes thebe + thee thee theft theft + thefts theft thein thein + their their theirs their + theise theis them them + theme theme themes theme + themselves themselv then then + thence thenc thenceforth thenceforth + theoric theoric there there + thereabout thereabout thereabouts thereabout + thereafter thereaft thereat thereat + thereby therebi therefore therefor + therein therein thereof thereof + thereon thereon thereto thereto + thereunto thereunto thereupon thereupon + therewith therewith therewithal therewith + thersites thersit these these + theseus theseu thessalian thessalian + thessaly thessali thetis theti + thews thew they thei + thick thick thicken thicken + thickens thicken thicker thicker + thickest thickest thicket thicket + thickskin thickskin thief thief + thievery thieveri thieves thiev + thievish thievish thigh thigh + thighs thigh thimble thimbl + thimbles thimbl thin thin + thine thine thing thing + things thing think think + thinkest thinkest thinking think + thinkings think thinks think + thinkst thinkst thinly thinli + third third thirdly thirdli + thirds third thirst thirst + thirsting thirst thirsts thirst + thirsty thirsti thirteen thirteen + thirties thirti thirtieth thirtieth + thirty thirti this thi + thisby thisbi thisne thisn + thistle thistl thistles thistl + thither thither thitherward thitherward + thoas thoa thomas thoma + thorn thorn thorns thorn + thorny thorni thorough thorough + thoroughly thoroughli those those + thou thou though though + thought thought thoughtful thought + thoughts thought thousand thousand + thousands thousand thracian thracian + thraldom thraldom thrall thrall + thralled thrall thralls thrall + thrash thrash thrasonical thrason + thread thread threadbare threadbar + threaden threaden threading thread + threat threat threaten threaten + threatening threaten threatens threaten + threatest threatest threats threat + three three threefold threefold + threepence threepenc threepile threepil + threes three threescore threescor + thresher thresher threshold threshold + threw threw thrice thrice + thrift thrift thriftless thriftless + thrifts thrift thrifty thrifti + thrill thrill thrilling thrill + thrills thrill thrive thrive + thrived thrive thrivers thriver + thrives thrive thriving thrive + throat throat throats throat + throbbing throb throbs throb + throca throca throe throe + throes throe thromuldo thromuldo + thron thron throne throne + throned throne thrones throne + throng throng thronging throng + throngs throng throstle throstl + throttle throttl through through + throughfare throughfar throughfares throughfar + throughly throughli throughout throughout + throw throw thrower thrower + throwest throwest throwing throw + thrown thrown throws throw + thrum thrum thrumm thrumm + thrush thrush thrust thrust + thrusteth thrusteth thrusting thrust + thrusts thrust thumb thumb + thumbs thumb thump thump + thund thund thunder thunder + thunderbolt thunderbolt thunderbolts thunderbolt + thunderer thunder thunders thunder + thunderstone thunderston thunderstroke thunderstrok + thurio thurio thursday thursdai + thus thu thwack thwack + thwart thwart thwarted thwart + thwarting thwart thwartings thwart + thy thy thyme thyme + thymus thymu thyreus thyreu + thyself thyself ti ti + tib tib tiber tiber + tiberio tiberio tibey tibei + ticed tice tick tick + tickl tickl tickle tickl + tickled tickl tickles tickl + tickling tickl ticklish ticklish + tiddle tiddl tide tide + tides tide tidings tide + tidy tidi tie tie + tied ti ties ti + tiff tiff tiger tiger + tigers tiger tight tight + tightly tightli tike tike + til til tile tile + till till tillage tillag + tilly tilli tilt tilt + tilter tilter tilth tilth + tilting tilt tilts tilt + tiltyard tiltyard tim tim + timandra timandra timber timber + time time timeless timeless + timelier timeli timely time + times time timon timon + timor timor timorous timor + timorously timor tinct tinct + tincture tinctur tinctures tinctur + tinder tinder tingling tingl + tinker tinker tinkers tinker + tinsel tinsel tiny tini + tip tip tipp tipp + tippling tippl tips tip + tipsy tipsi tiptoe tipto + tir tir tire tire + tired tire tires tire + tirest tirest tiring tire + tirra tirra tirrits tirrit + tis ti tish tish + tisick tisick tissue tissu + titan titan titania titania + tithe tith tithed tith + tithing tith titinius titiniu + title titl titled titl + titleless titleless titles titl + tittle tittl tittles tittl + titular titular titus titu + tn tn to to + toad toad toads toad + toadstool toadstool toast toast + toasted toast toasting toast + toasts toast toaze toaz + toby tobi tock tock + tod tod today todai + todpole todpol tods tod + toe toe toes toe + tofore tofor toge toge + toged toge together togeth + toil toil toiled toil + toiling toil toils toil + token token tokens token + told told toledo toledo + tolerable toler toll toll + tolling toll tom tom + tomb tomb tombe tomb + tombed tomb tombless tombless + tomboys tomboi tombs tomb + tomorrow tomorrow tomyris tomyri + ton ton tongs tong + tongu tongu tongue tongu + tongued tongu tongueless tongueless + tongues tongu tonight tonight + too too took took + tool tool tools tool + tooth tooth toothache toothach + toothpick toothpick toothpicker toothpick + top top topas topa + topful top topgallant topgal + topless topless topmast topmast + topp topp topping top + topple toppl topples toppl + tops top topsail topsail + topsy topsi torch torch + torchbearer torchbear torchbearers torchbear + torcher torcher torches torch + torchlight torchlight tore tore + torment torment tormenta tormenta + tormente torment tormented torment + tormenting torment tormentors tormentor + torments torment torn torn + torrent torrent tortive tortiv + tortoise tortois tortur tortur + torture tortur tortured tortur + torturer tortur torturers tortur + tortures tortur torturest torturest + torturing tortur toryne toryn + toss toss tossed toss + tosseth tosseth tossing toss + tot tot total total + totally total tott tott + tottered totter totters totter + tou tou touch touch + touched touch touches touch + toucheth toucheth touching touch + touchstone touchston tough tough + tougher tougher toughness tough + touraine tourain tournaments tournament + tours tour tous tou + tout tout touze touz + tow tow toward toward + towardly towardli towards toward + tower tower towering tower + towers tower town town + towns town township township + townsman townsman townsmen townsmen + towton towton toy toi + toys toi trace trace + traces trace track track + tract tract tractable tractabl + trade trade traded trade + traders trader trades trade + tradesman tradesman tradesmen tradesmen + trading trade tradition tradit + traditional tradit traduc traduc + traduced traduc traducement traduc + traffic traffic traffickers traffick + traffics traffic tragedian tragedian + tragedians tragedian tragedies tragedi + tragedy tragedi tragic tragic + tragical tragic trail trail + train train trained train + training train trains train + trait trait traitor traitor + traitorly traitorli traitorous traitor + traitorously traitor traitors traitor + traitress traitress traject traject + trammel trammel trample trampl + trampled trampl trampling trampl + tranc tranc trance tranc + tranio tranio tranquil tranquil + tranquillity tranquil transcendence transcend + transcends transcend transferred transfer + transfigur transfigur transfix transfix + transform transform transformation transform + transformations transform transformed transform + transgress transgress transgresses transgress + transgressing transgress transgression transgress + translate translat translated translat + translates translat translation translat + transmigrates transmigr transmutation transmut + transparent transpar transport transport + transportance transport transported transport + transporting transport transports transport + transpose transpos transshape transshap + trap trap trapp trapp + trappings trap traps trap + trash trash travail travail + travails travail travel travel + traveler travel traveling travel + travell travel travelled travel + traveller travel travellers travel + travellest travellest travelling travel + travels travel travers traver + traverse travers tray trai + treacherous treacher treacherously treacher + treachers treacher treachery treacheri + tread tread treading tread + treads tread treason treason + treasonable treason treasonous treason + treasons treason treasure treasur + treasurer treasur treasures treasur + treasuries treasuri treasury treasuri + treat treat treaties treati + treatise treatis treats treat + treaty treati treble trebl + trebled trebl trebles trebl + trebonius treboniu tree tree + trees tree tremble trembl + trembled trembl trembles trembl + tremblest tremblest trembling trembl + tremblingly tremblingli tremor tremor + trempling trempl trench trench + trenchant trenchant trenched trench + trencher trencher trenchering trencher + trencherman trencherman trenchers trencher + trenches trench trenching trench + trent trent tres tre + trespass trespass trespasses trespass + tressel tressel tresses tress + treys trei trial trial + trials trial trib trib + tribe tribe tribes tribe + tribulation tribul tribunal tribun + tribune tribun tribunes tribun + tributaries tributari tributary tributari + tribute tribut tributes tribut + trice trice trick trick + tricking trick trickling trickl + tricks trick tricksy tricksi + trident trident tried tri + trier trier trifle trifl + trifled trifl trifler trifler + trifles trifl trifling trifl + trigon trigon trill trill + trim trim trimly trimli + trimm trimm trimmed trim + trimming trim trims trim + trinculo trinculo trinculos trinculo + trinkets trinket trip trip + tripartite tripartit tripe tripe + triple tripl triplex triplex + tripoli tripoli tripolis tripoli + tripp tripp tripping trip + trippingly trippingli trips trip + tristful trist triton triton + triumph triumph triumphant triumphant + triumphantly triumphantli triumpher triumpher + triumphers triumpher triumphing triumph + triumphs triumph triumvir triumvir + triumvirate triumvir triumvirs triumvir + triumviry triumviri trivial trivial + troat troat trod trod + trodden trodden troiant troiant + troien troien troilus troilu + troiluses troilus trojan trojan + trojans trojan troll troll + tromperies tromperi trompet trompet + troop troop trooping troop + troops troop trop trop + trophies trophi trophy trophi + tropically tropic trot trot + troth troth trothed troth + troths troth trots trot + trotting trot trouble troubl + troubled troubl troubler troubler + troubles troubl troublesome troublesom + troublest troublest troublous troublou + trough trough trout trout + trouts trout trovato trovato + trow trow trowel trowel + trowest trowest troy troi + troyan troyan troyans troyan + truant truant truce truce + truckle truckl trudge trudg + true true trueborn trueborn + truepenny truepenni truer truer + truest truest truie truie + trull trull trulls trull + truly truli trump trump + trumpery trumperi trumpet trumpet + trumpeter trumpet trumpeters trumpet + trumpets trumpet truncheon truncheon + truncheoners truncheon trundle trundl + trunk trunk trunks trunk + trust trust trusted trust + truster truster trusters truster + trusting trust trusts trust + trusty trusti truth truth + truths truth try try + ts ts tu tu + tuae tuae tub tub + tubal tubal tubs tub + tuck tuck tucket tucket + tuesday tuesdai tuft tuft + tufts tuft tug tug + tugg tugg tugging tug + tuition tuition tullus tullu + tully tulli tumble tumbl + tumbled tumbl tumbler tumbler + tumbling tumbl tumult tumult + tumultuous tumultu tun tun + tune tune tuneable tuneabl + tuned tune tuners tuner + tunes tune tunis tuni + tuns tun tupping tup + turban turban turbans turban + turbulence turbul turbulent turbul + turd turd turf turf + turfy turfi turk turk + turkey turkei turkeys turkei + turkish turkish turks turk + turlygod turlygod turmoil turmoil + turmoiled turmoil turn turn + turnbull turnbul turncoat turncoat + turncoats turncoat turned turn + turneth turneth turning turn + turnips turnip turns turn + turph turph turpitude turpitud + turquoise turquois turret turret + turrets turret turtle turtl + turtles turtl turvy turvi + tuscan tuscan tush tush + tut tut tutor tutor + tutored tutor tutors tutor + tutto tutto twain twain + twang twang twangling twangl + twas twa tway twai + tweaks tweak tween tween + twelfth twelfth twelve twelv + twelvemonth twelvemonth twentieth twentieth + twenty twenti twere twere + twice twice twig twig + twiggen twiggen twigs twig + twilight twilight twill twill + twilled twill twin twin + twine twine twink twink + twinkle twinkl twinkled twinkl + twinkling twinkl twinn twinn + twins twin twire twire + twist twist twisted twist + twit twit twits twit + twitting twit twixt twixt + two two twofold twofold + twopence twopenc twopences twopenc + twos two twould twould + tyb tyb tybalt tybalt + tybalts tybalt tyburn tyburn + tying ty tyke tyke + tymbria tymbria type type + types type typhon typhon + tyrannical tyrann tyrannically tyrann + tyrannize tyrann tyrannous tyrann + tyranny tyranni tyrant tyrant + tyrants tyrant tyrian tyrian + tyrrel tyrrel u u + ubique ubiqu udders udder + udge udg uds ud + uglier uglier ugliest ugliest + ugly ugli ulcer ulcer + ulcerous ulcer ulysses ulyss + um um umber umber + umbra umbra umbrage umbrag + umfrevile umfrevil umpire umpir + umpires umpir un un + unable unabl unaccommodated unaccommod + unaccompanied unaccompani unaccustom unaccustom + unaching unach unacquainted unacquaint + unactive unact unadvis unadvi + unadvised unadvis unadvisedly unadvisedli + unagreeable unagre unanel unanel + unanswer unansw unappeas unappea + unapproved unapprov unapt unapt + unaptness unapt unarm unarm + unarmed unarm unarms unarm + unassail unassail unassailable unassail + unattainted unattaint unattempted unattempt + unattended unattend unauspicious unauspici + unauthorized unauthor unavoided unavoid + unawares unawar unback unback + unbak unbak unbanded unband + unbar unbar unbarb unbarb + unbashful unbash unbated unbat + unbatter unbatt unbecoming unbecom + unbefitting unbefit unbegot unbegot + unbegotten unbegotten unbelieved unbeliev + unbend unbend unbent unbent + unbewail unbewail unbid unbid + unbidden unbidden unbind unbind + unbinds unbind unbitted unbit + unbless unbless unblest unblest + unbloodied unbloodi unblown unblown + unbodied unbodi unbolt unbolt + unbolted unbolt unbonneted unbonnet + unbookish unbookish unborn unborn + unbosom unbosom unbound unbound + unbounded unbound unbow unbow + unbowed unbow unbrac unbrac + unbraced unbrac unbraided unbraid + unbreathed unbreath unbred unbr + unbreech unbreech unbridled unbridl + unbroke unbrok unbruis unbrui + unbruised unbruis unbuckle unbuckl + unbuckles unbuckl unbuckling unbuckl + unbuild unbuild unburden unburden + unburdens unburden unburied unburi + unburnt unburnt unburthen unburthen + unbutton unbutton unbuttoning unbutton + uncapable uncap uncape uncap + uncase uncas uncasing uncas + uncaught uncaught uncertain uncertain + uncertainty uncertainti unchain unchain + unchanging unchang uncharge uncharg + uncharged uncharg uncharitably uncharit + unchary unchari unchaste unchast + uncheck uncheck unchilded unchild + uncivil uncivil unclaim unclaim + unclasp unclasp uncle uncl + unclean unclean uncleanliness uncleanli + uncleanly uncleanli uncleanness unclean + uncles uncl unclew unclew + unclog unclog uncoined uncoin + uncolted uncolt uncomeliness uncomeli + uncomfortable uncomfort uncompassionate uncompassion + uncomprehensive uncomprehens unconfinable unconfin + unconfirm unconfirm unconfirmed unconfirm + unconquer unconqu unconquered unconqu + unconsidered unconsid unconstant unconst + unconstrain unconstrain unconstrained unconstrain + uncontemn uncontemn uncontroll uncontrol + uncorrected uncorrect uncounted uncount + uncouple uncoupl uncourteous uncourt + uncouth uncouth uncover uncov + uncovered uncov uncropped uncrop + uncross uncross uncrown uncrown + unction unction unctuous unctuou + uncuckolded uncuckold uncurable uncur + uncurbable uncurb uncurbed uncurb + uncurls uncurl uncurrent uncurr + uncurse uncurs undaunted undaunt + undeaf undeaf undeck undeck + undeeded undeed under under + underbearing underbear underborne underborn + undercrest undercrest underfoot underfoot + undergo undergo undergoes undergo + undergoing undergo undergone undergon + underground underground underhand underhand + underlings underl undermine undermin + underminers undermin underneath underneath + underprizing underpr underprop underprop + understand understand understandeth understandeth + understanding understand understandings understand + understands understand understood understood + underta underta undertake undertak + undertakeing undertak undertaker undertak + undertakes undertak undertaking undertak + undertakings undertak undertook undertook + undervalu undervalu undervalued undervalu + underwent underw underwrit underwrit + underwrite underwrit undescried undescri + undeserved undeserv undeserver undeserv + undeservers undeserv undeserving undeserv + undetermin undetermin undid undid + undinted undint undiscernible undiscern + undiscover undiscov undishonoured undishonour + undispos undispo undistinguishable undistinguish + undistinguished undistinguish undividable undivid + undivided undivid undivulged undivulg + undo undo undoes undo + undoing undo undone undon + undoubted undoubt undoubtedly undoubtedli + undream undream undress undress + undressed undress undrown undrown + unduteous undut undutiful unduti + une un uneared unear + unearned unearn unearthly unearthli + uneasines uneasin uneasy uneasi + uneath uneath uneducated uneduc + uneffectual uneffectu unelected unelect + unequal unequ uneven uneven + unexamin unexamin unexecuted unexecut + unexpected unexpect unexperienc unexperienc + unexperient unexperi unexpressive unexpress + unfair unfair unfaithful unfaith + unfallible unfal unfam unfam + unfashionable unfashion unfasten unfasten + unfather unfath unfathered unfath + unfed unf unfeed unfe + unfeeling unfeel unfeigned unfeign + unfeignedly unfeignedli unfellowed unfellow + unfelt unfelt unfenced unfenc + unfilial unfili unfill unfil + unfinish unfinish unfirm unfirm + unfit unfit unfitness unfit + unfix unfix unfledg unfledg + unfold unfold unfolded unfold + unfoldeth unfoldeth unfolding unfold + unfolds unfold unfool unfool + unforc unforc unforced unforc + unforfeited unforfeit unfortified unfortifi + unfortunate unfortun unfought unfought + unfrequented unfrequ unfriended unfriend + unfurnish unfurnish ungain ungain + ungalled ungal ungart ungart + ungarter ungart ungenitur ungenitur + ungentle ungentl ungentleness ungentl + ungently ungent ungird ungird + ungodly ungodli ungor ungor + ungot ungot ungotten ungotten + ungovern ungovern ungracious ungraci + ungrateful ungrat ungravely ungrav + ungrown ungrown unguarded unguard + unguem unguem unguided unguid + unhack unhack unhair unhair + unhallow unhallow unhallowed unhallow + unhand unhand unhandled unhandl + unhandsome unhandsom unhang unhang + unhappied unhappi unhappily unhappili + unhappiness unhappi unhappy unhappi + unhardened unharden unharm unharm + unhatch unhatch unheard unheard + unhearts unheart unheedful unheed + unheedfully unheedfulli unheedy unheedi + unhelpful unhelp unhidden unhidden + unholy unholi unhop unhop + unhopefullest unhopefullest unhorse unhors + unhospitable unhospit unhous unhou + unhoused unhous unhurtful unhurt + unicorn unicorn unicorns unicorn + unimproved unimprov uninhabitable uninhabit + uninhabited uninhabit unintelligent unintellig + union union unions union + unite unit united unit + unity uniti universal univers + universe univers universities univers + university univers unjointed unjoint + unjust unjust unjustice unjustic + unjustly unjustli unkennel unkennel + unkept unkept unkind unkind + unkindest unkindest unkindly unkindli + unkindness unkind unking unk + unkinglike unkinglik unkiss unkiss + unknit unknit unknowing unknow + unknown unknown unlace unlac + unlaid unlaid unlawful unlaw + unlawfully unlawfulli unlearn unlearn + unlearned unlearn unless unless + unlesson unlesson unletter unlett + unlettered unlett unlick unlick + unlike unlik unlikely unlik + unlimited unlimit unlineal unlin + unlink unlink unload unload + unloaded unload unloading unload + unloads unload unlock unlock + unlocks unlock unlook unlook + unlooked unlook unloos unloo + unloose unloos unlov unlov + unloving unlov unluckily unluckili + unlucky unlucki unmade unmad + unmake unmak unmanly unmanli + unmann unmann unmanner unmann + unmannerd unmannerd unmannerly unmannerli + unmarried unmarri unmask unmask + unmasked unmask unmasking unmask + unmasks unmask unmast unmast + unmatch unmatch unmatchable unmatch + unmatched unmatch unmeasurable unmeasur + unmeet unmeet unmellowed unmellow + unmerciful unmerci unmeritable unmerit + unmeriting unmerit unminded unmind + unmindfull unmindful unmingled unmingl + unmitigable unmitig unmitigated unmitig + unmix unmix unmoan unmoan + unmov unmov unmoved unmov + unmoving unmov unmuffles unmuffl + unmuffling unmuffl unmusical unmus + unmuzzle unmuzzl unmuzzled unmuzzl + unnatural unnatur unnaturally unnatur + unnaturalness unnatur unnecessarily unnecessarili + unnecessary unnecessari unneighbourly unneighbourli + unnerved unnerv unnoble unnobl + unnoted unnot unnumb unnumb + unnumber unnumb unowed unow + unpack unpack unpaid unpaid + unparagon unparagon unparallel unparallel + unpartial unparti unpath unpath + unpaved unpav unpay unpai + unpeaceable unpeac unpeg unpeg + unpeople unpeopl unpeopled unpeopl + unperfect unperfect unperfectness unperfect + unpick unpick unpin unpin + unpink unpink unpitied unpiti + unpitifully unpitifulli unplagu unplagu + unplausive unplaus unpleas unplea + unpleasant unpleas unpleasing unpleas + unpolicied unpolici unpolish unpolish + unpolished unpolish unpolluted unpollut + unpossess unpossess unpossessing unpossess + unpossible unposs unpractis unpracti + unpregnant unpregn unpremeditated unpremedit + unprepar unprepar unprepared unprepar + unpress unpress unprevailing unprevail + unprevented unprev unpriz unpriz + unprizable unpriz unprofitable unprofit + unprofited unprofit unproper unprop + unproperly unproperli unproportion unproport + unprovide unprovid unprovided unprovid + unprovident unprovid unprovokes unprovok + unprun unprun unpruned unprun + unpublish unpublish unpurged unpurg + unpurpos unpurpo unqualitied unqual + unqueen unqueen unquestion unquest + unquestionable unquestion unquiet unquiet + unquietly unquietli unquietness unquiet + unraised unrais unrak unrak + unread unread unready unreadi + unreal unreal unreasonable unreason + unreasonably unreason unreclaimed unreclaim + unreconciled unreconcil unreconciliable unreconcili + unrecounted unrecount unrecuring unrecur + unregarded unregard unregist unregist + unrelenting unrel unremovable unremov + unremovably unremov unreprievable unrepriev + unresolv unresolv unrespected unrespect + unrespective unrespect unrest unrest + unrestor unrestor unrestrained unrestrain + unreveng unreveng unreverend unreverend + unreverent unrever unrevers unrev + unrewarded unreward unrighteous unright + unrightful unright unripe unrip + unripp unripp unrivall unrival + unroll unrol unroof unroof + unroosted unroost unroot unroot + unrough unrough unruly unruli + unsafe unsaf unsaluted unsalut + unsanctified unsanctifi unsatisfied unsatisfi + unsavoury unsavouri unsay unsai + unscalable unscal unscann unscann + unscarr unscarr unschool unschool + unscorch unscorch unscour unscour + unscratch unscratch unseal unseal + unseam unseam unsearch unsearch + unseason unseason unseasonable unseason + unseasonably unseason unseasoned unseason + unseconded unsecond unsecret unsecret + unseduc unseduc unseeing unse + unseeming unseem unseemly unseemli + unseen unseen unseminar unseminar + unseparable unsepar unserviceable unservic + unset unset unsettle unsettl + unsettled unsettl unsever unsev + unsex unsex unshak unshak + unshaked unshak unshaken unshaken + unshaped unshap unshapes unshap + unsheath unsheath unsheathe unsheath + unshorn unshorn unshout unshout + unshown unshown unshrinking unshrink + unshrubb unshrubb unshunn unshunn + unshunnable unshunn unsifted unsift + unsightly unsightli unsinew unsinew + unsisting unsist unskilful unskil + unskilfully unskilfulli unskillful unskil + unslipping unslip unsmirched unsmirch + unsoil unsoil unsolicited unsolicit + unsorted unsort unsought unsought + unsound unsound unsounded unsound + unspeak unspeak unspeakable unspeak + unspeaking unspeak unsphere unspher + unspoke unspok unspoken unspoken + unspotted unspot unsquar unsquar + unstable unstabl unstaid unstaid + unstain unstain unstained unstain + unstanched unstanch unstate unstat + unsteadfast unsteadfast unstooping unstoop + unstringed unstring unstuff unstuff + unsubstantial unsubstanti unsuitable unsuit + unsuiting unsuit unsullied unsulli + unsunn unsunn unsur unsur + unsure unsur unsuspected unsuspect + unsway unswai unswayable unsway + unswayed unswai unswear unswear + unswept unswept unsworn unsworn + untainted untaint untalk untalk + untangle untangl untangled untangl + untasted untast untaught untaught + untempering untemp untender untend + untent untent untented untent + unthankful unthank unthankfulness unthank + unthink unthink unthought unthought + unthread unthread unthrift unthrift + unthrifts unthrift unthrifty unthrifti + untie unti untied unti + until until untimber untimb + untimely untim untir untir + untirable untir untired untir + untitled untitl unto unto + untold untold untouch untouch + untoward untoward untowardly untowardli + untraded untrad untrain untrain + untrained untrain untread untread + untreasur untreasur untried untri + untrimmed untrim untrod untrod + untrodden untrodden untroubled untroubl + untrue untru untrussing untruss + untruth untruth untruths untruth + untucked untuck untun untun + untune untun untuneable untun + untutor untutor untutored untutor + untwine untwin unurg unurg + unus unu unused unus + unusual unusu unvalued unvalu + unvanquish unvanquish unvarnish unvarnish + unveil unveil unveiling unveil + unvenerable unvener unvex unvex + unviolated unviol unvirtuous unvirtu + unvisited unvisit unvulnerable unvulner + unwares unwar unwarily unwarili + unwash unwash unwatch unwatch + unwearied unweari unwed unw + unwedgeable unwedg unweeded unweed + unweighed unweigh unweighing unweigh + unwelcome unwelcom unwept unwept + unwhipp unwhipp unwholesome unwholesom + unwieldy unwieldi unwilling unwil + unwillingly unwillingli unwillingness unwilling + unwind unwind unwiped unwip + unwise unwis unwisely unwis + unwish unwish unwished unwish + unwitted unwit unwittingly unwittingli + unwonted unwont unwooed unwoo + unworthier unworthi unworthiest unworthiest + unworthily unworthili unworthiness unworthi + unworthy unworthi unwrung unwrung + unyok unyok unyoke unyok + up up upbraid upbraid + upbraided upbraid upbraidings upbraid + upbraids upbraid uphoarded uphoard + uphold uphold upholdeth upholdeth + upholding uphold upholds uphold + uplift uplift uplifted uplift + upmost upmost upon upon + upper upper uprear uprear + upreared uprear upright upright + uprighteously upright uprightness upright + uprise upris uprising upris + uproar uproar uproars uproar + uprous uprou upshoot upshoot + upshot upshot upside upsid + upspring upspr upstairs upstair + upstart upstart upturned upturn + upward upward upwards upward + urchin urchin urchinfield urchinfield + urchins urchin urg urg + urge urg urged urg + urgent urgent urges urg + urgest urgest urging urg + urinal urin urinals urin + urine urin urn urn + urns urn urs ur + ursa ursa ursley urslei + ursula ursula urswick urswick + us us usage usag + usance usanc usances usanc + use us used us + useful us useless useless + user user uses us + usest usest useth useth + usher usher ushered usher + ushering usher ushers usher + using us usual usual + usually usual usurer usur + usurers usur usuries usuri + usuring usur usurp usurp + usurpation usurp usurped usurp + usurper usurp usurpers usurp + usurping usurp usurpingly usurpingli + usurps usurp usury usuri + ut ut utensil utensil + utensils utensil utility util + utmost utmost utt utt + utter utter utterance utter + uttered utter uttereth uttereth + uttering utter utterly utterli + uttermost uttermost utters utter + uy uy v v + va va vacancy vacanc + vacant vacant vacation vacat + vade vade vagabond vagabond + vagabonds vagabond vagram vagram + vagrom vagrom vail vail + vailed vail vailing vail + vaillant vaillant vain vain + vainer vainer vainglory vainglori + vainly vainli vainness vain + vais vai valanc valanc + valance valanc vale vale + valence valenc valentine valentin + valentinus valentinu valentio valentio + valeria valeria valerius valeriu + vales vale valiant valiant + valiantly valiantli valiantness valiant + validity valid vallant vallant + valley vallei valleys vallei + vally valli valor valor + valorous valor valorously valor + valour valour valu valu + valuation valuat value valu + valued valu valueless valueless + values valu valuing valu + vane vane vanish vanish + vanished vanish vanishes vanish + vanishest vanishest vanishing vanish + vanities vaniti vanity vaniti + vanquish vanquish vanquished vanquish + vanquisher vanquish vanquishest vanquishest + vanquisheth vanquisheth vant vant + vantage vantag vantages vantag + vantbrace vantbrac vapians vapian + vapor vapor vaporous vapor + vapour vapour vapours vapour + vara vara variable variabl + variance varianc variation variat + variations variat varied vari + variest variest variety varieti + varld varld varlet varlet + varletry varletri varlets varlet + varletto varletto varnish varnish + varrius varriu varro varro + vary vari varying vari + vassal vassal vassalage vassalag + vassals vassal vast vast + vastidity vastid vasty vasti + vat vat vater vater + vaudemont vaudemont vaughan vaughan + vault vault vaultages vaultag + vaulted vault vaulting vault + vaults vault vaulty vaulti + vaumond vaumond vaunt vaunt + vaunted vaunt vaunter vaunter + vaunting vaunt vauntingly vauntingli + vaunts vaunt vauvado vauvado + vaux vaux vaward vaward + ve ve veal veal + vede vede vehemence vehem + vehemency vehem vehement vehement + vehor vehor veil veil + veiled veil veiling veil + vein vein veins vein + vell vell velure velur + velutus velutu velvet velvet + vendible vendibl venerable vener + venereal vener venetia venetia + venetian venetian venetians venetian + veneys venei venge veng + vengeance vengeanc vengeances vengeanc + vengeful veng veni veni + venial venial venice venic + venison venison venit venit + venom venom venomous venom + venomously venom vent vent + ventages ventag vented vent + ventidius ventidiu ventricle ventricl + vents vent ventur ventur + venture ventur ventured ventur + ventures ventur venturing ventur + venturous ventur venue venu + venus venu venuto venuto + ver ver verb verb + verba verba verbal verbal + verbatim verbatim verbosity verbos + verdict verdict verdun verdun + verdure verdur vere vere + verefore verefor verg verg + verge verg vergers verger + verges verg verier verier + veriest veriest verified verifi + verify verifi verily verili + veritable verit verite verit + verities veriti verity veriti + vermilion vermilion vermin vermin + vernon vernon verona verona + veronesa veronesa versal versal + verse vers verses vers + versing vers vert vert + very veri vesper vesper + vessel vessel vessels vessel + vestal vestal vestments vestment + vesture vestur vetch vetch + vetches vetch veux veux + vex vex vexation vexat + vexations vexat vexed vex + vexes vex vexest vexest + vexeth vexeth vexing vex + vi vi via via + vial vial vials vial + viand viand viands viand + vic vic vicar vicar + vice vice vicegerent viceger + vicentio vicentio viceroy viceroi + viceroys viceroi vices vice + vici vici vicious viciou + viciousness vicious vict vict + victims victim victor victor + victoress victoress victories victori + victorious victori victors victor + victory victori victual victual + victuall victual victuals victual + videlicet videlicet video video + vides vide videsne videsn + vidi vidi vie vie + vied vi vienna vienna + view view viewest viewest + vieweth vieweth viewing view + viewless viewless views view + vigil vigil vigilance vigil + vigilant vigil vigitant vigit + vigour vigour vii vii + viii viii vile vile + vilely vile vileness vile + viler viler vilest vilest + vill vill village villag + villager villag villagery villageri + villages villag villain villain + villainies villaini villainous villain + villainously villain villains villain + villainy villaini villanies villani + villanous villan villany villani + villiago villiago villian villian + villianda villianda villians villian + vinaigre vinaigr vincentio vincentio + vincere vincer vindicative vindic + vine vine vinegar vinegar + vines vine vineyard vineyard + vineyards vineyard vint vint + vintner vintner viol viol + viola viola violate violat + violated violat violates violat + violation violat violator violat + violence violenc violent violent + violenta violenta violenteth violenteth + violently violent violet violet + violets violet viper viper + viperous viper vipers viper + vir vir virgilia virgilia + virgin virgin virginal virgin + virginalling virginal virginity virgin + virginius virginiu virgins virgin + virgo virgo virtue virtu + virtues virtu virtuous virtuou + virtuously virtuous visag visag + visage visag visages visag + visard visard viscount viscount + visible visibl visibly visibl + vision vision visions vision + visit visit visitation visit + visitations visit visited visit + visiting visit visitings visit + visitor visitor visitors visitor + visits visit visor visor + vita vita vitae vita + vital vital vitement vitement + vitruvio vitruvio vitx vitx + viva viva vivant vivant + vive vive vixen vixen + viz viz vizaments vizament + vizard vizard vizarded vizard + vizards vizard vizor vizor + vlouting vlout vocation vocat + vocativo vocativo vocatur vocatur + voce voce voic voic + voice voic voices voic + void void voided void + voiding void voke voke + volable volabl volant volant + volivorco volivorco volley vollei + volquessen volquessen volsce volsc + volsces volsc volscian volscian + volscians volscian volt volt + voltemand voltemand volubility volubl + voluble volubl volume volum + volumes volum volumnia volumnia + volumnius volumniu voluntaries voluntari + voluntary voluntari voluptuously voluptu + voluptuousness voluptu vomissement vomiss + vomit vomit vomits vomit + vor vor vore vore + vortnight vortnight vot vot + votaries votari votarist votarist + votarists votarist votary votari + votre votr vouch vouch + voucher voucher vouchers voucher + vouches vouch vouching vouch + vouchsaf vouchsaf vouchsafe vouchsaf + vouchsafed vouchsaf vouchsafes vouchsaf + vouchsafing vouchsaf voudrais voudrai + vour vour vous vou + voutsafe voutsaf vow vow + vowed vow vowel vowel + vowels vowel vowing vow + vows vow vox vox + voyage voyag voyages voyag + vraiment vraiment vulcan vulcan + vulgar vulgar vulgarly vulgarli + vulgars vulgar vulgo vulgo + vulnerable vulner vulture vultur + vultures vultur vurther vurther + w w wad wad + waddled waddl wade wade + waded wade wafer wafer + waft waft waftage waftag + wafting waft wafts waft + wag wag wage wage + wager wager wagers wager + wages wage wagging wag + waggish waggish waggling waggl + waggon waggon waggoner waggon + wagon wagon wagoner wagon + wags wag wagtail wagtail + wail wail wailful wail + wailing wail wails wail + wain wain wainropes wainrop + wainscot wainscot waist waist + wait wait waited wait + waiter waiter waiteth waiteth + waiting wait waits wait + wak wak wake wake + waked wake wakefield wakefield + waken waken wakened waken + wakes wake wakest wakest + waking wake wales wale + walk walk walked walk + walking walk walks walk + wall wall walled wall + wallet wallet wallets wallet + wallon wallon walloon walloon + wallow wallow walls wall + walnut walnut walter walter + wan wan wand wand + wander wander wanderer wander + wanderers wander wandering wander + wanders wander wands wand + wane wane waned wane + wanes wane waning wane + wann wann want want + wanted want wanteth wanteth + wanting want wanton wanton + wantonly wantonli wantonness wanton + wantons wanton wants want + wappen wappen war war + warble warbl warbling warbl + ward ward warded ward + warden warden warder warder + warders warder wardrobe wardrob + wardrop wardrop wards ward + ware ware wares ware + warily warili warkworth warkworth + warlike warlik warm warm + warmed warm warmer warmer + warming warm warms warm + warmth warmth warn warn + warned warn warning warn + warnings warn warns warn + warp warp warped warp + warr warr warrant warrant + warranted warrant warranteth warranteth + warrantise warrantis warrantize warrant + warrants warrant warranty warranti + warren warren warrener warren + warring war warrior warrior + warriors warrior wars war + wart wart warwick warwick + warwickshire warwickshir wary wari + was wa wash wash + washed wash washer washer + washes wash washford washford + washing wash wasp wasp + waspish waspish wasps wasp + wassail wassail wassails wassail + wast wast waste wast + wasted wast wasteful wast + wasters waster wastes wast + wasting wast wat wat + watch watch watched watch + watchers watcher watches watch + watchful watch watching watch + watchings watch watchman watchman + watchmen watchmen watchword watchword + water water waterdrops waterdrop + watered water waterfly waterfli + waterford waterford watering water + waterish waterish waterpots waterpot + waterrugs waterrug waters water + waterton waterton watery wateri + wav wav wave wave + waved wave waver waver + waverer waver wavering waver + waves wave waving wave + waw waw wawl wawl + wax wax waxed wax + waxen waxen waxes wax + waxing wax way wai + waylaid waylaid waylay waylai + ways wai wayward wayward + waywarder wayward waywardness wayward + we we weak weak + weaken weaken weakens weaken + weaker weaker weakest weakest + weakling weakl weakly weakli + weakness weak weal weal + wealsmen wealsmen wealth wealth + wealthiest wealthiest wealthily wealthili + wealthy wealthi wealtlly wealtlli + wean wean weapon weapon + weapons weapon wear wear + wearer wearer wearers wearer + wearied weari wearies weari + weariest weariest wearily wearili + weariness weari wearing wear + wearisome wearisom wears wear + weary weari weasel weasel + weather weather weathercock weathercock + weathers weather weav weav + weave weav weaver weaver + weavers weaver weaves weav + weaving weav web web + wed wed wedded wed + wedding wed wedg wedg + wedged wedg wedges wedg + wedlock wedlock wednesday wednesdai + weed weed weeded weed + weeder weeder weeding weed + weeds weed weedy weedi + week week weeke week + weekly weekli weeks week + ween ween weening ween + weep weep weeper weeper + weeping weep weepingly weepingli + weepings weep weeps weep + weet weet weigh weigh + weighed weigh weighing weigh + weighs weigh weight weight + weightier weightier weightless weightless + weights weight weighty weighti + weird weird welcom welcom + welcome welcom welcomer welcom + welcomes welcom welcomest welcomest + welfare welfar welkin welkin + well well wells well + welsh welsh welshman welshman + welshmen welshmen welshwomen welshwomen + wench wench wenches wench + wenching wench wend wend + went went wept wept + weraday weradai were were + wert wert west west + western western westminster westminst + westmoreland westmoreland westward westward + wet wet wether wether + wetting wet wezand wezand + whale whale whales whale + wharf wharf wharfs wharf + what what whate whate + whatever whatev whatsoe whatso + whatsoever whatsoev whatsome whatsom + whe whe wheat wheat + wheaten wheaten wheel wheel + wheeling wheel wheels wheel + wheer wheer wheeson wheeson + wheezing wheez whelk whelk + whelks whelk whelm whelm + whelp whelp whelped whelp + whelps whelp when when + whenas whena whence whenc + whencesoever whencesoev whene whene + whenever whenev whensoever whensoev + where where whereabout whereabout + whereas wherea whereat whereat + whereby wherebi wherefore wherefor + wherein wherein whereinto whereinto + whereof whereof whereon whereon + whereout whereout whereso whereso + wheresoe whereso wheresoever wheresoev + wheresome wheresom whereto whereto + whereuntil whereuntil whereunto whereunto + whereupon whereupon wherever wherev + wherewith wherewith wherewithal wherewith + whet whet whether whether + whetstone whetston whetted whet + whew whew whey whei + which which whiff whiff + whiffler whiffler while while + whiles while whilst whilst + whin whin whine whine + whined whine whinid whinid + whining whine whip whip + whipp whipp whippers whipper + whipping whip whips whip + whipster whipster whipstock whipstock + whipt whipt whirl whirl + whirled whirl whirligig whirligig + whirling whirl whirlpool whirlpool + whirls whirl whirlwind whirlwind + whirlwinds whirlwind whisp whisp + whisper whisper whispering whisper + whisperings whisper whispers whisper + whist whist whistle whistl + whistles whistl whistling whistl + whit whit white white + whitehall whitehal whitely white + whiteness white whiter whiter + whites white whitest whitest + whither whither whiting white + whitmore whitmor whitsters whitster + whitsun whitsun whittle whittl + whizzing whizz who who + whoa whoa whoe whoe + whoever whoever whole whole + wholesom wholesom wholesome wholesom + wholly wholli whom whom + whoobub whoobub whoop whoop + whooping whoop whor whor + whore whore whoremaster whoremast + whoremasterly whoremasterli whoremonger whoremong + whores whore whoreson whoreson + whoresons whoreson whoring whore + whorish whorish whose whose + whoso whoso whosoe whoso + whosoever whosoev why why + wi wi wick wick + wicked wick wickednes wickedn + wickedness wicked wicket wicket + wicky wicki wid wid + wide wide widens widen + wider wider widow widow + widowed widow widower widow + widowhood widowhood widows widow + wield wield wife wife + wight wight wights wight + wild wild wildcats wildcat + wilder wilder wilderness wilder + wildest wildest wildfire wildfir + wildly wildli wildness wild + wilds wild wiles wile + wilful wil wilfull wilful + wilfully wilfulli wilfulnes wilfuln + wilfulness wil will will + willed will willers willer + willeth willeth william william + williams william willing will + willingly willingli willingness willing + willoughby willoughbi willow willow + wills will wilt wilt + wiltshire wiltshir wimpled wimpl + win win wince winc + winch winch winchester winchest + wincot wincot wind wind + winded wind windgalls windgal + winding wind windlasses windlass + windmill windmil window window + windows window windpipe windpip + winds wind windsor windsor + windy windi wine wine + wing wing winged wing + wingfield wingfield wingham wingham + wings wing wink wink + winking wink winks wink + winner winner winners winner + winning win winnow winnow + winnowed winnow winnows winnow + wins win winter winter + winterly winterli winters winter + wip wip wipe wipe + wiped wipe wipes wipe + wiping wipe wire wire + wires wire wiry wiri + wisdom wisdom wisdoms wisdom + wise wise wiselier wiseli + wisely wise wiser wiser + wisest wisest wish wish + wished wish wisher wisher + wishers wisher wishes wish + wishest wishest wisheth wisheth + wishful wish wishing wish + wishtly wishtli wisp wisp + wist wist wit wit + witb witb witch witch + witchcraft witchcraft witches witch + witching witch with with + withal withal withdraw withdraw + withdrawing withdraw withdrawn withdrawn + withdrew withdrew wither wither + withered wither withering wither + withers wither withheld withheld + withhold withhold withholds withhold + within within withold withold + without without withstand withstand + withstanding withstand withstood withstood + witless witless witness wit + witnesses wit witnesseth witnesseth + witnessing wit wits wit + witted wit wittenberg wittenberg + wittiest wittiest wittily wittili + witting wit wittingly wittingli + wittol wittol wittolly wittolli + witty witti wiv wiv + wive wive wived wive + wives wive wiving wive + wizard wizard wizards wizard + wo wo woe woe + woeful woeful woefull woeful + woefullest woefullest woes woe + woful woful wolf wolf + wolfish wolfish wolsey wolsei + wolves wolv wolvish wolvish + woman woman womanhood womanhood + womanish womanish womankind womankind + womanly womanli womb womb + wombs womb womby wombi + women women won won + woncot woncot wond wond + wonder wonder wondered wonder + wonderful wonder wonderfully wonderfulli + wondering wonder wonders wonder + wondrous wondrou wondrously wondrous + wont wont wonted wont + woo woo wood wood + woodbine woodbin woodcock woodcock + woodcocks woodcock wooden wooden + woodland woodland woodman woodman + woodmonger woodmong woods wood + woodstock woodstock woodville woodvil + wooed woo wooer wooer + wooers wooer wooes wooe + woof woof wooing woo + wooingly wooingli wool wool + woollen woollen woolly woolli + woolsack woolsack woolsey woolsei + woolward woolward woos woo + wor wor worcester worcest + word word words word + wore wore worins worin + work work workers worker + working work workings work + workman workman workmanly workmanli + workmanship workmanship workmen workmen + works work worky worki + world world worldlings worldl + worldly worldli worlds world + worm worm worms worm + wormwood wormwood wormy wormi + worn worn worried worri + worries worri worry worri + worrying worri worse wors + worser worser worship worship + worshipful worship worshipfully worshipfulli + worshipp worshipp worshipper worshipp + worshippers worshipp worshippest worshippest + worships worship worst worst + worsted worst wort wort + worth worth worthied worthi + worthier worthier worthies worthi + worthiest worthiest worthily worthili + worthiness worthi worthless worthless + worths worth worthy worthi + worts wort wot wot + wots wot wotting wot + wouid wouid would would + wouldest wouldest wouldst wouldst + wound wound wounded wound + wounding wound woundings wound + woundless woundless wounds wound + wouns woun woven woven + wow wow wrack wrack + wrackful wrack wrangle wrangl + wrangler wrangler wranglers wrangler + wrangling wrangl wrap wrap + wrapp wrapp wraps wrap + wrapt wrapt wrath wrath + wrathful wrath wrathfully wrathfulli + wraths wrath wreak wreak + wreakful wreak wreaks wreak + wreath wreath wreathed wreath + wreathen wreathen wreaths wreath + wreck wreck wrecked wreck + wrecks wreck wren wren + wrench wrench wrenching wrench + wrens wren wrest wrest + wrested wrest wresting wrest + wrestle wrestl wrestled wrestl + wrestler wrestler wrestling wrestl + wretch wretch wretchcd wretchcd + wretched wretch wretchedness wretched + wretches wretch wring wring + wringer wringer wringing wring + wrings wring wrinkle wrinkl + wrinkled wrinkl wrinkles wrinkl + wrist wrist wrists wrist + writ writ write write + writer writer writers writer + writes write writhled writhl + writing write writings write + writs writ written written + wrong wrong wronged wrong + wronger wronger wrongful wrong + wrongfully wrongfulli wronging wrong + wrongly wrongli wrongs wrong + wronk wronk wrote wrote + wroth wroth wrought wrought + wrung wrung wry wry + wrying wry wt wt + wul wul wye wye + x x xanthippe xanthipp + xi xi xii xii + xiii xiii xiv xiv + xv xv y y + yard yard yards yard + yare yare yarely yare + yarn yarn yaughan yaughan + yaw yaw yawn yawn + yawning yawn ycleped yclepe + ycliped yclipe ye ye + yea yea yead yead + year year yearly yearli + yearn yearn yearns yearn + years year yeas yea + yeast yeast yedward yedward + yell yell yellow yellow + yellowed yellow yellowing yellow + yellowness yellow yellows yellow + yells yell yelping yelp + yeoman yeoman yeomen yeomen + yerk yerk yes ye + yesterday yesterdai yesterdays yesterdai + yesternight yesternight yesty yesti + yet yet yew yew + yicld yicld yield yield + yielded yield yielder yielder + yielders yielder yielding yield + yields yield yok yok + yoke yoke yoked yoke + yokefellow yokefellow yokes yoke + yoketh yoketh yon yon + yond yond yonder yonder + yongrey yongrei yore yore + yorick yorick york york + yorkists yorkist yorks york + yorkshire yorkshir you you + young young younger younger + youngest youngest youngling youngl + younglings youngl youngly youngli + younker younker your your + yours your yourself yourself + yourselves yourselv youth youth + youthful youth youths youth + youtli youtli zanies zani + zany zani zeal zeal + zealous zealou zeals zeal + zed zed zenelophon zenelophon + zenith zenith zephyrs zephyr + zir zir zo zo + zodiac zodiac zodiacs zodiac + zone zone zounds zound + zwagger zwagger +} + + +set i 0 +foreach {in out} $test_vocab { + do_test "1.$i.($in -> $out)" { + lindex [sqlite3_fts5_tokenize db porter $in] 0 + } $out + incr i +} + + +finish_test + diff --git a/ext/fts5/test/fts5porter2.test b/ext/fts5/test/fts5porter2.test new file mode 100644 index 0000000..5e0aeb0 --- /dev/null +++ b/ext/fts5/test/fts5porter2.test @@ -0,0 +1,70 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Tests focusing on the fts5 porter stemmer implementation. +# +# These are extra tests added to those in fts5porter.test in order to +# improve test coverage of the porter stemmer implementation. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5porter2 + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +set test_vocab { + tion tion + ation ation + vation vation + avation avat + vion vion + ion ion + relational relat + relation relat + relate relat + zzz zzz + ii ii + iiing ii + xtional xtional + xenci xenci + xlogi xlogi + realization realiz + realize realiz + xization xizat + capitalism capit + talism talism + xiveness xive + xfulness xful + xousness xous + xical xical + xicate xicat + xicity xiciti + ies ie + eed e + eing e + s s +} + +set i 0 +foreach {in out} $test_vocab { + do_test "1.$i.($in -> $out)" { + lindex [sqlite3_fts5_tokenize db porter $in] 0 + } $out + incr i +} + + +finish_test + diff --git a/ext/fts5/test/fts5prefix.test b/ext/fts5/test/fts5prefix.test new file mode 100644 index 0000000..8e0d5a2 --- /dev/null +++ b/ext/fts5/test/fts5prefix.test @@ -0,0 +1,345 @@ +# 2015 Jan 13 +# +# 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 containst tests focused on prefix indexes. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5prefix + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE xx USING fts5(x, prefix=1); + INSERT INTO xx VALUES('one two three'); + INSERT INTO xx VALUES('four five six'); + INSERT INTO xx VALUES('seven eight nine ten'); +} + +do_execsql_test 1.1 { + SELECT rowid FROM xx WHERE xx MATCH 't*' +} {1 3} + + +#------------------------------------------------------------------------- +# Check that prefix indexes really do index n-character prefixes, not +# n-byte prefixes. Use the ascii tokenizer so as not to be confused by +# diacritic removal. +# +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = ascii, prefix = 2) +} + +do_test 2.1 { + foreach {rowid string} { + 1 "\xCA\xCB\xCC\xCD" + 2 "\u1234\u5678\u4321\u8765" + } { + execsql { INSERT INTO t1(rowid, x) VALUES($rowid, $string) } + } +} {} + +do_execsql_test 2.2 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} + +foreach {tn q res} { + 1 "SELECT rowid FROM t1 WHERE t1 MATCH '\xCA\xCB*'" 1 + 2 "SELECT rowid FROM t1 WHERE t1 MATCH '\u1234\u5678*'" 2 +} { + do_execsql_test 2.3.$tn $q $res +} + +#------------------------------------------------------------------------- +# Check that prefix queries with: +# +# * a column filter, and +# * no prefix index. +# +# work Ok. +# +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE t3 USING fts5(a, b, c); + INSERT INTO t3(t3, rank) VALUES('pgsz', 32); + BEGIN; + INSERT INTO t3 VALUES('acb ccc bba', 'cca bba bca', 'bbc ccc bca'); -- 1 + INSERT INTO t3 VALUES('cbb cac cab', 'abb aac bba', 'aab ccc cac'); -- 2 + INSERT INTO t3 VALUES('aac bcb aac', 'acb bcb caa', 'aca bab bca'); -- 3 + INSERT INTO t3 VALUES('aab ccb ccc', 'aca cba cca', 'aca aac cbb'); -- 4 + INSERT INTO t3 VALUES('bac aab bab', 'ccb bac cba', 'acb aba abb'); -- 5 + INSERT INTO t3 VALUES('bab abc ccb', 'acb cba abb', 'cbb aaa cab'); -- 6 + INSERT INTO t3 VALUES('cbb bbc baa', 'aab aca baa', 'bcc cca aca'); -- 7 + INSERT INTO t3 VALUES('abc bba abb', 'cac abc cba', 'acc aac cac'); -- 8 + INSERT INTO t3 VALUES('bbc bbc cab', 'bcb ccb cba', 'bcc cac acb'); -- 9 + COMMIT; +} + +foreach {tn match res} { + 1 "a : c*" {1 2 4 6 7 9} + 2 "b : c*" {1 3 4 5 6 8 9} + 3 "c : c*" {1 2 4 6 7 8 9} + 4 "a : b*" {1 3 5 6 7 8 9} + 5 "b : b*" {1 2 3 5 7 9} + 6 "c : b*" {1 3 7 9} + 7 "a : a*" {1 3 4 5 6 8} + 8 "b : a*" {2 3 4 6 7 8} + 9 "c : a*" {2 3 4 5 6 7 8 9} +} { + do_execsql_test 3.1.$tn { + SELECT rowid FROM t3($match) + } $res +} + +do_test 3.2 { + expr srand(0) + execsql { DELETE FROM t3 } + for {set i 0} {$i < 1000} {incr i} { + set a [fts5_rnddoc 3] + set b [fts5_rnddoc 8] + set c [fts5_rnddoc 20] + execsql { INSERT INTO t3 VALUES($a, $b, $c) } + } + execsql { INSERT INTO t3(t3) VALUES('integrity-check') } +} {} + +proc gmatch {col pattern} { + expr {[lsearch -glob $col $pattern]>=0} +} +db func gmatch gmatch + +proc ghl {col pattern} { + foreach t $col { + if {[string match $pattern $t]} { + lappend res "*$t*" + } else { + lappend res $t + } + } + set res +} +db func ghl ghl + +set COLS(a) 0 +set COLS(b) 1 +set COLS(c) 2 + +for {set x 0} {$x<2} {incr x} { + foreach {tn pattern} { + 1 {xa*} + 2 {xb*} + 3 {xc*} + 4 {xd*} + 5 {xe*} + 6 {xf*} + 7 {xg*} + 8 {xh*} + 9 {xi*} + 10 {xj*} + } { + foreach col {a b c} { + + # Check that the list of returned rowids is correct. + # + set res [db eval "SELECT rowid FROM t3 WHERE gmatch($col, '$pattern')"] + set query "$col : $pattern" + do_execsql_test 3.3.$x.$tn.$col.rowid { + SELECT rowid FROM t3($query); + } $res + + # Check that the highlight() function works. + # + set res [db eval \ + "SELECT ghl($col, '$pattern') FROM t3 WHERE gmatch($col, '$pattern')" + ] + set idx $COLS($col) + do_execsql_test 3.3.$x.$tn.$col.highlight { + SELECT highlight(t3, $idx, '*', '*') FROM t3($query); + } $res + } + + foreach colset {{a b} {b c} {c a} {a c} {b a}} { + # Check that the list of returned rowids is correct. + # + foreach {col1 col2} $colset {} + set expr "gmatch($col1, '$pattern') OR gmatch($col2, '$pattern')" + set res [db eval "SELECT rowid FROM t3 WHERE $expr"] + set query "{$colset} : $pattern" + do_execsql_test 3.3.$x.$tn.{$colset}.rowid { + SELECT rowid FROM t3($query); + } $res + + set resq "SELECT ghl($col1, '$pattern'), ghl($col2, '$pattern')" + append resq " FROM t3 WHERE $expr" + set res [db eval $resq] + set idx1 $COLS($col1) + set idx2 $COLS($col2) + do_execsql_test 3.3.$x.$tn.{$colset}.highlight { + SELECT highlight(t3, $idx1, '*', '*'), highlight(t3, $idx2, '*', '*') + FROM t3($query) + } $res + } + } + execsql { INSERT INTO t3(t3) VALUES('optimize') } + execsql { INSERT INTO t3(t3) VALUES('integrity-check') } +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE t2 USING fts5(c1, c2); + INSERT INTO t2 VALUES('xa xb', 'xb xa'); + + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 2 + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 4 + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 8 + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 16 + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 32 + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 64 + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 128 + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 256 + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 512 + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 1024 + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 2048 + INSERT INTO t2 SELECT c1||' '||c1, c2||' '||c2 FROM t2; -- 4096 + + SELECT count(*) FROM t2('x*'); +} {4096} + +do_execsql_test 4.1 { + UPDATE t2 SET c2 = 'ya yb'; + SELECT count(*) FROM t2('c1:x*'); + SELECT count(*) FROM t2('c2:x*'); +} {4096 0} + +do_execsql_test 4.2 { + UPDATE t2 SET c2 = 'xa'; + SELECT count(*) FROM t2('c1:x*'); + SELECT count(*) FROM t2('c2:x*'); +} {4096 4096} + +#------------------------------------------------------------------------- +# +reset_db +proc rnddoc {n} { + set map [list a b c d] + set doc [list] + for {set i 0} {$i < $n} {incr i} { + lappend doc "x[lindex $map [expr int(rand()*4)]]" + } + set doc +} +set cols [list] +for {set i 1} {$i<250} {incr i} { + lappend cols "c$i" + lappend vals "'[rnddoc 10]'" +} + +do_test 5.0 { + execsql "CREATE VIRTUAL TABLE t4 USING fts5([join $cols ,])" + execsql {INSERT INTO t4(t4, rank) VALUES('pgsz', 32)} + execsql "INSERT INTO t4 VALUES([join $vals ,])" + execsql "INSERT INTO t4 VALUES([join $vals ,])" + execsql "INSERT INTO t4 VALUES([join $vals ,])" + execsql "INSERT INTO t4 VALUES([join $vals ,])" +} {} + +proc gmatch {col pattern} { + expr {[lsearch -glob $col $pattern]>=0} +} +db func gmatch gmatch +foreach {tn col pattern} { + 1 c100 {xa*} + 2 c200 {xb*} +} { + set res [db eval "SELECT rowid FROM t4 WHERE gmatch($col, \$pattern)"] + set query "$col : $pattern" + do_execsql_test 5.$tn { SELECT rowid FROM t4($query) } $res +} + +reset_db +db func fts5_rnddoc fts5_rnddoc +do_test 6.0 { + execsql { + CREATE VIRTUAL TABLE t5 USING fts5(x, y); + INSERT INTO t5 VALUES( fts5_rnddoc(10000), fts5_rnddoc(10000) ); + INSERT INTO t5 VALUES( fts5_rnddoc(10000), fts5_rnddoc(10000) ); + INSERT INTO t5 VALUES( fts5_rnddoc(10000), fts5_rnddoc(10000) ); + INSERT INTO t5 VALUES( fts5_rnddoc(10000), fts5_rnddoc(10000) ); + } +} {} + +proc gmatch {col pattern} { + expr {[lsearch -glob $col $pattern]>=0} +} +db func gmatch gmatch +foreach {tn col pattern} { + 1 y {xa*} + 2 y {xb*} + 3 y {xc*} + 4 x {xa*} + 5 x {xb*} + 6 x {xc*} +} { + set res [db eval "SELECT rowid FROM t5 WHERE gmatch($col, \$pattern)"] + set query "$col : $pattern" + do_execsql_test 6.$tn { SELECT rowid FROM t5($query) } $res +} + +#------------------------------------------------------------------------- +# Check that the various ways of creating prefix indexes produce the +# same database on disk. +# +save_prng_state +foreach {tn create} { + 1 { CREATE VIRTUAL TABLE tt USING fts5(x, y, prefix="1,2,3") } + 2 { CREATE VIRTUAL TABLE tt USING fts5(x, y, prefix="1 2 3") } + 3 { CREATE VIRTUAL TABLE tt USING fts5(x, y, prefix=1, prefix=2, prefix=3) } + 4 { CREATE VIRTUAL TABLE tt USING fts5(x, y, prefix="1 2", prefix=3) } +} { + execsql { DROP TABLE IF EXISTS tt } + restore_prng_state + execsql $create + execsql { + INSERT INTO tt VALUES('cc b ggg ccc aa eee hh', 'aa g b hh a e'); + INSERT INTO tt VALUES('cc bb cc gg j g cc', 'ii jjj ggg jjj cc cc'); + INSERT INTO tt VALUES('h eee cc h iii', 'aaa iii dd iii dd'); + INSERT INTO tt VALUES('jjj hh eee c e b gg', 'j bbb jj ddd jj'); + INSERT INTO tt VALUES('ii hhh aaa ff c hhh iii', 'j cc hh bb e'); + INSERT INTO tt VALUES('e fff hhh i aaa', 'g b aa gg c aa dd'); + INSERT INTO tt VALUES('i aaa ccc gg hhh aa h', 'j bbb bbb d ff'); + INSERT INTO tt VALUES('g f gg ff ff jjj d', 'jjj d j fff fff ee j'); + INSERT INTO tt VALUES('a cc e ccc jjj c', 'ccc iii d bb a eee g'); + INSERT INTO tt VALUES('jj hh hh bb bbb gg', 'j c jjj bb iii f'); + INSERT INTO tt VALUES('a ggg g cc ccc aa', 'jjj j j aaa c'); + INSERT INTO tt VALUES('ddd j dd b i', 'aaa bbb iii ggg ff ccc ddd'); + INSERT INTO tt VALUES('jj ii hh c ii h gg', 'hhh bbb ddd bbb hh g ggg'); + INSERT INTO tt VALUES('aa hhh ccc h ggg ccc', 'iii d jj a ff ii'); + } + + #db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM tt_data} {puts $r} + + if {$tn==1} { + set ::checksum [execsql {SELECT md5sum(id, block) FROM tt_data}] + } else { + do_execsql_test 7.$tn { + SELECT md5sum(id, block) FROM tt_data + } [list $::checksum] + } +} + +finish_test + + diff --git a/ext/fts5/test/fts5query.test b/ext/fts5/test/fts5query.test new file mode 100644 index 0000000..570abf4 --- /dev/null +++ b/ext/fts5/test/fts5query.test @@ -0,0 +1,83 @@ +# 2015 October 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. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the FTS5 module. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5query + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +for {set tn 1 ; set pgsz 64} {$tn<32} {incr tn; incr pgsz 16} { + reset_db + do_test 1.$tn.1 { + execsql { + CREATE VIRTUAL TABLE t1 USING fts5(x); + INSERT INTO t1(t1, rank) VALUES('pgsz', $pgsz); + BEGIN; + } + foreach x [list aaa bbb ccc ddd eee fff ggg hhh iii jjj] { + set doc [string repeat "$x " 30] + execsql { INSERT INTO t1 VALUES($doc) } + } + execsql COMMIT + } {} + + do_execsql_test 1.$tn.2 { + INSERT INTO t1(t1) VALUES('integrity-check'); + } + + set ret 1 + foreach x [list a b c d e f g h i j] { + do_execsql_test 1.$tn.3.$ret { + SELECT rowid FROM t1 WHERE t1 MATCH $x || '*'; + } $ret + incr ret + } +} + +for {set tn 1 ; set pgsz 64} {$tn<32} {incr tn; incr pgsz 16} { + reset_db + do_test 2.$tn.1 { + execsql { + CREATE VIRTUAL TABLE t1 USING fts5(x); + INSERT INTO t1(t1, rank) VALUES('pgsz', $pgsz); + BEGIN; + } + foreach x [list bbb ddd fff hhh jjj lll nnn ppp rrr ttt] { + set doc [string repeat "$x " 30] + execsql { INSERT INTO t1 VALUES($doc) } + } + execsql COMMIT + } {} + + do_execsql_test 1.$tn.2 { + INSERT INTO t1(t1) VALUES('integrity-check'); + } + + set ret 1 + foreach x [list a c e g i k m o q s u] { + do_execsql_test 2.$tn.3.$ret { + SELECT rowid FROM t1 WHERE t1 MATCH $x || '*'; + } {} + incr ret + } +} + + +finish_test + + diff --git a/ext/fts5/test/fts5rank.test b/ext/fts5/test/fts5rank.test new file mode 100644 index 0000000..4961b42 --- /dev/null +++ b/ext/fts5/test/fts5rank.test @@ -0,0 +1,100 @@ +# 2014 Dec 20 +# +# 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 focuses on testing queries that use the "rank" column. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5rank + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + + +#------------------------------------------------------------------------- +# "ORDER BY rank" + highlight() + large poslists. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE xyz USING fts5(z); +} +do_test 1.1 { + set doc [string trim [string repeat "x y " 500]] + execsql { INSERT INTO xyz VALUES($doc) } +} {} +do_execsql_test 1.2 { + SELECT highlight(xyz, 0, '[', ']') FROM xyz WHERE xyz MATCH 'x' ORDER BY rank +} [list [string map {x [x]} $doc]] + +do_execsql_test 1.3 { + SELECT highlight(xyz, 0, '[', ']') FROM xyz + WHERE xyz MATCH 'x AND y' ORDER BY rank +} [list [string map {x [x] y [y]} $doc]] + +#------------------------------------------------------------------------- +# Check that the 'rank' option really is persistent. +# +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE tt USING fts5(a); + INSERT INTO tt VALUES('a x x x x'); + INSERT INTO tt VALUES('x x a a a'); + INSERT INTO tt VALUES('x a a x x'); +} + +proc firstinst {cmd} { + foreach {p c o} [$cmd xInst 0] {} + return $o +} +sqlite3_fts5_create_function db firstinst firstinst + +do_execsql_test 2.1 { + SELECT rowid FROM tt('a') ORDER BY rank; +} {2 3 1} + +do_execsql_test 2.2 { + SELECT rowid FROM tt('a', 'firstinst()') ORDER BY rank; +} {1 3 2} + +do_execsql_test 2.3 { + INSERT INTO tt(tt, rank) VALUES('rank', 'firstinst()'); + SELECT rowid FROM tt('a') ORDER BY rank; +} {1 3 2} + +do_test 2.4 { + sqlite3 db2 test.db + catchsql { SELECT rowid FROM tt('a') ORDER BY rank; } db2 +} {1 {no such function: firstinst}} + +do_test 2.5 { + db2 close + sqlite3 db2 test.db + sqlite3_fts5_create_function db2 firstinst firstinst + execsql { SELECT rowid FROM tt('a') ORDER BY rank; } db2 +} {1 3 2} + +do_test 2.6 { + execsql { SELECT rowid FROM tt('a') ORDER BY rank; } db2 +} {1 3 2} + +do_test 2.7 { + execsql { SELECT rowid FROM tt('a') ORDER BY rank; } db +} {1 3 2} + + + + + + + +finish_test + diff --git a/ext/fts5/test/fts5rebuild.test b/ext/fts5/test/fts5rebuild.test new file mode 100644 index 0000000..1044421 --- /dev/null +++ b/ext/fts5/test/fts5rebuild.test @@ -0,0 +1,67 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5rebuild + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.1 { + CREATE VIRTUAL TABLE f1 USING fts5(a, b); + INSERT INTO f1(a, b) VALUES('one', 'o n e'); + INSERT INTO f1(a, b) VALUES('two', 't w o'); + INSERT INTO f1(a, b) VALUES('three', 't h r e e'); +} + +do_execsql_test 1.2 { + INSERT INTO f1(f1) VALUES('integrity-check'); +} {} + +do_execsql_test 1.3 { + INSERT INTO f1(f1) VALUES('rebuild'); +} {} + +do_execsql_test 1.4 { + INSERT INTO f1(f1) VALUES('integrity-check'); +} {} + +do_execsql_test 1.5 { + DELETE FROM f1_data; +} {} + +do_catchsql_test 1.6 { + INSERT INTO f1(f1) VALUES('integrity-check'); +} {1 {database disk image is malformed}} + +do_execsql_test 1.7 { + INSERT INTO f1(f1) VALUES('rebuild'); + INSERT INTO f1(f1) VALUES('integrity-check'); +} {} + + +#------------------------------------------------------------------------- +# Check that 'rebuild' may not be used with a contentless table. +# +do_execsql_test 2.1 { + CREATE VIRTUAL TABLE nc USING fts5(doc, content=); +} + +do_catchsql_test 2.2 { + INSERT INTO nc(nc) VALUES('rebuild'); +} {1 {'rebuild' may not be used with a contentless fts5 table}} +finish_test + diff --git a/ext/fts5/test/fts5restart.test b/ext/fts5/test/fts5restart.test new file mode 100644 index 0000000..0dd7d69 --- /dev/null +++ b/ext/fts5/test/fts5restart.test @@ -0,0 +1,152 @@ +# 2015 April 28 +# +# 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 focuses on testing the planner (xBestIndex function). +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5restart + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE f1 USING fts5(ff); +} + +#------------------------------------------------------------------------- +# Run the 'optimize' command. Check that it does not disturb ongoing +# full-text queries. +# +do_test 1.1 { + for {set i 1} {$i < 1000} {incr i} { + execsql { INSERT INTO f1 VALUES('a b c d e') } + lappend lRowid $i + } +} {} + +do_execsql_test 1.2 { + SELECT rowid FROM f1 WHERE f1 MATCH 'c'; +} $lRowid + +do_test 1.3 { + set res [list] + db eval { SELECT rowid FROM f1 WHERE f1 MATCH 'c' } { + if {$rowid == 100} { + execsql { INSERT INTO f1(f1) VALUES('optimize') } + } + lappend res $rowid + } + set res +} $lRowid + +do_test 1.4.1 { + sqlite3 db2 test.db + set res [list] + db2 eval { SELECT rowid FROM f1 WHERE f1 MATCH 'c' } { + if {$rowid == 100} { + set cres [catchsql { INSERT INTO f1(f1) VALUES('optimize') }] + } + lappend res $rowid + } + set res +} $lRowid + +do_test 1.4.2 { + db2 close + set cres +} {1 {database is locked}} + +#------------------------------------------------------------------------- +# Open a couple of cursors. Then close them in the same order. +# +do_test 2.1 { + set ::s1 [sqlite3_prepare db "SELECT rowid FROM f1 WHERE f1 MATCH 'b'" -1 X] + set ::s2 [sqlite3_prepare db "SELECT rowid FROM f1 WHERE f1 MATCH 'c'" -1 X] + + sqlite3_step $::s1 +} {SQLITE_ROW} +do_test 2.2 { + sqlite3_step $::s2 +} {SQLITE_ROW} + +do_test 2.1 { + sqlite3_finalize $::s1 + sqlite3_finalize $::s2 +} {SQLITE_OK} + +#------------------------------------------------------------------------- +# Copy data between two FTS5 tables. +# +do_execsql_test 3.1 { + CREATE VIRTUAL TABLE f2 USING fts5(gg); + INSERT INTO f2 SELECT ff FROM f1 WHERE f1 MATCH 'b+c+d'; +} +do_execsql_test 3.2 { + SELECT rowid FROM f2 WHERE f2 MATCH 'a+b+c+d+e' +} $lRowid + +#------------------------------------------------------------------------- +# Remove the row that an FTS5 cursor is currently pointing to. And +# various other similar things. Check that this does not disturb +# ongoing scans. +# +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE n4 USING fts5(n); + INSERT INTO n4(rowid, n) VALUES(100, '1 2 3 4 5'); + INSERT INTO n4(rowid, n) VALUES(200, '1 2 3 4'); + INSERT INTO n4(rowid, n) VALUES(300, '2 3 4'); + INSERT INTO n4(rowid, n) VALUES(400, '2 3'); + INSERT INTO n4(rowid, n) VALUES(500, '3'); +} + +do_test 4.1 { + set res [list] + db eval { SELECT rowid FROM n4 WHERE n4 MATCH '3' } { + if {$rowid==300} { + execsql { DELETE FROM n4 WHERE rowid=300 } + } + lappend res $rowid + } + set res +} {100 200 300 400 500} + +do_test 4.2 { + execsql { INSERT INTO n4(rowid, n) VALUES(300, '2 3 4') } + set res [list] + db eval { SELECT rowid FROM n4 WHERE n4 MATCH '3' ORDER BY rowid DESC} { + if {$rowid==300} { + execsql { DELETE FROM n4 WHERE rowid=300 } + } + lappend res $rowid + } + set res +} {500 400 300 200 100} + +do_test 4.3 { + execsql { INSERT INTO n4(rowid, n) VALUES(300, '2 3 4') } + set res [list] + db eval { SELECT rowid FROM n4 WHERE n4 MATCH '3' ORDER BY rowid DESC} { + if {$rowid==300} { + execsql { DELETE FROM n4 } + } + lappend res $rowid + } + set res +} {500 400 300} + + + +finish_test + diff --git a/ext/fts5/test/fts5rowid.test b/ext/fts5/test/fts5rowid.test new file mode 100644 index 0000000..19590cd --- /dev/null +++ b/ext/fts5/test/fts5rowid.test @@ -0,0 +1,219 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Tests of the scalar fts5_rowid() and fts5_decode() functions. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5rowid + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_catchsql_test 1.1 { + SELECT fts5_rowid() +} {1 {should be: fts5_rowid(subject, ....)}} + +do_catchsql_test 1.2 { + SELECT fts5_rowid('segment') +} {1 {should be: fts5_rowid('segment', segid, pgno))}} + +do_execsql_test 1.3 { + SELECT fts5_rowid('segment', 1, 1) +} {137438953473} + +do_catchsql_test 1.4 { + SELECT fts5_rowid('nosucharg'); +} {1 {first arg to fts5_rowid() must be 'segment'}} + + +#------------------------------------------------------------------------- +# Tests of the fts5_decode() function. +# +reset_db +do_execsql_test 2.1 { + CREATE VIRTUAL TABLE x1 USING fts5(a, b); + INSERT INTO x1(x1, rank) VALUES('pgsz', 32); +} {} + +proc rnddoc {n} { + set map [list 0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j] + set doc [list] + for {set i 0} {$i < $n} {incr i} { + lappend doc [string map $map [format %.3d [expr int(rand()*100)]]] + } + set doc +} +db func rnddoc rnddoc + +do_execsql_test 2.2 { + WITH r(a, b) AS ( + SELECT rnddoc(6), rnddoc(6) UNION ALL + SELECT rnddoc(6), rnddoc(6) FROM r + ) + INSERT INTO x1 SELECT * FROM r LIMIT 10000; + DELETE FROM x1 WHERE (rowid%2); +} + +set res [db one {SELECT count(*) FROM x1_data}] +do_execsql_test 2.3 { + SELECT count(fts5_decode(rowid, block)) FROM x1_data; +} $res +do_execsql_test 2.4 { + UPDATE x1_data SET block = X''; + SELECT count(fts5_decode(rowid, block)) FROM x1_data; +} $res + +do_execsql_test 2.5 { + INSERT INTO x1(x1, rank) VALUES('pgsz', 1024); + INSERT INTO x1(x1) VALUES('rebuild'); +} + +set res [db one {SELECT count(*) FROM x1_data}] +do_execsql_test 2.6 { + SELECT count(fts5_decode(rowid, block)) FROM x1_data; +} $res + +# This is really a corruption test... +#do_execsql_test 2.7 { +# UPDATE x1_data SET block = X''; +# SELECT count(fts5_decode(rowid, block)) FROM x1_data; +#} $res + +do_execsql_test 2.8 { + SELECT fts5_decode(fts5_rowid('segment', 1000, 1), X'AB') +} {corrupt} + +#------------------------------------------------------------------------- +# Tests with very large tokens. +# +set strlist [list \ + "[string repeat x 400]" \ + "[string repeat x 300][string repeat w 100]" \ + "[string repeat x 300][string repeat y 100]" \ + "[string repeat x 300][string repeat z 600]" \ +] +do_test 3.0 { + execsql { + BEGIN; + CREATE VIRTUAL TABLE x2 USING fts5(a); + } + foreach str $strlist { execsql { INSERT INTO x2 VALUES($str) } } + execsql COMMIT +} {} + +for {set tn 0} {$tn<[llength $strlist]} {incr tn} { + set str [lindex $strlist $tn] + do_execsql_test 3.1.$tn { + SELECT rowid FROM x2 WHERE x2 MATCH $str + } [expr $tn+1] +} + +set res [db one {SELECT count(*) FROM x2_data}] +do_execsql_test 3.2 { + SELECT count(fts5_decode(rowid, block)) FROM x2_data; +} $res + +#------------------------------------------------------------------------- +# Leaf pages with no terms or rowids at all. +# +set strlist [list \ + "[string repeat {w } 400]" \ + "[string repeat {x } 400]" \ + "[string repeat {y } 400]" \ + "[string repeat {z } 400]" \ +] +do_test 4.0 { + execsql { + BEGIN; + CREATE VIRTUAL TABLE x3 USING fts5(a); + INSERT INTO x3(x3, rank) VALUES('pgsz', 32); + } + foreach str $strlist { execsql { INSERT INTO x3 VALUES($str) } } + execsql COMMIT +} {} + +for {set tn 0} {$tn<[llength $strlist]} {incr tn} { + set str [lindex $strlist $tn] + do_execsql_test 4.1.$tn { + SELECT rowid FROM x3 WHERE x3 MATCH $str + } [expr $tn+1] +} + +set res [db one {SELECT count(*) FROM x3_data}] +do_execsql_test 4.2 { + SELECT count(fts5_decode(rowid, block)) FROM x3_data; +} $res + +#------------------------------------------------------------------------- +# Position lists with large values. +# +set strlist [list \ + "[string repeat {w } 400]a" \ + "[string repeat {x } 400]a" \ + "[string repeat {y } 400]a" \ + "[string repeat {z } 400]a" \ +] +do_test 5.0 { + execsql { + BEGIN; + CREATE VIRTUAL TABLE x4 USING fts5(a); + INSERT INTO x4(x4, rank) VALUES('pgsz', 32); + } + foreach str $strlist { execsql { INSERT INTO x4 VALUES($str) } } + execsql COMMIT +} {} + +do_execsql_test 5.1 { + SELECT rowid FROM x4 WHERE x4 MATCH 'a' +} {1 2 3 4} + +set res [db one {SELECT count(*) FROM x4_data}] +do_execsql_test 5.2 { + SELECT count(fts5_decode(rowid, block)) FROM x4_data; +} $res + +#------------------------------------------------------------------------- +# + +do_execsql_test 6.0 { + CREATE VIRTUAL TABLE x5 USING fts5(x, detail=none); + INSERT INTO x5(x5, rank) VALUES('pgsz', 32); + INSERT INTO x5 VALUES('a b c d e f'); + INSERT INTO x5 VALUES('a b c d e f'); + INSERT INTO x5 VALUES('a b c d e f'); + BEGIN; + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 + ) INSERT INTO x5 SELECT 'a b c d e f' FROM s; + COMMIT; + SELECT count(fts5_decode_none(rowid, block)) FROM x5_data; +} {32} + +do_execsql_test 6.1 { + DELETE FROM x5 WHERE rowid <= 2; + SELECT count(fts5_decode_none(rowid, block)) FROM x5_data; +} {34} + +do_execsql_test 6.2 { + UPDATE x5 SET x='a b c d e f' WHERE rowid=3; + SELECT count(fts5_decode_none(rowid, block)) FROM x5_data; +} {36} + +#db eval {SELECT rowid, fts5_decode_none(rowid, block) aS r FROM x5_data} {puts $r} + + + +finish_test + diff --git a/ext/fts5/test/fts5simple.test b/ext/fts5/test/fts5simple.test new file mode 100644 index 0000000..a095a16 --- /dev/null +++ b/ext/fts5/test/fts5simple.test @@ -0,0 +1,413 @@ +# 2015 September 05 +# +# 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. +# +#************************************************************************* +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5simple + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +if 1 { + +#------------------------------------------------------------------------- +# +set doc "x x [string repeat {y } 50]z z" +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + BEGIN; + INSERT INTO t1 VALUES($doc); + COMMIT; +} + +do_execsql_test 1.1 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + INSERT INTO t1 VALUES('a b c'); + INSERT INTO t1 VALUES('d e f'); + INSERT INTO t1(t1) VALUES('optimize'); +} + +do_execsql_test 2.1 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {} + + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE t1 USING fts5(x, prefix='1,2'); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + BEGIN; + INSERT INTO t1 VALUES('one'); + SELECT * FROM t1 WHERE t1 MATCH 'o*'; +} {one} + +do_execsql_test 3.1 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 4.1 { + CREATE VIRTUAL TABLE t11 USING fts5(content); + INSERT INTO t11(t11, rank) VALUES('pgsz', 32); + INSERT INTO t11 VALUES('another'); + INSERT INTO t11 VALUES('string'); + INSERT INTO t11 VALUES('of'); + INSERT INTO t11 VALUES('text'); +} +do_test 4.2 { + execsql { INSERT INTO t11(t11) VALUES('optimize') } +} {} +do_execsql_test 4.3 { + INSERT INTO t11(t11) VALUES('integrity-check'); +} {} + +#db eval { SELECT fts5_decode(rowid, block) as x FROM t11_data } { puts $x } + +#------------------------------------------------------------------------- +reset_db +set doc [string repeat "x y " 5] +do_execsql_test 5.1 { + CREATE VIRTUAL TABLE yy USING fts5(content); + INSERT INTO yy(yy, rank) VALUES('pgsz', 32); + BEGIN; + INSERT INTO yy VALUES($doc); + INSERT INTO yy VALUES($doc); + INSERT INTO yy VALUES($doc); + INSERT INTO yy VALUES($doc); + INSERT INTO yy VALUES($doc); + INSERT INTO yy VALUES($doc); + INSERT INTO yy VALUES($doc); + INSERT INTO yy VALUES($doc); + COMMIT; +} + +do_execsql_test 5.2 { + SELECT rowid FROM yy WHERE yy MATCH 'y' ORDER BY rowid ASC +} {1 2 3 4 5 6 7 8} + +do_execsql_test 5.3 { + SELECT rowid FROM yy WHERE yy MATCH 'y' ORDER BY rowid DESC +} {8 7 6 5 4 3 2 1} + +#db eval { SELECT fts5_decode(rowid, block) as x FROM yy_data } { puts $x } + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 5.1 { + CREATE VIRTUAL TABLE tt USING fts5(content); + INSERT INTO tt(tt, rank) VALUES('pgsz', 32); + INSERT INTO tt VALUES('aa'); +} + +do_execsql_test 5.2 { + SELECT rowid FROM tt WHERE tt MATCH 'a*'; +} {1} + +do_execsql_test 5.3 { + DELETE FROM tt; + BEGIN; + INSERT INTO tt VALUES('aa'); + INSERT INTO tt VALUES('ab'); + COMMIT; +} {} + +do_execsql_test 5.4 { + SELECT rowid FROM tt WHERE tt MATCH 'a*'; +} {1 2} + +do_execsql_test 5.5 { + DELETE FROM tt; + BEGIN; + INSERT INTO tt VALUES('aa'); + INSERT INTO tt VALUES('ab'); + INSERT INTO tt VALUES('aa'); + INSERT INTO tt VALUES('ab'); + INSERT INTO tt VALUES('aa'); + INSERT INTO tt VALUES('ab'); + INSERT INTO tt VALUES('aa'); + INSERT INTO tt VALUES('ab'); + COMMIT; + SELECT rowid FROM tt WHERE tt MATCH 'a*'; +} {1 2 3 4 5 6 7 8} + +do_execsql_test 5.6 { + INSERT INTO tt(tt) VALUES('integrity-check'); +} + +reset_db +do_execsql_test 5.7 { + CREATE VIRTUAL TABLE tt USING fts5(content); + INSERT INTO tt(tt, rank) VALUES('pgsz', 32); + INSERT INTO tt VALUES('aa ab ac ad ae af'); +} + +do_execsql_test 5.8 { + SELECT rowid FROM tt WHERE tt MATCH 'a*'; +} {1} + +#------------------------------------------------------------------------- + +reset_db +do_execsql_test 6.1 { + CREATE VIRTUAL TABLE xyz USING fts5(x, y, z); + INSERT INTO xyz VALUES('x', 'y', 'z'); +} + +do_catchsql_test 6.2 { + SELECT * FROM xyz WHERE xyz MATCH '' +} {1 {fts5: syntax error near ""}} +do_catchsql_test 6.3 { + SELECT * FROM xyz WHERE xyz MATCH NULL +} {1 {fts5: syntax error near ""}} + +#------------------------------------------------------------------------- + +do_execsql_test 7.1 { + CREATE VIRTUAL TABLE ft2 USING fts5(content); + INSERT INTO ft2(rowid, content) VALUES(1, 'a b c'); + INSERT INTO ft2(rowid, content) VALUES(2, 'a b d'); +} + +do_catchsql_test 7.2 { + BEGIN; + UPDATE ft2 SET rowid=2 WHERE rowid=1; +} {1 {constraint failed}} + +do_execsql_test 7.3 { + COMMIT; + INSERT INTO ft2(ft2) VALUES('integrity-check'); +} {} + +do_execsql_test 7.4 { + SELECT * FROM ft2; +} {{a b c} {a b d}} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 8.1 { + CREATE VIRTUAL TABLE ft2 USING fts5(content); + INSERT INTO ft2(rowid, content) VALUES(1, 'a b'); +} + +do_execsql_test 8.2 { + BEGIN; + INSERT INTO ft2(rowid, content) VALUES(4, 'a x'); +} + +do_execsql_test 8.3 { + INSERT INTO ft2(ft2) VALUES('integrity-check'); +} + +#------------------------------------------------------------------------- +# Check that the "table function" syntax works. +# +reset_db +do_execsql_test 9.1 { + CREATE VIRTUAL TABLE ft2 USING fts5(content); + INSERT INTO ft2(rowid, content) VALUES(1, 'a b'); + INSERT INTO ft2(rowid, content) VALUES(2, 'a b c d'); + INSERT INTO ft2(rowid, content) VALUES(3, 'c d e f'); +} + +do_execsql_test 9.2 { + SELECT rowid FROM ft2('a'); +} {1 2} + +do_execsql_test 9.3 { + SELECT rowid FROM ft2('b AND c'); +} {2} + +#------------------------------------------------------------------------- +# +do_execsql_test 10.0 { + CREATE VIRTUAL TABLE t3 USING fts5(a, b, c); + INSERT INTO t3 VALUES('bac aab bab', 'c bac c', 'acb aba abb'); -- 1 + INSERT INTO t3 VALUES('bab abc c', 'acb c abb', 'c aaa c'); -- 2 +} + +do_execsql_test 10.1 { + SELECT rowid FROM t3('c: c*'); +} {2} + +do_execsql_test 10.2 { + SELECT rowid FROM t3('b: acb'); +} {2} + +#------------------------------------------------------------------------- +# Test that character 0x1A is allowed in fts5 barewords. +# +do_test 11.0 { + execsql "CREATE VIRTUAL TABLE t4 USING fts5(x, tokenize=\"ascii tokenchars '\x1A'\")" + execsql " + INSERT INTO t4 VALUES('a b c \x1A'); + INSERT INTO t4 VALUES('a b c d\x1A'); + INSERT INTO t4 VALUES('a b c \x1Ad'); + INSERT INTO t4 VALUES('a b c d'); + " +} {} + +do_test 11.1 { + execsql "SELECT rowid FROM t4('\x1A')" +} {1} +do_test 11.2 { + execsql "SELECT rowid FROM t4('\x1A*')" +} {1 3} +do_test 11.3 { + execsql "SELECT rowid FROM t4('d\x1A')" +} {2} + +do_test 11.4 { + catchsql "SELECT rowid FROM t4('d\x1B')" +} {/fts5: syntax error/} +do_test 11.5 { + catchsql "SELECT rowid FROM t4('d\x19')" +} {/fts5: syntax error/} + +#------------------------------------------------------------------------- +# +do_test 12.1 { + execsql { + CREATE VIRTUAL TABLE xx USING fts5(x,y); + BEGIN; + INSERT INTO xx VALUES('1 2 3', 'a b c'); + } +} {} + +do_execsql_test 12.2 { + SELECT rowid FROM xx('x:a'); + COMMIT; +} {} + +#------------------------------------------------------------------------- +# Try an UPDATE OR REPLACE query. +# +do_execsql_test 13.1 { + CREATE VIRTUAL TABLE xy USING fts5(x); + INSERT INTO xy(rowid, x) VALUES(1, '1 2 3'); + INSERT INTO xy(rowid, x) VALUES(2, '2 3 4'); + INSERT INTO xy(rowid, x) VALUES(3, '3 4 5'); +} + +do_execsql_test 13.2 { + UPDATE OR REPLACE xy SET rowid=3 WHERE rowid = 2; + SELECT rowid, x FROM xy; +} { + 1 {1 2 3} + 3 {2 3 4} +} + +do_execsql_test 13.3 { + INSERT INTO xy(xy) VALUES('integrity-check'); +} + +#------------------------------------------------------------------------- +# +do_execsql_test 14.1 { + CREATE VIRTUAL TABLE ttt USING fts5(x); + BEGIN; + INSERT INTO ttt(rowid, x) VALUES(1, 'a b c'); + INSERT INTO ttt(rowid, x) VALUES(2, 'a b c'); + INSERT INTO ttt(rowid, x) VALUES(3, 'a b c'); + COMMIT; +} +do_test 14.2 { + fts5_level_segs ttt +} {1} + +#------------------------------------------------------------------------- +db func rnddoc fts5_rnddoc +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE x1 USING fts5(x); + INSERT INTO x1(x1, rank) VALUES('pgsz', 32); + + WITH ii(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<10 ) + INSERT INTO x1 SELECT rnddoc(5) FROM ii; +} + +do_execsql_test 4.1 { + SELECT rowid, x, x1 FROM x1 WHERE x1 MATCH '*reads' +} {0 {} 4} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 15.0 { + CREATE VIRTUAL TABLE x2 USING fts5(x, prefix=1); + INSERT INTO x2 VALUES('ab'); +} + +do_execsql_test 15.1 { + INSERT INTO x2(x2) VALUES('integrity-check'); +} + +#------------------------------------------------------------------------- +foreach_detail_mode $testprefix { + reset_db + fts5_aux_test_functions db + do_execsql_test 16.0 { + CREATE VIRTUAL TABLE x3 USING fts5(x, detail=%DETAIL%); + INSERT INTO x3 VALUES('a b c d e f'); + } + do_execsql_test 16.1 { + SELECT fts5_test_poslist(x3) FROM x3('(a NOT b) OR c'); + } {2.0.2} + + do_execsql_test 16.1 { + SELECT fts5_test_poslist(x3) FROM x3('a OR c'); + } {{0.0.0 1.0.2}} +} + +} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 17.0 { + CREATE VIRTUAL TABLE x3 USING fts5(x); + INSERT INTO x3 VALUES('a b c'); +} + +do_execsql_test 17.1 { + SELECT rowid FROM x3('b AND d'); +} + +#------------------------------------------------------------------------- +do_execsql_test 18.1 { + CREATE VIRTUAL TABLE x4 USING fts5(x); + SELECT rowid FROM x4('""'); +} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 19.1 { + CREATE VIRTUAL TABLE x1 USING fts5(a,b,c); +} + +do_catchsql_test 19.2 { + SELECT * FROM x1 WHERE x1 MATCH 'c0 AND (c1 AND (c2 AND (c3 AND (c4 AND (c5 AND (c6 AND (c7 AND (c8 AND (c9 AND (c10 AND (c11 AND (c12 AND (c13 AND (c14 AND (c15 AND (c16 AND (c17 AND (c18 AND (c19 AND (c20 AND (c21 AND (c22 AND (c23 AND (c24 AND (c25 AND (c26 AND (c27 AND (c28 AND (c29 AND (c30 AND (c31 AND (c32 AND (c33 AND (c34 AND (c35 AND (c36 AND (c37 AND (c38 AND (c39 AND (c40 AND (c41 AND (c42 AND (c43 AND (c44 AND (c45 AND (c46 AND (c47 AND (c48 AND (c49 AND (c50 AND (c51 AND (c52 AND (c53 AND (c54 AND (c55 AND (c56 AND (c57 AND (c58 AND (c59 AND (c60 AND (c61 AND (c62 AND (c63 AND (c64 AND (c65 AND (c66 AND (c67 AND (c68 AND (c69 AND (c70 AND (c71 AND (c72 AND (c73 AND (c74 AND (c75 AND (c76 AND (c77 AND (c78 AND (c79 AND (c80 AND (c81 AND (c82 AND (c83 AND (c84 AND (c85 AND (c86 AND (c87 AND (c88 AND (c89 AND (c90 AND (c91 AND (c92 AND (c93 AND (c94 AND (c95 AND (c96 AND (c97 AND (c98 AND (c99 AND (c100 AND (c101 AND (c102 AND (c103 AND (c104 AND (c105 AND (c106 AND (c107 AND (c108 AND (c109 AND (c110 AND (c111 AND (c112 AND (c113 AND (c114 AND (c115 AND (c116 AND (c117 AND (c118 AND (c119 AND (c120 AND (c121 AND (c122 AND (c123 AND (c124 AND (c125 AND (c126 AND (c127 AND (c128 AND (c129 AND (c130 AND (c131 AND (c132 AND (c133 AND (c134 AND (c135 AND (c136 AND (c137 AND (c138 AND (c139 AND (c140 AND (c141 AND (c142 AND (c143 AND (c144 AND (c145 AND (c146 AND (c147 AND (c148 AND (c149 AND (c150 AND (c151 AND (c152 AND (c153 AND (c154 AND (c155 AND (c156 AND (c157 AND (c158 AND (c159 AND (c160 AND (c161 AND (c162 AND (c163 AND (c164 AND (c165 AND (c166 AND (c167 AND (c168 AND (c169 AND (c170 AND (c171 AND (c172 AND (c173 AND (c174 AND (c175 AND (c176 AND (c177 AND (c178 AND (c179 AND (c180 AND (c181 AND (c182 AND (c183 AND (c184 AND (c185 AND (c186 AND (c187 AND (c188 AND (c189 AND (c190 AND (c191 AND (c192 AND (c193 AND (c194 AND (c195 AND (c196 AND (c197 AND (c198 AND (c199 AND c200)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))'; +} {1 {fts5: parser stack overflow}} + +finish_test + diff --git a/ext/fts5/test/fts5simple2.test b/ext/fts5/test/fts5simple2.test new file mode 100644 index 0000000..186d771 --- /dev/null +++ b/ext/fts5/test/fts5simple2.test @@ -0,0 +1,338 @@ +# 2015 September 05 +# +# 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. +# +#************************************************************************* +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5simple2 + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=none); + INSERT INTO t1 VALUES('a b c'); +} +do_execsql_test 1.1 { + SELECT rowid FROM t1('c a b') +} {1} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=none); + BEGIN; + INSERT INTO t1 VALUES('b c d'); + INSERT INTO t1 VALUES('b c d'); + COMMIT; +} +do_execsql_test 2.1 { + SELECT rowid FROM t1('b c d') +} {1 2} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=none); + BEGIN; + INSERT INTO t1 VALUES('b c d'); + INSERT INTO t1 VALUES('b c d'); +} +do_execsql_test 3.1 { + SELECT rowid FROM t1('b c d'); COMMIT; +} {1 2} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=none); + BEGIN; + INSERT INTO t1 VALUES('a1 b1 c1'); + INSERT INTO t1 VALUES('a2 b2 c2'); + INSERT INTO t1 VALUES('a3 b3 c3'); + COMMIT; +} +do_execsql_test 4.1 { + SELECT rowid FROM t1('b*'); +} {1 2 3} + + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=none); + BEGIN; + INSERT INTO t1 VALUES('a1 b1 c1'); + INSERT INTO t1 VALUES('a2 b2 c2'); + INSERT INTO t1 VALUES('a1 b1 c1'); + COMMIT; +} +do_execsql_test 5.1 { SELECT rowid FROM t1('b*') } {1 2 3} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 6.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=full); + BEGIN; + INSERT INTO t1 VALUES('a1 b1 c1'); + INSERT INTO t1 VALUES('a1 b1 c1'); + INSERT INTO t1 VALUES('a1 b1 c1'); + COMMIT; +} + +do_execsql_test 6.1 { SELECT rowid FROM t1('a1') ORDER BY rowid DESC } {3 2 1} +do_execsql_test 6.2 { SELECT rowid FROM t1('b1') ORDER BY rowid DESC } {3 2 1} +do_execsql_test 6.3 { SELECT rowid FROM t1('c1') ORDER BY rowid DESC } {3 2 1} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 7.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=none); + BEGIN; + INSERT INTO t1 VALUES('a1 b1'); + INSERT INTO t1 VALUES('a1 b2'); + COMMIT; +} +do_execsql_test 7.1 { SELECT rowid FROM t1('b*') ORDER BY rowid DESC } {2 1} +do_execsql_test 7.2 { SELECT rowid FROM t1('a1') ORDER BY rowid DESC } {2 1} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 8.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=none); + INSERT INTO t1 VALUES('a1 b1 c1'); + INSERT INTO t1 VALUES('a2 b2 c2'); + INSERT INTO t1 VALUES('a1 b1 c1'); +} +do_execsql_test 8.0.1 { SELECT rowid FROM t1('b*') } {1 2 3} +do_execsql_test 8.0.2 { SELECT rowid FROM t1('a1') } {1 3} +do_execsql_test 8.0.3 { SELECT rowid FROM t1('c2') } {2} + +do_execsql_test 8.0.4 { SELECT rowid FROM t1('b*') ORDER BY rowid DESC } {3 2 1} +do_execsql_test 8.0.5 { SELECT rowid FROM t1('a1') ORDER BY rowid DESC } {3 1} +do_execsql_test 8.0.8 { SELECT rowid FROM t1('c2') ORDER BY rowid DESC } {2} + +do_execsql_test 8.1.0 { INSERT INTO t1(t1) VALUES('optimize') } + +do_execsql_test 8.1.1 { SELECT rowid FROM t1('b*') } {1 2 3} +do_execsql_test 8.1.2 { SELECT rowid FROM t1('a1') } {1 3} +do_execsql_test 8.1.3 { SELECT rowid FROM t1('c2') } {2} + +do_execsql_test 8.2.1 { SELECT rowid FROM t1('b*') ORDER BY rowid DESC} {3 2 1} +do_execsql_test 8.2.2 { SELECT rowid FROM t1('a1') ORDER BY rowid DESC} {3 1} +do_execsql_test 8.2.3 { SELECT rowid FROM t1('c2') ORDER BY rowid DESC} {2} + +#-------------------------------------------------------------------------- +# +reset_db +do_execsql_test 9.0.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=none); + INSERT INTO t1 VALUES('a1 b1 c1'); + INSERT INTO t1 VALUES('a2 b2 c2'); + INSERT INTO t1 VALUES('a1 b1 c1'); +} +do_execsql_test 9.0.1 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {} + +reset_db +do_execsql_test 9.1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=none); + INSERT INTO t1 VALUES('a1 b1 c1', 'x y z'); + INSERT INTO t1 VALUES('a2 b2 c2', '1 2 3'); + INSERT INTO t1 VALUES('a1 b1 c1', 'x 2 z'); +} +do_execsql_test 9.2.1 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {} + +#-------------------------------------------------------------------------- +# +reset_db +do_execsql_test 10.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=none); + INSERT INTO t1 VALUES('b1'); + INSERT INTO t1 VALUES('b1'); + DELETE FROM t1 WHERE rowid=1; +} + +do_execsql_test 10.1 { + SELECT rowid FROM t1('b1'); +} {2} + +do_execsql_test 10.2 { + SELECT rowid FROM t1('b1') ORDER BY rowid DESC; +} {2} + +do_execsql_test 10.3 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} {} + +#-------------------------------------------------------------------------- +# +reset_db +do_execsql_test 11.1 { + CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=none); + INSERT INTO t1(t1, rank) VALUES('pgsz', 32); + WITH d(x,y) AS ( + SELECT NULL, 'xyz' UNION ALL SELECT NULL, 'xyz' FROM d + ) + INSERT INTO t1 SELECT * FROM d LIMIT 23; +} + +#db eval { SELECT rowid AS r, quote(block) AS b FROM t1_data } { puts "$r: $b" } +do_execsql_test 11.2 { + SELECT rowid FROM t1; +} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23} + +do_execsql_test 11.3 { + SELECT rowid FROM t1('xyz'); +} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23} + +do_execsql_test 11.4 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 12.0 { + CREATE VIRTUAL TABLE yy USING fts5(x, detail=none); + INSERT INTO yy VALUES('in if'); + INSERT INTO yy VALUES('if'); +} {} + +do_execsql_test 12.1 { + SELECT rowid FROM yy('i*'); +} {1 2} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 13.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, prefix=1, detail=none); +} {} +foreach {rowid a} { + 0 {f} + 1 {u} + 2 {k} + 3 {a} + 4 {a} + 5 {u} + 6 {u} + 7 {u} + 8 {f} + 9 {f} + 10 {a} + 11 {p} + 12 {f} + 13 {u} + 14 {a} + 15 {a} +} { + do_execsql_test 13.1.$rowid { + INSERT INTO t1(rowid, a) VALUES($rowid, $a); + } +} + +#------------------------------------------------------------------------- +# +reset_db +fts5_aux_test_functions db +do_execsql_test 14.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, detail=none); + INSERT INTO t1 VALUES('a b c d'); +} {} + +do_execsql_test 14.1 { + SELECT fts5_test_poslist(t1) FROM t1('b') ORDER BY rank; +} {0.0.1} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 15.1 { + CREATE VIRTUAL TABLE t1 USING fts5(x, detail=none); + BEGIN; + INSERT INTO t1(rowid, x) VALUES(1, 'sqlite'); + INSERT INTO t1(rowid, x) VALUES(2, 'sqlite'); + COMMIT; +} {} + +do_test 15.1 { + execsql { INSERT INTO t1(t1) VALUES('integrity-check') } +} {} + +do_test 15.2 { + execsql { DELETE FROM t1 } +} {} + +do_execsql_test 15.3.1 { + SELECT rowid FROM t1('sqlite'); +} {} + +do_execsql_test 15.3.2 { + SELECT rowid FROM t1('sqlite') ORDER BY rowid DESC; +} {} + +do_test 15.4 { + execsql { INSERT INTO t1(t1) VALUES('integrity-check') } +} {} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 16.0 { + CREATE VIRTUAL TABLE t2 USING fts5(x, detail=none); + BEGIN; + INSERT INTO t2(rowid, x) VALUES(1, 'a b c'); + INSERT INTO t2(rowid, x) VALUES(456, 'a b c'); + INSERT INTO t2(rowid, x) VALUES(1000, 'a b c'); + COMMIT; + UPDATE t2 SET x=x; +} + +do_execsql_test 16.1 { + INSERT INTO t2(t2) VALUES('integrity-check'); +} {} + +do_execsql_test 16.2 { + SELECT rowid FROM t2('b') ORDER BY rowid DESC +} {1000 456 1} + + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 16.0 { + CREATE VIRTUAL TABLE t2 USING fts5(x, detail=none); + BEGIN; + INSERT INTO t2(rowid, x) VALUES(1, 'a b c'); + INSERT INTO t2(rowid, x) VALUES(456, 'a b c'); + INSERT INTO t2(rowid, x) VALUES(1000, 'a b c'); + COMMIT; + UPDATE t2 SET x=x; + DELETE FROM t2; +} + +#db eval {SELECT rowid, fts5_decode_none(rowid, block) aS r FROM t2_data} {puts $r} + +finish_test + diff --git a/ext/fts5/test/fts5simple3.test b/ext/fts5/test/fts5simple3.test new file mode 100644 index 0000000..b6922f8 --- /dev/null +++ b/ext/fts5/test/fts5simple3.test @@ -0,0 +1,85 @@ +# 2015 September 05 +# +# 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. +# +#************************************************************************* +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5simple3 + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +fts5_aux_test_functions db + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, c, detail=col); + INSERT INTO t1 VALUES('a', 'b', 'c'); + INSERT INTO t1 VALUES('x', 'x', 'x'); +} + +do_execsql_test 1.1 { + SELECT rowid, fts5_test_collist(t1) FROM t1('a:a'); +} {1 0.0} + +do_execsql_test 1.2 { + SELECT rowid, fts5_test_collist(t1) FROM t1('b:x'); +} {2 0.1} + +do_execsql_test 1.3 { + SELECT rowid, fts5_test_collist(t1) FROM t1('b:a'); +} {} + +#------------------------------------------------------------------------- +# Create detail=col and detail=full tables with 998 columns. +# +foreach_detail_mode $testprefix { + if {[detail_is_none]} continue + + do_test 2.1 { + execsql { DROP TABLE IF EXISTS t2 } + set cols [list] + set vals [list] + for {set i 1} {$i <= 998} {incr i} { + lappend cols "c$i" + lappend vals "'val$i'" + } + execsql "CREATE VIRTUAL TABLE t2 USING fts5(detail=%DETAIL%,[join $cols ,])" + } {} + + do_test 2.2 { + execsql "INSERT INTO t2 VALUES([join $vals ,])" + } {} + + foreach {tn q res} { + 1 { c1:val1 } 1 + 2 { c300:val300 } 1 + 3 { c300:val1 } {} + 4 { c1:val300 } {} + } { + do_execsql_test 2.3.$tn { + SELECT rowid FROM t2($q) + } $res + } +} + +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE x3 USING fts5(one); + INSERT INTO x3 VALUES('a b c'); + INSERT INTO x3 VALUES('c b a'); + INSERT INTO x3 VALUES('o t t'); + SELECT * FROM x3('x OR y OR z'); +} + + +finish_test + diff --git a/ext/fts5/test/fts5synonym.test b/ext/fts5/test/fts5synonym.test new file mode 100644 index 0000000..185dda3 --- /dev/null +++ b/ext/fts5/test/fts5synonym.test @@ -0,0 +1,424 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Tests focusing on custom tokenizers that support synonyms. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5synonym + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +proc tcl_create {args} { return "tcl_tokenize" } + +foreach_detail_mode $testprefix { + +#------------------------------------------------------------------------- +# Warm body test for the code in fts5_tcl.c. +# +fts5_tclnum_register db +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE ft USING fts5(x, tokenize = "tclnum document", detail=%DETAIL%); + INSERT INTO ft VALUES('abc def ghi'); + INSERT INTO ft VALUES('jkl mno pqr'); + SELECT rowid, x FROM ft WHERE ft MATCH 'def'; + SELECT x, rowid FROM ft WHERE ft MATCH 'pqr'; +} {1 {abc def ghi} {jkl mno pqr} 2} + +#------------------------------------------------------------------------- +# Test a tokenizer that supports synonyms by adding extra entries to the +# FTS index. +# +reset_db +fts5_tclnum_register db + +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE ft USING fts5( + x, tokenize = "tclnum document", detail=%DETAIL% + ); + INSERT INTO ft VALUES('one two three'); + INSERT INTO ft VALUES('four five six'); + INSERT INTO ft VALUES('eight nine ten'); +} {} + +foreach {tn expr res} { + 1 "3" 1 + 2 "eight OR 8 OR 5" {2 3} + 3 "10" {} + 4 "1*" {1} + 5 "1 + 2" {1} +} { + if {![fts5_expr_ok $expr ft]} continue + do_execsql_test 2.1.$tn { + SELECT rowid FROM ft WHERE ft MATCH $expr + } $res +} + +#------------------------------------------------------------------------- +# Test some broken tokenizers: +# +# 3.1.*: A tokenizer that declares the very first token to be colocated. +# +# 3.2.*: A tokenizer that reports two identical tokens at the same position. +# This is allowed. +# +reset_db +sqlite3_fts5_create_tokenizer db tcl tcl_create +proc tcl_tokenize {tflags text} { + set bColo 1 + foreach {w iStart iEnd} [fts5_tokenize_split $text] { + if {$bColo} { + sqlite3_fts5_token -colo $w $iStart $iEnd + set bColo 0 + } { + sqlite3_fts5_token $w $iStart $iEnd + } + } +} +do_execsql_test 3.1.0 { + CREATE VIRTUAL TABLE ft USING fts5(x, tokenize = tcl); + INSERT INTO ft VALUES('one two three'); + CREATE VIRTUAL TABLE vv USING fts5vocab(ft, row); + SELECT * FROM vv; +} { + one 1 1 three 1 1 two 1 1 +} + +do_execsql_test 3.1.1 { + INSERT INTO ft(ft) VALUES('integrity-check'); +} {} + +proc tcl_tokenize {tflags text} { + foreach {w iStart iEnd} [fts5_tokenize_split $text] { + sqlite3_fts5_token $w $iStart $iEnd + } +} + +do_execsql_test 3.1.2 { + SELECT rowid FROM ft WHERE ft MATCH 'one two three' +} {1} + +reset_db +sqlite3_fts5_create_tokenizer db tcl tcl_create +proc tcl_tokenize {tflags text} { + foreach {w iStart iEnd} [fts5_tokenize_split $text] { + sqlite3_fts5_token $w $iStart $iEnd + sqlite3_fts5_token -colo $w $iStart $iEnd + } +} +do_execsql_test 3.2.0 { + CREATE VIRTUAL TABLE ft USING fts5(x, tokenize = tcl); + INSERT INTO ft VALUES('one one two three'); + CREATE VIRTUAL TABLE vv USING fts5vocab(ft, row); + SELECT * FROM vv; +} { + one 1 4 three 1 2 two 1 2 +} +do_execsql_test 3.2.1 { + SELECT rowid FROM ft WHERE ft MATCH 'one'; +} {1} +do_execsql_test 3.2.2 { + SELECT rowid FROM ft WHERE ft MATCH 'one two three'; +} {1} +do_execsql_test 3.2.3 { + SELECT rowid FROM ft WHERE ft MATCH 'one + one + two + three'; +} {1} +do_execsql_test 3.2.4 { + SELECT rowid FROM ft WHERE ft MATCH 'one two two three'; +} {1} +do_execsql_test 3.2.5 { + SELECT rowid FROM ft WHERE ft MATCH 'one + two + two + three'; +} {} + +#------------------------------------------------------------------------- +# Check that expressions with synonyms can be parsed and executed. +# +reset_db +fts5_tclnum_register db + +foreach {tn expr res} { + 1 {abc} {"abc"} + 2 {one} {"one"|"i"|"1"} + 3 {3} {"3"|"iii"|"three"} + 4 {3*} {"3"|"iii"|"three" *} +} { + do_execsql_test 4.1.$tn { + SELECT fts5_expr($expr, 'tokenize=tclnum') + } [list $res] +} + +do_execsql_test 4.2.1 { + CREATE VIRTUAL TABLE xx USING fts5(x, tokenize=tclnum, detail=%DETAIL%); + INSERT INTO xx VALUES('one two'); + INSERT INTO xx VALUES('three four'); +} + +do_execsql_test 4.2.2 { + SELECT rowid FROM xx WHERE xx MATCH '2' +} {1} + +do_execsql_test 4.2.3 { + SELECT rowid FROM xx WHERE xx MATCH '3' +} {2} + +do_test 5.0 { + execsql { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, tokenize=tclnum, detail=%DETAIL%) + } + foreach {rowid a b} { + 1 {four v 4 i three} {1 3 five five 4 one} + 2 {5 1 3 4 i} {2 2 v two 4} + 3 {5 i 5 2 four 4 1} {iii ii five two 1} + 4 {ii four 4 one 5 three five} {one 5 1 iii 4 3} + 5 {three i v i four 4 1} {ii five five five iii} + 6 {4 2 ii two 2 iii} {three 1 four 4 iv 1 iv} + 7 {ii ii two three 2 5} {iii i ii iii iii one one} + 8 {2 ii i two 3 three 2} {two iv v iii 3 five} + 9 {i 2 iv 3 five four v} {iii 4 three i three ii 1} + } { + execsql { INSERT INTO t1(rowid, a, b) VALUES($rowid, $a, $b) } + } +} {} + + +foreach {tn q res} { + 1 {one} { + 1 {four v 4 [i] three} {[1] 3 five five 4 [one]} + 2 {5 [1] 3 4 [i]} {2 2 v two 4} + 3 {5 [i] 5 2 four 4 [1]} {iii ii five two [1]} + 4 {ii four 4 [one] 5 three five} {[one] 5 [1] iii 4 3} + 5 {three [i] v [i] four 4 [1]} {ii five five five iii} + 6 {4 2 ii two 2 iii} {three [1] four 4 iv [1] iv} + 7 {ii ii two three 2 5} {iii [i] ii iii iii [one] [one]} + 8 {2 ii [i] two 3 three 2} {two iv v iii 3 five} + 9 {[i] 2 iv 3 five four v} {iii 4 three [i] three ii [1]} + } + 2 {five four} { + 1 {[four] [v] [4] i three} {1 3 [five] [five] [4] one} + 2 {[5] 1 3 [4] i} {2 2 [v] two [4]} + 3 {[5] i [5] 2 [four] [4] 1} {iii ii [five] two 1} + 4 {ii [four] [4] one [5] three [five]} {one [5] 1 iii [4] 3} + 5 {three i [v] i [four] [4] 1} {ii [five] [five] [five] iii} + 8 {2 ii i two 3 three 2} {two [iv] [v] iii 3 [five]} + 9 {i 2 [iv] 3 [five] [four] [v]} {iii [4] three i three ii 1} + } + 3 {one OR two OR iii OR 4 OR v} { + 1 {[four] [v] [4] [i] [three]} {[1] [3] [five] [five] [4] [one]} + 2 {[5] [1] [3] [4] [i]} {[2] [2] [v] [two] [4]} + 3 {[5] [i] [5] [2] [four] [4] [1]} {[iii] [ii] [five] [two] [1]} + 4 {[ii] [four] [4] [one] [5] [three] [five]} {[one] [5] [1] [iii] [4] [3]} + 5 {[three] [i] [v] [i] [four] [4] [1]} {[ii] [five] [five] [five] [iii]} + 6 {[4] [2] [ii] [two] [2] [iii]} {[three] [1] [four] [4] [iv] [1] [iv]} + 7 {[ii] [ii] [two] [three] [2] [5]} {[iii] [i] [ii] [iii] [iii] [one] [one]} + 8 {[2] [ii] [i] [two] [3] [three] [2]} {[two] [iv] [v] [iii] [3] [five]} + 9 {[i] [2] [iv] [3] [five] [four] [v]} {[iii] [4] [three] [i] [three] [ii] [1]} + } + + 4 {5 + 1} { + 2 {[5 1] 3 4 i} {2 2 v two 4} + 3 {[5 i] 5 2 four 4 1} {iii ii five two 1} + 4 {ii four 4 one 5 three five} {one [5 1] iii 4 3} + 5 {three i [v i] four 4 1} {ii five five five iii} + } + + 5 {one + two + three} { + 7 {ii ii two three 2 5} {iii [i ii iii] iii one one} + 8 {2 ii [i two 3] three 2} {two iv v iii 3 five} + } + + 6 {"v v"} { + 1 {four v 4 i three} {1 3 [five five] 4 one} + 5 {three i v i four 4 1} {ii [five five five] iii} + } +} { + if {![fts5_expr_ok $q t1]} continue + do_execsql_test 5.1.$tn { + SELECT rowid, highlight(t1, 0, '[', ']'), highlight(t1, 1, '[', ']') + FROM t1 WHERE t1 MATCH $q + } $res +} + +# Test that the xQueryPhrase() API works with synonyms. +# +proc mit {blob} { + set scan(littleEndian) i* + set scan(bigEndian) I* + binary scan $blob $scan($::tcl_platform(byteOrder)) r + return $r +} +db func mit mit +sqlite3_fts5_register_matchinfo db + +foreach {tn q res} { + 1 {one} { + 1 {1 11 7 2 12 6} 2 {2 11 7 0 12 6} + 3 {2 11 7 1 12 6} 4 {1 11 7 2 12 6} + 5 {3 11 7 0 12 6} 6 {0 11 7 2 12 6} + 7 {0 11 7 3 12 6} 8 {1 11 7 0 12 6} + 9 {1 11 7 2 12 6} + } +} { + do_execsql_test 5.2.$tn { + SELECT rowid, mit(matchinfo(t1, 'x')) FROM t1 WHERE t1 MATCH $q + } $res +} + +#------------------------------------------------------------------------- +# Test terms with more than 4 synonyms. +# +reset_db +sqlite3_fts5_create_tokenizer db tcl tcl_create +proc tcl_tokenize {tflags text} { + foreach {w iStart iEnd} [fts5_tokenize_split $text] { + sqlite3_fts5_token $w $iStart $iEnd + if {$tflags=="query" && [string length $w]==1} { + for {set i 2} {$i<=10} {incr i} { + sqlite3_fts5_token -colo [string repeat $w $i] $iStart $iEnd + } + } + } +} + +do_execsql_test 6.0.1 { + CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize=tcl, detail=%DETAIL%); + INSERT INTO t1 VALUES('yy xx qq'); + INSERT INTO t1 VALUES('yy xx xx'); +} +if {[fts5_expr_ok "NEAR(y q)" t1]} { + do_execsql_test 6.0.2 { + SELECT * FROM t1 WHERE t1 MATCH 'NEAR(y q)'; + } {{yy xx qq}} +} + +do_test 6.0.3 { + execsql { + CREATE VIRTUAL TABLE t2 USING fts5(a, b, tokenize=tcl, detail=%DETAIL%) + } + foreach {rowid a b} { + 1 {yyyy vvvvv qq oo yyyyyy vvvv eee} {ffff uu r qq aaaa} + 2 {ww oooooo bbbbb ssssss mm} {ffffff yy iiii rr s ccc qqqqq} + 3 {zzzz llll gggggg cccc uu} {hhhhhh aaaa ppppp rr ee jjjj} + 4 {r f i rrrrrr ww hhh} {aa yyy t x aaaaa ii} + 5 {fffff mm vvvv ooo ffffff kkkk tttt} {cccccc bb e zzz d n} + 6 {iii dddd hh qqqq ddd ooo} {ttt d c b aaaaaa qqqq} + 7 {jjjj rrrr v zzzzz u tt t} {ppppp pp dddd mm hhh uuu} + 8 {gggg rrrrrr kkkk vvvv gggg jjjjjj b} {dddddd jj r w cccc wwwwww ss} + 9 {kkkkk qqq oooo e tttttt mmm} {e ss qqqqqq hhhh llllll gg} + } { + execsql { INSERT INTO t2(rowid, a, b) VALUES($rowid, $a, $b) } + } +} {} + +foreach {tn q res} { + 1 {a} { + 1 {yyyy vvvvv qq oo yyyyyy vvvv eee} {ffff uu r qq [aaaa]} + 3 {zzzz llll gggggg cccc uu} {hhhhhh [aaaa] ppppp rr ee jjjj} + 4 {r f i rrrrrr ww hhh} {[aa] yyy t x [aaaaa] ii} + 6 {iii dddd hh qqqq ddd ooo} {ttt d c b [aaaaaa] qqqq} + } + + 2 {a AND q} { + 1 {yyyy vvvvv [qq] oo yyyyyy vvvv eee} {ffff uu r [qq] [aaaa]} + 6 {iii dddd hh [qqqq] ddd ooo} {ttt d c b [aaaaaa] [qqqq]} + } + + 3 {o OR (q AND a)} { + 1 {yyyy vvvvv [qq] [oo] yyyyyy vvvv eee} {ffff uu r [qq] [aaaa]} + 2 {ww [oooooo] bbbbb ssssss mm} {ffffff yy iiii rr s ccc qqqqq} + 5 {fffff mm vvvv [ooo] ffffff kkkk tttt} {cccccc bb e zzz d n} + 6 {iii dddd hh [qqqq] ddd [ooo]} {ttt d c b [aaaaaa] [qqqq]} + 9 {kkkkk qqq [oooo] e tttttt mmm} {e ss qqqqqq hhhh llllll gg} + } + + 4 {NEAR(q y, 20)} { + 1 {[yyyy] vvvvv [qq] oo [yyyyyy] vvvv eee} {ffff uu r qq aaaa} + 2 {ww oooooo bbbbb ssssss mm} {ffffff [yy] iiii rr s ccc [qqqqq]} + } +} { + if {![fts5_expr_ok $q t2]} continue + + do_execsql_test 6.1.$tn.asc { + SELECT rowid, highlight(t2, 0, '[', ']'), highlight(t2, 1, '[', ']') + FROM t2 WHERE t2 MATCH $q + } $res + + set res2 [list] + foreach {rowid a b} $res { + set res2 [concat [list $rowid $a $b] $res2] + } + + do_execsql_test 6.1.$tn.desc { + SELECT rowid, highlight(t2, 0, '[', ']'), highlight(t2, 1, '[', ']') + FROM t2 WHERE t2 MATCH $q ORDER BY rowid DESC + } $res2 +} + +do_execsql_test 6.2.1 { + INSERT INTO t2(rowid, a, b) VALUES(13, + 'x xx xxx xxxx xxxxx xxxxxx xxxxxxx', 'y yy yyy yyyy yyyyy yyyyyy yyyyyyy' + ); + SELECT rowid, highlight(t2, 0, '<', '>'), highlight(t2, 1, '(', ')') + FROM t2 WHERE t2 MATCH 'x OR y' +} { + 1 { vvvvv qq oo vvvv eee} {ffff uu r qq aaaa} + 2 {ww oooooo bbbbb ssssss mm} {ffffff (yy) iiii rr s ccc qqqqq} + 4 {r f i rrrrrr ww hhh} {aa (yyy) t (x) aaaaa ii} + 13 { } + {(y) (yy) (yyy) (yyyy) (yyyyy) (yyyyyy) (yyyyyyy)} +} + +#------------------------------------------------------------------------- +# Test that the xColumnSize() API is not confused by colocated tokens. +# +reset_db +sqlite3_fts5_create_tokenizer db tcl tcl_create +fts5_aux_test_functions db +proc tcl_tokenize {tflags text} { + foreach {w iStart iEnd} [fts5_tokenize_split $text] { + sqlite3_fts5_token $w $iStart $iEnd + if {[string length $w]==1} { + for {set i 2} {$i<=10} {incr i} { + sqlite3_fts5_token -colo [string repeat $w $i] $iStart $iEnd + } + } + } +} + +do_execsql_test 7.0.1 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, columnsize=1, tokenize=tcl, detail=%DETAIL%); + INSERT INTO t1 VALUES('0 2 3', '4 5 6 7'); + INSERT INTO t1 VALUES('8 9', '0 0 0 0 0 0 0 0 0 0'); + SELECT fts5_test_columnsize(t1) FROM t1 WHERE t1 MATCH '000 AND 00 AND 0'; +} {{3 4} {2 10}} + +do_execsql_test 7.0.2 { + INSERT INTO t1(t1) VALUES('integrity-check'); +} + +do_execsql_test 7.1.1 { + CREATE VIRTUAL TABLE t2 USING fts5(a, b, columnsize=0, tokenize=tcl, detail=%DETAIL%); + INSERT INTO t2 VALUES('0 2 3', '4 5 6 7'); + INSERT INTO t2 VALUES('8 9', '0 0 0 0 0 0 0 0 0 0'); + SELECT fts5_test_columnsize(t2) FROM t2 WHERE t2 MATCH '000 AND 00 AND 0'; +} {{3 4} {2 10}} + +do_execsql_test 7.1.2 { + INSERT INTO t2(t2) VALUES('integrity-check'); +} + +} ;# foreach_detail_mode + +finish_test + diff --git a/ext/fts5/test/fts5synonym2.test b/ext/fts5/test/fts5synonym2.test new file mode 100644 index 0000000..7e92822 --- /dev/null +++ b/ext/fts5/test/fts5synonym2.test @@ -0,0 +1,164 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Tests focusing on custom tokenizers that support synonyms. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5synonym2 + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach tok {query document} { +foreach_detail_mode $testprefix { + +fts5_tclnum_register db +fts5_aux_test_functions db + +proc fts5_test_bothlist {cmd} { + + for {set i 0} {$i < [$cmd xPhraseCount]} {incr i} { + set bFirst 1 + $cmd xPhraseColumnForeach $i c { + lappend CL $i.$c + if {$bFirst} { $cmd xPhraseForeach $i c o { lappend PL $i.$c.$o } } + set bFirst 0 + } + } + + list [sort_poslist $PL] $CL +} +sqlite3_fts5_create_function db fts5_test_bothlist fts5_test_bothlist + +proc fts5_rowid {cmd} { expr [$cmd xColumnText -1] } +sqlite3_fts5_create_function db fts5_rowid fts5_rowid + +do_execsql_test 1.$tok.0.1 " + CREATE VIRTUAL TABLE ss USING fts5(a, b, + tokenize='tclnum $tok', detail=%DETAIL%); + INSERT INTO ss(ss, rank) VALUES('rank', 'fts5_rowid()'); +" + +do_execsql_test 1.$tok.0.2 { + INSERT INTO ss VALUES('5 5 five seven 3 seven i', '2 1 5 0 two 1 i'); + INSERT INTO ss VALUES('six ix iii 7 i vii iii', 'one seven nine 4 9 1 vi'); + INSERT INTO ss VALUES('6 viii i five six zero seven', '5 v iii iv iv 3'); + INSERT INTO ss VALUES('9 ii six 8 1 6', 'six 4 iv iv 7'); + INSERT INTO ss VALUES('1 5 4 eight ii iv iii', 'nine 2 eight ix v vii'); + INSERT INTO ss VALUES('one 7 seven six 2 two', '1 2 four 7 4 3 4'); + INSERT INTO ss VALUES('eight iv 4 nine vii six 1', '5 6 v one zero 4'); + INSERT INTO ss VALUES('v 9 8 iii 4', '9 4 seven two vi vii'); + INSERT INTO ss VALUES('3 ix two 9 0 nine i', 'five ii nine two viii i five'); + INSERT INTO ss VALUES('six iii 9 two eight 2', 'nine i nine vii nine'); + INSERT INTO ss VALUES('6 three zero seven vii five', '8 vii ix 0 7 seven'); + INSERT INTO ss VALUES('8 vii 8 7 3 4', 'eight iii four viii nine iv three'); + INSERT INTO ss VALUES('4 v 7 two 0 one 8', 'vii 1 two five i zero 9'); + INSERT INTO ss VALUES('3 ii vii vi eight', '8 4 ix one three eight'); + INSERT INTO ss VALUES('iv eight seven 6 9 seven', 'one vi two five seven'); + INSERT INTO ss VALUES('i i 5 i v vii eight', '2 seven i 2 2 four'); + INSERT INTO ss VALUES('0 i iii nine 3 ix five', '0 eight iv 0 six 2'); + INSERT INTO ss VALUES('iv vii three 3 9 one 8', '2 ii 6 eight ii six six'); + INSERT INTO ss VALUES('eight one two nine six', '8 9 3 viii vi'); + INSERT INTO ss VALUES('one 0 four ii eight one 3', 'iii eight vi vi vi'); + INSERT INTO ss VALUES('4 0 eight 0 0', '1 four one vii seven ii'); + INSERT INTO ss VALUES('1 zero nine 2 2', 'viii iv two vi nine v iii'); + INSERT INTO ss VALUES('5 five viii four four vi', '8 five 7 vii 6 4'); + INSERT INTO ss VALUES('7 ix four 8 vii', 'nine three nine ii ix vii'); + INSERT INTO ss VALUES('nine iv v i 0 v', 'two iv vii six i ix 4'); + INSERT INTO ss VALUES('one v v one viii 3 8', '2 1 3 five iii'); + INSERT INTO ss VALUES('six ii 5 nine 4 viii seven', 'eight i ix ix 7 four'); + INSERT INTO ss VALUES('9 ii two seven three 7 0', 'six viii seven 7 five'); + INSERT INTO ss VALUES('five two 4 viii nine', '9 7 nine zero 1 two one'); + INSERT INTO ss VALUES('viii 8 iii i ii 8 3', '4 2 7 v 8 8'); + INSERT INTO ss VALUES('four vii 4 iii zero 0 vii', '3 viii iii zero 9 i'); + INSERT INTO ss VALUES('0 seven v five i five v', 'one 4 2 ix 9'); + INSERT INTO ss VALUES('two 5 two two ix 4 1', '3 nine ii v nine 3 five'); + INSERT INTO ss VALUES('five 5 7 4 6 vii', 'three 2 ix 2 8 6'); + INSERT INTO ss VALUES('six iii vi iv seven eight', '8 six 7 0 4'); + INSERT INTO ss VALUES('vi vi iv 3 0 one one', '9 6 eight ix iv'); + INSERT INTO ss VALUES('7 2 2 iii 0', '0 0 seven 1 nine'); + INSERT INTO ss VALUES('8 6 iv six ii', 'iv 6 3 4 ii five'); + INSERT INTO ss VALUES('0 two two seven ii', 'vii ix four 4 zero vi vi'); + INSERT INTO ss VALUES('2 one eight 8 9 7', 'vi 3 0 3 vii'); + INSERT INTO ss VALUES('iii ii ix iv three', 'vi i 6 1 two'); + INSERT INTO ss VALUES('eight four nine 8 seven', 'one three i nine iii one'); + INSERT INTO ss VALUES('iii seven five ix 8', 'ii 7 seven 0 four ii'); + INSERT INTO ss VALUES('four 0 1 5 two', 'iii 9 5 ii ii 2 4'); + INSERT INTO ss VALUES('iii nine four vi 8 five six', 'i i ii seven vi vii'); + INSERT INTO ss VALUES('eight vii eight six 3', 'i vii 1 six 9 vii'); + INSERT INTO ss VALUES('9 0 viii viii five', 'i 1 viii ix 3 4'); + INSERT INTO ss VALUES('three nine 5 nine viii four zero', 'ii i 1 5 2 viii'); + INSERT INTO ss VALUES('5 vii three 9 four', 'three five one 7 2 eight one'); +} + +foreach {tn expr} { + 2.1 "one OR two OR three OR four" + + 1.1 "one" 1.2 "two" 1.3 "three" 1.4 "four" + 1.5 "v" 1.6 "vi" 1.7 "vii" 1.8 "viii" + 1.9 "9" 1.10 "0" 1.11 "1" 1.12 "2" + + 2.1 "one OR two OR three OR four" + 2.2 "(one AND two) OR (three AND four)" + 2.3 "(one AND two) OR (three AND four) NOT five" + 2.4 "(one AND two) NOT 6" + + 3.1 "b:one AND a:two" + 3.2 "b:one OR a:two" + 3.3 "a:one OR b:1 OR {a b} : i" + + 4.1 "NEAR(one two, 2)" + 4.2 "NEAR(one two three, 2)" + 4.3 "NEAR(eight nine, 1) OR NEAR(six seven, 1)" +} { + if {[fts5_expr_ok $expr ss]==0} { + do_test 1.$tok.$tn.OMITTED { list } [list] + continue + } + + set res [fts5_query_data $expr ss ASC ::tclnum_syn] + do_execsql_test 1.$tok.$tn.[llength $res].asc.1 { + SELECT rowid, fts5_test_poslist2(ss), fts5_test_collist(ss) FROM ss($expr) + } $res + + do_execsql_test 1.$tok.$tn.[llength $res].asc.2 { + SELECT rowid, fts5_test_poslist(ss), fts5_test_collist(ss) FROM ss($expr) + } $res + + do_execsql_test 1.$tok.$tn.[llength $res].asc.2 { + SELECT rowid, fts5_test_poslist2(ss), fts5_test_collist(ss) FROM ss($expr) + ORDER BY rank ASC + } $res + + set res2 [list] + foreach {a b c} $res { lappend res2 $a $c $b } + do_execsql_test 1.$tok.$tn.[llength $res].asc.3 { + SELECT rowid, fts5_test_collist(ss), fts5_test_poslist2(ss) FROM ss($expr) + } $res2 + + set res3 [list] + foreach {a b c} $res { lappend res3 $a [list $b $c] } + do_execsql_test 1.$tok.$tn.[llength $res].asc.3 { + SELECT rowid, fts5_test_bothlist(ss) FROM ss($expr) + } $res3 + + +} + +} +} + +finish_test + diff --git a/ext/fts5/test/fts5tok1.test b/ext/fts5/test/fts5tok1.test new file mode 100644 index 0000000..6ba1700 --- /dev/null +++ b/ext/fts5/test/fts5tok1.test @@ -0,0 +1,115 @@ +# 2016 Jan 15 +# +# 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. +# +#************************************************************************* +# + +source [file join [file dirname [info script]] fts5_common.tcl] +ifcapable !fts5 { finish_test ; return } +set ::testprefix fts5tok1 + + +sqlite3_fts5_register_fts5tokenize db + +#------------------------------------------------------------------------- +# Simple test cases. Using the default (ascii) tokenizer. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5tokenize(ascii); + CREATE VIRTUAL TABLE t2 USING fts5tokenize(); + CREATE VIRTUAL TABLE t3 USING fts5tokenize( + ascii, 'separators', 'xyz', tokenchars, '''' + ); +} + +foreach {tn tbl} {1 t1 2 t2 3 t3} { + do_execsql_test 1.$tn.1 "SELECT input, * FROM $tbl ('one two three')" { + {one two three} one 0 3 0 + {one two three} two 4 7 1 + {one two three} three 8 13 2 + } + + do_execsql_test 1.$tn.2 " + SELECT token FROM $tbl WHERE input = 'OnE tWo tHrEe' + " { + one two three + } +} + +do_execsql_test 1.4 { + SELECT token FROM t3 WHERE input = '1x2x3x' +} {1 2 3} + +do_execsql_test 1.5 { + SELECT token FROM t1 WHERE input = '1x2x3x' +} {1x2x3x} + +do_execsql_test 1.6 { + SELECT token FROM t3 WHERE input = '1''2x3x' +} {1'2 3} + +do_execsql_test 1.7 { + SELECT token FROM t3 WHERE input = '' +} {} + +do_execsql_test 1.8 { + SELECT token FROM t3 WHERE input = NULL +} {} + +do_execsql_test 1.9 { + SELECT input, * FROM t3 WHERE input = 123 +} {123 123 0 3 0} + +do_execsql_test 1.10 { + SELECT input, * FROM t1 WHERE input = 'a b c' AND token = 'b'; +} { + {a b c} b 2 3 1 +} + +do_execsql_test 1.11 { + SELECT input, * FROM t1 WHERE token = 'b' AND input = 'a b c'; +} { + {a b c} b 2 3 1 +} + +do_execsql_test 1.12 { + SELECT input, * FROM t1 WHERE input < 'b' AND input = 'a b c'; +} { + {a b c} a 0 1 0 + {a b c} b 2 3 1 + {a b c} c 4 5 2 +} + +do_execsql_test 1.13.1 { + CREATE TABLE c1(x); + INSERT INTO c1(x) VALUES('a b c'); + INSERT INTO c1(x) VALUES('d e f'); +} +do_execsql_test 1.13.2 { + SELECT c1.*, input, t1.* FROM c1, t1 WHERE input = x AND c1.rowid=t1.rowid; +} { + {a b c} {a b c} a 0 1 0 + {d e f} {d e f} e 2 3 1 +} + + +#------------------------------------------------------------------------- +# Error cases. +# +do_catchsql_test 2.0 { + CREATE VIRTUAL TABLE tX USING fts5tokenize(nosuchtokenizer); +} {1 {vtable constructor failed: tX}} + +do_catchsql_test 2.1 { + CREATE VIRTUAL TABLE t4 USING fts5tokenize; + SELECT * FROM t4; +} {1 {SQL logic error or missing database}} + + +finish_test diff --git a/ext/fts5/test/fts5tok2.test b/ext/fts5/test/fts5tok2.test new file mode 100644 index 0000000..77c7e1e --- /dev/null +++ b/ext/fts5/test/fts5tok2.test @@ -0,0 +1,47 @@ +# 2016 Jan 15 +# +# 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. +# +#************************************************************************* +# + +source [file join [file dirname [info script]] fts5_common.tcl] +ifcapable !fts5||!fts3 { finish_test ; return } +set ::testprefix fts5tok2 + +sqlite3_fts5_register_fts5tokenize db + +#------------------------------------------------------------------------- +# Simple test cases. Using the default (ascii) tokenizer. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t5 USING fts5tokenize(unicode61); + CREATE VIRTUAL TABLE t3 USING fts3tokenize(unicode61); +} + +do_test 1.1 { + array unset -nocomplain A + + for {set i 1} {$i < 65536} {incr i} { + set input [format "abc%cxyz" $i] + set expect [execsql { + SELECT input, token, start, end FROM t3 WHERE input=$input + }] + + incr A([llength $expect]) + + set res [execsql { + SELECT input, token, start, end FROM t5($input) + }] + if {$res != $expect} {error "failed at i=$i"} + } +} {} + +do_test 1.1.nTokenChars=$A(4).nSeparators=$A(8) {} {} + +finish_test diff --git a/ext/fts5/test/fts5tokenizer.test b/ext/fts5/test/fts5tokenizer.test new file mode 100644 index 0000000..9316d3c --- /dev/null +++ b/ext/fts5/test/fts5tokenizer.test @@ -0,0 +1,266 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Tests focusing on the built-in fts5 tokenizers. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5tokenizer + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE ft1 USING fts5(x, tokenize=porter); + DROP TABLE ft1; +} +do_execsql_test 1.1 { + CREATE VIRTUAL TABLE ft1 USING fts5(x, tokenize='porter'); + DROP TABLE ft1; +} +do_execsql_test 1.2 { + CREATE VIRTUAL TABLE ft1 USING fts5(x, tokenize = porter); + DROP TABLE ft1; +} +do_execsql_test 1.3 { + CREATE VIRTUAL TABLE ft1 USING fts5(x, tokenize = 'porter'); + DROP TABLE ft1; +} +do_execsql_test 1.4 { + CREATE VIRTUAL TABLE ft1 USING fts5(x, tokenize = 'porter ascii'); + DROP TABLE ft1; +} + +do_catchsql_test 1.5 { + CREATE VIRTUAL TABLE ft1 USING fts5(x, tokenize = 'nosuch'); +} {1 {no such tokenizer: nosuch}} + +do_catchsql_test 1.6 { + CREATE VIRTUAL TABLE ft1 USING fts5(x, tokenize = 'porter nosuch'); +} {1 {error in tokenizer constructor}} + +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE ft1 USING fts5(x, tokenize=porter); + INSERT INTO ft1 VALUES('embedded databases'); +} +do_execsql_test 2.1 { SELECT rowid FROM ft1 WHERE ft1 MATCH 'embedding' } 1 +do_execsql_test 2.2 { SELECT rowid FROM ft1 WHERE ft1 MATCH 'database' } 1 +do_execsql_test 2.3 { + SELECT rowid FROM ft1 WHERE ft1 MATCH 'database embedding' +} 1 + +proc tcl_create {args} { + set ::targs $args + error "failed" +} +sqlite3_fts5_create_tokenizer db tcl tcl_create + +foreach {tn directive expected} { + 1 {tokenize='tcl a b c'} {a b c} + 2 {tokenize='tcl ''d'' ''e'' ''f'''} {d e f} + 3 {tokenize="tcl 'g' 'h' 'i'"} {g h i} + 4 {tokenize = tcl} {} +} { + do_catchsql_test 3.$tn.1 " + CREATE VIRTUAL TABLE ft2 USING fts5(x, $directive) + " {1 {error in tokenizer constructor}} + do_test 3.$tn.2 { set ::targs } $expected +} + +do_catchsql_test 4.1 { + CREATE VIRTUAL TABLE ft2 USING fts5(x, tokenize = tcl abc); +} {1 {parse error in "tokenize = tcl abc"}} +do_catchsql_test 4.2 { + CREATE VIRTUAL TABLE ft2 USING fts5(x y) +} {1 {unrecognized column option: y}} + +#------------------------------------------------------------------------- +# Test the "separators" and "tokenchars" options a bit. +# +foreach {tn tokenizer} {1 ascii 2 unicode61} { + reset_db + set T "$tokenizer tokenchars ',.:' separators 'xyz'" + execsql "CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = \"$T\")" + do_execsql_test 5.$tn.1 { + INSERT INTO t1 VALUES('abcxdefyghizjkl.mno,pqr:stu/vwx+yz'); + } + foreach {tn2 token res} { + 1 abc 1 2 def 1 3 ghi 1 4 jkl {} + 5 mno {} 6 pqr {} 7 stu {} 8 jkl.mno,pqr:stu 1 + 9 vw 1 + } { + do_execsql_test 5.$tn.2.$tn2 " + SELECT rowid FROM t1 WHERE t1 MATCH '\"$token\"' + " $res + } +} + +#------------------------------------------------------------------------- +# Miscellaneous tests for the ascii tokenizer. +# +# 5.1.*: Test that the ascii tokenizer ignores non-ASCII characters in the +# 'separators' option. But unicode61 does not. +# +# 5.2.*: An option without an argument is an error. +# + +do_test 5.1.1 { + execsql " + CREATE VIRTUAL TABLE a1 USING fts5(x, tokenize=`ascii separators '\u1234'`); + INSERT INTO a1 VALUES('abc\u1234def'); + " + execsql { SELECT rowid FROM a1 WHERE a1 MATCH 'def' } +} {} + +do_test 5.1.2 { + execsql " + CREATE VIRTUAL TABLE a2 USING fts5( + x, tokenize=`unicode61 separators '\u1234'`); + INSERT INTO a2 VALUES('abc\u1234def'); + " + execsql { SELECT rowid FROM a2 WHERE a2 MATCH 'def' } +} {1} + +do_catchsql_test 5.2 { + CREATE VIRTUAL TABLE a3 USING fts5(x, y, tokenize = 'ascii tokenchars'); +} {1 {error in tokenizer constructor}} +do_catchsql_test 5.3 { + CREATE VIRTUAL TABLE a3 USING fts5(x, y, tokenize = 'ascii opt arg'); +} {1 {error in tokenizer constructor}} + +#------------------------------------------------------------------------- +# Test that the ASCII and unicode61 tokenizers both handle SQLITE_DONE +# correctly. +# + +proc test_token_cb {varname token iStart iEnd} { + upvar $varname var + lappend var $token + if {[llength $var]==3} { return "SQLITE_DONE" } + return "SQLITE_OK" +} + +proc tokenize {cmd} { + set res [list] + $cmd xTokenize [$cmd xColumnText 0] [list test_token_cb res] + set res +} +sqlite3_fts5_create_function db tokenize tokenize + +do_execsql_test 6.0 { + CREATE VIRTUAL TABLE x1 USING fts5(a, tokenize=ascii); + INSERT INTO x1 VALUES('q w e r t y'); + INSERT INTO x1 VALUES('y t r e w q'); + SELECT tokenize(x1) FROM x1 WHERE x1 MATCH 'e AND r'; +} { + {q w e} {y t r} +} + +do_execsql_test 6.1 { + CREATE VIRTUAL TABLE x2 USING fts5(a, tokenize=unicode61); + INSERT INTO x2 VALUES('q w e r t y'); + INSERT INTO x2 VALUES('y t r e w q'); + SELECT tokenize(x2) FROM x2 WHERE x2 MATCH 'e AND r'; +} { + {q w e} {y t r} +} + + +#------------------------------------------------------------------------- +# Miscellaneous tests for the unicode tokenizer. +# +do_catchsql_test 6.1 { + CREATE VIRTUAL TABLE a3 USING fts5(x, y, tokenize = 'unicode61 tokenchars'); +} {1 {error in tokenizer constructor}} +do_catchsql_test 6.2 { + CREATE VIRTUAL TABLE a3 USING fts5(x, y, tokenize = 'unicode61 a b'); +} {1 {error in tokenizer constructor}} +do_catchsql_test 6.3 { + CREATE VIRTUAL TABLE a3 USING fts5( + x, y, tokenize = 'unicode61 remove_diacritics 2' + ); +} {1 {error in tokenizer constructor}} +do_catchsql_test 6.4 { + CREATE VIRTUAL TABLE a3 USING fts5( + x, y, tokenize = 'unicode61 remove_diacritics 10' + ); +} {1 {error in tokenizer constructor}} + +#------------------------------------------------------------------------- +# Porter tokenizer with very large tokens. +# +set a [string repeat a 100] +set b [string repeat b 500] +set c [string repeat c 1000] +do_execsql_test 7.0 { + CREATE VIRTUAL TABLE e5 USING fts5(x, tokenize=porter); + INSERT INTO e5 VALUES($a || ' ' || $b); + INSERT INTO e5 VALUES($b || ' ' || $c); + INSERT INTO e5 VALUES($c || ' ' || $a); +} + +do_execsql_test 7.1 {SELECT rowid FROM e5 WHERE e5 MATCH $a} { 1 3 } +do_execsql_test 7.2 {SELECT rowid FROM e5 WHERE e5 MATCH $b} { 1 2 } +do_execsql_test 7.3 {SELECT rowid FROM e5 WHERE e5 MATCH $c} { 2 3 } + +#------------------------------------------------------------------------- +# Test the 'separators' option with the unicode61 tokenizer. +# +do_execsql_test 8.1 { + BEGIN; + CREATE VIRTUAL TABLE e6 USING fts5(x, + tokenize="unicode61 separators ABCDEFGHIJKLMNOPQRSTUVWXYZ" + ); + INSERT INTO e6 VALUES('theAquickBbrownCfoxDjumpedWoverXtheYlazyZdog'); + CREATE VIRTUAL TABLE e7 USING fts5vocab(e6, 'row'); + SELECT term FROM e7; + ROLLBACK; +} { + brown dog fox jumped lazy over quick the +} + +do_execsql_test 8.2 [subst { + BEGIN; + CREATE VIRTUAL TABLE e6 USING fts5(x, + tokenize="unicode61 separators '\u0E01\u0E02\u0E03\u0E04\u0E05\u0E06\u0E07'" + ); + INSERT INTO e6 VALUES('the\u0E01quick\u0E01brown\u0E01fox\u0E01' + || 'jumped\u0E01over\u0E01the\u0E01lazy\u0E01dog' + ); + INSERT INTO e6 VALUES('\u0E08\u0E07\u0E09'); + CREATE VIRTUAL TABLE e7 USING fts5vocab(e6, 'row'); + SELECT term FROM e7; + ROLLBACK; +}] [subst { + brown dog fox jumped lazy over quick the \u0E08 \u0E09 +}] + +# Test that the porter tokenizer correctly passes arguments through to +# its parent tokenizer. +do_execsql_test 8.3 { + BEGIN; + CREATE VIRTUAL TABLE e6 USING fts5(x, + tokenize="porter unicode61 separators ABCDEFGHIJKLMNOPQRSTUVWXYZ" + ); + INSERT INTO e6 VALUES('theAquickBbrownCfoxDjumpedWoverXtheYlazyZdog'); + CREATE VIRTUAL TABLE e7 USING fts5vocab(e6, 'row'); + SELECT term FROM e7; + ROLLBACK; +} { + brown dog fox jump lazi over quick the +} + +finish_test + diff --git a/ext/fts5/test/fts5unicode.test b/ext/fts5/test/fts5unicode.test new file mode 100644 index 0000000..46f4c4f --- /dev/null +++ b/ext/fts5/test/fts5unicode.test @@ -0,0 +1,62 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Tests focusing on the fts5 tokenizers +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5unicode + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +proc tokenize_test {tn tokenizer input output} { + uplevel [list do_test $tn [subst -nocommands { + set ret {} + foreach {z s e} [sqlite3_fts5_tokenize db {$tokenizer} {$input}] { + lappend ret [set z] + } + set ret + }] [list {*}$output]] +} + +foreach {tn t} {1 ascii 2 unicode61} { + tokenize_test 1.$tn.0 $t {A B C D} {a b c d} + tokenize_test 1.$tn.1 $t {May you share freely,} {may you share freely} + tokenize_test 1.$tn.2 $t {..May...you.shAre.freely} {may you share freely} + tokenize_test 1.$tn.3 $t {} {} +} + +#------------------------------------------------------------------------- +# Check that "unicode61" really is the default tokenizer. +# + +do_execsql_test 2.0 " + CREATE VIRTUAL TABLE t1 USING fts5(x); + CREATE VIRTUAL TABLE t2 USING fts5(x, tokenize = unicode61); + CREATE VIRTUAL TABLE t3 USING fts5(x, tokenize = ascii); + INSERT INTO t1 VALUES('\xC0\xC8\xCC'); + INSERT INTO t2 VALUES('\xC0\xC8\xCC'); + INSERT INTO t3 VALUES('\xC0\xC8\xCC'); +" +breakpoint +do_execsql_test 2.1 " + SELECT 't1' FROM t1 WHERE t1 MATCH '\xE0\xE8\xEC'; + SELECT 't2' FROM t2 WHERE t2 MATCH '\xE0\xE8\xEC'; + SELECT 't3' FROM t3 WHERE t3 MATCH '\xE0\xE8\xEC'; +" {t1 t2} + + +finish_test + diff --git a/ext/fts5/test/fts5unicode2.test b/ext/fts5/test/fts5unicode2.test new file mode 100644 index 0000000..d3ff512 --- /dev/null +++ b/ext/fts5/test/fts5unicode2.test @@ -0,0 +1,589 @@ +# 2012 May 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. +# +#************************************************************************* +# +# The tests in this file focus on testing the "unicode" FTS tokenizer. +# +# This is a modified copy of FTS4 test file "fts4_unicode.test". +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5unicode2 + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +proc do_unicode_token_test {tn input res} { + uplevel [list do_test $tn [list \ + sqlite3_fts5_tokenize -subst db "unicode61 remove_diacritics 0" $input + ] [list {*}$res]] +} + +proc do_unicode_token_test2 {tn input res} { + uplevel [list do_test $tn [list \ + sqlite3_fts5_tokenize -subst db "unicode61" $input + ] [list {*}$res]] +} + +proc do_unicode_token_test3 {tn args} { + set tokenizer [concat unicode61 {*}[lrange $args 0 end-2]] + set input [lindex $args end-1] + set res [lindex $args end] + uplevel [list do_test $tn [list \ + sqlite3_fts5_tokenize -subst db $tokenizer $input + ] [list {*}$res]] +} + +do_unicode_token_test 1.0 {a B c D} {a a b B c c d D} + +do_unicode_token_test 1.1 "\uC4 \uD6 \uDC" \ + "\uE4 \uC4 \uF6 \uD6 \uFC \uDC" + +do_unicode_token_test 1.2 "x\uC4x x\uD6x x\uDCx" \ + "x\uE4x x\uC4x x\uF6x x\uD6x x\uFCx x\uDCx" + +# 0x00DF is a small "sharp s". 0x1E9E is a capital sharp s. +do_unicode_token_test 1.3 "\uDF" "\uDF \uDF" +do_unicode_token_test 1.4 "\u1E9E" "\uDF \u1E9E" + +do_unicode_token_test 1.5 "The quick brown fox" { + the The quick quick brown brown fox fox +} +do_unicode_token_test 1.6 "The\u00bfquick\u224ebrown\u2263fox" { + the The quick quick brown brown fox fox +} + +do_unicode_token_test2 1.7 {a B c D} {a a b B c c d D} +do_unicode_token_test2 1.8 "\uC4 \uD6 \uDC" "a \uC4 o \uD6 u \uDC" + +do_unicode_token_test2 1.9 "x\uC4x x\uD6x x\uDCx" \ + "xax x\uC4x xox x\uD6x xux x\uDCx" + +# Check that diacritics are removed if remove_diacritics=1 is specified. +# And that they do not break tokens. +do_unicode_token_test2 1.10 "xx\u0301xx" "xxxx xx\u301xx" + +# Title-case mappings work +do_unicode_token_test 1.11 "\u01c5" "\u01c6 \u01c5" + +do_unicode_token_test 1.12 "\u00C1abc\u00C2 \u00D1def\u00C3" \ + "\u00E1abc\u00E2 \u00C1abc\u00C2 \u00F1def\u00E3 \u00D1def\u00C3" + +do_unicode_token_test 1.13 "\u00A2abc\u00A3 \u00A4def\u00A5" \ + "abc abc def def" + +#------------------------------------------------------------------------- +# +set docs [list { + Enhance the INSERT syntax to allow multiple rows to be inserted via the + VALUES clause. +} { + Enhance the CREATE VIRTUAL TABLE command to support the IF NOT EXISTS clause. +} { + Added the sqlite3_stricmp() interface as a counterpart to sqlite3_strnicmp(). +} { + Added the sqlite3_db_readonly() interface. +} { + Added the SQLITE_FCNTL_PRAGMA file control, giving VFS implementations the + ability to add new PRAGMA statements or to override built-in PRAGMAs. +} { + Queries of the form: "SELECT max(x), y FROM table" returns the value of y on + the same row that contains the maximum x value. +} { + Added support for the FTS4 languageid option. +} { + Documented support for the FTS4 content option. This feature has actually + been in the code since version 3.7.9 but is only now considered to be + officially supported. +} { + Pending statements no longer block ROLLBACK. Instead, the pending statement + will return SQLITE_ABORT upon next access after the ROLLBACK. +} { + Improvements to the handling of CSV inputs in the command-line shell +} { + Fix a bug introduced in version 3.7.10 that might cause a LEFT JOIN to be + incorrectly converted into an INNER JOIN if the WHERE clause indexable terms + connected by OR. +}] + +set map(a) [list "\u00C4" "\u00E4"] ; # LATIN LETTER A WITH DIAERESIS +set map(e) [list "\u00CB" "\u00EB"] ; # LATIN LETTER E WITH DIAERESIS +set map(i) [list "\u00CF" "\u00EF"] ; # LATIN LETTER I WITH DIAERESIS +set map(o) [list "\u00D6" "\u00F6"] ; # LATIN LETTER O WITH DIAERESIS +set map(u) [list "\u00DC" "\u00FC"] ; # LATIN LETTER U WITH DIAERESIS +set map(y) [list "\u0178" "\u00FF"] ; # LATIN LETTER Y WITH DIAERESIS +set map(h) [list "\u1E26" "\u1E27"] ; # LATIN LETTER H WITH DIAERESIS +set map(w) [list "\u1E84" "\u1E85"] ; # LATIN LETTER W WITH DIAERESIS +set map(x) [list "\u1E8C" "\u1E8D"] ; # LATIN LETTER X WITH DIAERESIS +foreach k [array names map] { + lappend mappings [string toupper $k] [lindex $map($k) 0] + lappend mappings $k [lindex $map($k) 1] +} +proc mapdoc {doc} { + set doc [regsub -all {[[:space:]]+} $doc " "] + string map $::mappings [string trim $doc] +} + +do_test 2.0 { + execsql { CREATE VIRTUAL TABLE t2 USING fts5(tokenize=unicode61, x); } + foreach doc $docs { + set d [mapdoc $doc] + execsql { INSERT INTO t2 VALUES($d) } + } +} {} + +do_test 2.1 { + set q [mapdoc "row"] + execsql { SELECT * FROM t2 WHERE t2 MATCH $q } +} [list [mapdoc { + Queries of the form: "SELECT max(x), y FROM table" returns the value of y on + the same row that contains the maximum x value. +}]] + +foreach {tn query snippet} { + 2 "row" { + ...returns the value of y on the same [row] that contains + the maximum x value. + } + 3 "ROW" { + ...returns the value of y on the same [row] that contains + the maximum x value. + } + 4 "rollback" { + ...[ROLLBACK]. Instead, the pending statement + will return SQLITE_ABORT upon next access after the [ROLLBACK]. + } + 5 "rOllback" { + ...[ROLLBACK]. Instead, the pending statement + will return SQLITE_ABORT upon next access after the [ROLLBACK]. + } + 6 "lang*" { + Added support for the FTS4 [languageid] option. + } +} { + do_test 2.$tn { + set q [mapdoc $query] + execsql { + SELECT snippet(t2, -1, '[', ']', '...', 15) FROM t2 WHERE t2 MATCH $q + } + } [list [mapdoc $snippet]] +} + +#------------------------------------------------------------------------- +# Make sure the unicode61 tokenizer does not crash if it is passed a +# NULL pointer. +reset_db +do_execsql_test 3.1 { + CREATE VIRTUAL TABLE t1 USING fts5(tokenize=unicode61, x, y); + INSERT INTO t1 VALUES(NULL, 'a b c'); +} + +do_execsql_test 3.2 { + SELECT snippet(t1, -1, '[', ']', '...', 15) FROM t1 WHERE t1 MATCH 'b' +} {{a [b] c}} + +do_execsql_test 3.3 { + BEGIN; + DELETE FROM t1; + INSERT INTO t1 VALUES('b b b b b b b b b b b', 'b b b b b b b b b b b b b'); + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 VALUES('a b c', NULL); + INSERT INTO t1 VALUES('a x c', NULL); + COMMIT; +} + +do_execsql_test 3.4 { + SELECT * FROM t1 WHERE t1 MATCH 'a b'; +} {{a b c} {}} + +#------------------------------------------------------------------------- +# +reset_db + +do_test 4.1 { + set a "abc\uFFFEdef" + set b "abc\uD800def" + set c "\uFFFEdef" + set d "\uD800def" + execsql { + CREATE VIRTUAL TABLE t1 USING fts5(tokenize=unicode61, x); + INSERT INTO t1 VALUES($a); + INSERT INTO t1 VALUES($b); + INSERT INTO t1 VALUES($c); + INSERT INTO t1 VALUES($d); + } + + execsql "CREATE VIRTUAL TABLE t8 USING fts5( + a, b, tokenize=\"unicode61 separators '\uFFFE\uD800\u00BF'\" + )" +} {} + +do_test 4.2 { + set a [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0x62}] + set b [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0xBF 0x62}] + set c [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0xBF 0xBF 0x62}] + set d [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0xBF 0xBF 0xBF 0x62}] + execsql { + INSERT INTO t1 VALUES($a); + INSERT INTO t1 VALUES($b); + INSERT INTO t1 VALUES($c); + INSERT INTO t1 VALUES($d); + } +} {} + +do_test 4.3 { + set a [binary format c* {0xF7 0xBF 0xBF 0xBF}] + set b [binary format c* {0xF7 0xBF 0xBF 0xBF 0xBF}] + set c [binary format c* {0xF7 0xBF 0xBF 0xBF 0xBF 0xBF}] + set d [binary format c* {0xF7 0xBF 0xBF 0xBF 0xBF 0xBF 0xBF}] + execsql { + INSERT INTO t1 VALUES($a); + INSERT INTO t1 VALUES($b); + INSERT INTO t1 VALUES($c); + INSERT INTO t1 VALUES($d); + } +} {} + +do_test 4.4 { + sqlite3_exec_hex db { + CREATE VIRTUAL TABLE t9 USING fts5(a, b, + tokenize="unicode61 separators '%C09004'" + ); + INSERT INTO t9(a) VALUES('abc%88def %89ghi%90'); + } +} {0 {}} + + +#------------------------------------------------------------------------- + +breakpoint +do_unicode_token_test3 5.1 {tokenchars {}} { + sqlite3_reset sqlite3_column_int +} { + sqlite3 sqlite3 + reset reset + sqlite3 sqlite3 + column column + int int +} + +do_unicode_token_test3 5.2 {tokenchars _} { + sqlite3_reset sqlite3_column_int +} { + sqlite3_reset sqlite3_reset + sqlite3_column_int sqlite3_column_int +} + +do_unicode_token_test3 5.3 {separators xyz} { + Laotianxhorseyrunszfast +} { + laotian Laotian + horse horse + runs runs + fast fast +} + +do_unicode_token_test3 5.4 {tokenchars xyz} { + Laotianxhorseyrunszfast +} { + laotianxhorseyrunszfast Laotianxhorseyrunszfast +} + +do_unicode_token_test3 5.5 {tokenchars _} {separators zyx} { + sqlite3_resetxsqlite3_column_intyhonda_phantom +} { + sqlite3_reset sqlite3_reset + sqlite3_column_int sqlite3_column_int + honda_phantom honda_phantom +} + +do_unicode_token_test3 5.6 "separators \u05D1" "abc\u05D1def" { + abc abc def def +} + +do_unicode_token_test3 5.7 \ + "tokenchars \u2444\u2445" \ + "separators \u05D0\u05D1\u05D2" \ + "\u2444fre\u2445sh\u05D0water\u05D2fish.\u2445timer" \ + [list \ + \u2444fre\u2445sh \u2444fre\u2445sh \ + water water \ + fish fish \ + \u2445timer \u2445timer \ + ] + +# Check that it is not possible to add a standalone diacritic codepoint +# to either separators or tokenchars. +do_unicode_token_test3 5.8 "separators \u0301" \ + "hello\u0301world \u0301helloworld" \ + "helloworld hello\u0301world helloworld helloworld" + +do_unicode_token_test3 5.9 "tokenchars \u0301" \ + "hello\u0301world \u0301helloworld" \ + "helloworld hello\u0301world helloworld helloworld" + +do_unicode_token_test3 5.10 "separators \u0301" \ + "remove_diacritics 0" \ + "hello\u0301world \u0301helloworld" \ + "hello\u0301world hello\u0301world helloworld helloworld" + +do_unicode_token_test3 5.11 "tokenchars \u0301" \ + "remove_diacritics 0" \ + "hello\u0301world \u0301helloworld" \ + "hello\u0301world hello\u0301world helloworld helloworld" + +#------------------------------------------------------------------------- + +proc do_tokenize {tokenizer txt} { + set res [list] + foreach {b c} [sqlite3_fts5_tokenize -subst db $tokenizer $txt] { + lappend res $b + } + set res +} + +# Argument $lCodepoint must be a list of codepoints (integers) that +# correspond to whitespace characters. This command creates a string +# $W from the codepoints, then tokenizes "${W}hello{$W}world${W}" +# using tokenizer $tokenizer. The test passes if the tokenizer successfully +# extracts the two 5 character tokens. +# +proc do_isspace_test {tn tokenizer lCp} { + set whitespace [format [string repeat %c [llength $lCp]] {*}$lCp] + set txt "${whitespace}hello${whitespace}world${whitespace}" + uplevel [list do_test $tn [list do_tokenize $tokenizer $txt] {hello world}] +} + +set tokenizers [list unicode61] +#ifcapable icu { lappend tokenizers icu } + +# Some tests to check that the tokenizers can both identify white-space +# codepoints. All codepoints tested below are of type "Zs" in the +# UnicodeData.txt file. +foreach T $tokenizers { + do_isspace_test 6.$T.1 $T 32 + do_isspace_test 6.$T.2 $T 160 + do_isspace_test 6.$T.3 $T 5760 + do_isspace_test 6.$T.4 $T 6158 + do_isspace_test 6.$T.5 $T 8192 + do_isspace_test 6.$T.6 $T 8193 + do_isspace_test 6.$T.7 $T 8194 + do_isspace_test 6.$T.8 $T 8195 + do_isspace_test 6.$T.9 $T 8196 + do_isspace_test 6.$T.10 $T 8197 + do_isspace_test 6.$T.11 $T 8198 + do_isspace_test 6.$T.12 $T 8199 + do_isspace_test 6.$T.13 $T 8200 + do_isspace_test 6.$T.14 $T 8201 + do_isspace_test 6.$T.15 $T 8202 + do_isspace_test 6.$T.16 $T 8239 + do_isspace_test 6.$T.17 $T 8287 + do_isspace_test 6.$T.18 $T 12288 + + do_isspace_test 6.$T.19 $T {32 160 5760 6158} + do_isspace_test 6.$T.20 $T {8192 8193 8194 8195} + do_isspace_test 6.$T.21 $T {8196 8197 8198 8199} + do_isspace_test 6.$T.22 $T {8200 8201 8202 8239} + do_isspace_test 6.$T.23 $T {8287 12288} +} + + +#------------------------------------------------------------------------- +# Test that the private use ranges are treated as alphanumeric. +# +foreach {tn1 c} { + 1 \ue000 2 \ue001 3 \uf000 4 \uf8fe 5 \uf8ff +} { + foreach {tn2 config res} { + 1 "" "hello*world hello*world" + 2 "separators *" "hello hello world world" + } { + set config [string map [list * $c] $config] + set input [string map [list * $c] "hello*world"] + set output [string map [list * $c] $res] + do_unicode_token_test3 7.$tn1.$tn2 {*}$config $input $output + } +} + +#------------------------------------------------------------------------- +# Cursory test of remove_diacritics=0. +# +# 00C4;LATIN CAPITAL LETTER A WITH DIAERESIS +# 00D6;LATIN CAPITAL LETTER O WITH DIAERESIS +# 00E4;LATIN SMALL LETTER A WITH DIAERESIS +# 00F6;LATIN SMALL LETTER O WITH DIAERESIS +# +do_execsql_test 8.1.1 " + CREATE VIRTUAL TABLE t3 USING fts5( + content, tokenize='unicode61 remove_diacritics 1' + ); + INSERT INTO t3 VALUES('o'); + INSERT INTO t3 VALUES('a'); + INSERT INTO t3 VALUES('O'); + INSERT INTO t3 VALUES('A'); + INSERT INTO t3 VALUES('\xD6'); + INSERT INTO t3 VALUES('\xC4'); + INSERT INTO t3 VALUES('\xF6'); + INSERT INTO t3 VALUES('\xE4'); +" +do_execsql_test 8.1.2 { + SELECT rowid FROM t3 WHERE t3 MATCH 'o' ORDER BY rowid ASC; +} {1 3 5 7} +do_execsql_test 8.1.3 { + SELECT rowid FROM t3 WHERE t3 MATCH 'a' ORDER BY rowid ASC; +} {2 4 6 8} +do_execsql_test 8.2.1 { + CREATE VIRTUAL TABLE t4 USING fts5( + content, tokenize='unicode61 remove_diacritics 0' + ); + INSERT INTO t4 SELECT * FROM t3 ORDER BY rowid ASC; +} +do_execsql_test 8.2.2 { + SELECT rowid FROM t4 WHERE t4 MATCH 'o' ORDER BY rowid ASC; +} {1 3} +do_execsql_test 8.2.3 { + SELECT rowid FROM t4 WHERE t4 MATCH 'a' ORDER BY rowid ASC; +} {2 4} + +#------------------------------------------------------------------------- +# +if 0 { +foreach {tn sql} { + 1 { + CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 [tokenchars= .]); + CREATE VIRTUAL TABLE t6 USING fts4( + tokenize=unicode61 [tokenchars=="] "tokenchars=[]"); + CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 [separators=x\xC4]); + } + 2 { + CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 "tokenchars= ."); + CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 "tokenchars=[=""]"); + CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 "separators=x\xC4"); + } + 3 { + CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 'tokenchars= .'); + CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 'tokenchars=="[]'); + CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 'separators=x\xC4'); + } + 4 { + CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 `tokenchars= .`); + CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 `tokenchars=[="]`); + CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 `separators=x\xC4`); + } +} { + do_execsql_test 9.$tn.0 { + DROP TABLE IF EXISTS t5; + DROP TABLE IF EXISTS t5aux; + DROP TABLE IF EXISTS t6; + DROP TABLE IF EXISTS t6aux; + DROP TABLE IF EXISTS t7; + DROP TABLE IF EXISTS t7aux; + } + do_execsql_test 9.$tn.1 $sql + + do_execsql_test 9.$tn.2 { + CREATE VIRTUAL TABLE t5aux USING fts4aux(t5); + INSERT INTO t5 VALUES('one two three/four.five.six'); + SELECT * FROM t5aux; + } { + four.five.six * 1 1 four.five.six 0 1 1 + {one two three} * 1 1 {one two three} 0 1 1 + } + + do_execsql_test 9.$tn.3 { + CREATE VIRTUAL TABLE t6aux USING fts4aux(t6); + INSERT INTO t6 VALUES('alpha=beta"gamma/delta[epsilon]zeta'); + SELECT * FROM t6aux; + } { + {alpha=beta"gamma} * 1 1 {alpha=beta"gamma} 0 1 1 + {delta[epsilon]zeta} * 1 1 {delta[epsilon]zeta} 0 1 1 + } + + do_execsql_test 9.$tn.4 { + CREATE VIRTUAL TABLE t7aux USING fts4aux(t7); + INSERT INTO t7 VALUES('alephxbeth\xC4gimel'); + SELECT * FROM t7aux; + } { + aleph * 1 1 aleph 0 1 1 + beth * 1 1 beth 0 1 1 + gimel * 1 1 gimel 0 1 1 + } +} + +# Check that multiple options are handled correctly. +# +do_execsql_test 10.1 { + DROP TABLE IF EXISTS t1; + CREATE VIRTUAL TABLE t1 USING fts4(tokenize=unicode61 + "tokenchars=xyz" "tokenchars=.=" "separators=.=" "separators=xy" + "separators=a" "separators=a" "tokenchars=a" "tokenchars=a" + ); + + INSERT INTO t1 VALUES('oneatwoxthreeyfour'); + INSERT INTO t1 VALUES('a.single=word'); + CREATE VIRTUAL TABLE t1aux USING fts4aux(t1); + SELECT * FROM t1aux; +} { + .single=word * 1 1 .single=word 0 1 1 + four * 1 1 four 0 1 1 + one * 1 1 one 0 1 1 + three * 1 1 three 0 1 1 + two * 1 1 two 0 1 1 +} + +# Test that case folding happens after tokenization, not before. +# +do_execsql_test 10.2 { + DROP TABLE IF EXISTS t2; + CREATE VIRTUAL TABLE t2 USING fts4(tokenize=unicode61 "separators=aB"); + INSERT INTO t2 VALUES('oneatwoBthree'); + INSERT INTO t2 VALUES('onebtwoAthree'); + CREATE VIRTUAL TABLE t2aux USING fts4aux(t2); + SELECT * FROM t2aux; +} { + one * 1 1 one 0 1 1 + onebtwoathree * 1 1 onebtwoathree 0 1 1 + three * 1 1 three 0 1 1 + two * 1 1 two 0 1 1 +} + +# Test that the tokenchars and separators options work with the +# fts3tokenize table. +# +do_execsql_test 11.1 { + CREATE VIRTUAL TABLE ft1 USING fts3tokenize( + "unicode61", "tokenchars=@.", "separators=1234567890" + ); + SELECT token FROM ft1 WHERE input = 'berlin@street123sydney.road'; +} { + berlin@street sydney.road +} + +} + +finish_test diff --git a/ext/fts5/test/fts5unicode3.test b/ext/fts5/test/fts5unicode3.test new file mode 100644 index 0000000..876ad27 --- /dev/null +++ b/ext/fts5/test/fts5unicode3.test @@ -0,0 +1,129 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Tests focusing on the fts5 tokenizers +# + +source [file join [file dirname [info script]] fts5_common.tcl] + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +proc fts3_unicode_path {file} { + file join [file dirname [info script]] .. .. fts3 unicode $file +} + +source [fts3_unicode_path parseunicode.tcl] +set testprefix fts5unicode3 + +set CF [fts3_unicode_path CaseFolding.txt] +set UD [fts3_unicode_path UnicodeData.txt] + +tl_load_casefolding_txt $CF +foreach x [an_load_unicodedata_text $UD] { + set aNotAlnum($x) 1 +} + +foreach {y} [rd_load_unicodedata_text $UD] { + foreach {code ascii} $y {} + if {$ascii==""} { + set int 0 + } else { + binary scan $ascii c int + } + set aDiacritic($code) $int +} + +proc tcl_fold {i {bRemoveDiacritic 0}} { + global tl_lookup_table + global aDiacritic + + if {[info exists tl_lookup_table($i)]} { + set i $tl_lookup_table($i) + } + if {$bRemoveDiacritic && [info exists aDiacritic($i)]} { + set i $aDiacritic($i) + } + expr $i +} +db func tcl_fold tcl_fold + +proc tcl_isalnum {i} { + global aNotAlnum + expr {![info exists aNotAlnum($i)]} +} +db func tcl_isalnum tcl_isalnum + + +do_catchsql_test 1.0.1 { + SELECT fts5_isalnum(1, 2, 3); +} {1 {wrong number of arguments to function fts5_isalnum}} +do_catchsql_test 1.0.2 { + SELECT fts5_fold(); +} {1 {wrong number of arguments to function fts5_fold}} +do_catchsql_test 1.0.3 { + SELECT fts5_fold(1,2,3); +} {1 {wrong number of arguments to function fts5_fold}} + +do_execsql_test 1.1 { + WITH ii(i) AS ( + SELECT -1 + UNION ALL + SELECT i+1 FROM ii WHERE i<100000 + ) + SELECT count(*), min(i) FROM ii WHERE fts5_fold(i)!=CAST(tcl_fold(i) AS int); +} {0 {}} + +do_execsql_test 1.2 { + WITH ii(i) AS ( + SELECT -1 + UNION ALL + SELECT i+1 FROM ii WHERE i<100000 + ) + SELECT count(*), min(i) FROM ii + WHERE fts5_fold(i,1)!=CAST(tcl_fold(i,1) AS int); +} {0 {}} + +do_execsql_test 1.3 { + WITH ii(i) AS ( + SELECT -1 + UNION ALL + SELECT i+1 FROM ii WHERE i<100000 + ) + SELECT count(*), min(i) FROM ii + WHERE fts5_isalnum(i)!=CAST(tcl_isalnum(i) AS int); +} {0 {}} + +do_test 1.4 { + set str {CREATE VIRTUAL TABLE f3 USING fts5(a, tokenize=} + append str {"unicode61 separators '} + for {set i 700} {$i<900} {incr i} { + append str [format %c $i] + } + append str {'");} + execsql $str +} {} +do_test 1.5 { + set str {CREATE VIRTUAL TABLE f5 USING fts5(a, tokenize=} + append str {"unicode61 tokenchars '} + for {set i 700} {$i<900} {incr i} { + append str [format %c $i] + } + append str {'");} + execsql $str +} {} + + +finish_test + diff --git a/ext/fts5/test/fts5unindexed.test b/ext/fts5/test/fts5unindexed.test new file mode 100644 index 0000000..16d43f8 --- /dev/null +++ b/ext/fts5/test/fts5unindexed.test @@ -0,0 +1,79 @@ +# 2015 Apr 24 +# +# 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. +# +#*********************************************************************** +# +# The tests in this file focus on "unindexed" columns. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5unindexed + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + + +do_execsql_test 1.1 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b UNINDEXED); + INSERT INTO t1 VALUES('a b c', 'd e f'); + INSERT INTO t1 VALUES('g h i', 'j k l'); +} {} + +do_execsql_test 1.2 { SELECT rowid FROM t1 WHERE t1 MATCH 'b' } {1} +do_execsql_test 1.3 { SELECT rowid FROM t1 WHERE t1 MATCH 'e' } {} + +do_execsql_test 1.4 { INSERT INTO t1(t1) VALUES('integrity-check') } {} +do_execsql_test 1.5 { INSERT INTO t1(t1) VALUES('rebuild') } {} +do_execsql_test 1.6 { INSERT INTO t1(t1) VALUES('integrity-check') } {} + +do_execsql_test 1.7 { SELECT rowid FROM t1 WHERE t1 MATCH 'b' } {1} +do_execsql_test 1.8 { SELECT rowid FROM t1 WHERE t1 MATCH 'e' } {} + +do_execsql_test 1.9 { DELETE FROM t1 WHERE t1 MATCH 'b' } {} + +do_execsql_test 1.10 { INSERT INTO t1(t1) VALUES('integrity-check') } {} +do_execsql_test 1.11 { INSERT INTO t1(t1) VALUES('rebuild') } {} +do_execsql_test 1.12 { INSERT INTO t1(t1) VALUES('integrity-check') } {} + +do_execsql_test 1.13 { SELECT rowid FROM t1 WHERE t1 MATCH 'i' } {2} +do_execsql_test 1.14 { SELECT rowid FROM t1 WHERE t1 MATCH 'l' } {} + +do_execsql_test 2.1 { + CREATE VIRTUAL TABLE t2 USING fts5(a UNINDEXED, b UNINDEXED); + INSERT INTO t1 VALUES('a b c', 'd e f'); + INSERT INTO t1 VALUES('g h i', 'j k l'); + SELECT rowid FROM t2_data; +} {1 10} +do_execsql_test 2.2 { + INSERT INTO t2(t2) VALUES('rebuild'); + INSERT INTO t2(t2) VALUES('integrity-check'); + SELECT rowid FROM t2_data; +} {1 10} + +do_execsql_test 3.1 { + CREATE TABLE x4(i INTEGER PRIMARY KEY, a, b, c); + CREATE VIRTUAL TABLE t4 USING fts5(a, b UNINDEXED, c, content=x4); + INSERT INTO x4 VALUES(10, 'a b c', 'd e f', 'g h i'); + INSERT INTO x4 VALUES(20, 'j k l', 'm n o', 'p q r'); + INSERT INTO t4(t4) VALUES('rebuild'); + INSERT INTO t4(t4) VALUES('integrity-check'); +} {} + +do_execsql_test 3.2 { + INSERT INTO t4(t4, rowid, a, b, c) VALUES('delete', 20, 'j k l', '', 'p q r'); + DELETE FROM x4 WHERE rowid=20; + INSERT INTO t4(t4) VALUES('integrity-check'); +} {} + + +finish_test + diff --git a/ext/fts5/test/fts5update.test b/ext/fts5/test/fts5update.test new file mode 100644 index 0000000..399c7ff --- /dev/null +++ b/ext/fts5/test/fts5update.test @@ -0,0 +1,121 @@ +# 2016 Jan 16 +# +# 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 FTS5 module. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5update + +# If SQLITE_ENABLE_FTS5 is not defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +set docs { + "eight zero iv eight 7" "ix one 8 one three ii one" + "1 9 9 three viii" "5 zero ii 6 nine ix 3" + "3 zero 5 2 seven nine" "two eight viii eight 1" + "4 six two 5 9 vii" "viii ii four 8 i i iv" + "vii 0 iv seven 7 viii" "five 1 nine vi seven" + "1 zero zero iii 1" "one one six 6 nine seven" + "one v 4 zero 4 iii ii" "2 3 eight six ix" + "six iv 7 three 5" "ix zero 0 8 ii 7 3" + "four six nine 2 vii 3" "five viii 5 8 0 7" +} + +foreach_detail_mode $::testprefix { + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%); +} {} + +do_test 1.1 { + foreach {a b} $docs { + execsql {INSERT INTO t1 VALUES($a, $b)} + } +} {} + +proc update {iRowid iA iB} { + set a [lindex $::docs $iA] + set b [lindex $::docs $iB] + execsql { UPDATE t1 SET a=$a, b=$b WHERE rowid=$iRowid } +} + +set nDoc [llength $::docs] +foreach n {1 5 10 50 100} { + do_test 1.2.$n { + execsql BEGIN + for {set i 1} {$i <= 1000} {incr i} { + set iRowid [expr {int(rand() * ($nDoc/2)) + 1}] + set iA [expr {int(rand() * $nDoc)}] + set iB [expr {int(rand() * $nDoc)}] + update $iRowid $iA $iB + + if {($i % $n)==0} { + execsql { COMMIT; BEGIN } + } + + if {($i % $n)==100} { + execsql { INSERT INTO t1(t1) VALUES('integrity-check') } + } + } + execsql COMMIT + execsql { INSERT INTO t1(t1) VALUES('integrity-check') } + } {} +} + +do_execsql_test 1.3 { + UPDATE t1 SET a=a AND b=b; + INSERT INTO t1(t1) VALUES('integrity-check'); +} + +do_test 1.4 { + execsql { INSERT INTO t1(t1, rank) VALUES('pgsz', 32) } + for {set i 0} {$i < 50} {incr i} { + execsql { UPDATE t1 SET a=a AND b=b } + execsql { INSERT INTO t1(t1) VALUES('integrity-check') } + } +} {} + +#------------------------------------------------------------------------- +# Lots of deletes/inserts of the same document with the same rowid. +# +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE x2 USING fts5(x, detail=%DETAIL%); + INSERT INTO x2(x2, rank) VALUES('crisismerge', 2); + INSERT INTO x2 VALUES('a b c'); + INSERT INTO x2 VALUES('a b c'); +} +do_test 2.1 { + for {set i 0} {$i < 1000} {incr i} { + execsql { DELETE FROM x2 WHERE rowid = 2 } + execsql { INSERT INTO x2(rowid, x) VALUES(2, 'a b c') } + } +} {} +do_execsql_test 2.1.integrity { + INSERT INTO x2(x2) VALUES('integrity-check'); +} + +do_test 2.2 { + for {set i 0} {$i < 1000} {incr i} { + execsql { UPDATE x2 SET x=x WHERE rowid=2 } + } +} {} +do_execsql_test 2.2.integrity { + INSERT INTO x2(x2) VALUES('integrity-check'); +} + +} +finish_test + + diff --git a/ext/fts5/test/fts5version.test b/ext/fts5/test/fts5version.test new file mode 100644 index 0000000..7e4d74d --- /dev/null +++ b/ext/fts5/test/fts5version.test @@ -0,0 +1,64 @@ +# 2015 Apr 24 +# +# 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. +# +#*********************************************************************** +# +# The tests in this file focus on testing that unrecognized file-format +# versions are detected and reported. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5version + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + + +do_execsql_test 1.1 { + CREATE VIRTUAL TABLE t1 USING fts5(one); + INSERT INTO t1 VALUES('a b c d'); +} {} + +do_execsql_test 1.2 { + SELECT * FROM t1_config WHERE k='version' +} {version 4} + +do_execsql_test 1.3 { + SELECT rowid FROM t1 WHERE t1 MATCH 'a'; +} {1} + +do_execsql_test 1.4 { + UPDATE t1_config set v=5 WHERE k='version'; +} + +do_test 1.5 { + db close + sqlite3 db test.db + catchsql { SELECT * FROM t1 WHERE t1 MATCH 'a' } +} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}} + +do_test 1.6 { + db close + sqlite3 db test.db + catchsql { INSERT INTO t1 VALUES('x y z') } +} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}} + +do_test 1.7 { + execsql { DELETE FROM t1_config WHERE k='version' } + db close + sqlite3 db test.db + catchsql { SELECT * FROM t1 WHERE t1 MATCH 'a' } +} {1 {invalid fts5 file format (found 0, expected 4) - run 'rebuild'}} + + +finish_test + diff --git a/ext/fts5/test/fts5vocab.test b/ext/fts5/test/fts5vocab.test new file mode 100644 index 0000000..f7278dd --- /dev/null +++ b/ext/fts5/test/fts5vocab.test @@ -0,0 +1,449 @@ +# 2015 Apr 24 +# +# 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. +# +#*********************************************************************** +# +# The tests in this file focus on testing the fts5vocab module. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5vocab + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +foreach_detail_mode $testprefix { + +proc null_list_entries {iFirst nInterval L} { + for {set i $iFirst} {$i < [llength $L]} {incr i $nInterval} { + lset L $i {} + } + return $L +} + +proc star_from_row {L} { + if {[detail_is_full]==0} { + set L [null_list_entries 2 3 $L] + } + return $L +} + +proc star_from_col {L} { + if {[detail_is_col]} { + set L [null_list_entries 3 4 $L] + } + if {[detail_is_none]} { + set L [null_list_entries 1 4 $L] + set L [null_list_entries 3 4 $L] + } + return $L +} + +proc row_to_col {L} { + if {[detail_is_none]==0} { error "this is for detail=none mode" } + set ret [list] + foreach {a b c} $L { + lappend ret $a {} $b {} + } + set ret +} + +if 1 { + +do_execsql_test 1.1.1 { + CREATE VIRTUAL TABLE t1 USING fts5(one, prefix=1, detail=%DETAIL%); + CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, 'row'); + PRAGMA table_info = v1; +} { + 0 term {} 0 {} 0 + 1 doc {} 0 {} 0 + 2 cnt {} 0 {} 0 +} + +do_execsql_test 1.1.2 { + CREATE VIRTUAL TABLE v2 USING fts5vocab(t1, 'col'); + PRAGMA table_info = v2; +} { + 0 term {} 0 {} 0 + 1 col {} 0 {} 0 + 2 doc {} 0 {} 0 + 3 cnt {} 0 {} 0 +} + +do_execsql_test 1.2.1 { SELECT * FROM v1 } { } +do_execsql_test 1.2.2 { SELECT * FROM v2 } { } + +do_execsql_test 1.3 { + INSERT INTO t1 VALUES('x y z'); + INSERT INTO t1 VALUES('x x x'); +} + +do_execsql_test 1.4.1 { + SELECT * FROM v1; +} [star_from_row {x 2 4 y 1 1 z 1 1}] + +do_execsql_test 1.4.2 { + SELECT * FROM v2; +} [star_from_col {x one 2 4 y one 1 1 z one 1 1}] + +do_execsql_test 1.5.1 { + BEGIN; + INSERT INTO t1 VALUES('a b c'); + SELECT * FROM v1 WHERE term<'d'; +} [star_from_row {a 1 1 b 1 1 c 1 1}] + +do_execsql_test 1.5.2 { + SELECT * FROM v2 WHERE term<'d'; + COMMIT; +} [star_from_col {a one 1 1 b one 1 1 c one 1 1}] + +do_execsql_test 1.6 { + DELETE FROM t1 WHERE one = 'a b c'; + SELECT * FROM v1; +} [star_from_row {x 2 4 y 1 1 z 1 1}] + +#------------------------------------------------------------------------- +# +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE tt USING fts5(a, b, detail=%DETAIL%); + INSERT INTO tt VALUES('d g b f d f', 'f c e c d a'); + INSERT INTO tt VALUES('f a e a a b', 'e d c f d d'); + INSERT INTO tt VALUES('b c a a a b', 'f f c c b c'); + INSERT INTO tt VALUES('f d c a c e', 'd g d e g d'); + INSERT INTO tt VALUES('g d e f a g x', 'f f d a a b'); + INSERT INTO tt VALUES('g c f b c g', 'a g f d c b'); + INSERT INTO tt VALUES('c e c f g b', 'f e d b g a'); + INSERT INTO tt VALUES('g d e f d e', 'a c d b a g'); + INSERT INTO tt VALUES('e f a c c b', 'b f e a f d y'); + INSERT INTO tt VALUES('c c a a c f', 'd g a e b g'); +} + +set res_row [star_from_row { + a 10 20 b 9 14 c 9 20 d 9 19 + e 8 13 f 10 20 g 7 14 x 1 1 + y 1 1 +}] +set res_col [star_from_col { + a a 6 11 a b 7 9 + b a 6 7 b b 7 7 + c a 6 12 c b 5 8 + d a 4 6 d b 9 13 + e a 6 7 e b 6 6 + f a 9 10 f b 7 10 + g a 5 7 g b 5 7 + x a 1 1 y b 1 1 +}] +if {[detail_is_none]} { + set res_col [row_to_col $res_row] +} + +foreach {tn tbl resname} { + 1 "fts5vocab(tt, 'col')" res_col + 2 "fts5vocab(tt, 'row')" res_row + 3 "fts5vocab(tt, \"row\")" res_row + 4 "fts5vocab(tt, [row])" res_row + 5 "fts5vocab(tt, `row`)" res_row + + 6 "fts5vocab('tt', 'row')" res_row + 7 "fts5vocab(\"tt\", \"row\")" res_row + 8 "fts5vocab([tt], [row])" res_row + 9 "fts5vocab(`tt`, `row`)" res_row +} { + do_execsql_test 2.$tn " + DROP TABLE IF EXISTS tv; + CREATE VIRTUAL TABLE tv USING $tbl; + SELECT * FROM tv; + " [set $resname] +} + +#------------------------------------------------------------------------- +# Test errors in the CREATE VIRTUAL TABLE statement. +# +foreach {tn sql} { + 1 { CREATE VIRTUAL TABLE aa USING fts5vocab() } + 2 { CREATE VIRTUAL TABLE aa USING fts5vocab(x) } + 3 { CREATE VIRTUAL TABLE aa USING fts5vocab(x,y,z) } + 4 { CREATE VIRTUAL TABLE temp.aa USING fts5vocab(x,y,z,y) } +} { + do_catchsql_test 3.$tn $sql {1 {wrong number of vtable arguments}} +} + +do_catchsql_test 4.0 { + CREATE VIRTUAL TABLE cc USING fts5vocab(tbl, unknown); +} {1 {fts5vocab: unknown table type: 'unknown'}} + +do_catchsql_test 4.1 { + ATTACH 'test.db' AS aux; + CREATE VIRTUAL TABLE aux.cc USING fts5vocab(main, tbl, row); +} {1 {wrong number of vtable arguments}} + +#------------------------------------------------------------------------- +# Test fts5vocab tables created in the temp schema. +# +reset_db +forcedelete test.db2 +do_execsql_test 5.0 { + ATTACH 'test.db2' AS aux; + CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%); + CREATE VIRTUAL TABLE temp.t1 USING fts5(x, detail=%DETAIL%); + CREATE VIRTUAL TABLE aux.t1 USING fts5(x, detail=%DETAIL%); + + INSERT INTO main.t1 VALUES('a b c'); + INSERT INTO main.t1 VALUES('d e f'); + INSERT INTO main.t1 VALUES('a e c'); + + INSERT INTO temp.t1 VALUES('1 2 3'); + INSERT INTO temp.t1 VALUES('4 5 6'); + INSERT INTO temp.t1 VALUES('1 5 3'); + + INSERT INTO aux.t1 VALUES('x y z'); + INSERT INTO aux.t1 VALUES('m n o'); + INSERT INTO aux.t1 VALUES('x n z'); +} + +breakpoint +do_execsql_test 5.1 { + CREATE VIRTUAL TABLE temp.vm USING fts5vocab(main, t1, row); + CREATE VIRTUAL TABLE temp.vt1 USING fts5vocab(t1, row); + CREATE VIRTUAL TABLE temp.vt2 USING fts5vocab(temp, t1, row); + CREATE VIRTUAL TABLE temp.va USING fts5vocab(aux, t1, row); +} + +do_execsql_test 5.2 { SELECT * FROM vm } [star_from_row { + a 2 2 b 1 1 c 2 2 d 1 1 e 2 2 f 1 1 +}] +do_execsql_test 5.3 { SELECT * FROM vt1 } [star_from_row { + 1 2 2 2 1 1 3 2 2 4 1 1 5 2 2 6 1 1 +}] +do_execsql_test 5.4 { SELECT * FROM vt2 } [star_from_row { + 1 2 2 2 1 1 3 2 2 4 1 1 5 2 2 6 1 1 +}] +do_execsql_test 5.5 { SELECT * FROM va } [star_from_row { + m 1 1 n 2 2 o 1 1 x 2 2 y 1 1 z 2 2 +}] + +#------------------------------------------------------------------------- +# +do_execsql_test 6.0 { + CREATE TABLE iii(iii); + CREATE TABLE jjj(x); +} + +do_catchsql_test 6.1 { + CREATE VIRTUAL TABLE vocab1 USING fts5vocab(iii, row); + SELECT * FROM vocab1; +} {1 {no such fts5 table: main.iii}} + +do_catchsql_test 6.2 { + CREATE VIRTUAL TABLE vocab2 USING fts5vocab(jjj, row); + SELECT * FROM vocab2; +} {1 {no such fts5 table: main.jjj}} + +do_catchsql_test 6.2 { + CREATE VIRTUAL TABLE vocab3 USING fts5vocab(lll, row); + SELECT * FROM vocab3; +} {1 {no such fts5 table: main.lll}} + +#------------------------------------------------------------------------- +# Test single term queries on fts5vocab tables (i.e. those with term=? +# constraints in the WHERE clause). +# +do_execsql_test 7.0 { + CREATE VIRTUAL TABLE tx USING fts5(one, two, detail=%DETAIL%); + INSERT INTO tx VALUES('g a ggg g a b eee', 'cc d aa ff g ee'); + INSERT INTO tx VALUES('dd fff i a i jjj', 'f fff hh jj e f'); + INSERT INTO tx VALUES('ggg a f f fff dd aa', 'd ggg f f j gg ddd'); + INSERT INTO tx VALUES('e bb h jjj ii gg', 'e aa e f c fff'); + INSERT INTO tx VALUES('j ff aa a h', 'h a j bbb bb'); + INSERT INTO tx VALUES('cc i ff c d f', 'dd ii fff f c cc d'); + INSERT INTO tx VALUES('jjj g i bb cc eee', 'hhh iii aaa b bbb aaa'); + INSERT INTO tx VALUES('hhh hhh hhh bb fff f', 'fff gg aa ii h a'); + INSERT INTO tx VALUES('b c cc aaa iii ggg f', 'iii ff ee a ff c cc'); + INSERT INTO tx VALUES('hhh b hhh aaa j i i', 'dd ee ee aa bbb iii'); + INSERT INTO tx VALUES('hh dd h b g ff i', 'ccc bb cc ccc f a d'); + INSERT INTO tx VALUES('g d b ggg jj', 'fff jj ff jj g gg ee'); + INSERT INTO tx VALUES('g ee ggg ggg cc bb eee', 'aa j jjj bbb dd eee ff'); + INSERT INTO tx VALUES('c jjj hh ddd dd h', 'e aaa h jjj gg'); + + CREATE VIRTUAL TABLE txr USING fts5vocab(tx, row); + CREATE VIRTUAL TABLE txc USING fts5vocab(tx, col); +} + +proc cont {L elem} { + set n 0 + foreach e $L { if {$elem==$e} {incr n} } + set n +} +db func cont cont + +foreach {term} { + a aa aaa + b bb bbb + c cc ccc + d dd ddd + e ee eee + f ff fff + g gg ggg + h hh hhh + i ii iii + j jj jjj +} { + set resr [db eval { + SELECT $term, + sum(cont(one || ' ' || two, $term) > 0), + sum(cont(one || ' ' || two, $term)) + FROM tx + }] + if {[lindex $resr 1]==0} {set resr [list]} + + set r1 [db eval { + SELECT $term, 'one', sum(cont(one, $term)>0), sum(cont(one, $term)) FROM tx + }] + if {[lindex $r1 2]==0} {set r1 [list]} + + set r2 [db eval { + SELECT $term, 'two', sum(cont(two, $term)>0), sum(cont(two, $term)) FROM tx + }] + if {[lindex $r2 2]==0} {set r2 [list]} + + set resc [concat $r1 $r2] + + set resc [star_from_col $resc] + set resr [star_from_row $resr] + if {[detail_is_none]} { set resc [row_to_col $resr] } + do_execsql_test 7.$term.1 {SELECT * FROM txc WHERE term=$term} $resc + do_execsql_test 7.$term.2 {SELECT * FROM txr WHERE term=$term} $resr +} + +do_execsql_test 7.1 { + CREATE TABLE txr_c AS SELECT * FROM txr; + CREATE TABLE txc_c AS SELECT * FROM txc; +} + +# Test range queries on the fts5vocab tables created above. +# +foreach {tn a b} { + 1 a jjj + 2 bb j + 3 ccc ddd + 4 dd xyz + 5 xzy dd + 6 h hh +} { + do_execsql_test 7.2.$tn.1 { + SELECT * FROM txr WHERE term>=$a + } [db eval {SELECT * FROM txr_c WHERE term>=$a}] + do_execsql_test 7.2.$tn.2 { + SELECT * FROM txr WHERE term<=$b + } [db eval {SELECT * FROM txr_c WHERE term <=$b}] + do_execsql_test 7.2.$tn.3 { + SELECT * FROM txr WHERE term>=$a AND term<=$b + } [db eval {SELECT * FROM txr_c WHERE term>=$a AND term <=$b}] + + do_execsql_test 7.2.$tn.4 { + SELECT * FROM txc WHERE term>=$a + } [db eval {SELECT * FROM txc_c WHERE term>=$a}] + do_execsql_test 7.2.$tn.5 { + SELECT * FROM txc WHERE term<=$b + } [db eval {SELECT * FROM txc_c WHERE term <=$b}] + do_execsql_test 7.2.$tn.6 { + SELECT * FROM txc WHERE term>=$a AND term<=$b + } [db eval {SELECT * FROM txc_c WHERE term>=$a AND term <=$b}] + + do_execsql_test 7.2.$tn.7 { + SELECT * FROM txr WHERE term>$a + } [db eval {SELECT * FROM txr_c WHERE term>$a}] + do_execsql_test 7.2.$tn.8 { + SELECT * FROM txr WHERE term<$b + } [db eval {SELECT * FROM txr_c WHERE term<$b}] + do_execsql_test 7.2.$tn.9 { + SELECT * FROM txr WHERE term>$a AND term<$b + } [db eval {SELECT * FROM txr_c WHERE term>$a AND term <$b}] + + do_execsql_test 7.2.$tn.10 { + SELECT * FROM txc WHERE term>$a + } [db eval {SELECT * FROM txc_c WHERE term>$a}] + do_execsql_test 7.2.$tn.11 { + SELECT * FROM txc WHERE term<$b + } [db eval {SELECT * FROM txc_c WHERE term<$b}] + do_execsql_test 7.2.$tn.12 { + SELECT * FROM txc WHERE term>$a AND term<$b + } [db eval {SELECT * FROM txc_c WHERE term>$a AND term <$b}] +} + +do_execsql_test 7.3.1 { + SELECT count(*) FROM txr, txr_c WHERE txr.term = txr_c.term; +} {30} + +if {![detail_is_none]} { + do_execsql_test 7.3.2 { + SELECT count(*) FROM txc, txc_c + WHERE txc.term = txc_c.term AND txc.col=txc_c.col; + } {57} +} + +} + +#------------------------------------------------------------------------- +# Test the fts5vocab tables response to a specific types of corruption: +# where the fts5 index contains hits for columns that do not exist. +# +do_execsql_test 8.0 { + CREATE VIRTUAL TABLE x1 USING fts5(a, b, c, detail=%DETAIL%); + INSERT INTO x1 VALUES('a b c', 'd e f', 'g h i'); + INSERT INTO x1 VALUES('g h i', 'a b c', 'd e f'); + INSERT INTO x1 VALUES('d e f', 'g h i', 'a b c'); + CREATE VIRTUAL TABLE x1_r USING fts5vocab(x1, row); + CREATE VIRTUAL TABLE x1_c USING fts5vocab(x1, col); +} + +set resr [star_from_row {a 3 3 b 3 3 c 3 3 d 3 3 e 3 3 f 3 3 g 3 3 h 3 3 i 3 3}] +set resc [star_from_col { + a a 1 1 a b 1 1 a c 1 1 b a 1 1 + b b 1 1 b c 1 1 c a 1 1 c b 1 1 + c c 1 1 d a 1 1 d b 1 1 d c 1 1 + e a 1 1 e b 1 1 e c 1 1 f a 1 1 + f b 1 1 f c 1 1 g a 1 1 g b 1 1 + g c 1 1 h a 1 1 h b 1 1 h c 1 1 + i a 1 1 i b 1 1 i c 1 1 +}] +if {[detail_is_none]} { set resc [row_to_col $resr] } + +do_execsql_test 8.1.1 { SELECT * FROM x1_r; } $resr +do_execsql_test 8.1.2 { SELECT * FROM x1_c } $resc + +do_execsql_test 8.2 { + PRAGMA writable_schema = 1; + UPDATE sqlite_master + SET sql = 'CREATE VIRTUAL TABLE x1 USING fts5(a, detail=%DETAIL%)' + WHERE name = 'x1'; +} +db close +sqlite3 db test.db +sqlite3_fts5_may_be_corrupt 1 + +do_execsql_test 8.2.1 { SELECT * FROM x1_r } $resr + +if {[detail_is_none]} { + do_execsql_test 8.2.2 { SELECT * FROM x1_c } $resc +} else { + do_catchsql_test 8.2.2 { + SELECT * FROM x1_c + } {1 {database disk image is malformed}} +} + +sqlite3_fts5_may_be_corrupt 0 + +} + +finish_test + diff --git a/ext/fts5/tool/fts5speed.tcl b/ext/fts5/tool/fts5speed.tcl new file mode 100644 index 0000000..0f38638 --- /dev/null +++ b/ext/fts5/tool/fts5speed.tcl @@ -0,0 +1,64 @@ + + +set Q { + {1 "SELECT count(*) FROM t1 WHERE t1 MATCH 'enron'"} + {25 "SELECT count(*) FROM t1 WHERE t1 MATCH 'hours'"} + {300 "SELECT count(*) FROM t1 WHERE t1 MATCH 'acid'"} + {100 "SELECT count(*) FROM t1 WHERE t1 MATCH 'loaned OR mobility OR popcore OR sunk'"} + {100 "SELECT count(*) FROM t1 WHERE t1 MATCH 'enron AND myapps'"} + {1 "SELECT count(*) FROM t1 WHERE t1 MATCH 'en* AND my*'"} + + {1 "SELECT count(*) FROM t1 WHERE t1 MATCH 'c:t*'"} + {1 "SELECT count(*) FROM t1 WHERE t1 MATCH 'a:t* OR b:t* OR c:t* OR d:t* OR e:t* OR f:t* OR g:t*'"} + {1 "SELECT count(*) FROM t1 WHERE t1 MATCH 'a:t*'"} + {2 "SELECT count(*) FROM t1 WHERE t1 MATCH 'c:the'"} + + {2 "SELECT count(*) FROM t1 WHERE t1 MATCH 'd:holmes OR e:holmes OR f:holmes OR g:holmes'" } + {2 "SELECT count(*) FROM t1 WHERE t1 MATCH 'd:holmes AND e:holmes AND f:holmes AND g:holmes'" } + {4 "SELECT count(*) FROM t1 WHERE t1 MATCH 'd:holmes NOT e:holmes'" } +} + +proc usage {} { + global Q + puts stderr "Usage: $::argv0 DATABASE QUERY" + puts stderr "" + for {set i 1} {$i <= [llength $Q]} {incr i} { + puts stderr " $i. [lindex $Q [expr $i-1]]" + } + puts stderr "" + exit -1 +} + + +set nArg [llength $argv] +if {$nArg!=2 && $nArg!=3} usage +set database [lindex $argv 0] +set iquery [lindex $argv 1] +if {$iquery<1 || $iquery>[llength $Q]} usage +set nRepeat 0 +if {$nArg==3} { set nRepeat [lindex $argv 2] } + + +sqlite3 db $database +catch { load_static_extension db fts5 } + +incr iquery -1 +set sql [lindex $Q $iquery 1] +if {$nRepeat==0} { + set nRepeat [lindex $Q $iquery 0] +} + +puts "sql: $sql" +puts "nRepeat: $nRepeat" +if {[regexp matchinfo $sql]} { + sqlite3_fts5_register_matchinfo db + db eval $sql +} else { + puts "result: [db eval $sql]" +} + +for {set i 1} {$i < $nRepeat} {incr i} { + db eval $sql +} + + diff --git a/ext/fts5/tool/fts5txt2db.tcl b/ext/fts5/tool/fts5txt2db.tcl new file mode 100644 index 0000000..d5df971 --- /dev/null +++ b/ext/fts5/tool/fts5txt2db.tcl @@ -0,0 +1,228 @@ +########################################################################## +# 2016 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. +# +proc process_cmdline {} { + cmdline::process ::A $::argv { + {fts5 "use fts5 (this is the default)"} + {fts4 "use fts4"} + {colsize "10 10 10" "list of column sizes"} + {tblname "t1" "table name to create"} + {detail "full" "Fts5 detail mode to use"} + {repeat 1 "Load each file this many times"} + {prefix "" "Fts prefix= option"} + database + file... + } { + This script is designed to create fts4/5 tables with more than one column. + The -colsize option should be set to a Tcl list of integer values, one for + each column in the table. Each value is the number of tokens that will be + inserted into the column value for each row. For example, setting the -colsize + option to "5 10" creates an FTS table with 2 columns, with roughly 5 and 10 + tokens per row in each, respectively. + + Each "FILE" argument should be a text file. The contents of these text files + is split on whitespace characters to form a list of tokens. The first N1 + tokens are used for the first column of the first row, where N1 is the first + element of the -colsize list. The next N2 are used for the second column of + the first row, and so on. Rows are added to the table until the entire list + of tokens is exhausted. + } +} + +########################################################################### +########################################################################### +# Command line options processor. This is generic code that can be copied +# between scripts. +# +namespace eval cmdline { + proc cmdline_error {O E {msg ""}} { + if {$msg != ""} { + puts stderr "Error: $msg" + puts stderr "" + } + + set L [list] + foreach o $O { + if {[llength $o]==1} { + lappend L [string toupper $o] + } + } + + puts stderr "Usage: $::argv0 ?SWITCHES? $L" + puts stderr "" + puts stderr "Switches are:" + foreach o $O { + if {[llength $o]==3} { + foreach {a b c} $o {} + puts stderr [format " -%-15s %s (default \"%s\")" "$a VAL" $c $b] + } elseif {[llength $o]==2} { + foreach {a b} $o {} + puts stderr [format " -%-15s %s" $a $b] + } + } + puts stderr "" + puts stderr $E + exit -1 + } + + proc process {avar lArgs O E} { + upvar $avar A + set zTrailing "" ;# True if ... is present in $O + set lPosargs [list] + + # Populate A() with default values. Also, for each switch in the command + # line spec, set an entry in the idx() array as follows: + # + # {tblname t1 "table name to use"} + # -> [set idx(-tblname) {tblname t1 "table name to use"} + # + # For each position parameter, append its name to $lPosargs. If the ... + # specifier is present, set $zTrailing to the name of the prefix. + # + foreach o $O { + set nm [lindex $o 0] + set nArg [llength $o] + switch -- $nArg { + 1 { + if {[string range $nm end-2 end]=="..."} { + set zTrailing [string range $nm 0 end-3] + } else { + lappend lPosargs $nm + } + } + 2 { + set A($nm) 0 + set idx(-$nm) $o + } + 3 { + set A($nm) [lindex $o 1] + set idx(-$nm) $o + } + default { + error "Error in command line specification" + } + } + } + + # Set explicitly specified option values + # + set nArg [llength $lArgs] + for {set i 0} {$i < $nArg} {incr i} { + set opt [lindex $lArgs $i] + if {[string range $opt 0 0]!="-" || $opt=="--"} break + set c [array names idx "${opt}*"] + if {[llength $c]==0} { cmdline_error $O $E "Unrecognized option: $opt"} + if {[llength $c]>1} { cmdline_error $O $E "Ambiguous option: $opt"} + + if {[llength $idx($c)]==3} { + if {$i==[llength $lArgs]-1} { + cmdline_error $O $E "Option requires argument: $c" + } + incr i + set A([lindex $idx($c) 0]) [lindex $lArgs $i] + } else { + set A([lindex $idx($c) 0]) 1 + } + } + + # Deal with position arguments. + # + set nPosarg [llength $lPosargs] + set nRem [expr $nArg - $i] + if {$nRem < $nPosarg || ($zTrailing=="" && $nRem > $nPosarg)} { + cmdline_error $O $E + } + for {set j 0} {$j < $nPosarg} {incr j} { + set A([lindex $lPosargs $j]) [lindex $lArgs [expr $j+$i]] + } + if {$zTrailing!=""} { + set A($zTrailing) [lrange $lArgs [expr $j+$i] end] + } + } +} ;# namespace eval cmdline +# End of command line options processor. +########################################################################### +########################################################################### + +process_cmdline + +# If -fts4 was specified, use fts4. Otherwise, fts5. +if {$A(fts4)} { + set A(fts) fts4 +} else { + set A(fts) fts5 +} + +sqlite3 db $A(database) + +# Create the FTS table in the db. Return a list of the table columns. +# +proc create_table {} { + global A + set cols [list a b c d e f g h i j k l m n o p q r s t u v w x y z] + + set nCol [llength $A(colsize)] + set cols [lrange $cols 0 [expr $nCol-1]] + + set sql "CREATE VIRTUAL TABLE IF NOT EXISTS $A(tblname) USING $A(fts) (" + append sql [join $cols ,] + if {$A(fts)=="fts5"} { append sql ",detail=$A(detail)" } + append sql ", prefix='$A(prefix)');" + + db eval $sql + return $cols +} + +# Return a list of tokens from the named file. +# +proc readfile {file} { + set fd [open $file] + set data [read $fd] + close $fd + split $data +} + +proc repeat {L n} { + set res [list] + for {set i 0} {$i < $n} {incr i} { + set res [concat $res $L] + } + set res +} + + +# Load all the data into a big list of tokens. +# +set tokens [list] +foreach f $A(file) { + set tokens [concat $tokens [repeat [readfile $f] $A(repeat)]] +} + +set N [llength $tokens] +set i 0 +set cols [create_table] +set sql "INSERT INTO $A(tblname) VALUES(\$R([lindex $cols 0])" +foreach c [lrange $cols 1 end] { + append sql ", \$R($c)" +} +append sql ")" + +db eval BEGIN + while {$i < $N} { + foreach c $cols s $A(colsize) { + set R($c) [lrange $tokens $i [expr $i+$s-1]] + incr i $s + } + db eval $sql + } +db eval COMMIT + + + diff --git a/ext/fts5/tool/loadfts5.tcl b/ext/fts5/tool/loadfts5.tcl new file mode 100644 index 0000000..96fd692 --- /dev/null +++ b/ext/fts5/tool/loadfts5.tcl @@ -0,0 +1,172 @@ + + +proc loadfile {f} { + set fd [open $f] + set data [read $fd] + close $fd + return $data +} + +set ::nRow 0 +set ::nRowPerDot 1000 + +proc load_hierachy {dir} { + foreach f [glob -nocomplain -dir $dir *] { + if {$::O(limit) && $::nRow>=$::O(limit)} break + if {[file isdir $f]} { + load_hierachy $f + } else { + db eval { INSERT INTO t1 VALUES($f, loadfile($f)) } + incr ::nRow + + if {$::O(trans) && ($::nRow % $::O(trans))==0} { + db eval { COMMIT } + db eval { INSERT INTO t1(t1) VALUES('integrity-check') } + db eval { BEGIN } + } + + if {($::nRow % $::nRowPerDot)==0} { + puts -nonewline . + if {($::nRow % (65*$::nRowPerDot))==0} { puts "" } + flush stdout + } + + } + } +} + +proc usage {} { + puts stderr "Usage: $::argv0 ?SWITCHES? DATABASE PATH" + puts stderr "" + puts stderr "Switches are:" + puts stderr " -fts4 (use fts4 instead of fts5)" + puts stderr " -fts5 (use fts5)" + puts stderr " -porter (use porter tokenizer)" + puts stderr " -delete (delete the database file before starting)" + puts stderr " -limit N (load no more than N documents)" + puts stderr " -automerge N (set the automerge parameter to N)" + puts stderr " -crisismerge N (set the crisismerge parameter to N)" + puts stderr " -prefix PREFIX (comma separated prefix= argument)" + puts stderr " -trans N (commit after N inserts - 0 == never)" + puts stderr " -hashsize N (set the fts5 hashsize parameter to N)" + puts stderr " -detail MODE (detail mode for fts5 tables)" + exit 1 +} + +set O(vtab) fts5 +set O(tok) "" +set O(limit) 0 +set O(delete) 0 +set O(automerge) -1 +set O(crisismerge) -1 +set O(prefix) "" +set O(trans) 0 +set O(hashsize) -1 +set O(detail) full + +if {[llength $argv]<2} usage +set nOpt [expr {[llength $argv]-2}] +for {set i 0} {$i < $nOpt} {incr i} { + set arg [lindex $argv $i] + switch -- [lindex $argv $i] { + -fts4 { + set O(vtab) fts4 + } + + -fts5 { + set O(vtab) fts5 + } + + -porter { + set O(tok) ", tokenize=porter" + } + + -delete { + set O(delete) 1 + } + + -limit { + if { [incr i]>=$nOpt } usage + set O(limit) [lindex $argv $i] + } + + -trans { + if { [incr i]>=$nOpt } usage + set O(trans) [lindex $argv $i] + } + + -automerge { + if { [incr i]>=$nOpt } usage + set O(automerge) [lindex $argv $i] + } + + -crisismerge { + if { [incr i]>=$nOpt } usage + set O(crisismerge) [lindex $argv $i] + } + + -prefix { + if { [incr i]>=$nOpt } usage + set O(prefix) [lindex $argv $i] + } + + -hashsize { + if { [incr i]>=$nOpt } usage + set O(hashsize) [lindex $argv $i] + } + + -detail { + if { [incr i]>=$nOpt } usage + set O(detail) [lindex $argv $i] + } + + default { + usage + } + } +} + +set dbfile [lindex $argv end-1] +if {$O(delete)} { file delete -force $dbfile } +sqlite3 db $dbfile +catch { load_static_extension db fts5 } +db func loadfile loadfile +db eval "PRAGMA page_size=4096" + +db eval BEGIN + set pref "" + if {$O(prefix)!=""} { set pref ", prefix='$O(prefix)'" } + if {$O(vtab)=="fts5"} { + append pref ", detail=$O(detail)" + } + catch { + db eval "CREATE VIRTUAL TABLE t1 USING $O(vtab) (path, content$O(tok)$pref)" + db eval "INSERT INTO t1(t1, rank) VALUES('pgsz', 4050);" + } + + if {$O(hashsize)>=0} { + catch { + db eval "INSERT INTO t1(t1, rank) VALUES('hashsize', $O(hashsize));" + } + } + + + if {$O(automerge)>=0} { + if {$O(vtab) == "fts5"} { + db eval { INSERT INTO t1(t1, rank) VALUES('automerge', $O(automerge)) } + } else { + db eval { INSERT INTO t1(t1) VALUES('automerge=' || $O(automerge)) } + } + } + if {$O(crisismerge)>=0} { + if {$O(vtab) == "fts5"} { + db eval {INSERT INTO t1(t1, rank) VALUES('crisismerge', $O(crisismerge))} + } else { + } + } + load_hierachy [lindex $argv end] +db eval COMMIT +puts "" + + + diff --git a/ext/fts5/tool/mkfts5c.tcl b/ext/fts5/tool/mkfts5c.tcl new file mode 100644 index 0000000..797811d --- /dev/null +++ b/ext/fts5/tool/mkfts5c.tcl @@ -0,0 +1,113 @@ +#!/bin/sh +# restart with tclsh \ +exec tclsh "$0" "$@" + +set srcdir [file dirname [file dirname [info script]]] +set G(src) [string map [list %dir% $srcdir] { + %dir%/fts5.h + %dir%/fts5Int.h + fts5parse.h + fts5parse.c + %dir%/fts5_aux.c + %dir%/fts5_buffer.c + %dir%/fts5_config.c + %dir%/fts5_expr.c + %dir%/fts5_hash.c + %dir%/fts5_index.c + %dir%/fts5_main.c + %dir%/fts5_storage.c + %dir%/fts5_tokenize.c + %dir%/fts5_unicode2.c + %dir%/fts5_varint.c + %dir%/fts5_vocab.c +}] + +set G(hdr) { + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) + +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +# define NDEBUG 1 +#endif +#if defined(NDEBUG) && defined(SQLITE_DEBUG) +# undef NDEBUG +#endif + +} + +set G(footer) { + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */ +} + +#------------------------------------------------------------------------- +# Read and return the entire contents of text file $zFile from disk. +# +proc readfile {zFile} { + set fd [open $zFile] + set data [read $fd] + close $fd + return $data +} + +#------------------------------------------------------------------------- +# This command returns a string identifying the current sqlite version - +# the equivalent of the SQLITE_SOURCE_ID string. +# +proc fts5_source_id {zDir} { + set top [file dirname [file dirname $zDir]] + set uuid [string trim [readfile [file join $top manifest.uuid]]] + + set L [split [readfile [file join $top manifest]]] + set date [lindex $L [expr [lsearch -exact $L D]+1]] + set date [string range $date 0 [string last . $date]-1] + set date [string map {T { }} $date] + + return "fts5: $date $uuid" +} + +proc fts5c_init {zOut} { + global G + set G(fd) stdout + set G(fd) [open $zOut w] + + puts -nonewline $G(fd) $G(hdr) +} + +proc fts5c_printfile {zIn} { + global G + set data [readfile $zIn] + set zTail [file tail $zIn] + puts $G(fd) "#line 1 \"$zTail\"" + + set sub_map [list --FTS5-SOURCE-ID-- [fts5_source_id $::srcdir]] + if {$zTail=="fts5parse.c"} { + lappend sub_map yy fts5yy YY fts5YY TOKEN FTS5TOKEN + } + + foreach line [split $data "\n"] { + if {[regexp {^#include.*fts5} $line]} { + set line "/* $line */" + } elseif { + ![regexp { sqlite3Fts5Init\(} $line] + && [regexp {^(const )?[a-zA-Z][a-zA-Z0-9]* [*]?sqlite3Fts5} $line] + } { + set line "static $line" + } + set line [string map $sub_map $line] + puts $G(fd) $line + } +} + +proc fts5c_close {} { + global G + puts -nonewline $G(fd) $G(footer) + if {$G(fd)!="stdout"} { + close $G(fd) + } +} + + +fts5c_init fts5.c +foreach f $G(src) { fts5c_printfile $f } +fts5c_close diff --git a/ext/fts5/tool/showfts5.tcl b/ext/fts5/tool/showfts5.tcl new file mode 100644 index 0000000..75ac0f1 --- /dev/null +++ b/ext/fts5/tool/showfts5.tcl @@ -0,0 +1,97 @@ + + + +#------------------------------------------------------------------------- +# Process command line arguments. +# +proc usage {} { + puts stderr "usage: $::argv0 ?OPTIONS? database table" + puts stderr "" + puts stderr " -nterm (count number of terms in each segment)" + puts stderr " -segments (output segment contents)" + puts stderr "" + exit 1 +} + +set O(nterm) 0 +set O(segments) 0 + +if {[llength $argv]<2} usage +foreach a [lrange $argv 0 end-2] { + switch -- $a { + -nterm { + set O(nterm) 1 + } + + -segments { + set O(segments) 1 + } + + default { + usage + } + } +} + +set database [lindex $argv end-1] +set tbl [lindex $argv end] + + +#------------------------------------------------------------------------- +# Count the number of terms in each segment of fts5 table $tbl. Store the +# counts in the array variable in the parent context named by parameter +# $arrayname, indexed by segment-id. Example: +# +# count_terms fts_tbl A +# foreach {k v} [array get A] { puts "segid=$k nTerm=$v" } +# +proc count_terms {tbl arrayname} { + upvar A $arrayname + array unset A + db eval "SELECT fts5_decode(rowid, block) AS d FROM ${tbl}_data" { + set desc [lindex $d 0] + if {[regexp {^segid=([0-9]*)} $desc -> id]} { + foreach i [lrange $d 1 end] { + if {[string match {term=*} $i]} { incr A($id) } + } + } + } +} + + +#------------------------------------------------------------------------- +# Start of main program. +# +sqlite3 db $database +catch { load_static_extension db fts5 } + +if {$O(nterm)} { count_terms $tbl A } + +db eval "SELECT fts5_decode(rowid, block) AS d FROM ${tbl}_data WHERE id=10" { + foreach lvl [lrange $d 1 end] { + puts [lrange $lvl 0 2] + + foreach seg [lrange $lvl 3 end] { + if {$::O(nterm)} { + regexp {^id=([0-9]*)} $seg -> id + set nTerm 0 + catch { set nTerm $A($id) } + puts [format " % -28s nTerm=%d" $seg $nTerm] + } else { + puts [format " % -28s" $seg] + } + } + } +} + +if {$O(segments)} { + puts "" + db eval "SELECT fts5_decode(rowid, block) AS d FROM ${tbl}_data WHERE id>10" { + puts $d + } +} + + + + + diff --git a/ext/icu/icu.c b/ext/icu/icu.c index 1ce1e0c..a2ff492 100644 --- a/ext/icu/icu.c +++ b/ext/icu/icu.c @@ -83,7 +83,6 @@ static int icuLikeCompare( /* Read (and consume) the next character from the input pattern. */ UChar32 uPattern; U8_NEXT_UNSAFE(zPattern, iPattern, uPattern); - assert(uPattern!=0); /* There are now 4 possibilities: ** @@ -422,6 +421,7 @@ static void icuLoadCollation( int rc; /* Return code from sqlite3_create_collation_x() */ assert(nArg==2); + (void)nArg; /* Unused parameter */ zLocale = (const char *)sqlite3_value_text(apArg[0]); zName = (const char *)sqlite3_value_text(apArg[1]); diff --git a/ext/misc/amatch.c b/ext/misc/amatch.c index d08ef57..8524919 100644 --- a/ext/misc/amatch.c +++ b/ext/misc/amatch.c @@ -816,10 +816,10 @@ static const char *amatchValueOfKey(const char *zKey, const char *zStr){ int i; if( nStr>= 1; e++; } - while( ((m>>32)&0xfff00000)==0 ){ + while( m!=0 && ((m>>32)&0xfff00000)==0 ){ m <<= 1; e--; } e += 1075; if( e<0 ) e = m = 0; - if( e>0x7ff ) m = 0; + if( e>0x7ff ) e = 0x7ff; a = m & ((((sqlite3_int64)1)<<52)-1); a |= e<<52; - if( isNeg ) a |= ((sqlite3_int64)1)<<63; + if( isNeg ) a |= ((sqlite3_uint64)1)<<63; memcpy(&r, &a, sizeof(r)); sqlite3_result_double(context, r); } diff --git a/ext/misc/json1.c b/ext/misc/json1.c new file mode 100644 index 0000000..99d299c --- /dev/null +++ b/ext/misc/json1.c @@ -0,0 +1,2192 @@ +/* +** 2015-08-12 +** +** 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 SQLite extension implements JSON functions. The interface is +** modeled after MySQL JSON functions: +** +** https://dev.mysql.com/doc/refman/5.7/en/json.html +** +** For the time being, all JSON is stored as pure text. (We might add +** a JSONB type in the future which stores a binary encoding of JSON in +** a BLOB, but there is no support for JSONB in the current implementation. +** This implementation parses JSON text at 250 MB/s, so it is hard to see +** how JSONB might improve on that.) +*/ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) +#if !defined(_SQLITEINT_H_) +#include "sqlite3ext.h" +#endif +SQLITE_EXTENSION_INIT1 +#include +#include +#include +#include + +/* Mark a function parameter as unused, to suppress nuisance compiler +** warnings. */ +#ifndef UNUSED_PARAM +# define UNUSED_PARAM(X) (void)(X) +#endif + +#ifndef LARGEST_INT64 +# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) +# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64) +#endif + +/* +** Versions of isspace(), isalnum() and isdigit() to which it is safe +** to pass signed char values. +*/ +#ifdef sqlite3Isdigit + /* Use the SQLite core versions if this routine is part of the + ** SQLite amalgamation */ +# define safe_isdigit(x) sqlite3Isdigit(x) +# define safe_isalnum(x) sqlite3Isalnum(x) +#else + /* Use the standard library for separate compilation */ +#include /* amalgamator: keep */ +# define safe_isdigit(x) isdigit((unsigned char)(x)) +# define safe_isalnum(x) isalnum((unsigned char)(x)) +#endif + +/* +** Growing our own isspace() routine this way is twice as fast as +** the library isspace() function, resulting in a 7% overall performance +** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). +*/ +static const char jsonIsSpace[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define safe_isspace(x) (jsonIsSpace[(unsigned char)x]) + +#ifndef SQLITE_AMALGAMATION + /* Unsigned integer types. These are already defined in the sqliteInt.h, + ** but the definitions need to be repeated for separate compilation. */ + typedef sqlite3_uint64 u64; + typedef unsigned int u32; + typedef unsigned char u8; +#endif + +/* Objects */ +typedef struct JsonString JsonString; +typedef struct JsonNode JsonNode; +typedef struct JsonParse JsonParse; + +/* An instance of this object represents a JSON string +** under construction. Really, this is a generic string accumulator +** that can be and is used to create strings other than JSON. +*/ +struct JsonString { + sqlite3_context *pCtx; /* Function context - put error messages here */ + char *zBuf; /* Append JSON content here */ + u64 nAlloc; /* Bytes of storage available in zBuf[] */ + u64 nUsed; /* Bytes of zBuf[] currently used */ + u8 bStatic; /* True if zBuf is static space */ + u8 bErr; /* True if an error has been encountered */ + char zSpace[100]; /* Initial static space */ +}; + +/* JSON type values +*/ +#define JSON_NULL 0 +#define JSON_TRUE 1 +#define JSON_FALSE 2 +#define JSON_INT 3 +#define JSON_REAL 4 +#define JSON_STRING 5 +#define JSON_ARRAY 6 +#define JSON_OBJECT 7 + +/* The "subtype" set for JSON values */ +#define JSON_SUBTYPE 74 /* Ascii for "J" */ + +/* +** Names of the various JSON types: +*/ +static const char * const jsonType[] = { + "null", "true", "false", "integer", "real", "text", "array", "object" +}; + +/* Bit values for the JsonNode.jnFlag field +*/ +#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */ +#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */ +#define JNODE_REMOVE 0x04 /* Do not output */ +#define JNODE_REPLACE 0x08 /* Replace with JsonNode.iVal */ +#define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */ +#define JNODE_LABEL 0x20 /* Is a label of an object */ + + +/* A single node of parsed JSON +*/ +struct JsonNode { + u8 eType; /* One of the JSON_ type values */ + u8 jnFlags; /* JNODE flags */ + u8 iVal; /* Replacement value when JNODE_REPLACE */ + u32 n; /* Bytes of content, or number of sub-nodes */ + union { + const char *zJContent; /* Content for INT, REAL, and STRING */ + u32 iAppend; /* More terms for ARRAY and OBJECT */ + u32 iKey; /* Key for ARRAY objects in json_tree() */ + } u; +}; + +/* A completely parsed JSON string +*/ +struct JsonParse { + u32 nNode; /* Number of slots of aNode[] used */ + u32 nAlloc; /* Number of slots of aNode[] allocated */ + JsonNode *aNode; /* Array of nodes containing the parse */ + const char *zJson; /* Original JSON string */ + u32 *aUp; /* Index of parent of each node */ + u8 oom; /* Set to true if out of memory */ + u8 nErr; /* Number of errors seen */ +}; + +/************************************************************************** +** Utility routines for dealing with JsonString objects +**************************************************************************/ + +/* Set the JsonString object to an empty string +*/ +static void jsonZero(JsonString *p){ + p->zBuf = p->zSpace; + p->nAlloc = sizeof(p->zSpace); + p->nUsed = 0; + p->bStatic = 1; +} + +/* Initialize the JsonString object +*/ +static void jsonInit(JsonString *p, sqlite3_context *pCtx){ + p->pCtx = pCtx; + p->bErr = 0; + jsonZero(p); +} + + +/* Free all allocated memory and reset the JsonString object back to its +** initial state. +*/ +static void jsonReset(JsonString *p){ + if( !p->bStatic ) sqlite3_free(p->zBuf); + jsonZero(p); +} + + +/* Report an out-of-memory (OOM) condition +*/ +static void jsonOom(JsonString *p){ + p->bErr = 1; + sqlite3_result_error_nomem(p->pCtx); + jsonReset(p); +} + +/* Enlarge pJson->zBuf so that it can hold at least N more bytes. +** Return zero on success. Return non-zero on an OOM error +*/ +static int jsonGrow(JsonString *p, u32 N){ + u64 nTotal = NnAlloc ? p->nAlloc*2 : p->nAlloc+N+10; + char *zNew; + if( p->bStatic ){ + if( p->bErr ) return 1; + zNew = sqlite3_malloc64(nTotal); + if( zNew==0 ){ + jsonOom(p); + return SQLITE_NOMEM; + } + memcpy(zNew, p->zBuf, (size_t)p->nUsed); + p->zBuf = zNew; + p->bStatic = 0; + }else{ + zNew = sqlite3_realloc64(p->zBuf, nTotal); + if( zNew==0 ){ + jsonOom(p); + return SQLITE_NOMEM; + } + p->zBuf = zNew; + } + p->nAlloc = nTotal; + return SQLITE_OK; +} + +/* Append N bytes from zIn onto the end of the JsonString string. +*/ +static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ + if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return; + memcpy(p->zBuf+p->nUsed, zIn, N); + p->nUsed += N; +} + +/* Append formatted text (not to exceed N bytes) to the JsonString. +*/ +static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ + va_list ap; + if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return; + va_start(ap, zFormat); + sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); + va_end(ap); + p->nUsed += (int)strlen(p->zBuf+p->nUsed); +} + +/* Append a single character +*/ +static void jsonAppendChar(JsonString *p, char c){ + if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return; + p->zBuf[p->nUsed++] = c; +} + +/* Append a comma separator to the output buffer, if the previous +** character is not '[' or '{'. +*/ +static void jsonAppendSeparator(JsonString *p){ + char c; + if( p->nUsed==0 ) return; + c = p->zBuf[p->nUsed-1]; + if( c!='[' && c!='{' ) jsonAppendChar(p, ','); +} + +/* Append the N-byte string in zIn to the end of the JsonString string +** under construction. Enclose the string in "..." and escape +** any double-quotes or backslash characters contained within the +** string. +*/ +static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ + u32 i; + if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return; + p->zBuf[p->nUsed++] = '"'; + for(i=0; inUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; + p->zBuf[p->nUsed++] = '\\'; + }else if( c<=0x1f ){ + static const char aSpecial[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + assert( sizeof(aSpecial)==32 ); + assert( aSpecial['\b']=='b' ); + assert( aSpecial['\f']=='f' ); + assert( aSpecial['\n']=='n' ); + assert( aSpecial['\r']=='r' ); + assert( aSpecial['\t']=='t' ); + if( aSpecial[c] ){ + c = aSpecial[c]; + goto json_simple_escape; + } + if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return; + p->zBuf[p->nUsed++] = '\\'; + p->zBuf[p->nUsed++] = 'u'; + p->zBuf[p->nUsed++] = '0'; + p->zBuf[p->nUsed++] = '0'; + p->zBuf[p->nUsed++] = '0' + (c>>4); + c = "0123456789abcdef"[c&0xf]; + } + p->zBuf[p->nUsed++] = c; + } + p->zBuf[p->nUsed++] = '"'; + assert( p->nUsednAlloc ); +} + +/* +** Append a function parameter value to the JSON string under +** construction. +*/ +static void jsonAppendValue( + JsonString *p, /* Append to this JSON string */ + sqlite3_value *pValue /* Value to append */ +){ + switch( sqlite3_value_type(pValue) ){ + case SQLITE_NULL: { + jsonAppendRaw(p, "null", 4); + break; + } + case SQLITE_INTEGER: + case SQLITE_FLOAT: { + const char *z = (const char*)sqlite3_value_text(pValue); + u32 n = (u32)sqlite3_value_bytes(pValue); + jsonAppendRaw(p, z, n); + break; + } + case SQLITE_TEXT: { + const char *z = (const char*)sqlite3_value_text(pValue); + u32 n = (u32)sqlite3_value_bytes(pValue); + if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){ + jsonAppendRaw(p, z, n); + }else{ + jsonAppendString(p, z, n); + } + break; + } + default: { + if( p->bErr==0 ){ + sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); + p->bErr = 2; + jsonReset(p); + } + break; + } + } +} + + +/* Make the JSON in p the result of the SQL function. +*/ +static void jsonResult(JsonString *p){ + if( p->bErr==0 ){ + sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, + p->bStatic ? SQLITE_TRANSIENT : sqlite3_free, + SQLITE_UTF8); + jsonZero(p); + } + assert( p->bStatic ); +} + +/************************************************************************** +** Utility routines for dealing with JsonNode and JsonParse objects +**************************************************************************/ + +/* +** Return the number of consecutive JsonNode slots need to represent +** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and +** OBJECT types, the number might be larger. +** +** Appended elements are not counted. The value returned is the number +** by which the JsonNode counter should increment in order to go to the +** next peer value. +*/ +static u32 jsonNodeSize(JsonNode *pNode){ + return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; +} + +/* +** Reclaim all memory allocated by a JsonParse object. But do not +** delete the JsonParse object itself. +*/ +static void jsonParseReset(JsonParse *pParse){ + sqlite3_free(pParse->aNode); + pParse->aNode = 0; + pParse->nNode = 0; + pParse->nAlloc = 0; + sqlite3_free(pParse->aUp); + pParse->aUp = 0; +} + +/* +** Convert the JsonNode pNode into a pure JSON string and +** append to pOut. Subsubstructure is also included. Return +** the number of JsonNode objects that are encoded. +*/ +static void jsonRenderNode( + JsonNode *pNode, /* The node to render */ + JsonString *pOut, /* Write JSON here */ + sqlite3_value **aReplace /* Replacement values */ +){ + switch( pNode->eType ){ + default: { + assert( pNode->eType==JSON_NULL ); + jsonAppendRaw(pOut, "null", 4); + break; + } + case JSON_TRUE: { + jsonAppendRaw(pOut, "true", 4); + break; + } + case JSON_FALSE: { + jsonAppendRaw(pOut, "false", 5); + break; + } + case JSON_STRING: { + if( pNode->jnFlags & JNODE_RAW ){ + jsonAppendString(pOut, pNode->u.zJContent, pNode->n); + break; + } + /* Fall through into the next case */ + } + case JSON_REAL: + case JSON_INT: { + jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); + break; + } + case JSON_ARRAY: { + u32 j = 1; + jsonAppendChar(pOut, '['); + for(;;){ + while( j<=pNode->n ){ + if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){ + if( pNode[j].jnFlags & JNODE_REPLACE ){ + jsonAppendSeparator(pOut); + jsonAppendValue(pOut, aReplace[pNode[j].iVal]); + } + }else{ + jsonAppendSeparator(pOut); + jsonRenderNode(&pNode[j], pOut, aReplace); + } + j += jsonNodeSize(&pNode[j]); + } + if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; + pNode = &pNode[pNode->u.iAppend]; + j = 1; + } + jsonAppendChar(pOut, ']'); + break; + } + case JSON_OBJECT: { + u32 j = 1; + jsonAppendChar(pOut, '{'); + for(;;){ + while( j<=pNode->n ){ + if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){ + jsonAppendSeparator(pOut); + jsonRenderNode(&pNode[j], pOut, aReplace); + jsonAppendChar(pOut, ':'); + if( pNode[j+1].jnFlags & JNODE_REPLACE ){ + jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]); + }else{ + jsonRenderNode(&pNode[j+1], pOut, aReplace); + } + } + j += 1 + jsonNodeSize(&pNode[j+1]); + } + if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; + pNode = &pNode[pNode->u.iAppend]; + j = 1; + } + jsonAppendChar(pOut, '}'); + break; + } + } +} + +/* +** Return a JsonNode and all its descendents as a JSON string. +*/ +static void jsonReturnJson( + JsonNode *pNode, /* Node to return */ + sqlite3_context *pCtx, /* Return value for this function */ + sqlite3_value **aReplace /* Array of replacement values */ +){ + JsonString s; + jsonInit(&s, pCtx); + jsonRenderNode(pNode, &s, aReplace); + jsonResult(&s); + sqlite3_result_subtype(pCtx, JSON_SUBTYPE); +} + +/* +** Make the JsonNode the return value of the function. +*/ +static void jsonReturn( + JsonNode *pNode, /* Node to return */ + sqlite3_context *pCtx, /* Return value for this function */ + sqlite3_value **aReplace /* Array of replacement values */ +){ + switch( pNode->eType ){ + default: { + assert( pNode->eType==JSON_NULL ); + sqlite3_result_null(pCtx); + break; + } + case JSON_TRUE: { + sqlite3_result_int(pCtx, 1); + break; + } + case JSON_FALSE: { + sqlite3_result_int(pCtx, 0); + break; + } + case JSON_INT: { + sqlite3_int64 i = 0; + const char *z = pNode->u.zJContent; + if( z[0]=='-' ){ z++; } + while( z[0]>='0' && z[0]<='9' ){ + unsigned v = *(z++) - '0'; + if( i>=LARGEST_INT64/10 ){ + if( i>LARGEST_INT64/10 ) goto int_as_real; + if( z[0]>='0' && z[0]<='9' ) goto int_as_real; + if( v==9 ) goto int_as_real; + if( v==8 ){ + if( pNode->u.zJContent[0]=='-' ){ + sqlite3_result_int64(pCtx, SMALLEST_INT64); + goto int_done; + }else{ + goto int_as_real; + } + } + } + i = i*10 + v; + } + if( pNode->u.zJContent[0]=='-' ){ i = -i; } + sqlite3_result_int64(pCtx, i); + int_done: + break; + int_as_real: /* fall through to real */; + } + case JSON_REAL: { + double r; +#ifdef SQLITE_AMALGAMATION + const char *z = pNode->u.zJContent; + sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); +#else + r = strtod(pNode->u.zJContent, 0); +#endif + sqlite3_result_double(pCtx, r); + break; + } + case JSON_STRING: { +#if 0 /* Never happens because JNODE_RAW is only set by json_set(), + ** json_insert() and json_replace() and those routines do not + ** call jsonReturn() */ + if( pNode->jnFlags & JNODE_RAW ){ + sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n, + SQLITE_TRANSIENT); + }else +#endif + assert( (pNode->jnFlags & JNODE_RAW)==0 ); + if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ + /* JSON formatted without any backslash-escapes */ + sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2, + SQLITE_TRANSIENT); + }else{ + /* Translate JSON formatted string into raw text */ + u32 i; + u32 n = pNode->n; + const char *z = pNode->u.zJContent; + char *zOut; + u32 j; + zOut = sqlite3_malloc( n+1 ); + if( zOut==0 ){ + sqlite3_result_error_nomem(pCtx); + break; + } + for(i=1, j=0; i='0' && c<='9' ) v = v*16 + c - '0'; + else if( c>='A' && c<='F' ) v = v*16 + c - 'A' + 10; + else if( c>='a' && c<='f' ) v = v*16 + c - 'a' + 10; + else break; + } + if( v==0 ) break; + if( v<=0x7f ){ + zOut[j++] = (char)v; + }else if( v<=0x7ff ){ + zOut[j++] = (char)(0xc0 | (v>>6)); + zOut[j++] = 0x80 | (v&0x3f); + }else{ + zOut[j++] = (char)(0xe0 | (v>>12)); + zOut[j++] = 0x80 | ((v>>6)&0x3f); + zOut[j++] = 0x80 | (v&0x3f); + } + }else{ + if( c=='b' ){ + c = '\b'; + }else if( c=='f' ){ + c = '\f'; + }else if( c=='n' ){ + c = '\n'; + }else if( c=='r' ){ + c = '\r'; + }else if( c=='t' ){ + c = '\t'; + } + zOut[j++] = c; + } + } + } + zOut[j] = 0; + sqlite3_result_text(pCtx, zOut, j, sqlite3_free); + } + break; + } + case JSON_ARRAY: + case JSON_OBJECT: { + jsonReturnJson(pNode, pCtx, aReplace); + break; + } + } +} + +/* Forward reference */ +static int jsonParseAddNode(JsonParse*,u32,u32,const char*); + +/* +** A macro to hint to the compiler that a function should not be +** inlined. +*/ +#if defined(__GNUC__) +# define JSON_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) && _MSC_VER>=1310 +# define JSON_NOINLINE __declspec(noinline) +#else +# define JSON_NOINLINE +#endif + + +static JSON_NOINLINE int jsonParseAddNodeExpand( + JsonParse *pParse, /* Append the node to this object */ + u32 eType, /* Node type */ + u32 n, /* Content size or sub-node count */ + const char *zContent /* Content */ +){ + u32 nNew; + JsonNode *pNew; + assert( pParse->nNode>=pParse->nAlloc ); + if( pParse->oom ) return -1; + nNew = pParse->nAlloc*2 + 10; + pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew); + if( pNew==0 ){ + pParse->oom = 1; + return -1; + } + pParse->nAlloc = nNew; + pParse->aNode = pNew; + assert( pParse->nNodenAlloc ); + return jsonParseAddNode(pParse, eType, n, zContent); +} + +/* +** Create a new JsonNode instance based on the arguments and append that +** instance to the JsonParse. Return the index in pParse->aNode[] of the +** new node, or -1 if a memory allocation fails. +*/ +static int jsonParseAddNode( + JsonParse *pParse, /* Append the node to this object */ + u32 eType, /* Node type */ + u32 n, /* Content size or sub-node count */ + const char *zContent /* Content */ +){ + JsonNode *p; + if( pParse->nNode>=pParse->nAlloc ){ + return jsonParseAddNodeExpand(pParse, eType, n, zContent); + } + p = &pParse->aNode[pParse->nNode]; + p->eType = (u8)eType; + p->jnFlags = 0; + p->iVal = 0; + p->n = n; + p->u.zJContent = zContent; + return pParse->nNode++; +} + +/* +** Parse a single JSON value which begins at pParse->zJson[i]. Return the +** index of the first character past the end of the value parsed. +** +** Return negative for a syntax error. Special cases: return -2 if the +** first non-whitespace character is '}' and return -3 if the first +** non-whitespace character is ']'. +*/ +static int jsonParseValue(JsonParse *pParse, u32 i){ + char c; + u32 j; + int iThis; + int x; + JsonNode *pNode; + while( safe_isspace(pParse->zJson[i]) ){ i++; } + if( (c = pParse->zJson[i])=='{' ){ + /* Parse object */ + iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + if( iThis<0 ) return -1; + for(j=i+1;;j++){ + while( safe_isspace(pParse->zJson[j]) ){ j++; } + x = jsonParseValue(pParse, j); + if( x<0 ){ + if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; + return -1; + } + if( pParse->oom ) return -1; + pNode = &pParse->aNode[pParse->nNode-1]; + if( pNode->eType!=JSON_STRING ) return -1; + pNode->jnFlags |= JNODE_LABEL; + j = x; + while( safe_isspace(pParse->zJson[j]) ){ j++; } + if( pParse->zJson[j]!=':' ) return -1; + j++; + x = jsonParseValue(pParse, j); + if( x<0 ) return -1; + j = x; + while( safe_isspace(pParse->zJson[j]) ){ j++; } + c = pParse->zJson[j]; + if( c==',' ) continue; + if( c!='}' ) return -1; + break; + } + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; + return j+1; + }else if( c=='[' ){ + /* Parse array */ + iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); + if( iThis<0 ) return -1; + for(j=i+1;;j++){ + while( safe_isspace(pParse->zJson[j]) ){ j++; } + x = jsonParseValue(pParse, j); + if( x<0 ){ + if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; + return -1; + } + j = x; + while( safe_isspace(pParse->zJson[j]) ){ j++; } + c = pParse->zJson[j]; + if( c==',' ) continue; + if( c!=']' ) return -1; + break; + } + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; + return j+1; + }else if( c=='"' ){ + /* Parse string */ + u8 jnFlags = 0; + j = i+1; + for(;;){ + c = pParse->zJson[j]; + if( c==0 ) return -1; + if( c=='\\' ){ + c = pParse->zJson[++j]; + if( c==0 ) return -1; + jnFlags = JNODE_ESCAPE; + }else if( c=='"' ){ + break; + } + j++; + } + jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]); + if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; + return j+1; + }else if( c=='n' + && strncmp(pParse->zJson+i,"null",4)==0 + && !safe_isalnum(pParse->zJson[i+4]) ){ + jsonParseAddNode(pParse, JSON_NULL, 0, 0); + return i+4; + }else if( c=='t' + && strncmp(pParse->zJson+i,"true",4)==0 + && !safe_isalnum(pParse->zJson[i+4]) ){ + jsonParseAddNode(pParse, JSON_TRUE, 0, 0); + return i+4; + }else if( c=='f' + && strncmp(pParse->zJson+i,"false",5)==0 + && !safe_isalnum(pParse->zJson[i+5]) ){ + jsonParseAddNode(pParse, JSON_FALSE, 0, 0); + return i+5; + }else if( c=='-' || (c>='0' && c<='9') ){ + /* Parse number */ + u8 seenDP = 0; + u8 seenE = 0; + j = i+1; + for(;; j++){ + c = pParse->zJson[j]; + if( c>='0' && c<='9' ) continue; + if( c=='.' ){ + if( pParse->zJson[j-1]=='-' ) return -1; + if( seenDP ) return -1; + seenDP = 1; + continue; + } + if( c=='e' || c=='E' ){ + if( pParse->zJson[j-1]<'0' ) return -1; + if( seenE ) return -1; + seenDP = seenE = 1; + c = pParse->zJson[j+1]; + if( c=='+' || c=='-' ){ + j++; + c = pParse->zJson[j+1]; + } + if( c<'0' || c>'9' ) return -1; + continue; + } + break; + } + if( pParse->zJson[j-1]<'0' ) return -1; + jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, + j - i, &pParse->zJson[i]); + return j; + }else if( c=='}' ){ + return -2; /* End of {...} */ + }else if( c==']' ){ + return -3; /* End of [...] */ + }else if( c==0 ){ + return 0; /* End of file */ + }else{ + return -1; /* Syntax error */ + } +} + +/* +** Parse a complete JSON string. Return 0 on success or non-zero if there +** are any errors. If an error occurs, free all memory associated with +** pParse. +** +** pParse is uninitialized when this routine is called. +*/ +static int jsonParse( + JsonParse *pParse, /* Initialize and fill this JsonParse object */ + sqlite3_context *pCtx, /* Report errors here */ + const char *zJson /* Input JSON text to be parsed */ +){ + int i; + memset(pParse, 0, sizeof(*pParse)); + if( zJson==0 ) return 1; + pParse->zJson = zJson; + i = jsonParseValue(pParse, 0); + if( pParse->oom ) i = -1; + if( i>0 ){ + while( safe_isspace(zJson[i]) ) i++; + if( zJson[i] ) i = -1; + } + if( i<=0 ){ + if( pCtx!=0 ){ + if( pParse->oom ){ + sqlite3_result_error_nomem(pCtx); + }else{ + sqlite3_result_error(pCtx, "malformed JSON", -1); + } + } + jsonParseReset(pParse); + return 1; + } + return 0; +} + +/* Mark node i of pParse as being a child of iParent. Call recursively +** to fill in all the descendants of node i. +*/ +static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){ + JsonNode *pNode = &pParse->aNode[i]; + u32 j; + pParse->aUp[i] = iParent; + switch( pNode->eType ){ + case JSON_ARRAY: { + for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){ + jsonParseFillInParentage(pParse, i+j, i); + } + break; + } + case JSON_OBJECT: { + for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){ + pParse->aUp[i+j] = i; + jsonParseFillInParentage(pParse, i+j+1, i); + } + break; + } + default: { + break; + } + } +} + +/* +** Compute the parentage of all nodes in a completed parse. +*/ +static int jsonParseFindParents(JsonParse *pParse){ + u32 *aUp; + assert( pParse->aUp==0 ); + aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode ); + if( aUp==0 ){ + pParse->oom = 1; + return SQLITE_NOMEM; + } + jsonParseFillInParentage(pParse, 0, 0); + return SQLITE_OK; +} + +/* +** Compare the OBJECT label at pNode against zKey,nKey. Return true on +** a match. +*/ +static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){ + if( pNode->jnFlags & JNODE_RAW ){ + if( pNode->n!=nKey ) return 0; + return strncmp(pNode->u.zJContent, zKey, nKey)==0; + }else{ + if( pNode->n!=nKey+2 ) return 0; + return strncmp(pNode->u.zJContent+1, zKey, nKey)==0; + } +} + +/* forward declaration */ +static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**); + +/* +** Search along zPath to find the node specified. Return a pointer +** to that node, or NULL if zPath is malformed or if there is no such +** node. +** +** If pApnd!=0, then try to append new nodes to complete zPath if it is +** possible to do so and if no existing node corresponds to zPath. If +** new nodes are appended *pApnd is set to 1. +*/ +static JsonNode *jsonLookupStep( + JsonParse *pParse, /* The JSON to search */ + u32 iRoot, /* Begin the search at this node */ + const char *zPath, /* The path to search */ + int *pApnd, /* Append nodes to complete path if not NULL */ + const char **pzErr /* Make *pzErr point to any syntax error in zPath */ +){ + u32 i, j, nKey; + const char *zKey; + JsonNode *pRoot = &pParse->aNode[iRoot]; + if( zPath[0]==0 ) return pRoot; + if( zPath[0]=='.' ){ + if( pRoot->eType!=JSON_OBJECT ) return 0; + zPath++; + if( zPath[0]=='"' ){ + zKey = zPath + 1; + for(i=1; zPath[i] && zPath[i]!='"'; i++){} + nKey = i-1; + if( zPath[i] ){ + i++; + }else{ + *pzErr = zPath; + return 0; + } + }else{ + zKey = zPath; + for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){} + nKey = i; + } + if( nKey==0 ){ + *pzErr = zPath; + return 0; + } + j = 1; + for(;;){ + while( j<=pRoot->n ){ + if( jsonLabelCompare(pRoot+j, zKey, nKey) ){ + return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr); + } + j++; + j += jsonNodeSize(&pRoot[j]); + } + if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; + iRoot += pRoot->u.iAppend; + pRoot = &pParse->aNode[iRoot]; + j = 1; + } + if( pApnd ){ + u32 iStart, iLabel; + JsonNode *pNode; + iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); + iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath); + zPath += i; + pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); + if( pParse->oom ) return 0; + if( pNode ){ + pRoot = &pParse->aNode[iRoot]; + pRoot->u.iAppend = iStart - iRoot; + pRoot->jnFlags |= JNODE_APPEND; + pParse->aNode[iLabel].jnFlags |= JNODE_RAW; + } + return pNode; + } + }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){ + if( pRoot->eType!=JSON_ARRAY ) return 0; + i = 0; + j = 1; + while( safe_isdigit(zPath[j]) ){ + i = i*10 + zPath[j] - '0'; + j++; + } + if( zPath[j]!=']' ){ + *pzErr = zPath; + return 0; + } + zPath += j + 1; + j = 1; + for(;;){ + while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){ + if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--; + j += jsonNodeSize(&pRoot[j]); + } + if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; + iRoot += pRoot->u.iAppend; + pRoot = &pParse->aNode[iRoot]; + j = 1; + } + if( j<=pRoot->n ){ + return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr); + } + if( i==0 && pApnd ){ + u32 iStart; + JsonNode *pNode; + iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0); + pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); + if( pParse->oom ) return 0; + if( pNode ){ + pRoot = &pParse->aNode[iRoot]; + pRoot->u.iAppend = iStart - iRoot; + pRoot->jnFlags |= JNODE_APPEND; + } + return pNode; + } + }else{ + *pzErr = zPath; + } + return 0; +} + +/* +** Append content to pParse that will complete zPath. Return a pointer +** to the inserted node, or return NULL if the append fails. +*/ +static JsonNode *jsonLookupAppend( + JsonParse *pParse, /* Append content to the JSON parse */ + const char *zPath, /* Description of content to append */ + int *pApnd, /* Set this flag to 1 */ + const char **pzErr /* Make this point to any syntax error */ +){ + *pApnd = 1; + if( zPath[0]==0 ){ + jsonParseAddNode(pParse, JSON_NULL, 0, 0); + return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1]; + } + if( zPath[0]=='.' ){ + jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + }else if( strncmp(zPath,"[0]",3)==0 ){ + jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); + }else{ + return 0; + } + if( pParse->oom ) return 0; + return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr); +} + +/* +** Return the text of a syntax error message on a JSON path. Space is +** obtained from sqlite3_malloc(). +*/ +static char *jsonPathSyntaxError(const char *zErr){ + return sqlite3_mprintf("JSON path error near '%q'", zErr); +} + +/* +** Do a node lookup using zPath. Return a pointer to the node on success. +** Return NULL if not found or if there is an error. +** +** On an error, write an error message into pCtx and increment the +** pParse->nErr counter. +** +** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if +** nodes are appended. +*/ +static JsonNode *jsonLookup( + JsonParse *pParse, /* The JSON to search */ + const char *zPath, /* The path to search */ + int *pApnd, /* Append nodes to complete path if not NULL */ + sqlite3_context *pCtx /* Report errors here, if not NULL */ +){ + const char *zErr = 0; + JsonNode *pNode = 0; + char *zMsg; + + if( zPath==0 ) return 0; + if( zPath[0]!='$' ){ + zErr = zPath; + goto lookup_err; + } + zPath++; + pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr); + if( zErr==0 ) return pNode; + +lookup_err: + pParse->nErr++; + assert( zErr!=0 && pCtx!=0 ); + zMsg = jsonPathSyntaxError(zErr); + if( zMsg ){ + sqlite3_result_error(pCtx, zMsg, -1); + sqlite3_free(zMsg); + }else{ + sqlite3_result_error_nomem(pCtx); + } + return 0; +} + + +/* +** Report the wrong number of arguments for json_insert(), json_replace() +** or json_set(). +*/ +static void jsonWrongNumArgs( + sqlite3_context *pCtx, + const char *zFuncName +){ + char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", + zFuncName); + sqlite3_result_error(pCtx, zMsg, -1); + sqlite3_free(zMsg); +} + + +/**************************************************************************** +** SQL functions used for testing and debugging +****************************************************************************/ + +#ifdef SQLITE_DEBUG +/* +** The json_parse(JSON) function returns a string which describes +** a parse of the JSON provided. Or it returns NULL if JSON is not +** well-formed. +*/ +static void jsonParseFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString s; /* Output string - not real JSON */ + JsonParse x; /* The parse */ + u32 i; + + assert( argc==1 ); + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + jsonParseFindParents(&x); + jsonInit(&s, ctx); + for(i=0; ieType==JSON_ARRAY ){ + assert( (pNode->jnFlags & JNODE_APPEND)==0 ); + for(i=1; i<=pNode->n; n++){ + i += jsonNodeSize(&pNode[i]); + } + } + if( x.nErr==0 ) sqlite3_result_int64(ctx, n); + jsonParseReset(&x); +} + +/* +** json_extract(JSON, PATH, ...) +** +** Return the element described by PATH. Return NULL if there is no +** PATH element. If there are multiple PATHs, then return a JSON array +** with the result from each path. Throw an error if the JSON or any PATH +** is malformed. +*/ +static void jsonExtractFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse x; /* The parse */ + JsonNode *pNode; + const char *zPath; + JsonString jx; + int i; + + if( argc<2 ) return; + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + jsonInit(&jx, ctx); + jsonAppendChar(&jx, '['); + for(i=1; i2 ){ + jsonAppendSeparator(&jx); + if( pNode ){ + jsonRenderNode(pNode, &jx, 0); + }else{ + jsonAppendRaw(&jx, "null", 4); + } + }else if( pNode ){ + jsonReturn(pNode, ctx, 0); + } + } + if( argc>2 && i==argc ){ + jsonAppendChar(&jx, ']'); + jsonResult(&jx); + sqlite3_result_subtype(ctx, JSON_SUBTYPE); + } + jsonReset(&jx); + jsonParseReset(&x); +} + +/* +** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON +** object that contains all name/value given in arguments. Or if any name +** is not a string or if any value is a BLOB, throw an error. +*/ +static void jsonObjectFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + int i; + JsonString jx; + const char *z; + u32 n; + + if( argc&1 ){ + sqlite3_result_error(ctx, "json_object() requires an even number " + "of arguments", -1); + return; + } + jsonInit(&jx, ctx); + jsonAppendChar(&jx, '{'); + for(i=0; ijnFlags |= JNODE_REMOVE; + } + if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){ + jsonReturnJson(x.aNode, ctx, 0); + } +remove_done: + jsonParseReset(&x); +} + +/* +** json_replace(JSON, PATH, VALUE, ...) +** +** Replace the value at PATH with VALUE. If PATH does not already exist, +** this routine is a no-op. If JSON or PATH is malformed, throw an error. +*/ +static void jsonReplaceFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse x; /* The parse */ + JsonNode *pNode; + const char *zPath; + u32 i; + + if( argc<1 ) return; + if( (argc&1)==0 ) { + jsonWrongNumArgs(ctx, "replace"); + return; + } + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + assert( x.nNode ); + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + pNode = jsonLookup(&x, zPath, 0, ctx); + if( x.nErr ) goto replace_err; + if( pNode ){ + pNode->jnFlags |= (u8)JNODE_REPLACE; + pNode->iVal = (u8)(i+1); + } + } + if( x.aNode[0].jnFlags & JNODE_REPLACE ){ + sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); + }else{ + jsonReturnJson(x.aNode, ctx, argv); + } +replace_err: + jsonParseReset(&x); +} + +/* +** json_set(JSON, PATH, VALUE, ...) +** +** Set the value at PATH to VALUE. Create the PATH if it does not already +** exist. Overwrite existing values that do exist. +** If JSON or PATH is malformed, throw an error. +** +** json_insert(JSON, PATH, VALUE, ...) +** +** Create PATH and initialize it to VALUE. If PATH already exists, this +** routine is a no-op. If JSON or PATH is malformed, throw an error. +*/ +static void jsonSetFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse x; /* The parse */ + JsonNode *pNode; + const char *zPath; + u32 i; + int bApnd; + int bIsSet = *(int*)sqlite3_user_data(ctx); + + if( argc<1 ) return; + if( (argc&1)==0 ) { + jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); + return; + } + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + assert( x.nNode ); + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + bApnd = 0; + pNode = jsonLookup(&x, zPath, &bApnd, ctx); + if( x.oom ){ + sqlite3_result_error_nomem(ctx); + goto jsonSetDone; + }else if( x.nErr ){ + goto jsonSetDone; + }else if( pNode && (bApnd || bIsSet) ){ + pNode->jnFlags |= (u8)JNODE_REPLACE; + pNode->iVal = (u8)(i+1); + } + } + if( x.aNode[0].jnFlags & JNODE_REPLACE ){ + sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); + }else{ + jsonReturnJson(x.aNode, ctx, argv); + } +jsonSetDone: + jsonParseReset(&x); +} + +/* +** json_type(JSON) +** json_type(JSON, PATH) +** +** Return the top-level "type" of a JSON string. Throw an error if +** either the JSON or PATH inputs are not well-formed. +*/ +static void jsonTypeFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse x; /* The parse */ + const char *zPath; + JsonNode *pNode; + + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + assert( x.nNode ); + if( argc==2 ){ + zPath = (const char*)sqlite3_value_text(argv[1]); + pNode = jsonLookup(&x, zPath, 0, ctx); + }else{ + pNode = x.aNode; + } + if( pNode ){ + sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); + } + jsonParseReset(&x); +} + +/* +** json_valid(JSON) +** +** Return 1 if JSON is a well-formed JSON string according to RFC-7159. +** Return 0 otherwise. +*/ +static void jsonValidFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse x; /* The parse */ + int rc = 0; + + UNUSED_PARAM(argc); + if( jsonParse(&x, 0, (const char*)sqlite3_value_text(argv[0]))==0 ){ + rc = 1; + } + jsonParseReset(&x); + sqlite3_result_int(ctx, rc); +} + + +/**************************************************************************** +** Aggregate SQL function implementations +****************************************************************************/ +/* +** json_group_array(VALUE) +** +** Return a JSON array composed of all values in the aggregate. +*/ +static void jsonArrayStep( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString *pStr; + UNUSED_PARAM(argc); + pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); + if( pStr ){ + if( pStr->zBuf==0 ){ + jsonInit(pStr, ctx); + jsonAppendChar(pStr, '['); + }else{ + jsonAppendChar(pStr, ','); + pStr->pCtx = ctx; + } + jsonAppendValue(pStr, argv[0]); + } +} +static void jsonArrayFinal(sqlite3_context *ctx){ + JsonString *pStr; + pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); + if( pStr ){ + pStr->pCtx = ctx; + jsonAppendChar(pStr, ']'); + if( pStr->bErr ){ + if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); + assert( pStr->bStatic ); + }else{ + sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, + pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); + pStr->bStatic = 1; + } + }else{ + sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); + } + sqlite3_result_subtype(ctx, JSON_SUBTYPE); +} + +/* +** json_group_obj(NAME,VALUE) +** +** Return a JSON object composed of all names and values in the aggregate. +*/ +static void jsonObjectStep( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString *pStr; + const char *z; + u32 n; + UNUSED_PARAM(argc); + pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); + if( pStr ){ + if( pStr->zBuf==0 ){ + jsonInit(pStr, ctx); + jsonAppendChar(pStr, '{'); + }else{ + jsonAppendChar(pStr, ','); + pStr->pCtx = ctx; + } + z = (const char*)sqlite3_value_text(argv[0]); + n = (u32)sqlite3_value_bytes(argv[0]); + jsonAppendString(pStr, z, n); + jsonAppendChar(pStr, ':'); + jsonAppendValue(pStr, argv[1]); + } +} +static void jsonObjectFinal(sqlite3_context *ctx){ + JsonString *pStr; + pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); + if( pStr ){ + jsonAppendChar(pStr, '}'); + if( pStr->bErr ){ + if( pStr->bErr==0 ) sqlite3_result_error_nomem(ctx); + assert( pStr->bStatic ); + }else{ + sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, + pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); + pStr->bStatic = 1; + } + }else{ + sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); + } + sqlite3_result_subtype(ctx, JSON_SUBTYPE); +} + + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/**************************************************************************** +** The json_each virtual table +****************************************************************************/ +typedef struct JsonEachCursor JsonEachCursor; +struct JsonEachCursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + u32 iRowid; /* The rowid */ + u32 iBegin; /* The first node of the scan */ + u32 i; /* Index in sParse.aNode[] of current row */ + u32 iEnd; /* EOF when i equals or exceeds this value */ + u8 eType; /* Type of top-level element */ + u8 bRecursive; /* True for json_tree(). False for json_each() */ + char *zJson; /* Input JSON */ + char *zRoot; /* Path by which to filter zJson */ + JsonParse sParse; /* Parse of the input JSON */ +}; + +/* Constructor for the json_each virtual table */ +static int jsonEachConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + sqlite3_vtab *pNew; + int rc; + +/* Column numbers */ +#define JEACH_KEY 0 +#define JEACH_VALUE 1 +#define JEACH_TYPE 2 +#define JEACH_ATOM 3 +#define JEACH_ID 4 +#define JEACH_PARENT 5 +#define JEACH_FULLKEY 6 +#define JEACH_PATH 7 +#define JEACH_JSON 8 +#define JEACH_ROOT 9 + + UNUSED_PARAM(pzErr); + UNUSED_PARAM(argv); + UNUSED_PARAM(argc); + UNUSED_PARAM(pAux); + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path," + "json HIDDEN,root HIDDEN)"); + if( rc==SQLITE_OK ){ + pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + } + return rc; +} + +/* destructor for json_each virtual table */ +static int jsonEachDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} + +/* constructor for a JsonEachCursor object for json_each(). */ +static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + JsonEachCursor *pCur; + + UNUSED_PARAM(p); + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* constructor for a JsonEachCursor object for json_tree(). */ +static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + int rc = jsonEachOpenEach(p, ppCursor); + if( rc==SQLITE_OK ){ + JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; + pCur->bRecursive = 1; + } + return rc; +} + +/* Reset a JsonEachCursor back to its original state. Free any memory +** held. */ +static void jsonEachCursorReset(JsonEachCursor *p){ + sqlite3_free(p->zJson); + sqlite3_free(p->zRoot); + jsonParseReset(&p->sParse); + p->iRowid = 0; + p->i = 0; + p->iEnd = 0; + p->eType = 0; + p->zJson = 0; + p->zRoot = 0; +} + +/* Destructor for a jsonEachCursor object */ +static int jsonEachClose(sqlite3_vtab_cursor *cur){ + JsonEachCursor *p = (JsonEachCursor*)cur; + jsonEachCursorReset(p); + sqlite3_free(cur); + return SQLITE_OK; +} + +/* Return TRUE if the jsonEachCursor object has been advanced off the end +** of the JSON object */ +static int jsonEachEof(sqlite3_vtab_cursor *cur){ + JsonEachCursor *p = (JsonEachCursor*)cur; + return p->i >= p->iEnd; +} + +/* Advance the cursor to the next element for json_tree() */ +static int jsonEachNext(sqlite3_vtab_cursor *cur){ + JsonEachCursor *p = (JsonEachCursor*)cur; + if( p->bRecursive ){ + if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++; + p->i++; + p->iRowid++; + if( p->iiEnd ){ + u32 iUp = p->sParse.aUp[p->i]; + JsonNode *pUp = &p->sParse.aNode[iUp]; + p->eType = pUp->eType; + if( pUp->eType==JSON_ARRAY ){ + if( iUp==p->i-1 ){ + pUp->u.iKey = 0; + }else{ + pUp->u.iKey++; + } + } + } + }else{ + switch( p->eType ){ + case JSON_ARRAY: { + p->i += jsonNodeSize(&p->sParse.aNode[p->i]); + p->iRowid++; + break; + } + case JSON_OBJECT: { + p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]); + p->iRowid++; + break; + } + default: { + p->i = p->iEnd; + break; + } + } + } + return SQLITE_OK; +} + +/* Append the name of the path for element i to pStr +*/ +static void jsonEachComputePath( + JsonEachCursor *p, /* The cursor */ + JsonString *pStr, /* Write the path here */ + u32 i /* Path to this element */ +){ + JsonNode *pNode, *pUp; + u32 iUp; + if( i==0 ){ + jsonAppendChar(pStr, '$'); + return; + } + iUp = p->sParse.aUp[i]; + jsonEachComputePath(p, pStr, iUp); + pNode = &p->sParse.aNode[i]; + pUp = &p->sParse.aNode[iUp]; + if( pUp->eType==JSON_ARRAY ){ + jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); + }else{ + assert( pUp->eType==JSON_OBJECT ); + if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--; + assert( pNode->eType==JSON_STRING ); + assert( pNode->jnFlags & JNODE_LABEL ); + jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1); + } +} + +/* Return the value of a column */ +static int jsonEachColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + JsonEachCursor *p = (JsonEachCursor*)cur; + JsonNode *pThis = &p->sParse.aNode[p->i]; + switch( i ){ + case JEACH_KEY: { + if( p->i==0 ) break; + if( p->eType==JSON_OBJECT ){ + jsonReturn(pThis, ctx, 0); + }else if( p->eType==JSON_ARRAY ){ + u32 iKey; + if( p->bRecursive ){ + if( p->iRowid==0 ) break; + iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey; + }else{ + iKey = p->iRowid; + } + sqlite3_result_int64(ctx, (sqlite3_int64)iKey); + } + break; + } + case JEACH_VALUE: { + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + jsonReturn(pThis, ctx, 0); + break; + } + case JEACH_TYPE: { + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); + break; + } + case JEACH_ATOM: { + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + if( pThis->eType>=JSON_ARRAY ) break; + jsonReturn(pThis, ctx, 0); + break; + } + case JEACH_ID: { + sqlite3_result_int64(ctx, + (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0)); + break; + } + case JEACH_PARENT: { + if( p->i>p->iBegin && p->bRecursive ){ + sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]); + } + break; + } + case JEACH_FULLKEY: { + JsonString x; + jsonInit(&x, ctx); + if( p->bRecursive ){ + jsonEachComputePath(p, &x, p->i); + }else{ + if( p->zRoot ){ + jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot)); + }else{ + jsonAppendChar(&x, '$'); + } + if( p->eType==JSON_ARRAY ){ + jsonPrintf(30, &x, "[%d]", p->iRowid); + }else{ + jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1); + } + } + jsonResult(&x); + break; + } + case JEACH_PATH: { + if( p->bRecursive ){ + JsonString x; + jsonInit(&x, ctx); + jsonEachComputePath(p, &x, p->sParse.aUp[p->i]); + jsonResult(&x); + break; + } + /* For json_each() path and root are the same so fall through + ** into the root case */ + } + case JEACH_ROOT: { + const char *zRoot = p->zRoot; + if( zRoot==0 ) zRoot = "$"; + sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); + break; + } + case JEACH_JSON: { + assert( i==JEACH_JSON ); + sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); + break; + } + } + return SQLITE_OK; +} + +/* Return the current rowid value */ +static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + JsonEachCursor *p = (JsonEachCursor*)cur; + *pRowid = p->iRowid; + return SQLITE_OK; +} + +/* The query strategy is to look for an equality constraint on the json +** column. Without such a constraint, the table cannot operate. idxNum is +** 1 if the constraint is found, 3 if the constraint and zRoot are found, +** and 0 otherwise. +*/ +static int jsonEachBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + int i; + int jsonIdx = -1; + int rootIdx = -1; + const struct sqlite3_index_constraint *pConstraint; + + UNUSED_PARAM(tab); + pConstraint = pIdxInfo->aConstraint; + for(i=0; inConstraint; i++, pConstraint++){ + if( pConstraint->usable==0 ) continue; + if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; + switch( pConstraint->iColumn ){ + case JEACH_JSON: jsonIdx = i; break; + case JEACH_ROOT: rootIdx = i; break; + default: /* no-op */ break; + } + } + if( jsonIdx<0 ){ + pIdxInfo->idxNum = 0; + pIdxInfo->estimatedCost = 1e99; + }else{ + pIdxInfo->estimatedCost = 1.0; + pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1; + pIdxInfo->aConstraintUsage[jsonIdx].omit = 1; + if( rootIdx<0 ){ + pIdxInfo->idxNum = 1; + }else{ + pIdxInfo->aConstraintUsage[rootIdx].argvIndex = 2; + pIdxInfo->aConstraintUsage[rootIdx].omit = 1; + pIdxInfo->idxNum = 3; + } + } + return SQLITE_OK; +} + +/* Start a search on a new JSON string */ +static int jsonEachFilter( + sqlite3_vtab_cursor *cur, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + JsonEachCursor *p = (JsonEachCursor*)cur; + const char *z; + const char *zRoot = 0; + sqlite3_int64 n; + + UNUSED_PARAM(idxStr); + UNUSED_PARAM(argc); + jsonEachCursorReset(p); + if( idxNum==0 ) return SQLITE_OK; + z = (const char*)sqlite3_value_text(argv[0]); + if( z==0 ) return SQLITE_OK; + n = sqlite3_value_bytes(argv[0]); + p->zJson = sqlite3_malloc64( n+1 ); + if( p->zJson==0 ) return SQLITE_NOMEM; + memcpy(p->zJson, z, (size_t)n+1); + if( jsonParse(&p->sParse, 0, p->zJson) ){ + int rc = SQLITE_NOMEM; + if( p->sParse.oom==0 ){ + sqlite3_free(cur->pVtab->zErrMsg); + cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); + if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR; + } + jsonEachCursorReset(p); + return rc; + }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){ + jsonEachCursorReset(p); + return SQLITE_NOMEM; + }else{ + JsonNode *pNode = 0; + if( idxNum==3 ){ + const char *zErr = 0; + zRoot = (const char*)sqlite3_value_text(argv[1]); + if( zRoot==0 ) return SQLITE_OK; + n = sqlite3_value_bytes(argv[1]); + p->zRoot = sqlite3_malloc64( n+1 ); + if( p->zRoot==0 ) return SQLITE_NOMEM; + memcpy(p->zRoot, zRoot, (size_t)n+1); + if( zRoot[0]!='$' ){ + zErr = zRoot; + }else{ + pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr); + } + if( zErr ){ + sqlite3_free(cur->pVtab->zErrMsg); + cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr); + jsonEachCursorReset(p); + return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; + }else if( pNode==0 ){ + return SQLITE_OK; + } + }else{ + pNode = p->sParse.aNode; + } + p->iBegin = p->i = (int)(pNode - p->sParse.aNode); + p->eType = pNode->eType; + if( p->eType>=JSON_ARRAY ){ + pNode->u.iKey = 0; + p->iEnd = p->i + pNode->n + 1; + if( p->bRecursive ){ + p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType; + if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){ + p->i--; + } + }else{ + p->i++; + } + }else{ + p->iEnd = p->i+1; + } + } + return SQLITE_OK; +} + +/* The methods of the json_each virtual table */ +static sqlite3_module jsonEachModule = { + 0, /* iVersion */ + 0, /* xCreate */ + jsonEachConnect, /* xConnect */ + jsonEachBestIndex, /* xBestIndex */ + jsonEachDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + jsonEachOpenEach, /* xOpen - open a cursor */ + jsonEachClose, /* xClose - close a cursor */ + jsonEachFilter, /* xFilter - configure scan constraints */ + jsonEachNext, /* xNext - advance a cursor */ + jsonEachEof, /* xEof - check for end of scan */ + jsonEachColumn, /* xColumn - read data */ + jsonEachRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0 /* xRollbackTo */ +}; + +/* The methods of the json_tree virtual table. */ +static sqlite3_module jsonTreeModule = { + 0, /* iVersion */ + 0, /* xCreate */ + jsonEachConnect, /* xConnect */ + jsonEachBestIndex, /* xBestIndex */ + jsonEachDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + jsonEachOpenTree, /* xOpen - open a cursor */ + jsonEachClose, /* xClose - close a cursor */ + jsonEachFilter, /* xFilter - configure scan constraints */ + jsonEachNext, /* xNext - advance a cursor */ + jsonEachEof, /* xEof - check for end of scan */ + jsonEachColumn, /* xColumn - read data */ + jsonEachRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0 /* xRollbackTo */ +}; +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +/**************************************************************************** +** The following routines are the only publically visible identifiers in this +** file. Call the following routines in order to register the various SQL +** functions and the virtual table implemented by this file. +****************************************************************************/ + +int sqlite3Json1Init(sqlite3 *db){ + int rc = SQLITE_OK; + unsigned int i; + static const struct { + const char *zName; + int nArg; + int flag; + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + } aFunc[] = { + { "json", 1, 0, jsonRemoveFunc }, + { "json_array", -1, 0, jsonArrayFunc }, + { "json_array_length", 1, 0, jsonArrayLengthFunc }, + { "json_array_length", 2, 0, jsonArrayLengthFunc }, + { "json_extract", -1, 0, jsonExtractFunc }, + { "json_insert", -1, 0, jsonSetFunc }, + { "json_object", -1, 0, jsonObjectFunc }, + { "json_remove", -1, 0, jsonRemoveFunc }, + { "json_replace", -1, 0, jsonReplaceFunc }, + { "json_set", -1, 1, jsonSetFunc }, + { "json_type", 1, 0, jsonTypeFunc }, + { "json_type", 2, 0, jsonTypeFunc }, + { "json_valid", 1, 0, jsonValidFunc }, + +#if SQLITE_DEBUG + /* DEBUG and TESTING functions */ + { "json_parse", 1, 0, jsonParseFunc }, + { "json_test1", 1, 0, jsonTest1Func }, +#endif + }; + static const struct { + const char *zName; + int nArg; + void (*xStep)(sqlite3_context*,int,sqlite3_value**); + void (*xFinal)(sqlite3_context*); + } aAgg[] = { + { "json_group_array", 1, jsonArrayStep, jsonArrayFinal }, + { "json_group_object", 2, jsonObjectStep, jsonObjectFinal }, + }; +#ifndef SQLITE_OMIT_VIRTUALTABLE + static const struct { + const char *zName; + sqlite3_module *pModule; + } aMod[] = { + { "json_each", &jsonEachModule }, + { "json_tree", &jsonTreeModule }, + }; +#endif + for(i=0; i