diff --git a/ext/fts5/test/fts5leftjoin.test b/ext/fts5/test/fts5leftjoin.test new file mode 100644 index 0000000000..f13ca5206b --- /dev/null +++ b/ext/fts5/test/fts5leftjoin.test @@ -0,0 +1,45 @@ +# 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 fts5leftjoin + +# If SQLITE_ENABLE_FTS5 is not defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE vt USING fts5(x); + INSERT INTO vt VALUES('abc'); + INSERT INTO vt VALUES('xyz'); + + CREATE TABLE t1(a INTEGER PRIMARY KEY); + INSERT INTO t1 VALUES(1), (2); +} + +do_execsql_test 1.1 { + SELECT * FROM t1 LEFT JOIN ( + SELECT rowid AS rrr, * FROM vt WHERE vt MATCH 'abc' + ) ON t1.a = rrr +} {1 1 abc 2 {} {}} + +do_execsql_test 1.2 { + SELECT * FROM t1 LEFT JOIN vt ON (vt MATCH 'abc') +} {1 abc 2 abc} + +finish_test + + diff --git a/ext/misc/csv.c b/ext/misc/csv.c index f887784ab8..6d99634274 100644 --- a/ext/misc/csv.c +++ b/ext/misc/csv.c @@ -77,6 +77,7 @@ struct CsvReader { int n; /* Number of bytes in z */ int nAlloc; /* Space allocated for z[] */ int nLine; /* Current line number */ + int bNotFirst; /* True if prior text has been seen */ char cTerm; /* Character that terminated the most recent field */ size_t iIn; /* Next unread character in the input buffer */ size_t nIn; /* Number of characters in the input buffer */ @@ -91,6 +92,7 @@ static void csv_reader_init(CsvReader *p){ p->n = 0; p->nAlloc = 0; p->nLine = 0; + p->bNotFirst = 0; p->nIn = 0; p->zIn = 0; p->zErr[0] = 0; @@ -251,6 +253,21 @@ static char *csv_read_one_field(CsvReader *p){ pc = c; } }else{ + /* If this is the first field being parsed and it begins with the + ** UTF-8 BOM (0xEF BB BF) then skip the BOM */ + if( (c&0xff)==0xef && p->bNotFirst==0 ){ + csv_append(p, (char)c); + c = csv_getc(p); + if( (c&0xff)==0xbb ){ + csv_append(p, (char)c); + c = csv_getc(p); + if( (c&0xff)==0xbf ){ + p->bNotFirst = 1; + p->n = 0; + return csv_read_one_field(p); + } + } + } while( c>',' || (c!=EOF && c!=',' && c!='\n') ){ if( csv_append(p, (char)c) ) return 0; c = csv_getc(p); @@ -262,6 +279,7 @@ static char *csv_read_one_field(CsvReader *p){ p->cTerm = (char)c; } if( p->z ) p->z[p->n] = 0; + p->bNotFirst = 1; return p->z; } diff --git a/manifest b/manifest index 795c5df67f..58683ef5d7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Consider\sthe\svalues\sbound\sto\sSQL\svariables\swhen\sdetermining\swhether\sor\snot\sa\npartial\sindex\smay\sbe\sused. -D 2017-06-24T18:10:29.777 +C Merge\sthe\sin\sthe\slatest\senhancements\sfrom\strunk. +D 2017-06-28T18:07:29.453 F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 8eeb80162074004e906b53d7340a12a14c471a83743aab975947e95ce061efcc @@ -168,6 +168,7 @@ F ext/fts5/test/fts5fuzz1.test bece4695fc169b61ab236ada7931c6e4942cbef9 F ext/fts5/test/fts5hash.test 06f9309ccb4d5050a131594e9e47d0b21456837d F ext/fts5/test/fts5integrity.test f5e4f8d284385875068ad0f3e894ce43e9de835d F ext/fts5/test/fts5lastrowid.test 4fac1aba696dd6c956e03b0cf91f6f1f3aaec494 +F ext/fts5/test/fts5leftjoin.test 513ad7a7c053f8a6b7968ed6c84d1fc8c7a84fd29cfde0d14cc085ae6ca682c6 F ext/fts5/test/fts5matchinfo.test f7dde99697bcb310ea8faa8eb2714d9f4dfc0e1b F ext/fts5/test/fts5merge.test 9f65f090d214ff865c56bef4f864aaa1182af6e3 F ext/fts5/test/fts5merge2.test a6da3c16d694235938d1939f503cfa53f0943d75 @@ -214,7 +215,7 @@ F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a2 F ext/misc/carray.c 40c27641010a4dc67e3690bdb7c9d36ca58b3c2d F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704 F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83 -F ext/misc/csv.c 531a46cbad789fca0aa9db69a0e6c8ac9e68767d +F ext/misc/csv.c d91c0388445b08f6e373dd0e8fc024d4551b1fcaf64e876a1c3f4fac8a63adc2 F ext/misc/dbdump.c 3509fa6b8932d04e932d6b6b827b6a82ca362781b8e8f3c77336f416793e215e F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2 F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f @@ -341,17 +342,17 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c 3b23977620ce9662ac54443f65b87ba996e36121 +F src/alter.c 850ede4e607f12fa25ea4f3cb6ece2b2e29d1aa50e3f786ce49d615788849552 F src/analyze.c 0d0ccf7520a201d8747ea2f02c92c26e26f801bc161f714f27b9f7630dde0421 F src/attach.c 3bd555e28382603e80d430dfebb2270f86e1e375b4c4be3e1ab1aec3a0c44943 F src/auth.c 79f96c6f33bf0e5da8d1c282cee5ebb1852bb8a6ccca3e485d7c459b035d9c3c F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca -F src/btree.c 430e34151e6ef37e42d3f956bb062907c80ff91e1380704b967b8c1a02a98f64 +F src/btree.c 00579ff9c2831d6f98cc993f8f2a34c0ff996e89b3cd2f27928f75796bc3a58a F src/btree.h 3edc5329bc59534d2d15b4f069a9f54b779a7e51289e98fa481ae3c0e526a5ca F src/btreeInt.h a392d353104b4add58b4a59cb185f5d5693dde832c565b77d8d4c343ed98f610 -F src/build.c 88a8cdc11d1c081ed565aa3e795bdf9160f4556463b4c4555e9860b59dd80340 +F src/build.c b24e0889ba18ba0e93e03e2ef5c9f1a2ca043d77c5abbd3d333858a76b795da3 F src/callback.c 2e76147783386374bf01b227f752c81ec872d730 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c e9a6db1321c2353fe922533f202b85abb3084cdf569450abcabf55e21e104550 @@ -368,9 +369,9 @@ F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c bb70abf32c7c926745eb550938db9132309584a667a44c2db0e5fa3207600391 -F src/legacy.c e88ed13c2d531decde75d42c2e35623fb9ce3cb0 +F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e F src/loadext.c a72909474dadce771d3669bf84bf689424f6f87d471fee898589c3ef9b2acfd9 -F src/main.c 18f2145d572069dae91161add89446aec680aab296492a92ae5afcc2fc7c6b5a +F src/main.c 747ec45346c3826113bc081cafe1aa2df945e50540c4b3fb13ec02b5e231c3db F src/malloc.c e20bb2b48abec52d3faf01cce12e8b4f95973755fafec98d45162dfdab111978 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@ -394,28 +395,28 @@ F src/os_win.c 2a6c73eef01c51a048cc4ddccd57f981afbec18a F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 14f6982c470c05b8e85575c69e9c1712010602e20400f8670d8699e21283e0e4 F src/pager.h f2a99646c5533ffe11afa43e9e0bea74054e4efa -F src/parse.y 0513387ce02fea97897d8caef82d45f347818593f24f1bdc48e0c530a8af122d +F src/parse.y b13c9fc83cb634daf7fd5fef89127e8eafdf4904ab9a168d3e1862c5a3c7ae22 F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870 F src/pcache.h 521bb9610d38ef17a3cc9b5ddafd4546c2ea67fa3d0e464823d73c2a28d50e11 F src/pcache1.c 1195a21fe28e223e024f900b2011e80df53793f0356a24caace4188b098540dc F src/pragma.c 2362670a9d28b71708aecb2b9b10b3f7be71f4c950961c07e81dc400e3ce6371 -F src/pragma.h a8a949000214fefb6210330eed8ccbbb4f752619a9871f31b3dedd4a240277fd -F src/prepare.c b1140c3d0cf59bc85ace00ce363153041b424b7a +F src/pragma.h 99d3df4a3d2f12c5227ad403f767334910e6356325b6d155a9a99b4037093460 +F src/prepare.c a80a740b306a5fb2f2594d68776aade4ce1920687932e7c4dc0320ebdadcbb5d F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c d1e69759e7a79c156c692793f5d16f82f9a60ce5e82efd95e4374b2423034946 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac F src/select.c 741937503c74d85e64828b63d5a4219d3cfce480a717efef635839606001b1ba -F src/shell.c 2026e88e7892ba177eae79936285d781f1c449f7a7b4e8d86fd02739d4ead26b -F src/sqlite.h.in 67fa8bd29808e7988e0ce36c8d4c6043eb1727f94522fc612687aa5af51931e6 +F src/shell.c 227b86f2bdd707d0a177a4805a5c0b0378ef8337ab1ad04f5d79dc479568735a +F src/sqlite.h.in 2555ff1b79a1aadeb4eb761740351dc3027fa08120bf84511633ba75a630e7a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28 -F src/sqliteInt.h 770fd49c27345a46c9864470318aa0c384148128ab9ff6d8ea28d79720a326ce +F src/sqliteInt.h 37f1a9a3266aa7b11126585314cd98cf11ba6f174b1244de2221270107ea754d F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 -F src/tclsqlite.c 1ac29f18b1b3787a30b45dbbdf6fdc4aa4f1a2f8c7c8fe586beba1b177eba97d -F src/test1.c c99f0442918a7a5d5b68a95d6024c211989e6c782c15ced5a558994baaf76a5e +F src/tclsqlite.c cbf6313f86400acdf7dbf55fcd218cd28d43110a1210967efbc4f250646f81c0 +F src/test1.c 735f7711e787f30ad4e0001220c580ce456d9f731e22e0e5f86dd5c7e41ccd4d F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5 F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6 @@ -472,13 +473,13 @@ F src/update.c c443935c652af9365e033f756550b5032d02e1b06eb2cb890ed7511ae0c051dc F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c F src/util.c fc081ec6f63448dcd80d3dfad35baecfa104823254a815b081a4d9fe76e1db23 F src/vacuum.c 874c0f2f15ab2908748297d587d22d485ea96d55aaec91d4775dddb2e24d2ecf -F src/vdbe.c 6783778df820f3e0c68289fe5d12ddd34168b0eb1acf248668fec6e2ea1012d5 +F src/vdbe.c 50f4f47bb190099b61fe87e239de17ad00636a522a271dd9b28329053091401d F src/vdbe.h 70a409d171d4e51b962f0d53abf15c33c404c6aa4c9d62fb3a931b5a62ba9615 F src/vdbeInt.h cdcdabad4f5d6bf7a3beb826a7f33ee6f8f1cb220042bedd5b7d4bf2ea1d179f F src/vdbeapi.c c961d8d9e0f52e2df60a6ddbbccd7d99dc4d00103db7e53f77fcef44fbd23178 -F src/vdbeaux.c bc9b3228f6d99bef0d0ecaf3a0e0e8358b3873242d0d2fe944226de3fdf9521e +F src/vdbeaux.c d7c7a57f59dc22c05e9a16177615f604fe73588b0ebdc84b540ba5efe3ada430 F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9 -F src/vdbemem.c 94b17d851f31d4fd075d47d373d4b33ed3962a6ecb82cf385018025751091360 +F src/vdbemem.c 8d78df62becfd2dce3c317f64b32a94ecaff8346d814bc8b0b877b38a1ad3718 F src/vdbesort.c f512c68d0bf7e0105316a5594c4329358c8ee9cae3b25138df041d97516c0372 F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834 F src/vtab.c 35b9bdc2b41de32a417141d12097bcc4e29a77ed7cdb8f836d1d2305d946b61b @@ -489,7 +490,7 @@ F src/walker.c d46044e7a5842560dfe7122d93ff5145dd4a96f4d0bf5ba5910a7731b8c01e79 F src/where.c 563cd034b1d09e6b64a88cafc47a6f37de708d07d03c68b1d4185d8b7f3618bf F src/whereInt.h 2a4b634d63ce488b46d4b0da8f2eaa8f9aeab202bc25ef76f007de5e3fba1f20 F src/wherecode.c f17f5d51e372168db51af637e265aa5e80f99fcc81bfead96b66e71a7732bc62 -F src/whereexpr.c 5567f180ad1c4b278fb7b5d0c9d2904a0fc570bb2fa802ae0b2f7981f4ff31ea +F src/whereexpr.c fa51927cc6830b9d3155cafa4e589452ec023fe313a56550d2079dca6c52fbd8 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d @@ -504,7 +505,7 @@ F test/alter4.test b6d7b86860111864f6cddb54af313f5862dda23b F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f F test/analyze.test 3eb35a4af972f98422e5dc0586501b17d103d321 -F test/analyze3.test 1dccda46a6c374018af617fba00bfe297a61d442 +F test/analyze3.test 8b3ef8ba6d1096b76c40e0925c0fe51e700d2b779cdda40914580de3f9b9d80f F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213 F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4 F test/analyze6.test f1c552ce39cca4ec922a7e4e0e5d0203d6b3281f @@ -797,7 +798,7 @@ F test/fts3expr5.test f9abfffbf5e53d48a33e12a1e8f8ba2c551c9b49 F test/fts3fault.test 3764ecffb3d341c5b05b3abe64153f385880035e67706ca2fc719e5d3352aedb F test/fts3fault2.test 536bbe01fe2946ec24b063a5eee813e8fd90354a6ca0b8f941d299c405edd17e F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641 -F test/fts3join.test 34750f3ce1e29b2749eaf0f1be2fa6301c5d50da +F test/fts3join.test a758accc808cebaef8d622aac07994a2eae15c40eebc40888dcbbabc6f6bafb6 F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6 F test/fts3matchinfo.test ce864e0bd92429df8008f31cf557269ba172482a F test/fts3misc.test 66e7b59576ce2c795f0baff6d47f7f6f57e6f41101cf85fad05989e43bb060dd @@ -929,7 +930,7 @@ F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff F test/kvtest.c d2b8cfc91047ebf6cac4f3a04f19c3a864e4ecfd683bbb65c395df450b8dc79c F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 -F test/like.test 0603f4fa0dad50987f70032c05800cbfa8985302 +F test/like.test e7b1e724c731a219c4338e37cfe2c5861cd1cd7a856bbdd1d6045ae4f83dc7c7 F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da F test/like3.test 3608a2042b6f922f900fbfd5d3ce4e7eca57f7c4 F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e @@ -1127,11 +1128,11 @@ 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 50226a3a66bbd42a902e9f7698f768927eb33a56e9cfc55b7c157c38eb3e80ac +F test/shell1.test 65f55c120ab289bc72ec0e534d104e078124d94aeac75dc7444c338c4d84fd0d F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b F test/shell3.test 9b95ba643eaa228376f06a898fb410ee9b6e57c1 F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d -F test/shell5.test 50a732c1c2158b1cd62cf53975ce1ea7ce6b9dc9 +F test/shell5.test 0d973866d0df8501486a840f51d1502ab0d9b38ca12c9b242ee26adc788af576 F test/shell6.test ab1592ebe881371f651f18ee6a0df21cbfb5310f88cb832ab642d4038f679772 F test/shell7.test 07751911b294698e0c5df67bcbd29e7d2f0f2907 F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 @@ -1188,7 +1189,7 @@ F test/tabfunc01.test 699251cb99651415218a891384510a685c7ab012 F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 -F test/tclsqlite.test 1d73b9203b1ca8798d7d7310742b8d3febc0d56e +F test/tclsqlite.test c3d7ac9449634b9f17fd048a3c0212e88a7448be810a9c5bd051acc1ffa00d2f F test/tempdb.test bd92eba8f20e16a9136e434e20b280794de3cdb6 F test/tempdb2.test 27e41ed540b2f9b056c2e77e9bddc1b875358507 F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900 @@ -1509,8 +1510,8 @@ F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f -F tool/lemon.c f4f1045743e12f86b132253a3192ef92c94bfceb7f41ac41b8e3b373aa78474e -F tool/lempar.c db1bdb4821f2d8fbd76e577cf3ab18642c8d08d1 +F tool/lemon.c 5a04dff28578a67415cea5bf981b893c50cebfdd4388fb21254d1892525edfd8 +F tool/lempar.c f0dc07c2838febff4c34244651a6932fceb523065e6fe79bacfaa93019cc8cca F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9 F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca @@ -1522,7 +1523,7 @@ F tool/mkmsvcmin.tcl cbd93f1cfa3a0a9ae56fc958510aa3fc3ac65e29cb111716199e3d0e66e F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c F tool/mkopcodeh.tcl a01d2c1d8a6205b03fc635adf3735b4c523befd3 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e -F tool/mkpragmatab.tcl bdd4c76449e9e0874ae7f0846868c42583e63b47a081b177a97f94e2b702b3e7 +F tool/mkpragmatab.tcl aa94395a91b5bd47022b7db0c08126f047887e0d299cc19ec1c23a9e5b136961 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb F tool/mksqlite3c.tcl 226da6d794d7d43a31e159a6fa89db867bf1f5eafe4b37d031222287ef8dbadc @@ -1584,10 +1585,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c2ea62937ec8fabec72d3c7cd38d8e2cabbb5ce48638f8ce7ebefd6cd2716fd3 -R b8e9da98ffddd11a474e506223755851 -T *branch * partial-index-variables -T *sym-partial-index-variables * -T -sym-trunk * -U dan -Z 8e348d414463386c5669d14e46f9f0ff +P 7b59c353b805c64689b4ae9df347705acbb5f116346ad77af8ce087da7893747 f02a54599de7620438aecd3753199fc52ce8919d7503bb8b2f5592b0e51dbf8c +R 6145771861a818bdd35ee8936bd678fa +U drh +Z 027c22f2095cba4a04a80b38d45bc197 diff --git a/manifest.uuid b/manifest.uuid index 34b7cb6ce6..d6c36f7800 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7b59c353b805c64689b4ae9df347705acbb5f116346ad77af8ce087da7893747 \ No newline at end of file +8f63c5863231eba7f853f9587b58a81102c31708402fa9962a6e91aa622fad13 \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index 067cbb896d..8df06f0640 100644 --- a/src/alter.c +++ b/src/alter.c @@ -375,7 +375,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){ ** Or, if zName is not a system table, zero is returned. */ static int isSystemTable(Parse *pParse, const char *zName){ - if( sqlite3Strlen30(zName)>6 && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ + if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ sqlite3ErrorMsg(pParse, "table %s may not be altered", zName); return 1; } diff --git a/src/btree.c b/src/btree.c index 1f06e45031..be6c0dd171 100644 --- a/src/btree.c +++ b/src/btree.c @@ -152,7 +152,7 @@ static int hasSharedCacheTableLock( ** Return true immediately. */ if( (pBtree->sharable==0) - || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted)) + || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommit)) ){ return 1; } @@ -229,7 +229,7 @@ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){ for(p=pBtree->pBt->pCursor; p; p=p->pNext){ if( p->pgnoRoot==iRoot && p->pBtree!=pBtree - && 0==(p->pBtree->db->flags & SQLITE_ReadUncommitted) + && 0==(p->pBtree->db->flags & SQLITE_ReadUncommit) ){ return 1; } @@ -251,7 +251,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); - assert( !(p->db->flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 ); + assert( !(p->db->flags&SQLITE_ReadUncommit)||eLock==WRITE_LOCK||iTab==1 ); /* If requesting a write-lock, then the Btree must have an open write ** transaction on this file. And, obviously, for this to be so there @@ -329,7 +329,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ ** obtain a read-lock using this function. The only read-lock obtained ** by a connection in read-uncommitted mode is on the sqlite_master ** table, and that lock is obtained in BtreeBeginTrans(). */ - assert( 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK ); + assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK ); /* This function should only be called on a sharable b-tree after it ** has been determined that no other b-tree holds a conflicting lock. */ @@ -3021,7 +3021,7 @@ static int lockBtree(BtShared *pBt){ pageSize-usableSize); return rc; } - if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){ + if( (pBt->db->flags & SQLITE_WriteSchema)==0 && nPage>nPageFile ){ rc = SQLITE_CORRUPT_BKPT; goto page1_init_failed; } diff --git a/src/build.c b/src/build.c index c4bb0300a5..8a0624ea12 100644 --- a/src/build.c +++ b/src/build.c @@ -4185,7 +4185,9 @@ void sqlite3UniqueConstraint( assert( pIdx->aiColumn[j]>=0 ); zCol = pTab->aCol[pIdx->aiColumn[j]].zName; if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); - sqlite3XPrintf(&errMsg, "%s.%s", pTab->zName, zCol); + sqlite3StrAccumAppendAll(&errMsg, pTab->zName); + sqlite3StrAccumAppend(&errMsg, ".", 1); + sqlite3StrAccumAppendAll(&errMsg, zCol); } } zErr = sqlite3StrAccumFinish(&errMsg); diff --git a/src/legacy.c b/src/legacy.c index df8e2780fb..40959a8544 100644 --- a/src/legacy.c +++ b/src/legacy.c @@ -127,11 +127,8 @@ exec_out: rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && pzErrMsg ){ - int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db)); - *pzErrMsg = sqlite3Malloc(nErrMsg); - if( *pzErrMsg ){ - memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg); - }else{ + *pzErrMsg = sqlite3DbStrDup(0, sqlite3_errmsg(db)); + if( *pzErrMsg==0 ){ rc = SQLITE_NOMEM_BKPT; sqlite3Error(db, SQLITE_NOMEM); } diff --git a/src/main.c b/src/main.c index 6a48f93d17..f119426661 100644 --- a/src/main.c +++ b/src/main.c @@ -811,6 +811,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){ { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer }, { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension }, { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose }, + { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG }, }; unsigned int i; rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ @@ -2915,6 +2916,9 @@ static int openDatabase( #endif #if defined(SQLITE_ENABLE_FTS3_TOKENIZER) | SQLITE_Fts3Tokenizer +#endif +#if defined(SQLITE_ENABLE_QPSG) + | SQLITE_EnableQPSG #endif ; sqlite3HashInit(&db->aCollSeq); diff --git a/src/parse.y b/src/parse.y index 522c805482..91e498214c 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1375,8 +1375,7 @@ trigger_decl(A) ::= temp(T) TRIGGER ifnotexists(NOERR) nm(B) dbnm(Z) } %type trigger_time {int} -trigger_time(A) ::= BEFORE. { A = TK_BEFORE; } -trigger_time(A) ::= AFTER. { A = TK_AFTER; } +trigger_time(A) ::= BEFORE|AFTER(X). { A = @X; /*A-overwrites-X*/ } trigger_time(A) ::= INSTEAD OF. { A = TK_INSTEAD;} trigger_time(A) ::= . { A = TK_BEFORE; } diff --git a/src/pragma.h b/src/pragma.h index bf0f648f07..76e59cbc6b 100644 --- a/src/pragma.h +++ b/src/pragma.h @@ -458,7 +458,7 @@ static const PragmaName aPragmaName[] = { /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, - /* iArg: */ SQLITE_ReadUncommitted }, + /* iArg: */ SQLITE_ReadUncommit }, {/* zName: */ "recursive_triggers", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, @@ -610,7 +610,7 @@ static const PragmaName aPragmaName[] = { /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, - /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, + /* iArg: */ SQLITE_WriteSchema }, #endif }; /* Number of pragmas: 60 on by default, 74 total. */ diff --git a/src/prepare.c b/src/prepare.c index 74127bc76b..395b9e4045 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -25,7 +25,7 @@ static void corruptSchema( const char *zExtra /* Error information */ ){ sqlite3 *db = pData->db; - if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){ + if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){ char *z; if( zObj==0 ) zObj = "?"; z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); @@ -312,8 +312,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ rc = SQLITE_NOMEM_BKPT; sqlite3ResetAllSchemasOfConnection(db); } - if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){ - /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider + if( rc==SQLITE_OK || (db->flags&SQLITE_WriteSchema)){ + /* Black magic: If the SQLITE_WriteSchema flag is set, then consider ** the schema loaded, even if errors occurred. In this situation the ** current sqlite3_prepare() operation will fail, but the following one ** will attempt to compile the supplied statement against whatever subset @@ -561,7 +561,7 @@ static int sqlite3Prepare( if( rc ){ const char *zDb = db->aDb[i].zDbSName; sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); - testcase( db->flags & SQLITE_ReadUncommitted ); + testcase( db->flags & SQLITE_ReadUncommit ); goto end_prepare; } } diff --git a/src/shell.c b/src/shell.c index 490c922e60..ec255a6737 100644 --- a/src/shell.c +++ b/src/shell.c @@ -3822,6 +3822,7 @@ struct ImportCtx { int n; /* Number of bytes in z */ int nAlloc; /* Space allocated for z[] */ int nLine; /* Current line number */ + int bNotFirst; /* True if one or more bytes already read */ int cTerm; /* Character that terminated the most recent field */ int cColSep; /* The column separator character. (Usually ",") */ int cRowSep; /* The row separator character. (Usually "\n") */ @@ -3901,6 +3902,21 @@ static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){ pc = c; } }else{ + /* If this is the first field being parsed and it begins with the + ** UTF-8 BOM (0xEF BB BF) then skip the BOM */ + if( (c&0xff)==0xef && p->bNotFirst==0 ){ + import_append_char(p, c); + c = fgetc(p->in); + if( (c&0xff)==0xbb ){ + import_append_char(p, c); + c = fgetc(p->in); + if( (c&0xff)==0xbf ){ + p->bNotFirst = 1; + p->n = 0; + return csv_read_one_field(p); + } + } + } while( c!=EOF && c!=cSep && c!=rSep ){ import_append_char(p, c); c = fgetc(p->in); @@ -3912,6 +3928,7 @@ static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){ p->cTerm = c; } if( p->z ) p->z[p->n] = 0; + p->bNotFirst = 1; return p->z; } diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 1e4389215d..2f72f83f5d 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2007,6 +2007,17 @@ struct sqlite3_mem_methods { ** have been disabled - 0 if they are not disabled, 1 if they are. ** ** +**
SQLITE_DBCONFIG_ENABLE_QPSG
+**
The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates +** the [query planner stability guarantee] (QPSG). When the QPSG is active, +** a single SQL query statement will always use the same algorithm regardless +** of values of [bound parameters]. The QPSG disables some query optimizations +** that look at the values of bound parameters, which can make some queries +** slower. But the QPSG has the advantage of more predictable behavior. With +** the QPSG active, SQLite will always use the same query plan in the field as +** was used during testing in the lab. +**
+** ** */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ @@ -2016,6 +2027,7 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8cab60977c..ab6f10fd88 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1450,8 +1450,8 @@ struct sqlite3 { ** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC ** SQLITE_CacheSpill == PAGER_CACHE_SPILL */ -#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */ -#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */ +#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_MASTER */ +#define SQLITE_LegacyFileFmt 0x00000002 /* Create new databases in format 1 */ #define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */ #define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */ #define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */ @@ -1462,29 +1462,34 @@ struct sqlite3 { /* the count using a callback. */ #define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */ /* result set is empty */ -#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */ -#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */ -#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */ -#define SQLITE_VdbeAddopTrace 0x00001000 /* Trace sqlite3VdbeAddOp() calls */ -#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */ -#define SQLITE_ReadUncommitted 0x0004000 /* For shared-cache mode */ -#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ -#define SQLITE_RecoveryMode 0x00010000 /* Ignore schema errors */ -#define SQLITE_ReverseOrder 0x00020000 /* Reverse unordered SELECTs */ -#define SQLITE_RecTriggers 0x00040000 /* Enable recursive triggers */ -#define SQLITE_ForeignKeys 0x00080000 /* Enforce foreign key constraints */ -#define SQLITE_AutoIndex 0x00100000 /* Enable automatic indexes */ -#define SQLITE_PreferBuiltin 0x00200000 /* Preference to built-in funcs */ -#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */ -#define SQLITE_LoadExtFunc 0x00800000 /* Enable load_extension() SQL func */ -#define SQLITE_EnableTrigger 0x01000000 /* True to enable triggers */ -#define SQLITE_DeferFKs 0x02000000 /* Defer all FK constraints */ -#define SQLITE_QueryOnly 0x04000000 /* Disable database changes */ -#define SQLITE_VdbeEQP 0x08000000 /* Debug EXPLAIN QUERY PLAN */ -#define SQLITE_Vacuum 0x10000000 /* Currently in a VACUUM */ -#define SQLITE_CellSizeCk 0x20000000 /* Check btree cell sizes on load */ -#define SQLITE_Fts3Tokenizer 0x40000000 /* Enable fts3_tokenizer(2) */ -#define SQLITE_NoCkptOnClose 0x80000000 /* No checkpoint on close()/DETACH */ +#define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */ +#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */ +#define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */ +#define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */ +#define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */ +#define SQLITE_ForeignKeys 0x00004000 /* Enforce foreign key constraints */ +#define SQLITE_AutoIndex 0x00008000 /* Enable automatic indexes */ +#define SQLITE_LoadExtension 0x00010000 /* Enable load_extension */ +#define SQLITE_EnableTrigger 0x00020000 /* True to enable triggers */ +#define SQLITE_DeferFKs 0x00040000 /* Defer all FK constraints */ +#define SQLITE_QueryOnly 0x00080000 /* Disable database changes */ +#define SQLITE_CellSizeCk 0x00100000 /* Check btree cell sizes on load */ +#define SQLITE_Fts3Tokenizer 0x00200000 /* Enable fts3_tokenizer(2) */ +#define SQLITE_EnableQPSG 0x00400000 /* Query Planner Stability Guarantee */ +/* The next four values are not used by PRAGMAs or by sqlite3_dbconfig() and +** could be factored out into a separate bit vector of the sqlite3 object. */ +#define SQLITE_InternChanges 0x00800000 /* Uncommitted Hash table changes */ +#define SQLITE_LoadExtFunc 0x01000000 /* Enable load_extension() SQL func */ +#define SQLITE_PreferBuiltin 0x02000000 /* Preference to built-in funcs */ +#define SQLITE_Vacuum 0x04000000 /* Currently in a VACUUM */ +/* Flags used only if debugging */ +#ifdef SQLITE_DEBUG +#define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */ +#define SQLITE_VdbeListing 0x10000000 /* Debug listings of VDBE programs */ +#define SQLITE_VdbeTrace 0x20000000 /* True to trace VDBE execution */ +#define SQLITE_VdbeAddopTrace 0x40000000 /* Trace sqlite3VdbeAddOp() calls */ +#define SQLITE_VdbeEQP 0x80000000 /* Debug EXPLAIN QUERY PLAN */ +#endif /* diff --git a/src/tclsqlite.c b/src/tclsqlite.c index bb7c9e5b82..2ef9296096 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -1451,10 +1451,13 @@ struct DbEvalContext { const char *zSql; /* Remaining SQL to execute */ SqlPreparedStmt *pPreStmt; /* Current statement */ int nCol; /* Number of columns returned by pStmt */ + int evalFlags; /* Flags used */ Tcl_Obj *pArray; /* Name of array variable */ Tcl_Obj **apColName; /* Array of column names */ }; +#define SQLITE_EVAL_WITHOUTNULLS 0x00001 /* Unset array(*) for NULL */ + /* ** Release any cache of column names currently held as part of ** the DbEvalContext structure passed as the first argument. @@ -1487,7 +1490,8 @@ static void dbEvalInit( DbEvalContext *p, /* Pointer to structure to initialize */ SqliteDb *pDb, /* Database handle */ Tcl_Obj *pSql, /* Object containing SQL script */ - Tcl_Obj *pArray /* Name of Tcl array to set (*) element of */ + Tcl_Obj *pArray, /* Name of Tcl array to set (*) element of */ + int evalFlags /* Flags controlling evaluation */ ){ memset(p, 0, sizeof(DbEvalContext)); p->pDb = pDb; @@ -1498,6 +1502,7 @@ static void dbEvalInit( p->pArray = pArray; Tcl_IncrRefCount(pArray); } + p->evalFlags = evalFlags; } /* @@ -1730,11 +1735,15 @@ static int SQLITE_TCLAPI DbEvalNextCmd( Tcl_Obj **apColName; dbEvalRowInfo(p, &nCol, &apColName); for(i=0; ievalFlags & SQLITE_EVAL_WITHOUTNULLS)!=0 + && sqlite3_column_type(p->pPreStmt->pStmt, i)==SQLITE_NULL + ){ + Tcl_UnsetVar2(interp, Tcl_GetString(pArray), + Tcl_GetString(apColName[i]), 0); }else{ - Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0); + Tcl_ObjSetVar2(interp, pArray, apColName[i], dbEvalColumnValue(p,i), 0); } } @@ -2447,7 +2456,7 @@ static int SQLITE_TCLAPI DbObjCmd( return TCL_ERROR; } - dbEvalInit(&sEval, pDb, objv[2], 0); + dbEvalInit(&sEval, pDb, objv[2], 0, 0); rc = dbEvalStep(&sEval); if( choice==DB_ONECOLUMN ){ if( rc==TCL_OK ){ @@ -2468,7 +2477,7 @@ static int SQLITE_TCLAPI DbObjCmd( } /* - ** $db eval $sql ?array? ?{ ...code... }? + ** $db eval ?options? $sql ?array? ?{ ...code... }? ** ** The SQL statement in $sql is evaluated. For each row, the values are ** placed in elements of the array named "array" and ...code... is executed. @@ -2477,8 +2486,22 @@ static int SQLITE_TCLAPI DbObjCmd( ** that have the same name as the fields extracted by the query. */ case DB_EVAL: { + int evalFlags = 0; + const char *zOpt; + while( objc>3 && (zOpt = Tcl_GetString(objv[2]))!=0 && zOpt[0]=='-' ){ + if( strcmp(zOpt, "-withoutnulls")==0 ){ + evalFlags |= SQLITE_EVAL_WITHOUTNULLS; + } + else{ + Tcl_AppendResult(interp, "unknown option: \"", zOpt, "\"", (void*)0); + return TCL_ERROR; + } + objc--; + objv++; + } if( objc<3 || objc>5 ){ - Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?"); + Tcl_WrongNumArgs(interp, 2, objv, + "?OPTIONS? SQL ?ARRAY-NAME? ?SCRIPT?"); return TCL_ERROR; } @@ -2486,7 +2509,7 @@ static int SQLITE_TCLAPI DbObjCmd( DbEvalContext sEval; Tcl_Obj *pRet = Tcl_NewObj(); Tcl_IncrRefCount(pRet); - dbEvalInit(&sEval, pDb, objv[2], 0); + dbEvalInit(&sEval, pDb, objv[2], 0, 0); while( TCL_OK==(rc = dbEvalStep(&sEval)) ){ int i; int nCol; @@ -2507,14 +2530,14 @@ static int SQLITE_TCLAPI DbObjCmd( Tcl_Obj *pArray = 0; Tcl_Obj *pScript; - if( objc==5 && *(char *)Tcl_GetString(objv[3]) ){ + if( objc>=5 && *(char *)Tcl_GetString(objv[3]) ){ pArray = objv[3]; } pScript = objv[objc-1]; Tcl_IncrRefCount(pScript); p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext)); - dbEvalInit(p, pDb, objv[2], pArray); + dbEvalInit(p, pDb, objv[2], pArray, evalFlags); cd2[0] = (void *)p; cd2[1] = (void *)pScript; diff --git a/src/test1.c b/src/test1.c index 87b255c9e9..eaafd87755 100644 --- a/src/test1.c +++ b/src/test1.c @@ -7317,6 +7317,7 @@ static int SQLITE_TCLAPI test_sqlite3_db_config( { "FTS3_TOKENIZER", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER }, { "LOAD_EXTENSION", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION }, { "NO_CKPT_ON_CLOSE",SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE }, + { "QPSG", SQLITE_DBCONFIG_ENABLE_QPSG }, }; int i; int v; diff --git a/src/vdbe.c b/src/vdbe.c index 4a412b4e50..ecdd92be9c 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -6571,7 +6571,7 @@ case OP_Expire: { */ case OP_TableLock: { u8 isWriteLock = (u8)pOp->p3; - if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){ + if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){ int p1 = pOp->p1; assert( p1>=0 && p1nDb ); assert( DbMaskTest(p->btreeMask, p1) ); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 5dfbe4f5bd..aabc13275a 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -4542,6 +4542,7 @@ sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff){ assert( iVar>0 ); if( v ){ Mem *pMem = &v->aVar[iVar-1]; + assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); if( 0==(pMem->flags & MEM_Null) ){ sqlite3_value *pRet = sqlite3ValueNew(v->db); if( pRet ){ @@ -4561,6 +4562,7 @@ sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff){ */ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ assert( iVar>0 ); + assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); if( iVar>=32 ){ v->expmask |= 0x80000000; }else{ diff --git a/src/vdbemem.c b/src/vdbemem.c index 88c57f1aba..41bb9b5c43 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -1482,14 +1482,13 @@ static int stat4ValueFromExpr( /* Skip over any TK_COLLATE nodes */ pExpr = sqlite3ExprSkipCollate(pExpr); + assert( pExpr==0 || pExpr->op!=TK_REGISTER || pExpr->op2!=TK_VARIABLE ); 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) - ){ + }else if( pExpr->op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *v; int iBindVar = pExpr->iColumn; sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar); @@ -1497,9 +1496,7 @@ static int stat4ValueFromExpr( pVal = valueNew(db, pAlloc); if( pVal ){ rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]); - if( rc==SQLITE_OK ){ - sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); - } + sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); pVal->db = pParse->db; } } diff --git a/src/whereexpr.c b/src/whereexpr.c index 53bc3dba12..633fdaff39 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -216,7 +216,7 @@ static int isLikeOrGlob( pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr); op = pRight->op; - if( op==TK_VARIABLE ){ + if( op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *pReprepare = pParse->pReprepare; int iCol = pRight->iColumn; pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB); @@ -1178,6 +1178,9 @@ static void exprAnalyze( Expr *pNewExpr; pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 0, sqlite3ExprDup(db, pRight, 0)); + if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){ + ExprSetProperty(pNewExpr, EP_FromJoin); + } idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); pNewTerm = &pWC->a[idxNew]; diff --git a/test/analyze3.test b/test/analyze3.test index 2fb558d16a..3e721a0877 100644 --- a/test/analyze3.test +++ b/test/analyze3.test @@ -123,6 +123,36 @@ do_eqp_test analyze3-1.1.3 { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 } {0 0 0 {SCAN TABLE t1}} +# 2017-06-26: Verify that the SQLITE_DBCONFIG_ENABLE_QPSG setting disables +# the use of bound parameters by STAT4 +# +db cache flush +unset -nocomplain l +unset -nocomplain u +do_eqp_test analyze3-1.1.3.100 { + SELECT sum(y) FROM t1 WHERE x>$l AND x<$u +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x$l AND x<$u +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x$l AND x<$u +} {0 0 0 {SCAN TABLE t1}} +db cache flush +sqlite3_db_config db ENABLE_QPSG 1 +do_eqp_test analyze3-1.1.3.103 { + SELECT sum(y) FROM t1 WHERE x>$l AND x<$u +} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x$l AND x<$u +} {0 0 0 {SCAN TABLE t1}} + do_test analyze3-1.1.4 { sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } } {199 0 14850} diff --git a/test/fts3join.test b/test/fts3join.test index 0fb8c62022..6bebd33d6a 100644 --- a/test/fts3join.test +++ b/test/fts3join.test @@ -61,4 +61,24 @@ do_catchsql_test 2.5 { SELECT * FROM ft3, ft2 WHERE y MATCH x AND x MATCH y; } {1 {unable to use function MATCH in the requested context}} +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE vt USING fts3(x); + INSERT INTO vt VALUES('abc'); + INSERT INTO vt VALUES('xyz'); + + CREATE TABLE tt(a INTEGER PRIMARY KEY); + INSERT INTO tt VALUES(1), (2); +} + +do_execsql_test 3.1 { + SELECT * FROM tt LEFT JOIN ( + SELECT rowid AS rrr, * FROM vt WHERE vt MATCH 'abc' + ) ON tt.a = rrr +} {1 1 abc 2 {} {}} + +do_execsql_test 3.2 { + SELECT * FROM tt LEFT JOIN vt ON (vt MATCH 'abc') +} {1 abc 2 abc} + + finish_test diff --git a/test/like.test b/test/like.test index 8082b35123..e07b4e0603 100644 --- a/test/like.test +++ b/test/like.test @@ -160,6 +160,7 @@ ifcapable !like_opt { # proc queryplan {sql} { set ::sqlite_sort_count 0 + db cache flush set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x @@ -196,7 +197,7 @@ do_test like-3.2 { # With an index on t1.x and case sensitivity on, optimize completely. # -do_test like-3.3 { +do_test like-3.3.100 { set sqlite_like_count 0 execsql { PRAGMA case_sensitive_like=on; @@ -206,10 +207,51 @@ do_test like-3.3 { SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1; } } {abc abcd nosort {} i1} -do_test like-3.4 { +do_test like-3.3.101 { set sqlite_like_count } 0 +# The like optimization works even when the pattern is a bound parameter +# +do_test like-3.3.102 { + set sqlite_like_count 0 + unset -nocomplain ::likepat + set ::likepat abc% + queryplan { + SELECT x FROM t1 WHERE x LIKE $::likepat ORDER BY 1; + } +} {abc abcd nosort {} i1} +do_test like-3.3.103 { + set sqlite_like_count +} 0 + +# Except, the like optimization does not work for bound parameters if +# the query planner stability guarantee is active. +# +do_test like-3.3.104 { + set sqlite_like_count 0 + sqlite3_db_config db QPSG 1 + queryplan { + SELECT x FROM t1 WHERE x LIKE $::likepat ORDER BY 1; + } +} {abc abcd nosort {} i1} +do_test like-3.3.105 { + set sqlite_like_count +} 12 + +# The query planner stability guarantee does not disrupt explicit patterns +# +do_test like-3.3.105 { + set sqlite_like_count 0 + queryplan { + SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1; + } +} {abc abcd nosort {} i1} +do_test like-3.3.106 { + set sqlite_like_count +} 0 +sqlite3_db_config db QPSG 0 + # The LIKE optimization still works when the RHS is a string with no # wildcard. Ticket [e090183531fc2747] # diff --git a/test/shell1.test b/test/shell1.test index ac3403f810..4a4bbd5cf2 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -558,6 +558,7 @@ do_test shell1-3.20.4 { catchcmd "test.db" ".restore FOO BAR BAD" } {1 {Usage: .restore ?DB? FILE}} +ifcapable vtab { # .schema ?TABLE? Show the CREATE statements # If TABLE specified, only show tables matching # LIKE pattern TABLE. @@ -583,6 +584,7 @@ do_test shell1-3.21.4 { 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 column separator used by output and .import do_test shell1-3.22.1 { diff --git a/test/shell5.test b/test/shell5.test index bb2511a525..62b91ffa85 100644 --- a/test/shell5.test +++ b/test/shell5.test @@ -184,6 +184,36 @@ do_test shell5-1.4.10.2 { catchcmd "test.db" {SELECT b FROM t1 WHERE a='7';} } {0 {Now is the time for all good men to come to the aid of their country.}} +# import file with 2 rows, 2 columns and an initial BOM +# +do_test shell5-1.4.11 { + set in [open shell5.csv wb] + puts $in "\xef\xbb\xbf2|3" + puts $in "4|5" + close $in + set res [catchcmd "test.db" {CREATE TABLE t2(x INT, y INT); +.import shell5.csv t2 +.mode quote +.header on +SELECT * FROM t2;}] + string map {\n | \n\r |} $res +} {0 {'x','y'|2,3|4,5}} + +# import file with 2 rows, 2 columns or text with an initial BOM +# +do_test shell5-1.4.12 { + set in [open shell5.csv wb] + puts $in "\xef\xbb\xbf\"two\"|3" + puts $in "4|5" + close $in + set res [catchcmd "test.db" {DELETE FROM t2; +.import shell5.csv t2 +.mode quote +.header on +SELECT * FROM t2;}] + string map {\n | \n\r |} $res +} {0 {'x','y'|'two',3|4,5}} + # check importing very long field do_test shell5-1.5.1 { set str [string repeat X 999] @@ -210,7 +240,8 @@ do_test shell5-1.6.1 { set in [open shell5.csv w] puts $in $data close $in - set res [catchcmd "test.db" {.import shell5.csv t2 + set res [catchcmd "test.db" {DROP TABLE IF EXISTS t2; +.import shell5.csv t2 SELECT COUNT(*) FROM t2;}] } {0 1} diff --git a/test/tclsqlite.test b/test/tclsqlite.test index bdb0fc56d1..1b95a45a5c 100644 --- a/test/tclsqlite.test +++ b/test/tclsqlite.test @@ -113,7 +113,7 @@ ifcapable {complete} { do_test tcl-1.14 { set v [catch {db eval} msg] lappend v $msg -} {1 {wrong # args: should be "db eval SQL ?ARRAY-NAME? ?SCRIPT?"}} +} {1 {wrong # args: should be "db eval ?OPTIONS? SQL ?ARRAY-NAME? ?SCRIPT?"}} do_test tcl-1.15 { set v [catch {db function} msg] lappend v $msg @@ -665,6 +665,44 @@ do_test tcl-15.5 { } {0} +# 2017-06-26: The --withoutnulls flag to "db eval". +# +# In the "db eval --withoutnulls SQL ARRAY" form, NULL results cause the +# corresponding array entry to be unset. The default behavior (without +# the -withoutnulls flags) is for the corresponding array value to get +# the [db nullvalue] string. +# +catch {db close} +forcedelete test.db +sqlite3 db test.db +do_execsql_test tcl-16.100 { + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1,2),(2,NULL),(3,'xyz'); +} +do_test tcl-16.101 { + set res {} + unset -nocomplain x + db eval {SELECT * FROM t1} x { + lappend res $x(a) [array names x] + } + set res +} {1 {a b *} 2 {a b *} 3 {a b *}} +do_test tcl-16.102 { + set res [catch { + db eval -unknown {SELECT * FROM t1} x { + lappend res $x(a) [array names x] + } + } rc] + lappend res $rc +} {1 {unknown option: "-unknown"}} +do_test tcl-16.103 { + set res {} + unset -nocomplain x + db eval -withoutnulls {SELECT * FROM t1} x { + lappend res $x(a) [array names x] + } + set res +} {1 {a b *} 2 {a *} 3 {a b *}} diff --git a/tool/lemon.c b/tool/lemon.c index 37d2c781d9..fe0fb4c615 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -3297,7 +3297,14 @@ PRIVATE int compute_action(struct lemon *lemp, struct action *ap) int act; switch( ap->type ){ case SHIFT: act = ap->x.stp->statenum; break; - case SHIFTREDUCE: act = ap->x.rp->iRule + lemp->nstate; break; + case SHIFTREDUCE: { + act = ap->x.rp->iRule + lemp->nstate; + /* Since a SHIFT is inherient after a prior REDUCE, convert any + ** SHIFTREDUCE action with a nonterminal on the LHS into a simple + ** REDUCE action: */ + if( ap->sp->index>=lemp->nterminal ) act += lemp->nrule; + break; + } case REDUCE: act = ap->x.rp->iRule + lemp->nstate+lemp->nrule; break; case ERROR: act = lemp->nstate + lemp->nrule*2; break; case ACCEPT: act = lemp->nstate + lemp->nrule*2 + 1; break; @@ -4415,7 +4422,7 @@ void ReportTable( ** sequentually beginning with 0. */ for(rp=lemp->rule; rp; rp=rp->next){ - fprintf(out," { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++; + fprintf(out," { %d, %d },\n",rp->lhs->index,-rp->nrhs); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); diff --git a/tool/lempar.c b/tool/lempar.c index 21ed9d79ab..4a98d23700 100644 --- a/tool/lempar.c +++ b/tool/lempar.c @@ -221,6 +221,7 @@ struct yyParser { yyStackEntry yystk0; /* First stack entry */ #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ + yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif }; typedef struct yyParser yyParser; @@ -338,6 +339,7 @@ void ParseInit(void *yypParser){ pParser->yytos = pParser->yystack; pParser->yystack[0].stateno = 0; pParser->yystack[0].major = 0; + pParser->yystackEnd = &pParser->yystack[YYSTACKDEPTH-1]; } #ifndef Parse_ENGINEALWAYSONSTACK @@ -607,7 +609,7 @@ static void yy_shift( } #endif #if YYSTACKDEPTH>0 - if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){ + if( yypParser->yytos>yypParser->yystackEnd ){ yypParser->yytos--; yyStackOverflow(yypParser); return; @@ -635,8 +637,8 @@ static void yy_shift( ** is used during the reduce. */ static const struct { - YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ - unsigned char nrhs; /* Number of right-hand side symbols in the rule */ + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ + signed char nrhs; /* Negative of the number of RHS symbols in the rule */ } yyRuleInfo[] = { %% }; @@ -661,7 +663,7 @@ static void yy_reduce( if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ yysize = yyRuleInfo[yyruleno].nrhs; fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, - yyRuleName[yyruleno], yymsp[-yysize].stateno); + yyRuleName[yyruleno], yymsp[yysize].stateno); } #endif /* NDEBUG */ @@ -676,7 +678,7 @@ static void yy_reduce( } #endif #if YYSTACKDEPTH>0 - if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){ + if( yypParser->yytos>=yypParser->yystackEnd ){ yyStackOverflow(yypParser); return; } @@ -707,20 +709,24 @@ static void yy_reduce( assert( yyrulenoYY_MAX_SHIFT ){ - yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - } - yymsp -= yysize-1; + yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto); + + /* There are no SHIFTREDUCE actions on nonterminals because the table + ** generator has simplified them to pure REDUCE actions. */ + assert( !(yyact>YY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) ); + + /* It is not possible for a REDUCE to be followed by an error */ + assert( yyact!=YY_ERROR_ACTION ); + + if( yyact==YY_ACCEPT_ACTION ){ + yypParser->yytos += yysize; + yy_accept(yypParser); + }else{ + yymsp += yysize+1; yypParser->yytos = yymsp; yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yyTraceShift(yypParser, yyact); - }else{ - assert( yyact == YY_ACCEPT_ACTION ); - yypParser->yytos -= yysize; - yy_accept(yypParser); } } diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index 8eb8250535..c7001dc339 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -120,12 +120,12 @@ set pragma_def { NAME: writable_schema TYPE: FLAG - ARG: SQLITE_WriteSchema|SQLITE_RecoveryMode + ARG: SQLITE_WriteSchema IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: read_uncommitted TYPE: FLAG - ARG: SQLITE_ReadUncommitted + ARG: SQLITE_ReadUncommit IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: recursive_triggers